diff --git a/Mage.Client/pom.xml b/Mage.Client/pom.xml index 3dbe81fc391..8d242942186 100644 --- a/Mage.Client/pom.xml +++ b/Mage.Client/pom.xml @@ -63,13 +63,6 @@ 0.9.1 - - - - com.mortennobel - java-image-scaling - 0.8.6 - diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java index d5e8afa1a7e..4414f5960aa 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java @@ -110,7 +110,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { // deck legality cards selection Arrays.stream(deckLegalityDisplay.getComponents()) - .filter(c -> c instanceof LegalityLabel) + .filter(LegalityLabel.class::isInstance) .forEach(c -> { c.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { diff --git a/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.form b/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.form index 7c59eafa7cd..b033f0a9bf9 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.form @@ -9,9 +9,9 @@ - + - + @@ -71,8 +71,8 @@ - - + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.java b/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.java index 2102682b5ae..2f90a668379 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.java @@ -116,15 +116,15 @@ public class RandomPacksSelectorDialog extends javax.swing.JDialog { setTitle("Random Booster Draft Packs Selector"); setModal(true); setModalExclusionType(java.awt.Dialog.ModalExclusionType.APPLICATION_EXCLUDE); - setPreferredSize(new java.awt.Dimension(600, 450)); - setResizable(false); + setPreferredSize(new java.awt.Dimension(875, 475)); + setResizable(true); addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { formWindowClosing(evt); } }); - pnlPacks.setLayout(new java.awt.GridLayout(12, 13)); + pnlPacks.setLayout(new java.awt.GridLayout(14, 14)); pnlSelect.setLayout(new javax.swing.BoxLayout(pnlSelect, javax.swing.BoxLayout.LINE_AXIS)); diff --git a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java index 59fcb99ce2b..1b84aa1c7bb 100644 --- a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java +++ b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java @@ -466,50 +466,50 @@ public class CallbackClientImpl implements CallbackClient { switch (usedPanel.getChatType()) { case GAME: usedPanel.receiveMessage("", new StringBuilder() - .append("HOTKEYS:") - .append("
Turn mousewheel up (ALT-e) - enlarge image of card the mousepointer hovers over") - .append("
Turn mousewheel down (ALT-s) - enlarge original/alternate image of card the mousepointer hovers over") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_CONFIRM))) - .append(" - Confirm \"Ok\", \"Yes\" or \"Done\" button") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_NEXT_TURN))) - .append(" - Skip current turn but stop on declare attackers/blockers and something on the stack") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_END_STEP))) - .append(" - Skip to next end step but stop on declare attackers/blockers and something on the stack") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_SKIP_STEP))) - .append(" - Skip current turn but stop on declare attackers/blockers") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_MAIN_STEP))) - .append(" - Skip to next main phase but stop on declare attackers/blockers and something on the stack") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_YOUR_TURN))) - .append(" - Skip everything until your next turn") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_PRIOR_END))) - .append(" - Skip everything until the end step just prior to your turn") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_CANCEL_SKIP))) - .append(" - Undo F4/F5/F7/F9/F11") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_SWITCH_CHAT))) - .append(" - Switch in/out to chat text field") - /* + .append("HOTKEYS:") + .append("
Turn mousewheel up (ALT-e) - enlarge image of card the mousepointer hovers over") + .append("
Turn mousewheel down (ALT-s) - enlarge original/alternate image of card the mousepointer hovers over") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_CONFIRM))) + .append(" - Confirm \"Ok\", \"Yes\" or \"Done\" button") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_NEXT_TURN))) + .append(" - Skip current turn but stop on declare attackers/blockers and something on the stack") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_END_STEP))) + .append(" - Skip to next end step but stop on declare attackers/blockers and something on the stack") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_SKIP_STEP))) + .append(" - Skip current turn but stop on declare attackers/blockers") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_MAIN_STEP))) + .append(" - Skip to next main phase but stop on declare attackers/blockers and something on the stack") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_YOUR_TURN))) + .append(" - Skip everything until your next turn") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_PRIOR_END))) + .append(" - Skip everything until the end step just prior to your turn") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_CANCEL_SKIP))) + .append(" - Undo F4/F5/F7/F9/F11") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_SWITCH_CHAT))) + .append(" - Switch in/out to chat text field") + /* .append("
") .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_TOGGLE_MACRO))) .append(" - Toggle recording a sequence of actions to repeat. Will not pause if interrupted and can fail if a selected card changes such as when scrying top card to bottom.") .append("
").append(System.getProperty("os.name").contains("Mac OS X") ? "Cmd" : "Ctrl").append(" + click - Hold priority while casting a spell or activating an ability") - */ - .append("
") - .append("
") - .append("CHAT COMMANDS:") - .append("
").append("/h username - show player's stats (history)") - .append("
").append("/w username message - send private message to player (whisper)") - .append("
").append("/pings - show players and watchers ping") - .append("
").append("/fix - fix freezed game") - .toString(), + */ + .append("
") + .append("
") + .append("CHAT COMMANDS:") + .append("
").append("/h username - show player's stats (history)") + .append("
").append("/w username message - send private message to player (whisper)") + .append("
").append("/pings - show players and watchers ping") + .append("
").append("/fix - fix frozen game") + .toString(), null, null, MessageType.USER_INFO, ChatMessage.MessageColor.BLUE); break; case TOURNAMENT: @@ -519,10 +519,10 @@ public class CallbackClientImpl implements CallbackClient { case TABLES: String serverAddress = SessionHandler.getSession().getServerHostname().orElse(""); usedPanel.receiveMessage("", new StringBuilder("Download card images by using the \"Images\" main menu.") - .append("
Download icons and symbols by using the \"Symbols\" main menu.") - .append("
\\list - show a list of available chat commands.") - .append("
").append(IgnoreList.usage(serverAddress)) - .append("
Type \\w yourUserName profanity 0 (or 1 or 2) to turn off/on the profanity filter").toString(), + .append("
Download icons and symbols by using the \"Symbols\" main menu.") + .append("
\\list - show a list of available chat commands.") + .append("
").append(IgnoreList.usage(serverAddress)) + .append("
Type \\w yourUserName profanity 0 (or 1 or 2) to turn off/on the profanity filter").toString(), null, null, MessageType.USER_INFO, ChatMessage.MessageColor.BLUE); break; default: @@ -628,7 +628,7 @@ public class CallbackClientImpl implements CallbackClient { logger.fatal("Client error\n", ex); String errorMessage = ex.getMessage(); if (errorMessage == null || errorMessage.isEmpty() || errorMessage.equals("Null")) { - errorMessage = ex.getClass().getSimpleName() + " - look server or client logs for more details"; + errorMessage = ex.getClass().getSimpleName() + " - look at server or client logs for more details"; } frame.showError("Server's error: " + errorMessage); } diff --git a/Mage.Client/src/main/java/mage/client/util/TransformedImageCache.java b/Mage.Client/src/main/java/mage/client/util/TransformedImageCache.java index eee76a8d0b5..250e4ac0298 100644 --- a/Mage.Client/src/main/java/mage/client/util/TransformedImageCache.java +++ b/Mage.Client/src/main/java/mage/client/util/TransformedImageCache.java @@ -3,8 +3,6 @@ package mage.client.util; import java.awt.*; import java.awt.image.BufferedImage; -import com.mortennobel.imagescaling.ResampleOp; - /** * * @author user @@ -95,9 +93,12 @@ public final class TransformedImageCache { } private static BufferedImage resizeImage(BufferedImage original, int width, int height) { - ResampleOp resampleOp = new ResampleOp(width, height); - BufferedImage image = resampleOp.filter(original, null); - return image; + Image scaled = original.getScaledInstance(width, height, Image.SCALE_SMOOTH); + BufferedImage output = new BufferedImage(width, height, original.getType()); + Graphics2D graphics = output.createGraphics(); + graphics.drawImage(scaled, 0, 0, null); + graphics.dispose(); + return output; } public static BufferedImage getResizedImage(BufferedImage image, int width, int height) { diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ModernSplitCardRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/ModernSplitCardRenderer.java index 1d56ecde616..6ef22fdd34a 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/ModernSplitCardRenderer.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/ModernSplitCardRenderer.java @@ -49,8 +49,8 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { rightHalf.manaCostString = ManaSymbols.getClearManaCost(cardView.getRightSplitCostsStr()); leftHalf.manaCostString = ManaSymbols.getClearManaCost(cardView.getLeftSplitCostsStr()); - rightHalf.color = getColorFromManaCostHack(cardView.getRightSplitCostsStr()); - leftHalf.color = getColorFromManaCostHack(cardView.getLeftSplitCostsStr()); + rightHalf.color = new ObjectColor(cardView.getRightSplitCostsStr()); + leftHalf.color = new ObjectColor(cardView.getLeftSplitCostsStr()); parseRules(view.getRightSplitRules(), rightHalf.keywords, rightHalf.rules); parseRules(view.getLeftSplitRules(), leftHalf.keywords, leftHalf.rules); @@ -123,24 +123,6 @@ public class ModernSplitCardRenderer extends ModernCardRenderer { } } - // Ugly hack used here because the card database doesn't actually store color - // for each half of split cards separately. - private ObjectColor getColorFromManaCostHack(String costs) { - ObjectColor c = new ObjectColor(); - if (costs.contains("W")) { - c.setWhite(true); - } else if (costs.contains("U")) { - c.setBlue(true); - } else if (costs.contains("B")) { - c.setBlack(true); - } else if (costs.contains("R")) { - c.setRed(true); - } else if (costs.contains("G")) { - c.setGreen(true); - } - return c; - } - @Override protected void drawBackground(Graphics2D g) { if (cardView.isFaceDown()) { diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSymbols.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSymbols.java index 963c0ac1d2c..6e4dc613b92 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSymbols.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/GathererSymbols.java @@ -28,6 +28,7 @@ public class GathererSymbols implements Iterable { private static final String[] symbols = {"W", "U", "B", "R", "G", "W/U", "U/B", "B/R", "R/G", "G/W", "W/B", "U/R", "B/G", "R/W", "G/U", + "W/U/P", "U/B/P", "B/R/P", "R/G/P", "G/W/P", "W/B/P", "U/R/P", "B/G/P", "R/W/P", "G/U/P", "2/W", "2/U", "2/B", "2/R", "2/G", "WP", "UP", "BP", "RP", "GP", "X", "S", "T", "Q", "C", "E"}; diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java index e89d19462c5..559a1cffade 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java @@ -189,7 +189,7 @@ public class ScryfallImageSupportCards { add("ALA"); // Shards of Alara add("PALA"); // Shards of Alara Promos add("DD2"); // Duel Decks: Jace vs. Chandra - add("PWP09"); // Wizards Play Network 2009 + add("PW09"); // Wizards Play Network 2009 add("PDTP"); // Duels of the Planeswalkers 2009 Promos //add("PMPS09"); // Magic Premiere Shop 2009 add("P09"); // Magic Player Rewards 2009 @@ -209,7 +209,7 @@ public class ScryfallImageSupportCards { add("DDD"); // Duel Decks: Garruk vs. Liliana add("H09"); // Premium Deck Series: Slivers add("PDP10"); // Duels of the Planeswalkers 2010 Promos - add("PWP10"); // Wizards Play Network 2010 + add("PW10"); // Wizards Play Network 2010 //add("PMPS10"); // Magic Premiere Shop 2010 add("P10"); // Magic Player Rewards 2010 add("G10"); // Judge Gift Cards 2010 @@ -230,7 +230,7 @@ public class ScryfallImageSupportCards { add("TD0"); // Magic Online Theme Decks add("PD2"); // Premium Deck Series: Fire and Lightning //add("PMPS11"); // Magic Premiere Shop 2011 - add("PWP11"); // Wizards Play Network 2011 + add("PW11"); // Wizards Play Network 2011 //add("PS11"); // Salvat 2011 add("P11"); // Magic Player Rewards 2011 add("G11"); // Judge Gift Cards 2011 @@ -252,7 +252,7 @@ public class ScryfallImageSupportCards { add("ISD"); // Innistrad add("PD3"); // Premium Deck Series: Graveborn add("PIDW"); // IDW Comics 2012 - add("PWP12"); // Wizards Play Network 2012 + add("PW12"); // Wizards Play Network 2012 add("PDP12"); // Duels of the Planeswalkers 2012 Promos add("J12"); // Judge Gift Cards 2012 add("F12"); // Friday Night Magic 2012 @@ -503,6 +503,14 @@ public class ScryfallImageSupportCards { add("MIC"); // Midnight Hunt Commander add("VOW"); // Innistrad: Crimson Vow add("VOC"); // Crimson Vow Commander + add("Y22"); // Alchemy: Innistrad + add("DBL"); // Innistrad: Double Feature + add("NEO"); // Kamigawa: Neon Dynasty + add("NEC"); // Neon Dynasty Commander + add("SNC"); // Streets of New Capenna + add("NCC"); // New Capenna Commander + add("SLX"); // Universes Within + add("CLB"); // Commander Legends: Battle for Baldur's Gate } }; diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java index 313543dbafa..ee28a896c64 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java @@ -712,6 +712,136 @@ public class ScryfallImageSupportTokens { put("VOW/Zombie/1", "https://api.scryfall.com/cards/tvow/8/en?format=image"); // 2/2 put("VOW/Zombie/2", "https://api.scryfall.com/cards/tvow/5/en?format=image"); // */* + // UMA + put ("UMA/Citizen", "https://api.scryfall.com/cards/tuma/1/en?format=image"); + put ("UMA/Drake", "https://api.scryfall.com/cards/tuma/3/en?format=image"); + put ("UMA/Elemental/1", "https://api.scryfall.com/cards/tuma/13/en?format=image"); // green + put ("UMA/Elemental/2", "https://api.scryfall.com/cards/tuma/9/en?format=image"); + put ("UMA/Elemental/3", "https://api.scryfall.com/cards/tuma/10/en?format=image"); + put ("UMA/Faerie Rogue", "https://api.scryfall.com/cards/tuma/5/en?format=image"); + put ("UMA/Homunculus", "https://api.scryfall.com/cards/tuma/4/en?format=image"); + put ("UMA/Marit Lage", "https://api.scryfall.com/cards/tuma/6/en?format=image"); + put ("UMA/Ooze", "https://api.scryfall.com/cards/tuma/14/en?format=image"); + put ("UMA/Soldier", "https://api.scryfall.com/cards/tuma/11/en?format=image"); + put ("UMA/Spark Elemental", "https://api.scryfall.com/cards/tuma/12/en?format=image"); + put ("UMA/Spider", "https://api.scryfall.com/cards/tuma/15/en?format=image"); + put ("UMA/Spirit/1", "https://api.scryfall.com/cards/tuma/2/en?format=image"); // white + put ("UMA/Spirit/2", "https://api.scryfall.com/cards/tuma/16/en?format=image"); // white, black + put ("UMA/Wurm", "https://api.scryfall.com/cards/tuma/7/en?format=image"); + put ("UMA/Zombie", "https://api.scryfall.com/cards/tuma/8/en?format=image"); + + // MMA + put ("MMA/Bat", "https://api.scryfall.com/cards/tmma/5/en?format=image"); + put ("MMA/Dragon", "https://api.scryfall.com/cards/tmma/9/en?format=image"); + put ("MMA/Elemental", "https://api.scryfall.com/cards/tmma/11/en?format=image"); + put ("MMA/Emblem Elspeth, Knight Errant", "https://api.scryfall.com/cards/tmma/16/en?format=image"); + put ("MMA/Faerie Rogue", "https://api.scryfall.com/cards/tmma/14/en?format=image"); + put ("MMA/Giant Warrior", "https://api.scryfall.com/cards/tmma/1/en?format=image"); + put ("MMA/Goblin", "https://api.scryfall.com/cards/tmma/10/en?format=image"); + put ("MMA/Goblin Rogue", "https://api.scryfall.com/cards/tmma/6/en?format=image"); + put ("MMA/Illusion", "https://api.scryfall.com/cards/tmma/4/en?format=image"); + put ("MMA/Kithkin Soldier", "https://api.scryfall.com/cards/tmma/2/en?format=image"); + put ("MMA/Saproling", "https://api.scryfall.com/cards/tmma/12/en?format=image"); + put ("MMA/Soldier", "https://api.scryfall.com/cards/tmma/3/en?format=image"); + put ("MMA/Spider", "https://api.scryfall.com/cards/tmma/7/en?format=image"); + put ("MMA/Treefolk Shaman", "https://api.scryfall.com/cards/tmma/13/en?format=image"); + put ("MMA/Worm", "https://api.scryfall.com/cards/tmma/15/en?format=image"); + put ("MMA/Zombie", "https://api.scryfall.com/cards/tmma/8/en?format=image"); + + // SHM + put ("SHM/Elemental/1", "https://api.scryfall.com/cards/tshm/9/en?format=image"); // black, red + put ("SHM/Elemental/2", "https://api.scryfall.com/cards/tshm/4/en?format=image"); // haste + put ("SHM/Elf Warrior/1", "https://api.scryfall.com/cards/tshm/5/en?format=image"); // green + put ("SHM/Elf Warrior/2", "https://api.scryfall.com/cards/tshm/12/en?format=image"); // white, green + put ("SHM/Faerie Rogue", "https://api.scryfall.com/cards/tshm/8/en?format=image"); + put ("SHM/Giant Warrior", "https://api.scryfall.com/cards/tshm/10/en?format=image"); + put ("SHM/Goblin Warrior", "https://api.scryfall.com/cards/tshm/11/en?format=image"); + put ("SHM/Kithkin Soldier", "https://api.scryfall.com/cards/tshm/1/en?format=image"); + put ("SHM/Rat", "https://api.scryfall.com/cards/tshm/3/en?format=image"); + put ("SHM/Spider", "https://api.scryfall.com/cards/tshm/6/en?format=image"); + put ("SHM/Spirit", "https://api.scryfall.com/cards/tshm/2/en?format=image"); + put ("SHM/Wolf", "https://api.scryfall.com/cards/tshm/7/en?format=image"); + + // NEO + put ("NEO/Construct/1", "https://api.scryfall.com/cards/tneo/15/en?format=image"); // 1/1 + put ("NEO/Construct/2", "https://api.scryfall.com/cards/tneo/6/en?format=image"); // haste + put ("NEO/Dragon Spirit", "https://api.scryfall.com/cards/tneo/7/en?format=image"); + put ("NEO/Goblin Shaman", "https://api.scryfall.com/cards/tneo/8/en?format=image"); + put ("NEO/Human Monk", "https://api.scryfall.com/cards/tneo/10/en?format=image"); + put ("NEO/Emblem Kaito Shizuki", "https://api.scryfall.com/cards/tneo/18/en?format=image"); + put ("NEO/Keimi", "https://api.scryfall.com/cards/tneo/13/en?format=image"); + put ("NEO/Mechtitan", "https://api.scryfall.com/cards/tneo/14/en?format=image"); + put ("NEO/Ninja", "https://api.scryfall.com/cards/tneo/4/en?format=image"); + put ("NEO/Pilot", "https://api.scryfall.com/cards/tneo/1/en?format=image"); + put ("NEO/Rat Rogue", "https://api.scryfall.com/cards/tneo/5/en?format=image"); + put ("NEO/Samurai", "https://api.scryfall.com/cards/tneo/3/en?format=image"); + put ("NEO/Spirit/1", "https://api.scryfall.com/cards/tneo/2/en?format=image"); // colorless + put ("NEO/Spirit/2", "https://api.scryfall.com/cards/tneo/12/en?format=image"); // */* + put ("NEO/Spirit/3", "https://api.scryfall.com/cards/tneo/11/en?format=image"); // green + put ("NEO/Spirit/4", "https://api.scryfall.com/cards/tneo/9/en?format=image"); // red + put ("NEO/Tamiyo's Notebook", "https://api.scryfall.com/cards/tneo/16/en?format=image"); + put ("NEO/Emblem Tezzeret, Betrayer of Flesh", "https://api.scryfall.com/cards/tneo/19/en?format=image"); + put ("NEO/Treasure", "https://api.scryfall.com/cards/tneo/17/en?format=image"); + + // NEC + put ("NEC/Angel", "https://api.scryfall.com/cards/tnec/2/en?format=image"); + put ("NEC/Beast", "https://api.scryfall.com/cards/tnec/7/en?format=image"); + put ("NEC/Elemental", "https://api.scryfall.com/cards/tnec/4/en?format=image"); + put ("NEC/Elephant", "https://api.scryfall.com/cards/tnec/8/en?format=image"); + put ("NEC/Goblin", "https://api.scryfall.com/cards/tnec/5/en?format=image"); + put ("NEC/Myr", "https://api.scryfall.com/cards/tnec/11/en?format=image"); + put ("NEC/Phyrexian Germ", "https://api.scryfall.com/cards/tnec/3/en?format=image"); + put ("NEC/Plant", "https://api.scryfall.com/cards/tnec/9/en?format=image"); + put ("NEC/Saproling", "https://api.scryfall.com/cards/tnec/10/en?format=image"); + put ("NEC/Shrine", "https://api.scryfall.com/cards/tnec/1/en?format=image"); + put ("NEC/Smoke Blessing", "https://api.scryfall.com/cards/tnec/6/en?format=image"); + put ("NEC/Thopter", "https://api.scryfall.com/cards/tnec/12/en?format=image"); + + // SLD + put ("SLD/Clue", "https://api.scryfall.com/cards/sld/348/en?format=image"); + put ("SLD/Faerie Rogue/1", "https://api.scryfall.com/cards/sld/13/en?format=image"); + put ("SLD/Faerie Rogue/2", "https://api.scryfall.com/cards/sld/14/en?format=image"); + put ("SLD/Faerie Rogue/3", "https://api.scryfall.com/cards/sld/15/en?format=image"); + put ("SLD/Faerie Rogue/4", "https://api.scryfall.com/cards/sld/16/en?format=image"); + put ("SLD/Treasure", "https://api.scryfall.com/cards/sld/153/en?format=image"); + put ("SLD/Walker/1", "https://api.scryfall.com/cards/sld/148/en?format=image"); + put ("SLD/Walker/2", "https://api.scryfall.com/cards/sld/149/en?format=image"); + put ("SLD/Walker/3", "https://api.scryfall.com/cards/sld/150/en?format=image"); + put ("SLD/Walker/4", "https://api.scryfall.com/cards/sld/151/en?format=image"); + put ("SLD/Walker/5", "https://api.scryfall.com/cards/sld/152/en?format=image"); + + // 2XM + put ("2XM/Angel", "https://api.scryfall.com/cards/t2xm/3/en?format=image"); + put ("2XM/Ape", "https://api.scryfall.com/cards/t2xm/12/en?format=image"); + put ("2XM/Beast", "https://api.scryfall.com/cards/t2xm/13/en?format=image"); + put ("2XM/Cat", "https://api.scryfall.com/cards/t2xm/4/en?format=image"); + put ("2XM/Clue", "https://api.scryfall.com/cards/t2xm/22/en?format=image"); + put ("2XM/Demon", "https://api.scryfall.com/cards/t2xm/9/en?format=image"); + put ("2XM/Eldrazi Spawn", "https://api.scryfall.com/cards/t2xm/1/en?format=image"); + put ("2XM/Elemental", "https://api.scryfall.com/cards/t2xm/20/en?format=image"); + put ("2XM/Elephant", "https://api.scryfall.com/cards/t2xm/14/en?format=image"); + put ("2XM/Elf Warrior", "https://api.scryfall.com/cards/t2xm/21/en?format=image"); + put ("2XM/Phyrexian Germ", "https://api.scryfall.com/cards/t2xm/10/en?format=image"); + put ("2XM/Golem", "https://api.scryfall.com/cards/t2xm/23/en?format=image"); + put ("2XM/Human Soldier", "https://api.scryfall.com/cards/t2xm/5/en?format=image"); + put ("2XM/Marit Lage", "https://api.scryfall.com/cards/t2xm/11/en?format=image"); + put ("2XM/Myr", "https://api.scryfall.com/cards/t2xm/24/en?format=image"); + put ("2XM/Phyrexian Myr", "https://api.scryfall.com/cards/t2xm/7/en?format=image"); + put ("2XM/Ooze", "https://api.scryfall.com/cards/t2xm/15/en?format=image"); + put ("2XM/Plant", "https://api.scryfall.com/cards/t2xm/16/en?format=image"); + put ("2XM/Saproling", "https://api.scryfall.com/cards/t2xm/17/en?format=image"); + put ("2XM/Servo", "https://api.scryfall.com/cards/t2xm/25/en?format=image"); + put ("2XM/Shapeshifter", "https://api.scryfall.com/cards/t2xm/2/en?format=image"); + put ("2XM/Soldier", "https://api.scryfall.com/cards/t2xm/6/en?format=image"); + put ("2XM/Squirrel", "https://api.scryfall.com/cards/t2xm/18/en?format=image"); + put ("2XM/Thopter/1", "https://api.scryfall.com/cards/t2xm/26/en?format=image"); + put ("2XM/Thopter/2", "https://api.scryfall.com/cards/t2xm/8/en?format=image"); + put ("2XM/Treasure", "https://api.scryfall.com/cards/t2xm/27/en?format=image"); + put ("2XM/Tuktuk the Returned", "https://api.scryfall.com/cards/t2xm/28/en?format=image"); + put ("2XM/Wolf", "https://api.scryfall.com/cards/t2xm/19/en?format=image"); + put ("2XM/Phyrexian Wurm/1", "https://api.scryfall.com/cards/t2xm/29/en?format=image"); + put ("2XM/Phyrexian Wurm/2", "https://api.scryfall.com/cards/t2xm/30/en?format=image"); + // generate supported sets supportedSets.clear(); for (String cardName : this.keySet()) { diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallSymbolsSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallSymbolsSource.java index b4728feabfa..5e22e80d35e 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallSymbolsSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallSymbolsSource.java @@ -42,6 +42,7 @@ public class ScryfallSymbolsSource implements Iterable { // copy-past symbols list from gatherer download private static final String[] SYMBOLS_LIST = {"W", "U", "B", "R", "G", "W/U", "U/B", "B/R", "R/G", "G/W", "W/B", "U/R", "B/G", "R/W", "G/U", + "W/U/P", "U/B/P", "B/R/P", "R/G/P", "G/W/P", "W/B/P", "U/R/P", "B/G/P", "R/W/P", "G/U/P", "2/W", "2/U", "2/B", "2/R", "2/G", "WP", "UP", "BP", "RP", "GP", "X", "S", "T", "Q", "C", "E"}; diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java index da49df4be5f..2a3a16e6887 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java @@ -487,7 +487,7 @@ public final class ImageCache { * Returns the map key for a card, without any suffixes for the image size. */ private static String getKey(CardView card, String name, String suffix) { - return name + return (card.isToken() ? name.replace(" Token", "") : name) + '#' + card.getExpansionSetCode() + '#' + card.getType() + '#' + card.getCardNumber() diff --git a/Mage.Client/src/main/resources/card-pictures-tok.txt b/Mage.Client/src/main/resources/card-pictures-tok.txt index ba20a0a9b3c..23272c12fd7 100644 --- a/Mage.Client/src/main/resources/card-pictures-tok.txt +++ b/Mage.Client/src/main/resources/card-pictures-tok.txt @@ -115,6 +115,8 @@ |Generate|EMBLEM:MID|Teferi, Who Slows the Sunset||Emblem Teferi|TeferiWhoSlowsTheSunsetEmblem| |Generate|EMBLEM:MID|Wrenn and Seven||Emblem Wrenn|WrennAndSevenEmblem| |Generate|EMBLEM:VOW|Chandra, Dressed to Kill||Emblem Chandra|ChandraDressedToKillEmblem| +|Generate|EMBLEM:NEO|Kaito Shizuki||Emblem Kaito|KaitoShizukiEmblem| +|Generate|EMBLEM:NEO|Tezzeret, Betrayer of Flesh||Emblem Tezzeret|TezzeretBetrayerOfFleshEmblem| # Planes |Generate|PLANE:PCA|Plane - Academy at Tolaria West|||AcademyAtTolariaWestPlane| @@ -234,7 +236,7 @@ |Generate|TOK:ALL|Zombie|||ZombieToken| |Generate|TOK:APC|Angel|||HauntedAngelToken| |Generate|TOK:APC|Cat|||PenumbraBobcatToken| -|Generate|TOK:APC|Goblin Soldier|||GoblinTrenchesToken| +|Generate|TOK:APC|Goblin Soldier|||GoblinSoldierToken| |Generate|TOK:APC|Kavu|||PenumbraKavuToken| |Generate|TOK:APC|Saproling|||SaprolingToken| |Generate|TOK:APC|Wurm|||PenumbraWurmToken| @@ -506,7 +508,7 @@ |Generate|TOK:CNS|Wolf|||WolfToken| |Generate|TOK:CNS|Zombie|||ZombieToken| |Generate|TOK:CON|Angel|||AngelToken| -|Generate|TOK:CON|Elemental|||RakkaMarElementalToken| +|Generate|TOK:CON|Elemental|||ElementalTokenWithHaste| |Generate|TOK:CON|Saproling|||SaprolingToken| |Generate|TOK:CON|Soldier|||SoldierToken| |Generate|TOK:CON|Zombie|||ZombieToken| @@ -589,7 +591,7 @@ |Generate|TOK:DGM|Spirit|||TeysaEnvoyOfGhostsToken| |Generate|TOK:DGM|Wurm|1||WurmWithTrampleToken| |Generate|TOK:DGM|Wurm|2||Wurm55Token| -|Generate|TOK:DIS|Bird|||DovescapeToken| +|Generate|TOK:DIS|Bird|||WhiteBlueBirdToken| |Generate|TOK:DIS|Drake|||LeafdrakeRoostDrakeToken| |Generate|TOK:DIS|Elemental|||ResearchDevelopmentToken| |Generate|TOK:DIS|Goblin|||RakdosGuildmageGoblinToken| @@ -643,7 +645,7 @@ |Generate|TOK:EMA|Elemental|2||CallTheSkyBreakerElementalToken| |Generate|TOK:EMA|Elephant|||ElephantToken| |Generate|TOK:EMA|Elf Warrior|||ElfWarriorToken| -|Generate|TOK:EMA|Goblin Soldier|||GoblinTrenchesToken| +|Generate|TOK:EMA|Goblin Soldier|||GoblinSoldierToken| |Generate|TOK:EMA|Goblin|||GoblinToken| |Generate|TOK:EMA|Serf|||SerfToken| |Generate|TOK:EMA|Soldier|||SoldierToken| @@ -667,10 +669,10 @@ |Generate|TOK:EMN|Zombie|3||ZombieToken| |Generate|TOK:EMN|Zombie|4||ZombieToken2| |Generate|TOK:EVE|Beast|||BeastToken| -|Generate|TOK:EVE|Bird|||OwlToken| +|Generate|TOK:EVE|Bird|||BlueBirdToken| |Generate|TOK:EVE|Elemental|||CallTheSkyBreakerElementalToken| |Generate|TOK:EVE|Goat|||GoatToken| -|Generate|TOK:EVE|Goblin Soldier|||GoblinTrenchesToken| +|Generate|TOK:EVE|Goblin Soldier|||GoblinSoldierToken| |Generate|TOK:EVE|Kithkin Soldier|||KithkinSoldierToken| |Generate|TOK:EVE|Spirit|||BeckonApparitionToken| |Generate|TOK:EVE|Wolf|||WolfToken| @@ -733,7 +735,7 @@ |Generate|TOK:HOU|Steadfast Sentinel|||| |Generate|TOK:HOU|Sunscourge Champion|||| |Generate|TOK:ICE|Caribou|||CaribouToken| -|Generate|TOK:INV|Bird|||OwlToken| +|Generate|TOK:INV|Bird|||BlueBirdToken| |Generate|TOK:INV|Elephant|||ElephantToken| |Generate|TOK:INV|Reflection|||ReflectionToken| |Generate|TOK:INV|Saproling|||SaprolingToken| @@ -931,7 +933,7 @@ |Generate|TOK:MMA|Bat|||BatToken| |Generate|TOK:MMA|Dragon|||DragonToken| |Generate|TOK:MMA|Elemental|||WalkerOfTheGroveToken| -|Generate|TOK:MMA|Faerie Rogue|||OonaQueenFaerieToken| +|Generate|TOK:MMA|Faerie Rogue|||OonaQueenFaerieRogueToken| |Generate|TOK:MMA|Giant Warrior|||GiantWarriorToken| |Generate|TOK:MMA|Goblin Rogue|||GoblinRogueToken| |Generate|TOK:MMA|Goblin|||GoblinToken| @@ -1050,7 +1052,7 @@ |Generate|TOK:RAV|Wolf|||VojaToken| |Generate|TOK:RAV|Faerie|||FaerieToken| |Generate|TOK:RIX|Elemental|1||RekindlingPhoenixToken| -|Generate|TOK:RIX|Elemental|2||TilonallisSummonerElementalToken| +|Generate|TOK:RIX|Elemental|2||RedElementalToken| |Generate|TOK:RIX|Golem|||GoldForgeGarrisonGolemToken| |Generate|TOK:RIX|Saproling|||SaprolingToken| |Generate|TOK:ROE|Dragon|||DragonToken2| @@ -1081,12 +1083,10 @@ |Generate|TOK:SCG|Goblin|||GoblinToken| |Generate|TOK:SCG|Soldier|||SoldierToken| |Generate|TOK:SHM|Elemental|1||DinOfTheFireherdToken| -|Generate|TOK:SHM|Elemental|2||RedElementalToken| -|Generate|TOK:SHM|Elf Warrior|1| -|Generate|TOK:SHM|Elf Warrior|2| +|Generate|TOK:SHM|Elemental|2||ElementalMasteryElementalToken| |Generate|TOK:SHM|Elf Warrior|1||ElfWarriorToken| -|Generate|TOK:SHM|Elf Warrior|2||RhysTheRedeemedToken| -|Generate|TOK:SHM|Faerie Rogue|||OonaQueenFaerieToken| +|Generate|TOK:SHM|Elf Warrior|2||GreenWhiteElfWarriorToken| +|Generate|TOK:SHM|Faerie Rogue|||OonaQueenFaerieRogueToken| |Generate|TOK:SHM|Giant Warrior|||GiantBaitingGiantWarriorToken| |Generate|TOK:SHM|Goblin Warrior|||WortTheRaidmotherToken| |Generate|TOK:SHM|Kithkin Soldier|||KithkinSoldierToken| @@ -1139,7 +1139,7 @@ |Generate|TOK:THS|Cleric|||HeliodGodOfTheSunToken| |Generate|TOK:THS|Elemental|||MasterOfWavesElementalToken| |Generate|TOK:THS|Golem|||HammerOfPurphorosGolemToken| -|Generate|TOK:THS|Harpy|||AbhorrentOverlordHarpyToken| +|Generate|TOK:THS|Harpy|||HarpyToken| |Generate|TOK:THS|Satyr|||XenagosSatyrToken| |Generate|TOK:THS|Soldier|1||SoldierToken| |Generate|TOK:THS|Soldier|2||SoldierToken| @@ -1192,7 +1192,7 @@ |Generate|TOK:VMA|Boar|||BoarToken| |Generate|TOK:VMA|Demon|||ReignOfThePitToken| |Generate|TOK:VMA|Elephant|||ElephantToken| -|Generate|TOK:VMA|Goblin Soldier|||GoblinTrenchesToken| +|Generate|TOK:VMA|Goblin Soldier|||GoblinSoldierToken| |Generate|TOK:VMA|Goblin|||GoblinToken| |Generate|TOK:VMA|Insect|||InsectToken| |Generate|TOK:VMA|Reflection|||ReflectionToken| @@ -1467,7 +1467,7 @@ # KHM |Generate|TOK:KHM|Angel Warrior|||AngelWarriorVigilanceToken| |Generate|TOK:KHM|Bear|||BearToken| -|Generate|TOK:KHM|Bird|||OwlToken| +|Generate|TOK:KHM|Bird|||BlueBirdToken| |Generate|TOK:KHM|Cat|||GreenCat2Token| |Generate|TOK:KHM|Demon Berserker|||DemonBerserkerToken| |Generate|TOK:KHM|Dragon|||DragonToken2| @@ -1664,4 +1664,100 @@ |Generate|TOK:VOW|Wolf|1||WolfToken| |Generate|TOK:VOW|Wolf|2||RedWolfToken| |Generate|TOK:VOW|Zombie|1||ZombieToken| -|Generate|TOK:VOW|Zombie|2||StitcherGeralfZombieToken| \ No newline at end of file +|Generate|TOK:VOW|Zombie|2||StitcherGeralfZombieToken| + +# UMA +|Generate|TOK:UMA|Citizen|||CitizenToken| +|Generate|TOK:UMA|Drake|||DrakeToken| +|Generate|TOK:UMA|Elemental|1||WalkerOfTheGroveToken| +|Generate|TOK:UMA|Elemental|2||RedElementalToken| +|Generate|TOK:UMA|Elemental|3||RedElementalToken| +|Generate|TOK:UMA|Faerie Rogue|||FaerieRogueToken| +|Generate|TOK:UMA|Homunculus|||StitchersApprenticeHomunculusToken| +|Generate|TOK:UMA|Marit Lage|||MaritLageToken| +|Generate|TOK:UMA|Ooze|||OozeToken| +|Generate|TOK:UMA|Soldier|||AkroanSoldierToken| +|Generate|TOK:UMA|Spark Elemental|||SparkElementalToken| +|Generate|TOK:UMA|Spider|||SpiderToken| +|Generate|TOK:UMA|Spirit|1||SpiritWhiteToken| +|Generate|TOK:UMA|Spirit|2||WhiteBlackSpiritToken| +|Generate|TOK:UMA|Wurm|||PenumbraWurmToken| +|Generate|TOK:UMA|Zombie|||ZombieToken| + +# NEO +|Generate|TOK:NEO|Construct|1||ConstructToken| +|Generate|TOK:NEO|Construct|2||ConstructRedToken| +|Generate|TOK:NEO|Dragon Spirit|||DragonSpiritToken| +|Generate|TOK:NEO|Goblin Shaman|||FableOfTheMirrorBreakerToken| +|Generate|TOK:NEO|Human Monk|||HumanMonkToken| +|Generate|TOK:NEO|Keimi|||KeimiToken| +|Generate|TOK:NEO|Mechtitan|||MechtitanToken| +|Generate|TOK:NEO|Ninja|||NinjaToken| +|Generate|TOK:NEO|Pilot|||PilotToken| +|Generate|TOK:NEO|Rat Rogue|||RatRogueToken| +|Generate|TOK:NEO|Samurai|||SamuraiToken| +|Generate|TOK:NEO|Spirit|1||SpiritToken| +|Generate|TOK:NEO|Spirit|2||SpiritGreenXToken| +|Generate|TOK:NEO|Spirit|3||SpiritGreenToken| +|Generate|TOK:NEO|Spirit|4||SpiritRedToken| +|Generate|TOK:NEO|Tamiyo's Notebook|||TamiyosNotebookToken| +|Generate|TOK:NEO|Treasure|||TreasureToken| + +# NEC +|Generate|TOK:NEC|Angel|||AngelVigilanceToken| +|Generate|TOK:NEC|Beast|||BeastToken| +|Generate|TOK:NEC|Elemental|||RedElementalToken| +|Generate|TOK:NEC|Elephant|||ElephantToken| +|Generate|TOK:NEC|Goblin|||GoblinToken| +|Generate|TOK:NEC|Myr|||MyrToken| +|Generate|TOK:NEC|Phyrexian Germ|||PhyrexianGermToken| +|Generate|TOK:NEC|Plant|||PlantToken| +|Generate|TOK:NEC|Saproling|||SaprolingToken| +|Generate|TOK:NEC|Shrine|||ShrineToken| +|Generate|TOK:NEC|Smoke Blessing|||SmokeBlessingToken| +|Generate|TOK:NEC|Thopter|||ThopterColorlessToken| + +# SLD +|Generate|TOK:SLD|Clue|||ClueArtifactToken| +|Generate|TOK:SLD|Faerie Rogue|1||FaerieRogueToken| +|Generate|TOK:SLD|Faerie Rogue|2||FaerieRogueToken| +|Generate|TOK:SLD|Faerie Rogue|3||FaerieRogueToken| +|Generate|TOK:SLD|Faerie Rogue|4||FaerieRogueToken| +|Generate|TOK:SLD|Treasure|||TreasureToken| +|Generate|TOK:SLD|Walker|1||WalkerToken| +|Generate|TOK:SLD|Walker|2||WalkerToken| +|Generate|TOK:SLD|Walker|3||WalkerToken| +|Generate|TOK:SLD|Walker|4||WalkerToken| +|Generate|TOK:SLD|Walker|5||WalkerToken| + +# 2XM +|Generate|TOK:2XM|Angel|||AngelToken| +|Generate|TOK:2XM|Ape|||ApeToken| +|Generate|TOK:2XM|Beast|||BeastToken| +|Generate|TOK:2XM|Cat|||CatToken| +|Generate|TOK:2XM|Clue|||ClueArtifactToken| +|Generate|TOK:2XM|Demon|||DemonToken| +|Generate|TOK:2XM|Eldrazi Spawn|||EldraziSpawnToken| +|Generate|TOK:2XM|Elemental|||VoiceOfResurgenceToken| +|Generate|TOK:2XM|Elephant|||ElephantToken| +|Generate|TOK:2XM|Elf Warrior|||GreenWhiteElfWarriorToken| +|Generate|TOK:2XM|Phyrexian Germ|||PhyrexianGermToken| +|Generate|TOK:2XM|Golem|||GolemToken| +|Generate|TOK:2XM|Human Soldier|||HumanSoldierToken| +|Generate|TOK:2XM|Marit Lage|||MaritLageToken| +|Generate|TOK:2XM|Myr|||MyrToken| +|Generate|TOK:2XM|Phyrexian Myr|||BrudicladTelchorMyrToken| +|Generate|TOK:2XM|Ooze|||OozeToken| +|Generate|TOK:2XM|Plant|||PlantToken| +|Generate|TOK:2XM|Saproling|||SaprolingToken| +|Generate|TOK:2XM|Servo|||ServoToken| +|Generate|TOK:2XM|Shapeshifter|||CribSwapShapeshifterWhiteToken| +|Generate|TOK:2XM|Soldier|||SoldierToken| +|Generate|TOK:2XM|Squirrel|||SquirrelToken| +|Generate|TOK:2XM|Thopter|1||ThopterColorlessToken| +|Generate|TOK:2XM|Thopter|2||ThopterToken| +|Generate|TOK:2XM|Treasure|||TreasureToken| +|Generate|TOK:2XM|Tuktuk the Returned|||TuktukTheReturnedToken| +|Generate|TOK:2XM|Wolf|||WolfToken| +|Generate|TOK:2XM|Phyrexian Wurm|1||WurmWithDeathtouchToken| +|Generate|TOK:2XM|Phyrexian Wurm|2||WurmWithLifelinkToken| \ No newline at end of file diff --git a/Mage.Common/src/main/java/mage/remote/Connection.java b/Mage.Common/src/main/java/mage/remote/Connection.java index f3bf4296ee0..ddc30666f72 100644 --- a/Mage.Common/src/main/java/mage/remote/Connection.java +++ b/Mage.Common/src/main/java/mage/remote/Connection.java @@ -40,7 +40,7 @@ public class Connection { // private boolean confirmEmptyManaPool; // private String flagName; // private UserSkipPrioritySteps userSkipPrioritySteps; - private static final String serialization = "?serializationtype=jboss"; + private static final String serialization = "?serializationtype=java"; private static final String transport = "bisocket"; private static final String threadpool = "onewayThreadPool=mage.remote.CustomThreadPool"; diff --git a/Mage.Common/src/main/java/mage/view/CardView.java b/Mage.Common/src/main/java/mage/view/CardView.java index c81824204c3..9653a79bb76 100644 --- a/Mage.Common/src/main/java/mage/view/CardView.java +++ b/Mage.Common/src/main/java/mage/view/CardView.java @@ -32,6 +32,7 @@ import mage.game.permanent.PermanentToken; import mage.game.permanent.token.Token; import mage.game.stack.Spell; import mage.game.stack.StackAbility; +import mage.game.stack.StackObject; import mage.players.Player; import mage.target.Target; import mage.target.Targets; @@ -237,8 +238,8 @@ public class CardView extends SimpleCardView { * @param card * @param game * @param controlled is the card view created for the card controller - used - * for morph / face down cards to know which player may - * see information for the card + * for morph / face down cards to know which player may see information for + * the card */ public CardView(Card card, Game game, boolean controlled) { this(card, game, controlled, false, false); @@ -264,14 +265,12 @@ public class CardView extends SimpleCardView { /** * @param card * @param game - * @param controlled is the card view created for the card controller - * - used for morph / face down cards to know which - * player may see information for the card + * @param controlled is the card view created for the card controller - used + * for morph / face down cards to know which player may see information for + * the card * @param showFaceDownCard if true and the card is not on the battlefield, - * also a face down card is shown in the view, face - * down cards will be shown - * @param storeZone if true the card zone will be set in the zone - * attribute. + * also a face down card is shown in the view, face down cards will be shown + * @param storeZone if true the card zone will be set in the zone attribute. */ public CardView(Card card, Game game, boolean controlled, boolean showFaceDownCard, boolean storeZone) { super(card.getId(), card.getExpansionSetCode(), card.getCardNumber(), card.getUsesVariousArt(), card.getTokenSetCode(), game != null, card.getTokenDescriptor()); @@ -543,7 +542,7 @@ public class CardView extends SimpleCardView { } else if (spell.getCard() != null) { SplitCard wholeCard = ((SplitCardHalf) spell.getCard()).getParentCard(); Abilities aftermathHalfAbilities = wholeCard.getRightHalfCard().getAbilities(game); - if (aftermathHalfAbilities.stream().anyMatch(halfAbility -> halfAbility instanceof AftermathAbility)) { + if (aftermathHalfAbilities.stream().anyMatch(AftermathAbility.class::isInstance)) { if (ty == SpellAbilityType.SPLIT_RIGHT) { artRect = ArtRect.AFTERMATH_BOTTOM; } else { @@ -564,6 +563,23 @@ public class CardView extends SimpleCardView { this.rules.add("Chosen mode: " + mode.getEffects().getText(mode) + ""); } } + + // show target of a spell on the stack + if (!spell.getSpellAbility().getTargets().isEmpty()) { + StackObject stackObjectTarget = null; + for (Target target : spell.getSpellAbility().getTargets()) { + for (UUID targetId : target.getTargets()) { + MageObject mo = game.getObject(targetId); + if (mo instanceof StackObject) { + stackObjectTarget = (StackObject) mo; + } + if (stackObjectTarget != null) { + this.rules.add("Target on stack: " + stackObjectTarget.getIdName()); + } + } + } + + } } // Frame color @@ -573,7 +589,7 @@ public class CardView extends SimpleCardView { this.frameStyle = card.getFrameStyle(); // Get starting loyalty - this.startingLoyalty = "" + card.getStartingLoyalty(); + this.startingLoyalty = CardUtil.convertStartingLoyalty(card.getStartingLoyalty()); } public CardView(MageObject object, Game game) { @@ -647,7 +663,7 @@ public class CardView extends SimpleCardView { // Frame style this.frameStyle = object.getFrameStyle(); // Starting loyalty. Must be extracted from an ability - this.startingLoyalty = "" + object.getStartingLoyalty(); + this.startingLoyalty = CardUtil.convertStartingLoyalty(object.getStartingLoyalty()); } protected CardView() { @@ -993,7 +1009,8 @@ public class CardView extends SimpleCardView { } /** - * Name of the other side (transform), flipped, modal double faces card or copying card name. + * Name of the other side (transform), flipped, modal double faces card or + * copying card name. * * @return name */ diff --git a/Mage.Common/src/main/java/mage/view/StackAbilityView.java b/Mage.Common/src/main/java/mage/view/StackAbilityView.java index cbf08403122..b24dbc24913 100644 --- a/Mage.Common/src/main/java/mage/view/StackAbilityView.java +++ b/Mage.Common/src/main/java/mage/view/StackAbilityView.java @@ -21,6 +21,8 @@ import mage.util.GameLog; import java.util.ArrayList; import java.util.List; import java.util.UUID; +import mage.game.stack.StackObject; +import mage.target.Target; /** * @author BetaSteward_at_googlemail.com @@ -140,6 +142,24 @@ public class StackAbilityView extends CardView { HintUtils.appendHints(rules, abilityHints); } } + + // show target of an ability on the stack if "related objects" is empty + if (!ability.getTargets().isEmpty() + && names.isEmpty()) { + StackObject stackObjectTarget = null; + for (Target target : ability.getTargets()) { + for (UUID targetId : target.getTargets()) { + MageObject mo = game.getObject(targetId); + if (mo instanceof StackObject) { + stackObjectTarget = (StackObject) mo; + } + if (stackObjectTarget != null) { + this.rules.add("Targeted ability related to this card: " + game.getCard(stackObjectTarget.getSourceId()).getIdName()); + } + } + } + + } } public CardView getSourceCard() { diff --git a/Mage.Common/src/test/java/mage/remote/ConnectionTest.java b/Mage.Common/src/test/java/mage/remote/ConnectionTest.java index 1e49ed9c377..4aeaa1eccf1 100644 --- a/Mage.Common/src/test/java/mage/remote/ConnectionTest.java +++ b/Mage.Common/src/test/java/mage/remote/ConnectionTest.java @@ -72,7 +72,7 @@ public class ConnectionTest { void serialisation() { final String query = make(testeeBuilder).getQuery(); - assertThat(query).contains("serializationtype=jboss"); + assertThat(query).contains("serializationtype=java"); } @Test diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java new file mode 100644 index 00000000000..fce6e124024 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java @@ -0,0 +1,998 @@ +package mage.deck; + +import mage.MageObject; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.CanBeYourCommanderAbility; +import mage.abilities.common.CommanderChooseColorAbility; +import mage.abilities.keyword.CompanionAbility; +import mage.abilities.keyword.FriendsForeverAbility; +import mage.abilities.keyword.PartnerAbility; +import mage.abilities.keyword.PartnerWithAbility; +import mage.cards.Card; +import mage.cards.decks.Constructed; +import mage.cards.decks.Deck; +import mage.cards.decks.DeckValidatorErrorType; +import mage.constants.CardType; +import mage.filter.FilterMana; +import mage.util.CardUtil; +import mage.util.ManaUtil; + +import java.util.*; +import java.util.stream.Stream; + +/** + * @author TheElk801 + */ +public abstract class AbstractCommander extends Constructed { + + protected final List bannedCommander = new ArrayList<>(); + protected final List bannedPartner = new ArrayList<>(); + protected boolean partnerAllowed = true; + + public AbstractCommander(String name) { + super(name); + } + + @Override + public int getDeckMinSize() { + return 98; + } + + @Override + public int getSideboardMinSize() { + return 1; + } + + protected abstract boolean checkBanned(Map counts); + + protected boolean checkCommander(Card commander) { + if ((!commander.hasCardTypeForDeckbuilding(CardType.CREATURE) || !commander.isLegendary()) + && !commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance())) { + addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander invalid (" + commander.getName() + ')', true); + return false; + } + return true; + } + + private boolean checkColorIdentity(Deck deck, FilterMana colorIdentity, Set commanders) { + int piperCount = commanders + .stream() + .filter(CommanderChooseColorAbility::checkCard) + .mapToInt(x -> 1) + .sum(); + if (piperCount == 0) { + boolean valid = true; + for (Card card : deck.getCards()) { + if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) { + addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true); + valid = false; + } + } + for (Card card : deck.getSideboard()) { + if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) { + addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true); + valid = false; + } + } + return valid; + } + FilterMana filterMana = new FilterMana(); + Stream.concat( + deck.getCards().stream(), + deck.getSideboard().stream() + ).map(Card::getColorIdentity).forEach(filterMana::addAll); + if (colorIdentity.getColorCount() + piperCount >= filterMana.getColorCount()) { + return true; + } + StringBuilder sb = new StringBuilder() + .append("Invalid color, commander color identity has ") + .append(colorIdentity.getColorCount()) + .append(" color") + .append(colorIdentity.getColorCount() > 1 ? "s" : "") + .append(", plus ") + .append(piperCount) + .append(" cop") + .append(piperCount > 1 ? "ies" : "y") + .append(" of The Prismatic Piper, but the total amount of colors in the deck is ") + .append(filterMana.getColorCount()); + addError(DeckValidatorErrorType.OTHER, "The Prismatic Piper", sb.toString()); + return false; + } + + @Override + public boolean validate(Deck deck) { + boolean valid = true; + errorsList.clear(); + FilterMana colorIdentity = new FilterMana(); + Set commanders = new HashSet<>(); + Card companion; + + int sbsize = deck.getSideboard().size(); + Card card1; + Card card2; + Card card3; + Iterator iter; + switch (deck.getSideboard().size()) { + case 1: + companion = null; + commanders.add(deck.getSideboard().iterator().next()); + break; + case 2: + iter = deck.getSideboard().iterator(); + card1 = iter.next(); + card2 = iter.next(); + if (card1.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) { + companion = card1; + commanders.add(card2); + } else if (card2.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) { + companion = card2; + commanders.add(card1); + } else { + companion = null; + commanders.add(card1); + commanders.add(card2); + } + break; + case 3: + iter = deck.getSideboard().iterator(); + card1 = iter.next(); + card2 = iter.next(); + card3 = iter.next(); + if (card1.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) { + companion = card1; + commanders.add(card2); + commanders.add(card3); + } else if (card2.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) { + companion = card2; + commanders.add(card1); + commanders.add(card3); + } else if (card3.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) { + companion = card3; + commanders.add(card1); + commanders.add(card2); + } else { + companion = null; + addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion"); + valid = false; + } + break; + default: + companion = null; + addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion"); + valid = false; + } + + if (companion != null && deck.getCards().size() + deck.getSideboard().size() != 101) { + addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 101 + " cards (companion doesn't count for deck size): has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); + valid = false; + } else if (companion == null && deck.getCards().size() + deck.getSideboard().size() != 100) { + addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 100 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); + valid = false; + } + + Map counts = new HashMap<>(); + countCards(counts, deck.getCards()); + countCards(counts, deck.getSideboard()); + valid = checkCounts(1, counts) && valid; + + valid = checkBanned(counts) && valid; + + Set commanderNames = new HashSet<>(); + for (Card commander : commanders) { + commanderNames.add(commander.getName()); + } + if (commanders.size() == 2 + && commanders + .stream() + .map(MageObject::getAbilities) + .filter(abilities -> abilities.contains(PartnerAbility.getInstance())) + .count() != 2 + && commanders + .stream() + .map(MageObject::getAbilities) + .filter(abilities -> abilities.contains(FriendsForeverAbility.getInstance())) + .count() != 2 + && !CardUtil + .castStream(commanders.stream().map(MageObject::getAbilities), PartnerWithAbility.class) + .map(PartnerWithAbility::getPartnerName) + .allMatch(commanderNames::contains)) { + for (Card commander : commanders) { + addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander with invalid Partner (" + commander.getName() + ')', true); + valid = false; + } + } + for (Card commander : commanders) { + if (bannedCommander.contains(commander.getName())) { + addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander banned (" + commander.getName() + ')', true); + valid = false; + } + if ((!commander.hasCardTypeForDeckbuilding(CardType.CREATURE) || !commander.isLegendary()) + && !commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance())) { + addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander invalid (" + commander.getName() + ')', true); + valid = false; + } + if (commanders.size() == 2 && bannedPartner.contains(commander.getName())) { + addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander Partner banned (" + commander.getName() + ')', true); + valid = false; + } + ManaUtil.collectColorIdentity(colorIdentity, commander.getColorIdentity()); + } + + // no needs in cards check on wrong commanders + if (!valid) { + return false; + } + + valid = checkColorIdentity(deck, colorIdentity, commanders); + + for (Card card : deck.getCards()) { + if (!isSetAllowed(card.getExpansionSetCode())) { + if (!legalSets(card)) { + addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true); + valid = false; + } + } + } + for (Card card : deck.getSideboard()) { + if (!isSetAllowed(card.getExpansionSetCode())) { + if (!legalSets(card)) { + addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true); + valid = false; + } + } + } + // Check for companion legality + if (companion != null) { + Set cards = new HashSet<>(deck.getCards()); + cards.addAll(commanders); + for (Ability ability : companion.getAbilities()) { + if (ability instanceof CompanionAbility) { + CompanionAbility companionAbility = (CompanionAbility) ability; + if (!companionAbility.isLegal(cards, getDeckMinSize())) { + addError(DeckValidatorErrorType.PRIMARY, companion.getName(), + String.format("Commander companion illegal: %s", companionAbility.getLegalRule()), true); + valid = false; + } + break; + } + } + } + return valid; + } + + @Override + public int getEdhPowerLevel(Deck deck) { + if (deck == null) { + return 0; + } + + int edhPowerLevel = 0; + int commanderColors = 0; + int numberInfinitePieces = 0; + + for (Card card : deck.getCards()) { + + int thisMaxPower = 0; + + // Examine rules to work out most egregious functions in edh + boolean anyNumberOfTarget = false; + boolean annihilator = false; + boolean buyback = false; + boolean cascade = false; + boolean cantBe = false; + boolean cantUntap = false; + boolean copy = false; + boolean costLessEach = false; + boolean createToken = false; + boolean dredge = false; + boolean exile = false; + boolean exileAll = false; + boolean counter = false; + boolean destroy = false; + boolean destroyAll = false; + boolean each = false; + boolean exalted = false; + boolean doesntUntap = false; + boolean drawCards = false; + boolean evoke = false; + boolean extraTurns = false; + boolean flash = false; + boolean flashback = false; + boolean flicker = false; + boolean gainControl = false; + boolean hexproof = false; + boolean infect = false; + boolean lifeTotalBecomes = false; + boolean mayCastForFree = false; + boolean menace = false; + boolean miracle = false; + boolean overload = false; + boolean persist = false; + boolean preventDamage = false; + boolean proliferate = false; + boolean protection = false; + boolean putUnderYourControl = false; + boolean retrace = false; + boolean returnFromYourGY = false; + boolean sacrifice = false; + boolean shroud = false; + boolean skip = false; + boolean sliver = false; + boolean storm = false; + boolean trample = false; + boolean tutor = false; + boolean tutorBasic = false; + boolean twiceAs = false; + boolean unblockable = false; + boolean undying = false; + boolean untapTarget = false; + boolean wheneverEnters = false; + boolean whenCounterThatSpell = false; + boolean xCost = false; + boolean youControlTarget = false; + boolean yourOpponentsControl = false; + boolean whenYouCast = false; + + for (String str : card.getRules()) { + String s = str.toLowerCase(Locale.ENGLISH); + annihilator |= s.contains("annihilator"); + anyNumberOfTarget |= s.contains("any number"); + buyback |= s.contains("buyback"); + cantUntap |= s.contains("can't untap") || s.contains("don't untap"); + cantBe |= s.contains("can't be"); + cascade |= s.contains("cascade"); + copy |= s.contains("copy"); + costLessEach |= s.contains("cost") || s.contains("less") || s.contains("each"); + counter |= s.contains("counter") && s.contains("target"); + createToken |= s.contains("create") && s.contains("token"); + destroy |= s.contains("destroy"); + destroyAll |= s.contains("destroy all"); + doesntUntap |= s.contains("doesn't untap"); + doesntUntap |= s.contains("don't untap"); + drawCards |= s.contains("draw cards"); + dredge |= s.contains("dredge"); + each |= s.contains("each"); + evoke |= s.contains("evoke"); + exalted |= s.contains("exalted"); + exile |= s.contains("exile"); + exileAll |= s.contains("exile") && s.contains(" all "); + extraTurns |= s.contains("extra turn"); + flicker |= s.contains("exile") && s.contains("return") && s.contains("to the battlefield under"); + flash |= s.contains("flash"); + flashback |= s.contains("flashback"); + gainControl |= s.contains("gain control"); + hexproof |= s.contains("hexproof"); + infect |= s.contains("infect"); + lifeTotalBecomes |= s.contains("life total becomes"); + mayCastForFree |= s.contains("may cast") && s.contains("without paying"); + menace |= s.contains("menace"); + miracle |= s.contains("miracle"); + overload |= s.contains("overload"); + persist |= s.contains("persist"); + preventDamage |= s.contains("prevent") && s.contains("all") && s.contains("damage"); + proliferate |= s.contains("proliferate"); + protection |= s.contains("protection"); + putUnderYourControl |= s.contains("put") && s.contains("under your control"); + retrace |= s.contains("retrace"); + returnFromYourGY |= s.contains("return") && s.contains("from your graveyard"); + sacrifice |= s.contains("sacrifice"); + shroud |= s.contains("shroud"); + skip |= s.contains("skip"); + sliver |= s.contains("sliver"); + storm |= s.contains("storm"); + trample |= s.contains("trample"); + tutor |= s.contains("search your library") && !s.contains("basic land"); + tutorBasic |= s.contains("search your library") && s.contains("basic land"); + twiceAs |= s.contains("twice that many") || s.contains("twice as much"); + unblockable |= s.contains("can't be blocked"); + undying |= s.contains("undying"); + untapTarget |= s.contains("untap target"); + whenCounterThatSpell |= s.contains("when") && s.contains("counter that spell"); + wheneverEnters |= s.contains("when") && s.contains("another") && s.contains("enters"); + youControlTarget |= s.contains("you control target"); + yourOpponentsControl |= s.contains("your opponents control"); + whenYouCast |= s.contains("when you cast") || s.contains("whenever you cast"); + } + + for (String s : card.getManaCostSymbols()) { + if (s.contains("X")) { + xCost = true; + } + } + for (Ability a : card.getAbilities()) { + for (String s : a.getManaCostSymbols()) { + if (s.contains("X")) { + xCost = true; + } + } + } + + if (extraTurns) { + thisMaxPower = Math.max(thisMaxPower, 7); + } + if (buyback) { + thisMaxPower = Math.max(thisMaxPower, 6); + } + if (tutor) { + thisMaxPower = Math.max(thisMaxPower, 6); + } + if (annihilator) { + thisMaxPower = Math.max(thisMaxPower, 5); + } + if (cantUntap) { + thisMaxPower = Math.max(thisMaxPower, 5); + } + if (costLessEach) { + thisMaxPower = Math.max(thisMaxPower, 5); + } + if (infect) { + thisMaxPower = Math.max(thisMaxPower, 5); + } + if (overload) { + thisMaxPower = Math.max(thisMaxPower, 5); + } + if (twiceAs) { + thisMaxPower = Math.max(thisMaxPower, 5); + } + if (cascade) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (doesntUntap) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (each) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (exileAll) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (flash) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (flashback) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (flicker) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (gainControl) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (lifeTotalBecomes) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (mayCastForFree) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (preventDamage) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (proliferate) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (protection) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (putUnderYourControl) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (returnFromYourGY) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (sacrifice) { + thisMaxPower = Math.max(thisMaxPower, 2); + } + if (skip) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (storm) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (unblockable) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (whenCounterThatSpell) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (wheneverEnters) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (xCost) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (youControlTarget) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (yourOpponentsControl) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (whenYouCast) { + thisMaxPower = Math.max(thisMaxPower, 4); + } + if (anyNumberOfTarget) { + thisMaxPower = Math.max(thisMaxPower, 3); + } + if (createToken) { + thisMaxPower = Math.max(thisMaxPower, 3); + } + if (destroyAll) { + thisMaxPower = Math.max(thisMaxPower, 3); + } + if (dredge) { + thisMaxPower = Math.max(thisMaxPower, 3); + } + if (hexproof) { + thisMaxPower = Math.max(thisMaxPower, 3); + } + if (shroud) { + thisMaxPower = Math.max(thisMaxPower, 3); + } + if (undying) { + thisMaxPower = Math.max(thisMaxPower, 3); + } + if (persist) { + thisMaxPower = Math.max(thisMaxPower, 3); + } + if (cantBe) { + thisMaxPower = Math.max(thisMaxPower, 2); + } + if (evoke) { + thisMaxPower = Math.max(thisMaxPower, 2); + } + if (exile) { + thisMaxPower = Math.max(thisMaxPower, 2); + } + if (menace) { + thisMaxPower = Math.max(thisMaxPower, 2); + } + if (miracle) { + thisMaxPower = Math.max(thisMaxPower, 2); + } + if (sliver) { + thisMaxPower = Math.max(thisMaxPower, 2); + } + if (untapTarget) { + thisMaxPower = Math.max(thisMaxPower, 2); + } + if (copy) { + thisMaxPower = Math.max(thisMaxPower, 1); + } + if (counter) { + thisMaxPower = Math.max(thisMaxPower, 1); + } + if (destroy) { + thisMaxPower = Math.max(thisMaxPower, 1); + } + if (drawCards) { + thisMaxPower = Math.max(thisMaxPower, 1); + } + if (exalted) { + thisMaxPower = Math.max(thisMaxPower, 1); + } + if (retrace) { + thisMaxPower = Math.max(thisMaxPower, 1); + } + if (trample) { + thisMaxPower = Math.max(thisMaxPower, 1); + } + if (tutorBasic) { + thisMaxPower = Math.max(thisMaxPower, 1); + } + + if (card.isPlaneswalker()) { + thisMaxPower = Math.max(thisMaxPower, 6); + } + + String cn = card.getName().toLowerCase(Locale.ENGLISH); + if (cn.equals("ancient tomb") + || cn.equals("anafenza, the foremost") + || cn.equals("arcum dagsson") + || cn.equals("armageddon") + || cn.equals("aura shards") + || cn.equals("azami, lady of scrolls") + || cn.equals("azusa, lost but seeking") + || cn.equals("back to basics") + || cn.equals("bane of progress") + || cn.equals("basalt monolith") + || cn.equals("blightsteel collossus") + || cn.equals("blood moon") + || cn.equals("braids, cabal minion") + || cn.equals("cabal coffers") + || cn.equals("captain sisay") + || cn.equals("celestial dawn") + || cn.equals("child of alara") + || cn.equals("coalition relic") + || cn.equals("craterhoof behemoth") + || cn.equals("deepglow skate") + || cn.equals("derevi, empyrial tactician") + || cn.equals("dig through time") + || cn.equals("edric, spymaster of trest") + || cn.equals("elesh norn, grand cenobite") + || cn.equals("entomb") + || cn.equals("force of will") + || cn.equals("food chain") + || cn.equals("gaddock teeg") + || cn.equals("gaea's cradle") + || cn.equals("grand arbiter augustin iv") + || cn.equals("grim monolith") + || cn.equals("hermit druid") + || cn.equals("hokori, dust drinker") + || cn.equals("humility") + || cn.equals("imperial seal") + || cn.equals("iona, shield of emeria") + || cn.equals("jin-gitaxias, core augur") + || cn.equals("karador, ghost chieftain") + || cn.equals("karakas") + || cn.equals("kataki, war's wage") + || cn.equals("knowledge pool") + || cn.equals("linvala, keeper of silence") + || cn.equals("living death") + || cn.equals("llawan, cephalid empress") + || cn.equals("loyal retainers") + || cn.equals("maelstrom wanderer") + || cn.equals("malfegor") + || cn.equals("master of cruelties") + || cn.equals("mana crypt") + || cn.equals("mana drain") + || cn.equals("mana vault") + || cn.equals("michiko konda, truth seeker") + || cn.equals("nath of the gilt-leaf") + || cn.equals("natural order") + || cn.equals("necrotic ooze") + || cn.equals("nicol bolas") + || cn.equals("numot, the devastator") + || cn.equals("oath of druids") + || cn.equals("pattern of rebirth") + || cn.equals("protean hulk") + || cn.equals("purphoros, god of the forge") + || cn.equals("ravages of war") + || cn.equals("reclamation sage") + || cn.equals("sen triplets") + || cn.equals("serra's sanctum") + || cn.equals("sheoldred, whispering one") + || cn.equals("sol ring") + || cn.equals("spore frog") + || cn.equals("stasis") + || cn.equals("strip mine") + || cn.equals("the tabernacle at pendrell vale") + || cn.equals("tinker") + || cn.equals("treasure cruise") + || cn.equals("urabrask the hidden") + || cn.equals("vorinclex, voice of hunger") + || cn.equals("winter orb") + || cn.equals("zur the enchanter")) { + thisMaxPower = Math.max(thisMaxPower, 12); + } + + // Parts of infinite combos + if (cn.equals("animate artifact") || cn.equals("animar, soul of element") + || cn.equals("archaeomancer") + || cn.equals("ashnod's altar") || cn.equals("azami, lady of scrolls") + || cn.equals("aura flux") + || cn.equals("basalt monolith") || cn.equals("brago, king eternal") + || cn.equals("candelabra of tawnos") || cn.equals("cephalid aristocrat") + || cn.equals("cephalid illusionist") || cn.equals("changeling berserker") + || cn.equals("consecrated sphinx") + || cn.equals("cyclonic rift") + || cn.equals("the chain veil") + || cn.equals("cinderhaze wretch") || cn.equals("cryptic gateway") + || cn.equals("deadeye navigator") || cn.equals("derevi, empyrial tactician") + || cn.equals("doubling season") || cn.equals("dross scorpion") + || cn.equals("earthcraft") || cn.equals("erratic portal") + || cn.equals("enter the infinite") || cn.equals("omniscience") + || cn.equals("exquisite blood") || cn.equals("future sight") + || cn.equals("genesis chamber") + || cn.equals("ghave, guru of spores") + || cn.equals("grave pact") + || cn.equals("grave titan") || cn.equals("great whale") + || cn.equals("grim monolith") || cn.equals("gush") + || cn.equals("hellkite charger") || cn.equals("intruder alarm") + || cn.equals("helm of obedience") + || cn.equals("hermit druid") + || cn.equals("humility") + || cn.equals("iona, shield of emeria") + || cn.equals("karn, silver golem") || cn.equals("kiki-jiki, mirror breaker") + || cn.equals("krark-clan ironworks") || cn.equals("krenko, mob boss") + || cn.equals("krosan restorer") || cn.equals("laboratory maniac") + || cn.equals("leonin relic-warder") || cn.equals("leyline of the void") + || cn.equals("memnarch") + || cn.equals("meren of clan nel toth") || cn.equals("mikaeus, the unhallowed") + || cn.equals("mindcrank") || cn.equals("mindslaver") + || cn.equals("minion reflector") || cn.equals("mycosynth lattice") + || cn.equals("myr turbine") || cn.equals("narset, enlightened master") + || cn.equals("nekusar, the mindrazer") || cn.equals("norin the wary") + || cn.equals("notion thief") + || cn.equals("opalescence") || cn.equals("ornithopter") + || cn.equals("paradox engine") + || cn.equals("purphoros, god of the forge") + || cn.equals("peregrine drake") || cn.equals("palinchron") + || cn.equals("planar portal") || cn.equals("power artifact") + || cn.equals("rings of brighthearth") || cn.equals("rite of replication") + || cn.equals("sanguine bond") || cn.equals("sensei's divining top") + || cn.equals("splinter twin") || cn.equals("stony silence") + || cn.equals("sunder") + || cn.equals("storm cauldron") || cn.equals("teferi's puzzle box") + || cn.equals("tangle wire") + || cn.equals("teferi, mage of zhalfir") + || cn.equals("tezzeret the seeker") || cn.equals("time stretch") + || cn.equals("time warp") || cn.equals("training grounds") + || cn.equals("triskelavus") || cn.equals("triskelion") + || cn.equals("turnabout") || cn.equals("umbral mantle") + || cn.equals("uyo, silent prophet") || cn.equals("voltaic key") + || cn.equals("workhorse") || cn.equals("worldgorger dragon") + || cn.equals("worthy cause") || cn.equals("yawgmoth's will") + || cn.equals("zealous conscripts")) { + thisMaxPower = Math.max(thisMaxPower, 15); + numberInfinitePieces++; + } + + // Saltiest cards (edhrec) + if (cn.equals("acid rain") + || cn.equals("agent of treachery") + || cn.equals("apocalypse") + || cn.equals("armageddon") + || cn.equals("atraxa, praetors' voice") + || cn.equals("aura shards") + || cn.equals("avacyn, angel of hope") + || cn.equals("back to basics") + || cn.equals("bend or break") + || cn.equals("blightsteel colossus") + || cn.equals("blood moon") + || cn.equals("boil") + || cn.equals("boiling seas") + || cn.equals("bribery") + || cn.equals("burning sands") + || cn.equals("card view") + || cn.equals("cataclysm") + || cn.equals("catastrophe") + || cn.equals("chulane, teller of tales") + || cn.equals("confusion in the ranks") + || cn.equals("consecrated sphinx") + || cn.equals("contamination") + || cn.equals("craterhoof behemoth") + || cn.equals("cyclonic rift") + || cn.equals("death cloud") + || cn.equals("decree of annihilation") + || cn.equals("decree of silence") + || cn.equals("demonic consultation") + || cn.equals("derevi, empyrial tactician") + || cn.equals("devastation") + || cn.equals("divine intervention") + || cn.equals("dockside extortionist") + || cn.equals("doomsday") + || cn.equals("doubling season") + || cn.equals("drannith magistrate") + || cn.equals("elesh norn, grand cenobite") + || cn.equals("embargo") + || cn.equals("emrakul, the promised end") + || cn.equals("epicenter") + || cn.equals("expropriate") + || cn.equals("fall of the thran") + || cn.equals("fierce guardianship") + || cn.equals("food chain") + || cn.equals("force of negation") + || cn.equals("force of will") + || cn.equals("gaddock teeg") + || cn.equals("gaea's cradle") + || cn.equals("gilded drake") + || cn.equals("glenn, the voice of calm") + || cn.equals("global ruin") + || cn.equals("golos, tireless pilgrim") + || cn.equals("grand arbiter augustin iv") + || cn.equals("grip of chaos") + || cn.equals("hokori, dust drinker") + || cn.equals("humility") + || cn.equals("impending disaster") + || cn.equals("invoke prejudice") + || cn.equals("iona, shield of emeria") + || cn.equals("jin-gitaxias, core augur") + || cn.equals("jokulhaups") + || cn.equals("keldon firebombers") + || cn.equals("kinnan, bonder prodigy") + || cn.equals("kozilek, butcher of truth") + || cn.equals("land equilibrium") + || cn.equals("linvala, keeper of silence") + || cn.equals("magister sphinx") + || cn.equals("mana breach") + || cn.equals("mana crypt") + || cn.equals("mana drain") + || cn.equals("mana vortex") + || cn.equals("mindslaver") + || cn.equals("narset, enlightened master") + || cn.equals("narset, parter of veils") + || cn.equals("negan, the cold-blooded") + || cn.equals("nether void") + || cn.equals("nexus of fate") + || cn.equals("notion thief") + || cn.equals("obliterate") + || cn.equals("oko, thief of crowns") + || cn.equals("oloro, ageless ascetic") + || cn.equals("omniscience") + || cn.equals("opposition agent") + || cn.equals("oppression") + || cn.equals("overwhelming splendor") + || cn.equals("palinchron") + || cn.equals("paradox engine") + || cn.equals("possessed portal") + || cn.equals("price of glory") + || cn.equals("protean hulk") + || cn.equals("ravages of war") + || cn.equals("rhystic study") + || cn.equals("rick, steadfast leader") + || cn.equals("rising waters") + || cn.equals("ruination") + || cn.equals("scrambleverse") + || cn.equals("seedborn muse") + || cn.equals("sen triplets") + || cn.equals("sire of insanity") + || cn.equals("skithiryx, the blight dragon") + || cn.equals("smokestack") + || cn.equals("smothering tithe") + || cn.equals("sorin markov") + || cn.equals("stasis") + || cn.equals("static orb") + || cn.equals("storage matrix") + || cn.equals("sunder") + || cn.equals("survival of the fittest") + || cn.equals("table view") + || cn.equals("tainted aether") + || cn.equals("tectonic break") + || cn.equals("teferi's protection") + || cn.equals("teferi, master of time") + || cn.equals("teferi, time raveler") + || cn.equals("temporal manipulation") + || cn.equals("tergrid, god of fright") + || cn.equals("text view") + || cn.equals("thassa's oracle") + || cn.equals("the tabernacle at pendrell vale") + || cn.equals("thieves' auction") + || cn.equals("thoughts of ruin") + || cn.equals("thrasios, triton hero") + || cn.equals("time stretch") + || cn.equals("time warp") + || cn.equals("tooth and nail") + || cn.equals("torment of hailfire") + || cn.equals("torpor orb") + || cn.equals("triumph of the hordes") + || cn.equals("ugin, the spirit dragon") + || cn.equals("ulamog, the ceaseless hunger") + || cn.equals("ulamog, the infinite gyre") + || cn.equals("urza, lord high artificer") + || cn.equals("void winnower") + || cn.equals("vorinclex, voice of hunger") + || cn.equals("wake of destruction") + || cn.equals("warp world") + || cn.equals("winter orb") + || cn.equals("xanathar, guild kingpin") + || cn.equals("zur the enchanter")) { + thisMaxPower = Math.max(thisMaxPower, 15); + } + edhPowerLevel += thisMaxPower; + } + + ObjectColor color = null; + for (Card commander : deck.getSideboard()) { + int thisMaxPower = 0; + String cn = commander.getName().toLowerCase(Locale.ENGLISH); + if (color == null) { + color = commander.getColor(null); + } else { + color = color.union(commander.getColor(null)); + } + + FilterMana commanderColor = commander.getColorIdentity(); + if (commanderColor.isWhite()) { + color.setWhite(true); + } + if (commanderColor.isBlue()) { + color.setBlue(true); + } + if (commanderColor.isBlack()) { + color.setBlack(true); + } + if (commanderColor.isRed()) { + color.setRed(true); + } + if (commanderColor.isGreen()) { + color.setGreen(true); + } + + // Least fun commanders + if (cn.equals("animar, soul of element") + || cn.equals("anafenza, the foremost") + || cn.equals("arcum dagsson") + || cn.equals("azami, lady of scrolls") + || cn.equals("azusa, lost but seeking") + || cn.equals("brago, king eternal") + || cn.equals("braids, cabal minion") + || cn.equals("captain sisay") + || cn.equals("child of alara") + || cn.equals("derevi, empyrial tactician") + || cn.equals("edric, spymaster of trest") + || cn.equals("elesh norn, grand cenobite") + || cn.equals("gaddock teeg") + || cn.equals("grand arbiter augustin iv") + || cn.equals("hokori, dust drinker") + || cn.equals("iona, shield of emeria") + || cn.equals("jin-gitaxias, core augur") + || cn.equals("kaalia of the vast") + || cn.equals("karador, ghost chieftain") + || cn.equals("leovold, emissary of trest") + || cn.equals("linvala, keeper of silence") + || cn.equals("llawan, cephalid empress") + || cn.equals("maelstrom wanderer") + || cn.equals("malfegor") + || cn.equals("memnarch") + || cn.equals("meren of clan nel toth") + || cn.equals("michiko konda, truth seeker") + || cn.equals("mikaeus the unhallowed") + || cn.equals("narset, enlightened master") + || cn.equals("nath of the gilt-leaf") + || cn.equals("nekusar, the mindrazer") + || cn.equals("norin the wary") + || cn.equals("numot, the devastator") + || cn.equals("prossh, skyraider of kher") + || cn.equals("purphoros, god of the forge") + || cn.equals("sen triplets") + || cn.equals("sheoldred, whispering one") + || cn.equals("teferi, mage of zhalfir") + || cn.equals("urabrask the hidden") + || cn.equals("vorinclex, voice of hunger") + || cn.equals("zur the enchanter")) { + thisMaxPower = Math.max(thisMaxPower, 25); + } + + // Saltiest commanders + if (cn.equals("atraxa, praetors' voice") + || cn.equals("avacyn, angel of hope") + || cn.equals("chulane, teller of tales") + || cn.equals("derevi, empyrial tactician") + || cn.equals("elesh norn, grand cenobite") + || cn.equals("emrakul, the promised end") + || cn.equals("gaddock teeg") + || cn.equals("glenn, the voice of calm") + || cn.equals("golos, tireless pilgrim") + || cn.equals("grand arbiter augustin iv") + || cn.equals("hokori, dust drinker") + || cn.equals("iona, shield of emeria") + || cn.equals("jin-gitaxias, core augur") + || cn.equals("kinnan, bonder prodigy") + || cn.equals("kozilek, butcher of truth") + || cn.equals("linvala, keeper of silence") + || cn.equals("narset, enlightened master") + || cn.equals("negan, the cold-blooded") + || cn.equals("oko, thief of crowns") + || cn.equals("oloro, ageless ascetic") + || cn.equals("rick, steadfast leader") + || cn.equals("sen triplets") + || cn.equals("skithiryx, the blight dragon") + || cn.equals("teferi, master of time") + || cn.equals("teferi, time raveler") + || cn.equals("thrasios, triton hero") + || cn.equals("ulamog, the ceaseless hunger") + || cn.equals("ulamog, the infinite gyre") + || cn.equals("urza, lord high artificer") + || cn.equals("vorinclex, voice of hunger") + || cn.equals("xanathar, guild kingpin") + || cn.equals("zur the enchanter")) { + thisMaxPower = Math.max(thisMaxPower, 20); + } + edhPowerLevel += thisMaxPower; + } + + edhPowerLevel += numberInfinitePieces * 18; + edhPowerLevel = Math.round(edhPowerLevel / 10); + if (edhPowerLevel >= 100) { + edhPowerLevel = 99; + } + if (color != null) { + edhPowerLevel += (color.isWhite() ? 10000000 : 0); + edhPowerLevel += (color.isBlue() ? 1000000 : 0); + edhPowerLevel += (color.isBlack() ? 100000 : 0); + edhPowerLevel += (color.isRed() ? 10000 : 0); + edhPowerLevel += (color.isGreen() ? 1000 : 0); + } + return edhPowerLevel; + } +} diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java index ad029d22fe6..0eaa2ef5022 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java @@ -112,32 +112,6 @@ public class AusHighlander extends Constructed { valid = false; } - banned.add("Advantageous Proclamation"); - banned.add("Amulet of Quoz"); - banned.add("Backup Plan"); - banned.add("Brago's Favor"); - banned.add("Bronze Tablet"); - banned.add("Chaos Orb"); - banned.add("Contract from Below"); - banned.add("Darkpact"); - banned.add("Demonic Attorney"); - banned.add("Double Stroke"); - banned.add("Falling Star"); - banned.add("Immediate Action"); - banned.add("Iterative Analysis"); - banned.add("Jeweled Bird"); - banned.add("Muzzio's Preparations"); - banned.add("Power Play"); - banned.add("Rebirth"); - banned.add("Secret Summoning"); - banned.add("Secrets of Paradise"); - banned.add("Sentinel Dispatch"); - banned.add("Shahrazad"); - banned.add("Tempest Efreet"); - banned.add("Timmerian Fiends"); - banned.add("Unexpected Potential"); - banned.add("Worldknit"); - Map counts = new HashMap<>(); countCards(counts, deck.getCards()); countCards(counts, deck.getSideboard()); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java index 0b73210f0bf..b02e602b805 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java @@ -57,10 +57,10 @@ public class Brawl extends Constructed { Iterator iter = deck.getSideboard().iterator(); Card card1 = iter.next(); Card card2 = iter.next(); - if (card1.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) { + if (card1.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) { companion = card1; brawler = card2; - } else if (card2.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) { + } else if (card2.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) { companion = card2; brawler = card1; } else { @@ -156,7 +156,8 @@ public class Brawl extends Constructed { if (ability instanceof CompanionAbility) { CompanionAbility companionAbility = (CompanionAbility) ability; if (!companionAbility.isLegal(cards, getDeckMinSize())) { - addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Brawl Companion Invalid", true); + addError(DeckValidatorErrorType.PRIMARY, companion.getName(), + String.format("Brawl companion illegal: %s", companionAbility.getLegalRule()), true); valid = false; } break; diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CenturionCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CenturionCommander.java index f4e3977e6d9..3a22d6b174e 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CenturionCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CenturionCommander.java @@ -1,8 +1,6 @@ - package mage.deck; /** - * * @author andreacosta */ public class CenturionCommander extends Commander { @@ -16,14 +14,12 @@ public class CenturionCommander extends Commander { banned.add("Bazaar of Baghdad"); banned.add("Black Lotus"); banned.add("Channel"); - banned.add("Chaos Orb"); banned.add("Chrome Mox"); banned.add("Demonic Tutor"); banned.add("Dig Through Time"); banned.add("Emrakul, the Aeons Torn"); banned.add("Emrakul, the Promised End"); banned.add("Entomb"); - banned.add("Falling Star"); banned.add("Fastbond"); banned.add("Food Chain"); banned.add("Gaea's Cradle"); @@ -53,7 +49,6 @@ public class CenturionCommander extends Commander { banned.add("Parallax Tide"); banned.add("Protean Hulk"); banned.add("Sensei's Diving Top"); - banned.add("Sharazad"); banned.add("Survival of the Fittest"); banned.add("Sol Ring"); banned.add("Strip Mine"); @@ -83,5 +78,4 @@ public class CenturionCommander extends Commander { bannedPartner.add("Kraum, Ludevic's Opus"); bannedPartner.add("Thrasios, Triton Hero "); } - } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java index cdf129c452f..63e9bec779a 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java @@ -1,51 +1,25 @@ package mage.deck; -import mage.MageObject; -import mage.ObjectColor; -import mage.abilities.Ability; -import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.keyword.CompanionAbility; -import mage.abilities.keyword.FriendsForeverAbility; -import mage.abilities.keyword.PartnerAbility; -import mage.abilities.keyword.PartnerWithAbility; -import mage.cards.Card; import mage.cards.ExpansionSet; import mage.cards.Sets; -import mage.cards.decks.Constructed; -import mage.cards.decks.Deck; import mage.cards.decks.DeckValidatorErrorType; -import mage.constants.CardType; -import mage.filter.FilterMana; -import mage.util.CardUtil; -import mage.util.ManaUtil; -import java.util.*; +import java.util.Map; /** * @author Plopman */ -public class Commander extends Constructed { - - protected final List bannedCommander = new ArrayList<>(); - protected final List bannedPartner = new ArrayList<>(); - protected boolean partnerAllowed = true; +public class Commander extends AbstractCommander { public Commander() { - super("Commander"); - for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType().isEternalLegal()) { - setCodes.add(set.getCode()); - } - } + this("Commander"); banned.add("Ancestral Recall"); banned.add("Balance"); banned.add("Biorhythm"); banned.add("Black Lotus"); banned.add("Braids, Cabal Minion"); banned.add("Channel"); - banned.add("Cleanse"); banned.add("Coalition Victory"); - banned.add("Crusade"); banned.add("Emrakul, the Aeons Torn"); banned.add("Erayo, Soratami Ascendant"); banned.add("Fastbond"); @@ -54,8 +28,6 @@ public class Commander extends Constructed { banned.add("Golos, Tireless Pilgrim"); banned.add("Griselbrand"); banned.add("Hullbreacher"); - banned.add("Imprison"); - banned.add("Invoke Prejudice"); banned.add("Iona, Shield of Emeria"); banned.add("Jihad"); banned.add("Karakas"); @@ -70,12 +42,10 @@ public class Commander extends Constructed { banned.add("Mox Sapphire"); banned.add("Panoptic Mirror"); banned.add("Paradox Engine"); - banned.add("Pradesh Gypsies"); banned.add("Primeval Titan"); banned.add("Prophet of Kruphix"); banned.add("Recurring Nightmare"); banned.add("Rofellos, Llanowar Emissary"); - banned.add("Stone-Throwing Devils"); banned.add("Sundering Titan"); banned.add("Sway of the Stars"); banned.add("Sylvan Primordial"); @@ -88,931 +58,24 @@ public class Commander extends Constructed { banned.add("Yawgmoth's Bargain"); } - public Commander(String name) { + protected Commander(String name) { super(name); - } - - public Commander(String name, String shortName) { - super(name, shortName); + for (ExpansionSet set : Sets.getInstance().values()) { + if (set.getSetType().isEternalLegal()) { + setCodes.add(set.getCode()); + } + } } @Override - public int getDeckMinSize() { - return 98; - } - - @Override - public int getSideboardMinSize() { - return 1; - } - - @Override - public boolean validate(Deck deck) { + protected boolean checkBanned(Map counts) { boolean valid = true; - errorsList.clear(); - FilterMana colorIdentity = new FilterMana(); - Set commanders = new HashSet<>(); - Card companion; - - int sbsize = deck.getSideboard().size(); - Card card1; - Card card2; - Card card3; - Iterator iter; - switch (deck.getSideboard().size()) { - case 1: - companion = null; - commanders.add(deck.getSideboard().iterator().next()); - break; - case 2: - iter = deck.getSideboard().iterator(); - card1 = iter.next(); - card2 = iter.next(); - if (card1.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) { - companion = card1; - commanders.add(card2); - } else if (card2.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) { - companion = card2; - commanders.add(card1); - } else { - companion = null; - commanders.add(card1); - commanders.add(card2); - } - break; - case 3: - iter = deck.getSideboard().iterator(); - card1 = iter.next(); - card2 = iter.next(); - card3 = iter.next(); - if (card1.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) { - companion = card1; - commanders.add(card2); - commanders.add(card3); - } else if (card2.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) { - companion = card2; - commanders.add(card1); - commanders.add(card3); - } else if (card3.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) { - companion = card3; - commanders.add(card1); - commanders.add(card2); - } else { - companion = null; - addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion"); - valid = false; - } - break; - default: - companion = null; - addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion"); - valid = false; - } - - if (companion != null && deck.getCards().size() + deck.getSideboard().size() != 101) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 101 + " cards (companion doesn't count for deck size): has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); - valid = false; - } else if (companion == null && deck.getCards().size() + deck.getSideboard().size() != 100) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 100 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); - valid = false; - } - - Map counts = new HashMap<>(); - countCards(counts, deck.getCards()); - countCards(counts, deck.getSideboard()); - valid = checkCounts(1, counts) && valid; - for (String bannedCard : banned) { if (counts.containsKey(bannedCard)) { addError(DeckValidatorErrorType.BANNED, bannedCard, "Banned", true); valid = false; } } - - Set commanderNames = new HashSet<>(); - for (Card commander : commanders) { - commanderNames.add(commander.getName()); - } - if (commanders.size() == 2 - && commanders - .stream() - .map(MageObject::getAbilities) - .filter(abilities -> abilities.contains(PartnerAbility.getInstance())) - .count() != 2 - && commanders - .stream() - .map(MageObject::getAbilities) - .filter(abilities -> abilities.contains(FriendsForeverAbility.getInstance())) - .count() != 2 - && !CardUtil - .castStream(commanders.stream().map(MageObject::getAbilities), PartnerWithAbility.class) - .map(PartnerWithAbility::getPartnerName) - .allMatch(commanderNames::contains)) { - for (Card commander : commanders) { - addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander with invalid Partner (" + commander.getName() + ')', true); - valid = false; - } - } - for (Card commander : commanders) { - if (bannedCommander.contains(commander.getName())) { - addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander banned (" + commander.getName() + ')', true); - valid = false; - } - if ((!commander.hasCardTypeForDeckbuilding(CardType.CREATURE) || !commander.isLegendary()) - && !commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance())) { - addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander invalid (" + commander.getName() + ')', true); - valid = false; - } - if (commanders.size() == 2 && bannedPartner.contains(commander.getName())) { - addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander Partner banned (" + commander.getName() + ')', true); - valid = false; - } - ManaUtil.collectColorIdentity(colorIdentity, commander.getColorIdentity()); - } - - // no needs in cards check on wrong commanders - if (!valid) { - return false; - } - - for (Card card : deck.getCards()) { - if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) { - addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true); - valid = false; - } - } - for (Card card : deck.getSideboard()) { - if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) { - addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true); - valid = false; - } - } - for (Card card : deck.getCards()) { - if (!isSetAllowed(card.getExpansionSetCode())) { - if (!legalSets(card)) { - addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true); - valid = false; - } - } - } - for (Card card : deck.getSideboard()) { - if (!isSetAllowed(card.getExpansionSetCode())) { - if (!legalSets(card)) { - addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true); - valid = false; - } - } - } - // Check for companion legality - if (companion != null) { - Set cards = new HashSet<>(deck.getCards()); - cards.addAll(commanders); - for (Ability ability : companion.getAbilities()) { - if (ability instanceof CompanionAbility) { - CompanionAbility companionAbility = (CompanionAbility) ability; - if (!companionAbility.isLegal(cards, getDeckMinSize())) { - addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Commander Companion (deck invalid for companion)", true); - valid = false; - } - break; - } - } - } return valid; } - - @Override - public int getEdhPowerLevel(Deck deck) { - if (deck == null) { - return 0; - } - - int edhPowerLevel = 0; - int commanderColors = 0; - int numberInfinitePieces = 0; - - for (Card card : deck.getCards()) { - - int thisMaxPower = 0; - - // Examine rules to work out most egregious functions in edh - boolean anyNumberOfTarget = false; - boolean annihilator = false; - boolean buyback = false; - boolean cascade = false; - boolean cantBe = false; - boolean cantUntap = false; - boolean copy = false; - boolean costLessEach = false; - boolean createToken = false; - boolean dredge = false; - boolean exile = false; - boolean exileAll = false; - boolean counter = false; - boolean destroy = false; - boolean destroyAll = false; - boolean each = false; - boolean exalted = false; - boolean doesntUntap = false; - boolean drawCards = false; - boolean evoke = false; - boolean extraTurns = false; - boolean flash = false; - boolean flashback = false; - boolean flicker = false; - boolean gainControl = false; - boolean hexproof = false; - boolean infect = false; - boolean lifeTotalBecomes = false; - boolean mayCastForFree = false; - boolean menace = false; - boolean miracle = false; - boolean overload = false; - boolean persist = false; - boolean preventDamage = false; - boolean proliferate = false; - boolean protection = false; - boolean putUnderYourControl = false; - boolean retrace = false; - boolean returnFromYourGY = false; - boolean sacrifice = false; - boolean shroud = false; - boolean skip = false; - boolean sliver = false; - boolean storm = false; - boolean trample = false; - boolean tutor = false; - boolean tutorBasic = false; - boolean twiceAs = false; - boolean unblockable = false; - boolean undying = false; - boolean untapTarget = false; - boolean wheneverEnters = false; - boolean whenCounterThatSpell = false; - boolean xCost = false; - boolean youControlTarget = false; - boolean yourOpponentsControl = false; - boolean whenYouCast = false; - - for (String str : card.getRules()) { - String s = str.toLowerCase(Locale.ENGLISH); - annihilator |= s.contains("annihilator"); - anyNumberOfTarget |= s.contains("any number"); - buyback |= s.contains("buyback"); - cantUntap |= s.contains("can't untap") || s.contains("don't untap"); - cantBe |= s.contains("can't be"); - cascade |= s.contains("cascade"); - copy |= s.contains("copy"); - costLessEach |= s.contains("cost") || s.contains("less") || s.contains("each"); - counter |= s.contains("counter") && s.contains("target"); - createToken |= s.contains("create") && s.contains("token"); - destroy |= s.contains("destroy"); - destroyAll |= s.contains("destroy all"); - doesntUntap |= s.contains("doesn't untap"); - doesntUntap |= s.contains("don't untap"); - drawCards |= s.contains("draw cards"); - dredge |= s.contains("dredge"); - each |= s.contains("each"); - evoke |= s.contains("evoke"); - exalted |= s.contains("exalted"); - exile |= s.contains("exile"); - exileAll |= s.contains("exile") && s.contains(" all "); - extraTurns |= s.contains("extra turn"); - flicker |= s.contains("exile") && s.contains("return") && s.contains("to the battlefield under"); - flash |= s.contains("flash"); - flashback |= s.contains("flashback"); - gainControl |= s.contains("gain control"); - hexproof |= s.contains("hexproof"); - infect |= s.contains("infect"); - lifeTotalBecomes |= s.contains("life total becomes"); - mayCastForFree |= s.contains("may cast") && s.contains("without paying"); - menace |= s.contains("menace"); - miracle |= s.contains("miracle"); - overload |= s.contains("overload"); - persist |= s.contains("persist"); - preventDamage |= s.contains("prevent") && s.contains("all") && s.contains("damage"); - proliferate |= s.contains("proliferate"); - protection |= s.contains("protection"); - putUnderYourControl |= s.contains("put") && s.contains("under your control"); - retrace |= s.contains("retrace"); - returnFromYourGY |= s.contains("return") && s.contains("from your graveyard"); - sacrifice |= s.contains("sacrifice"); - shroud |= s.contains("shroud"); - skip |= s.contains("skip"); - sliver |= s.contains("sliver"); - storm |= s.contains("storm"); - trample |= s.contains("trample"); - tutor |= s.contains("search your library") && !s.contains("basic land"); - tutorBasic |= s.contains("search your library") && s.contains("basic land"); - twiceAs |= s.contains("twice that many") || s.contains("twice as much"); - unblockable |= s.contains("can't be blocked"); - undying |= s.contains("undying"); - untapTarget |= s.contains("untap target"); - whenCounterThatSpell |= s.contains("when") && s.contains("counter that spell"); - wheneverEnters |= s.contains("when") && s.contains("another") && s.contains("enters"); - youControlTarget |= s.contains("you control target"); - yourOpponentsControl |= s.contains("your opponents control"); - whenYouCast |= s.contains("when you cast") || s.contains("whenever you cast"); - } - - for (String s : card.getManaCostSymbols()) { - if (s.contains("X")) { - xCost = true; - } - } - for (Ability a : card.getAbilities()) { - for (String s : a.getManaCostSymbols()) { - if (s.contains("X")) { - xCost = true; - } - } - } - - if (extraTurns) { - thisMaxPower = Math.max(thisMaxPower, 7); - } - if (buyback) { - thisMaxPower = Math.max(thisMaxPower, 6); - } - if (tutor) { - thisMaxPower = Math.max(thisMaxPower, 6); - } - if (annihilator) { - thisMaxPower = Math.max(thisMaxPower, 5); - } - if (cantUntap) { - thisMaxPower = Math.max(thisMaxPower, 5); - } - if (costLessEach) { - thisMaxPower = Math.max(thisMaxPower, 5); - } - if (infect) { - thisMaxPower = Math.max(thisMaxPower, 5); - } - if (overload) { - thisMaxPower = Math.max(thisMaxPower, 5); - } - if (twiceAs) { - thisMaxPower = Math.max(thisMaxPower, 5); - } - if (cascade) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (doesntUntap) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (each) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (exileAll) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (flash) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (flashback) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (flicker) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (gainControl) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (lifeTotalBecomes) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (mayCastForFree) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (preventDamage) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (proliferate) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (protection) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (putUnderYourControl) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (returnFromYourGY) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (sacrifice) { - thisMaxPower = Math.max(thisMaxPower, 2); - } - if (skip) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (storm) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (unblockable) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (whenCounterThatSpell) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (wheneverEnters) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (xCost) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (youControlTarget) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (yourOpponentsControl) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (whenYouCast) { - thisMaxPower = Math.max(thisMaxPower, 4); - } - if (anyNumberOfTarget) { - thisMaxPower = Math.max(thisMaxPower, 3); - } - if (createToken) { - thisMaxPower = Math.max(thisMaxPower, 3); - } - if (destroyAll) { - thisMaxPower = Math.max(thisMaxPower, 3); - } - if (dredge) { - thisMaxPower = Math.max(thisMaxPower, 3); - } - if (hexproof) { - thisMaxPower = Math.max(thisMaxPower, 3); - } - if (shroud) { - thisMaxPower = Math.max(thisMaxPower, 3); - } - if (undying) { - thisMaxPower = Math.max(thisMaxPower, 3); - } - if (persist) { - thisMaxPower = Math.max(thisMaxPower, 3); - } - if (cantBe) { - thisMaxPower = Math.max(thisMaxPower, 2); - } - if (evoke) { - thisMaxPower = Math.max(thisMaxPower, 2); - } - if (exile) { - thisMaxPower = Math.max(thisMaxPower, 2); - } - if (menace) { - thisMaxPower = Math.max(thisMaxPower, 2); - } - if (miracle) { - thisMaxPower = Math.max(thisMaxPower, 2); - } - if (sliver) { - thisMaxPower = Math.max(thisMaxPower, 2); - } - if (untapTarget) { - thisMaxPower = Math.max(thisMaxPower, 2); - } - if (copy) { - thisMaxPower = Math.max(thisMaxPower, 1); - } - if (counter) { - thisMaxPower = Math.max(thisMaxPower, 1); - } - if (destroy) { - thisMaxPower = Math.max(thisMaxPower, 1); - } - if (drawCards) { - thisMaxPower = Math.max(thisMaxPower, 1); - } - if (exalted) { - thisMaxPower = Math.max(thisMaxPower, 1); - } - if (retrace) { - thisMaxPower = Math.max(thisMaxPower, 1); - } - if (trample) { - thisMaxPower = Math.max(thisMaxPower, 1); - } - if (tutorBasic) { - thisMaxPower = Math.max(thisMaxPower, 1); - } - - if (card.isPlaneswalker()) { - thisMaxPower = Math.max(thisMaxPower, 6); - } - - String cn = card.getName().toLowerCase(Locale.ENGLISH); - if (cn.equals("ancient tomb") - || cn.equals("anafenza, the foremost") - || cn.equals("arcum dagsson") - || cn.equals("armageddon") - || cn.equals("aura shards") - || cn.equals("azami, lady of scrolls") - || cn.equals("azusa, lost but seeking") - || cn.equals("back to basics") - || cn.equals("bane of progress") - || cn.equals("basalt monolith") - || cn.equals("blightsteel collossus") - || cn.equals("blood moon") - || cn.equals("braids, cabal minion") - || cn.equals("cabal coffers") - || cn.equals("captain sisay") - || cn.equals("celestial dawn") - || cn.equals("child of alara") - || cn.equals("coalition relic") - || cn.equals("craterhoof behemoth") - || cn.equals("deepglow skate") - || cn.equals("derevi, empyrial tactician") - || cn.equals("dig through time") - || cn.equals("edric, spymaster of trest") - || cn.equals("elesh norn, grand cenobite") - || cn.equals("entomb") - || cn.equals("force of will") - || cn.equals("food chain") - || cn.equals("gaddock teeg") - || cn.equals("gaea's cradle") - || cn.equals("grand arbiter augustin iv") - || cn.equals("grim monolith") - || cn.equals("hermit druid") - || cn.equals("hokori, dust drinker") - || cn.equals("humility") - || cn.equals("imperial seal") - || cn.equals("iona, shield of emeria") - || cn.equals("jin-gitaxias, core augur") - || cn.equals("karador, ghost chieftain") - || cn.equals("karakas") - || cn.equals("kataki, war's wage") - || cn.equals("knowledge pool") - || cn.equals("linvala, keeper of silence") - || cn.equals("living death") - || cn.equals("llawan, cephalid empress") - || cn.equals("loyal retainers") - || cn.equals("maelstrom wanderer") - || cn.equals("malfegor") - || cn.equals("master of cruelties") - || cn.equals("mana crypt") - || cn.equals("mana drain") - || cn.equals("mana vault") - || cn.equals("michiko konda, truth seeker") - || cn.equals("nath of the gilt-leaf") - || cn.equals("natural order") - || cn.equals("necrotic ooze") - || cn.equals("nicol bolas") - || cn.equals("numot, the devastator") - || cn.equals("oath of druids") - || cn.equals("pattern of rebirth") - || cn.equals("protean hulk") - || cn.equals("purphoros, god of the forge") - || cn.equals("ravages of war") - || cn.equals("reclamation sage") - || cn.equals("sen triplets") - || cn.equals("serra's sanctum") - || cn.equals("sheoldred, whispering one") - || cn.equals("sol ring") - || cn.equals("spore frog") - || cn.equals("stasis") - || cn.equals("strip mine") - || cn.equals("the tabernacle at pendrell vale") - || cn.equals("tinker") - || cn.equals("treasure cruise") - || cn.equals("urabrask the hidden") - || cn.equals("vorinclex, voice of hunger") - || cn.equals("winter orb") - || cn.equals("zur the enchanter")) { - thisMaxPower = Math.max(thisMaxPower, 12); - } - - // Parts of infinite combos - if (cn.equals("animate artifact") || cn.equals("animar, soul of element") - || cn.equals("archaeomancer") - || cn.equals("ashnod's altar") || cn.equals("azami, lady of scrolls") - || cn.equals("aura flux") - || cn.equals("basalt monolith") || cn.equals("brago, king eternal") - || cn.equals("candelabra of tawnos") || cn.equals("cephalid aristocrat") - || cn.equals("cephalid illusionist") || cn.equals("changeling berserker") - || cn.equals("consecrated sphinx") - || cn.equals("cyclonic rift") - || cn.equals("the chain veil") - || cn.equals("cinderhaze wretch") || cn.equals("cryptic gateway") - || cn.equals("deadeye navigator") || cn.equals("derevi, empyrial tactician") - || cn.equals("doubling season") || cn.equals("dross scorpion") - || cn.equals("earthcraft") || cn.equals("erratic portal") - || cn.equals("enter the infinite") || cn.equals("omniscience") - || cn.equals("exquisite blood") || cn.equals("future sight") - || cn.equals("genesis chamber") - || cn.equals("ghave, guru of spores") - || cn.equals("grave pact") - || cn.equals("grave titan") || cn.equals("great whale") - || cn.equals("grim monolith") || cn.equals("gush") - || cn.equals("hellkite charger") || cn.equals("intruder alarm") - || cn.equals("helm of obedience") - || cn.equals("hermit druid") - || cn.equals("humility") - || cn.equals("iona, shield of emeria") - || cn.equals("karn, silver golem") || cn.equals("kiki-jiki, mirror breaker") - || cn.equals("krark-clan ironworks") || cn.equals("krenko, mob boss") - || cn.equals("krosan restorer") || cn.equals("laboratory maniac") - || cn.equals("leonin relic-warder") || cn.equals("leyline of the void") - || cn.equals("memnarch") - || cn.equals("meren of clan nel toth") || cn.equals("mikaeus, the unhallowed") - || cn.equals("mindcrank") || cn.equals("mindslaver") - || cn.equals("minion reflector") || cn.equals("mycosynth lattice") - || cn.equals("myr turbine") || cn.equals("narset, enlightened master") - || cn.equals("nekusar, the mindrazer") || cn.equals("norin the wary") - || cn.equals("notion thief") - || cn.equals("opalescence") || cn.equals("ornithopter") - || cn.equals("paradox engine") - || cn.equals("purphoros, god of the forge") - || cn.equals("peregrine drake") || cn.equals("palinchron") - || cn.equals("planar portal") || cn.equals("power artifact") - || cn.equals("rings of brighthearth") || cn.equals("rite of replication") - || cn.equals("sanguine bond") || cn.equals("sensei's divining top") - || cn.equals("splinter twin") || cn.equals("stony silence") - || cn.equals("sunder") - || cn.equals("storm cauldron") || cn.equals("teferi's puzzle box") - || cn.equals("tangle wire") - || cn.equals("teferi, mage of zhalfir") - || cn.equals("tezzeret the seeker") || cn.equals("time stretch") - || cn.equals("time warp") || cn.equals("training grounds") - || cn.equals("triskelavus") || cn.equals("triskelion") - || cn.equals("turnabout") || cn.equals("umbral mantle") - || cn.equals("uyo, silent prophet") || cn.equals("voltaic key") - || cn.equals("workhorse") || cn.equals("worldgorger dragon") - || cn.equals("worthy cause") || cn.equals("yawgmoth's will") - || cn.equals("zealous conscripts")) { - thisMaxPower = Math.max(thisMaxPower, 15); - numberInfinitePieces++; - } - - // Saltiest cards (edhrec) - if (cn.equals("acid rain") - || cn.equals("agent of treachery") - || cn.equals("apocalypse") - || cn.equals("armageddon") - || cn.equals("atraxa, praetors' voice") - || cn.equals("aura shards") - || cn.equals("avacyn, angel of hope") - || cn.equals("back to basics") - || cn.equals("bend or break") - || cn.equals("blightsteel colossus") - || cn.equals("blood moon") - || cn.equals("boil") - || cn.equals("boiling seas") - || cn.equals("bribery") - || cn.equals("burning sands") - || cn.equals("card view") - || cn.equals("cataclysm") - || cn.equals("catastrophe") - || cn.equals("chulane, teller of tales") - || cn.equals("confusion in the ranks") - || cn.equals("consecrated sphinx") - || cn.equals("contamination") - || cn.equals("craterhoof behemoth") - || cn.equals("cyclonic rift") - || cn.equals("death cloud") - || cn.equals("decree of annihilation") - || cn.equals("decree of silence") - || cn.equals("demonic consultation") - || cn.equals("derevi, empyrial tactician") - || cn.equals("devastation") - || cn.equals("divine intervention") - || cn.equals("dockside extortionist") - || cn.equals("doomsday") - || cn.equals("doubling season") - || cn.equals("drannith magistrate") - || cn.equals("elesh norn, grand cenobite") - || cn.equals("embargo") - || cn.equals("emrakul, the promised end") - || cn.equals("epicenter") - || cn.equals("expropriate") - || cn.equals("fall of the thran") - || cn.equals("fierce guardianship") - || cn.equals("food chain") - || cn.equals("force of negation") - || cn.equals("force of will") - || cn.equals("gaddock teeg") - || cn.equals("gaea's cradle") - || cn.equals("gilded drake") - || cn.equals("glenn, the voice of calm") - || cn.equals("global ruin") - || cn.equals("golos, tireless pilgrim") - || cn.equals("grand arbiter augustin iv") - || cn.equals("grip of chaos") - || cn.equals("hokori, dust drinker") - || cn.equals("humility") - || cn.equals("impending disaster") - || cn.equals("invoke prejudice") - || cn.equals("iona, shield of emeria") - || cn.equals("jin-gitaxias, core augur") - || cn.equals("jokulhaups") - || cn.equals("keldon firebombers") - || cn.equals("kinnan, bonder prodigy") - || cn.equals("kozilek, butcher of truth") - || cn.equals("land equilibrium") - || cn.equals("linvala, keeper of silence") - || cn.equals("magister sphinx") - || cn.equals("mana breach") - || cn.equals("mana crypt") - || cn.equals("mana drain") - || cn.equals("mana vortex") - || cn.equals("mindslaver") - || cn.equals("narset, enlightened master") - || cn.equals("narset, parter of veils") - || cn.equals("negan, the cold-blooded") - || cn.equals("nether void") - || cn.equals("nexus of fate") - || cn.equals("notion thief") - || cn.equals("obliterate") - || cn.equals("oko, thief of crowns") - || cn.equals("oloro, ageless ascetic") - || cn.equals("omniscience") - || cn.equals("opposition agent") - || cn.equals("oppression") - || cn.equals("overwhelming splendor") - || cn.equals("palinchron") - || cn.equals("paradox engine") - || cn.equals("possessed portal") - || cn.equals("price of glory") - || cn.equals("protean hulk") - || cn.equals("ravages of war") - || cn.equals("rhystic study") - || cn.equals("rick, steadfast leader") - || cn.equals("rising waters") - || cn.equals("ruination") - || cn.equals("scrambleverse") - || cn.equals("seedborn muse") - || cn.equals("sen triplets") - || cn.equals("sire of insanity") - || cn.equals("skithiryx, the blight dragon") - || cn.equals("smokestack") - || cn.equals("smothering tithe") - || cn.equals("sorin markov") - || cn.equals("stasis") - || cn.equals("static orb") - || cn.equals("storage matrix") - || cn.equals("sunder") - || cn.equals("survival of the fittest") - || cn.equals("table view") - || cn.equals("tainted aether") - || cn.equals("tectonic break") - || cn.equals("teferi's protection") - || cn.equals("teferi, master of time") - || cn.equals("teferi, time raveler") - || cn.equals("temporal manipulation") - || cn.equals("tergrid, god of fright") - || cn.equals("text view") - || cn.equals("thassa's oracle") - || cn.equals("the tabernacle at pendrell vale") - || cn.equals("thieves' auction") - || cn.equals("thoughts of ruin") - || cn.equals("thrasios, triton hero") - || cn.equals("time stretch") - || cn.equals("time warp") - || cn.equals("tooth and nail") - || cn.equals("torment of hailfire") - || cn.equals("torpor orb") - || cn.equals("triumph of the hordes") - || cn.equals("ugin, the spirit dragon") - || cn.equals("ulamog, the ceaseless hunger") - || cn.equals("ulamog, the infinite gyre") - || cn.equals("urza, lord high artificer") - || cn.equals("void winnower") - || cn.equals("vorinclex, voice of hunger") - || cn.equals("wake of destruction") - || cn.equals("warp world") - || cn.equals("winter orb") - || cn.equals("xanathar, guild kingpin") - || cn.equals("zur the enchanter")) { - thisMaxPower = Math.max(thisMaxPower, 15); - } - edhPowerLevel += thisMaxPower; - } - - ObjectColor color = null; - for (Card commander : deck.getSideboard()) { - int thisMaxPower = 0; - String cn = commander.getName().toLowerCase(Locale.ENGLISH); - if (color == null) { - color = commander.getColor(null); - } else { - color = color.union(commander.getColor(null)); - } - - FilterMana commanderColor = commander.getColorIdentity(); - if (commanderColor.isWhite()) { - color.setWhite(true); - } - if (commanderColor.isBlue()) { - color.setBlue(true); - } - if (commanderColor.isBlack()) { - color.setBlack(true); - } - if (commanderColor.isRed()) { - color.setRed(true); - } - if (commanderColor.isGreen()) { - color.setGreen(true); - } - - // Least fun commanders - if (cn.equals("animar, soul of element") - || cn.equals("anafenza, the foremost") - || cn.equals("arcum dagsson") - || cn.equals("azami, lady of scrolls") - || cn.equals("azusa, lost but seeking") - || cn.equals("brago, king eternal") - || cn.equals("braids, cabal minion") - || cn.equals("captain sisay") - || cn.equals("child of alara") - || cn.equals("derevi, empyrial tactician") - || cn.equals("edric, spymaster of trest") - || cn.equals("elesh norn, grand cenobite") - || cn.equals("gaddock teeg") - || cn.equals("grand arbiter augustin iv") - || cn.equals("hokori, dust drinker") - || cn.equals("iona, shield of emeria") - || cn.equals("jin-gitaxias, core augur") - || cn.equals("kaalia of the vast") - || cn.equals("karador, ghost chieftain") - || cn.equals("leovold, emissary of trest") - || cn.equals("linvala, keeper of silence") - || cn.equals("llawan, cephalid empress") - || cn.equals("maelstrom wanderer") - || cn.equals("malfegor") - || cn.equals("memnarch") - || cn.equals("meren of clan nel toth") - || cn.equals("michiko konda, truth seeker") - || cn.equals("mikaeus the unhallowed") - || cn.equals("narset, enlightened master") - || cn.equals("nath of the gilt-leaf") - || cn.equals("nekusar, the mindrazer") - || cn.equals("norin the wary") - || cn.equals("numot, the devastator") - || cn.equals("prossh, skyraider of kher") - || cn.equals("purphoros, god of the forge") - || cn.equals("sen triplets") - || cn.equals("sheoldred, whispering one") - || cn.equals("teferi, mage of zhalfir") - || cn.equals("urabrask the hidden") - || cn.equals("vorinclex, voice of hunger") - || cn.equals("zur the enchanter")) { - thisMaxPower = Math.max(thisMaxPower, 25); - } - - // Saltiest commanders - if (cn.equals("atraxa, praetors' voice") - || cn.equals("avacyn, angel of hope") - || cn.equals("chulane, teller of tales") - || cn.equals("derevi, empyrial tactician") - || cn.equals("elesh norn, grand cenobite") - || cn.equals("emrakul, the promised end") - || cn.equals("gaddock teeg") - || cn.equals("glenn, the voice of calm") - || cn.equals("golos, tireless pilgrim") - || cn.equals("grand arbiter augustin iv") - || cn.equals("hokori, dust drinker") - || cn.equals("iona, shield of emeria") - || cn.equals("jin-gitaxias, core augur") - || cn.equals("kinnan, bonder prodigy") - || cn.equals("kozilek, butcher of truth") - || cn.equals("linvala, keeper of silence") - || cn.equals("narset, enlightened master") - || cn.equals("negan, the cold-blooded") - || cn.equals("oko, thief of crowns") - || cn.equals("oloro, ageless ascetic") - || cn.equals("rick, steadfast leader") - || cn.equals("sen triplets") - || cn.equals("skithiryx, the blight dragon") - || cn.equals("teferi, master of time") - || cn.equals("teferi, time raveler") - || cn.equals("thrasios, triton hero") - || cn.equals("ulamog, the ceaseless hunger") - || cn.equals("ulamog, the infinite gyre") - || cn.equals("urza, lord high artificer") - || cn.equals("vorinclex, voice of hunger") - || cn.equals("xanathar, guild kingpin") - || cn.equals("zur the enchanter")) { - thisMaxPower = Math.max(thisMaxPower, 20); - } - edhPowerLevel += thisMaxPower; - } - - edhPowerLevel += numberInfinitePieces * 18; - edhPowerLevel = Math.round(edhPowerLevel / 10); - if (edhPowerLevel >= 100) { - edhPowerLevel = 99; - } - if (color != null) { - edhPowerLevel += (color.isWhite() ? 10000000 : 0); - edhPowerLevel += (color.isBlue() ? 1000000 : 0); - edhPowerLevel += (color.isBlack() ? 100000 : 0); - edhPowerLevel += (color.isRed() ? 10000 : 0); - edhPowerLevel += (color.isGreen() ? 1000 : 0); - } - return edhPowerLevel; - } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/DuelCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/DuelCommander.java index 1461e02db88..82d7045d0ee 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/DuelCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/DuelCommander.java @@ -15,8 +15,6 @@ public class DuelCommander extends Commander { banned.add("Cavern of Souls"); banned.add("Channel"); banned.add("Chrome Mox"); - banned.add("Cleanse"); - banned.add("Crusade"); banned.add("Deflecting Swat"); banned.add("Dig Through Time"); banned.add("Eidolon of the Great Revel"); @@ -34,15 +32,12 @@ public class DuelCommander extends Commander { banned.add("High Tide"); banned.add("Humility"); banned.add("Imperial Seal"); - banned.add("Imprison"); - banned.add("Invoke Prejudice"); banned.add("Jeweled Lotus"); - banned.add("Jihad"); banned.add("Karakas"); banned.add("Library of Alexandria"); banned.add("Lion's Eye Diamond"); - banned.add("Lutri, The Spellchaser"); banned.add("Loyal Retainers"); + banned.add("Lutri, the Spellchaser"); banned.add("Maddening Hex"); banned.add("Mana Crypt"); banned.add("Mana Drain"); @@ -60,13 +55,11 @@ public class DuelCommander extends Commander { banned.add("Necrotic Ooze"); banned.add("Oath of Druids"); banned.add("Polymorph"); - banned.add("Pradesh Gypsies"); banned.add("Price of Progress"); banned.add("Protean Hulk"); banned.add("Scapeshift"); banned.add("Sensei's Divining Top"); banned.add("Sol Ring"); - banned.add("Stone-Throwing Devils"); banned.add("Strip Mine"); banned.add("Temporal Manipulation"); banned.add("Thassa's Oracle"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/EuropeanHighlander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/EuropeanHighlander.java index 85e04bb2c50..b661dd64125 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/EuropeanHighlander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/EuropeanHighlander.java @@ -10,6 +10,7 @@ import java.util.HashMap; import java.util.Map; /** + * @author ddzn * @brief European Highlander is a classic competitive singleton format formalized around 2003. * It is also known as 'German Highlander'. * In short: 20 pts starting life, 100 card singleton deck without sideboard. @@ -18,7 +19,6 @@ import java.util.Map; * More info at http://highlandermagic.info * Banned list here http://highlandermagic.info/banned-list * Watch list here http://highlandermagic.info/watch-list - * @author ddzn */ public class EuropeanHighlander extends Constructed { @@ -34,91 +34,10 @@ public class EuropeanHighlander extends Constructed { // Since then, the tournament organizer must decide if the cards are allowed // The following ban list is decided by the council in cooperation with the community (last update: 15.11.2020) - - // Silver-bordered cards are banned - - // Conspiracy cards are banned - banned.add("Adriana's Valor"); - banned.add("Advantageous Proclamation"); - banned.add("Assemble the Rank and Vile"); - banned.add("Backup Plan"); - banned.add("Brago's Favor"); - banned.add("Cleanse"); - banned.add("Crusade"); - banned.add("Double Stroke"); - banned.add("Echoing Boon"); - banned.add("Emissary's Ploy"); - banned.add("Hired Heist"); - banned.add("Hold the Perimeter"); - banned.add("Hymn of the Wilds"); - banned.add("Immediate Action"); - banned.add("Imprison"); - banned.add("Incendiary Dissent"); - banned.add("Iterative Analysis"); - banned.add("Invoke Prejudice"); - banned.add("Jihad"); - banned.add("Muzzio's Preparations"); - banned.add("Natural Unity"); - banned.add("Power Play"); - banned.add("Pradesh Gypsies"); - banned.add("Secrets of Paradise"); - banned.add("Secret Summoning"); - banned.add("Sentinel Dispatch"); - banned.add("Sovereign's Realm"); - banned.add("Stone-Throwing Devils"); - banned.add("Summoner's Bond"); - banned.add("Unexpected Potential"); - banned.add("Weight Advantage"); - banned.add("Worldknit"); - - // Dexterity cards are bannee - banned.add("Chaos Orb"); - banned.add("Falling Star"); - - // Sub-game cards are banned - banned.add("Shahrazad"); - - // Ante cards are banned - banned.add("Amulet of Quoz"); - banned.add("Bronze Tablet"); - banned.add("Contract from Below"); - banned.add("Darkpact"); - banned.add("Demonic Attorney"); - banned.add("Jeweled Bird"); - banned.add("Rebirth"); - banned.add("Tempest Efreet"); - banned.add("Timmerian Fiends"); - - // Potentially offensive cards are banned - banned.add("Cleanse"); - banned.add("Crusade"); - banned.add("Imprison"); - banned.add("Invoke Prejudice"); - banned.add("Jihad"); - banned.add("Pradesh Gypsies"); - banned.add("Stone-Throwing Devils"); - - // Cards from the "Living Dead" TV show crossover are banned - banned.add("Daryl, Hunter of Walkers"); - banned.add("Glenn, the Voice of Calm"); - banned.add("Michonne, Ruthless Survivor"); - banned.add("Negan, the Cold-Blooded"); - banned.add("Rick, Steadfast Leader"); - banned.add("Lucille"); - - // Power 9 except Time Twister - banned.add("Black Lotus"); banned.add("Ancestral Recall"); - banned.add("Mox Emerald"); - banned.add("Mox Jet"); - banned.add("Mox Pearl"); - banned.add("Mox Ruby"); - banned.add("Mox Sapphire"); - banned.add("Time Walk"); - - // Remaining cards banned.add("Balance"); banned.add("Birthing Pod"); + banned.add("Black Lotus"); banned.add("Flash"); banned.add("Gifts Ungiven"); banned.add("Library of Alexandria"); @@ -126,6 +45,11 @@ public class EuropeanHighlander extends Constructed { banned.add("Mana Vault"); banned.add("Mind Twist"); banned.add("Mystical Tutor"); + banned.add("Mox Emerald"); + banned.add("Mox Jet"); + banned.add("Mox Pearl"); + banned.add("Mox Ruby"); + banned.add("Mox Sapphire"); banned.add("Natural Order"); banned.add("Sensei's Divining Top"); banned.add("Skullclamp"); @@ -133,6 +57,7 @@ public class EuropeanHighlander extends Constructed { banned.add("Strip Mine"); banned.add("Survival of the Fittest"); banned.add("Time Vault"); + banned.add("Time Walk"); banned.add("Tinker"); banned.add("Tolarian Academy"); banned.add("Treasure Cruise"); @@ -140,7 +65,7 @@ public class EuropeanHighlander extends Constructed { banned.add("Umezawa's Jitte"); banned.add("Vampiric Tutor"); } - + @Override public int getDeckMinSize() { return 100; @@ -149,7 +74,7 @@ public class EuropeanHighlander extends Constructed { @Override public boolean validate(Deck deck) { errorsList.clear(); - + // Parent class checks the banned list boolean valid = super.validate(deck); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Freeform.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Freeform.java index f1336bf1026..db1e72f91cb 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Freeform.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Freeform.java @@ -10,11 +10,7 @@ import mage.cards.decks.DeckValidatorErrorType; public class Freeform extends DeckValidator { public Freeform() { - super("Constructed - Freeform"); - } - - public Freeform(String name) { - super(name); + this("Constructed - Freeform", null); } public Freeform(String name, String shortName) { diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java index 314df58b40c..dbaba363a59 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java @@ -1,28 +1,17 @@ package mage.deck; -import mage.abilities.Ability; -import mage.abilities.keyword.CompanionAbility; -import mage.abilities.keyword.PartnerAbility; -import mage.abilities.keyword.PartnerWithAbility; import mage.cards.Card; import mage.cards.ExpansionSet; import mage.cards.Sets; -import mage.cards.decks.Constructed; -import mage.cards.decks.Deck; import mage.cards.decks.DeckValidatorErrorType; import mage.constants.CardType; -import mage.filter.FilterMana; -import mage.util.ManaUtil; -import java.util.*; +import java.util.Map; /** * @author spjspj */ -public class FreeformCommander extends Constructed { - - protected List bannedCommander = new ArrayList<>(); - private static final Map pdAllowed = new HashMap<>(); +public class FreeformCommander extends AbstractCommander { public FreeformCommander() { super("Freeform Commander"); @@ -38,141 +27,17 @@ public class FreeformCommander extends Constructed { super(name); } - public FreeformCommander(String name, String shortName) { - super(name, shortName); + @Override + protected boolean checkBanned(Map counts) { + return true; } @Override - public int getDeckMinSize() { - return 98; - } - - @Override - public int getSideboardMinSize() { - return 1; - } - - @Override - public boolean validate(Deck deck) { - boolean valid = true; - errorsList.clear(); - FilterMana colorIdentity = new FilterMana(); - Set commanders = new HashSet<>(); - Card companion = null; - - if (deck.getSideboard().size() == 1) { - commanders.add(deck.getSideboard().iterator().next()); - } else if (deck.getSideboard().size() == 2) { - Iterator iter = deck.getSideboard().iterator(); - Card card1 = iter.next(); - Card card2 = iter.next(); - if (card1.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) { - companion = card1; - commanders.add(card2); - } else if (card2.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) { - companion = card2; - commanders.add(card1); - } else { - commanders.add(card1); - commanders.add(card2); - } - } else if (deck.getSideboard().size() == 3) { - Iterator iter = deck.getSideboard().iterator(); - Card card1 = iter.next(); - Card card2 = iter.next(); - Card card3 = iter.next(); - if (card1.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) { - companion = card1; - commanders.add(card2); - commanders.add(card3); - } else if (card2.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) { - companion = card2; - commanders.add(card1); - commanders.add(card3); - } else if (card3.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) { - companion = card3; - commanders.add(card1); - commanders.add(card2); - } else { - addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion"); - valid = false; - } - } else { - addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion"); - valid = false; - } - - if (companion != null && deck.getCards().size() + deck.getSideboard().size() != 101) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 101 + " cards (companion doesn't count for deck size): has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); - valid = false; - } else if (companion == null && deck.getCards().size() + deck.getSideboard().size() != 100) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 100 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); - valid = false; - } - - Map counts = new HashMap<>(); - countCards(counts, deck.getCards()); - countCards(counts, deck.getSideboard()); - valid = checkCounts(1, counts) && valid; - - Set commanderNames = new HashSet<>(); - for (Card commander : commanders) { - commanderNames.add(commander.getName()); - } - for (Card commander : commanders) { - if (!commander.hasCardTypeForDeckbuilding(CardType.CREATURE) && !commander.isLegendary()) { - addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "For Freeform Commander, the commander must be a creature or be legendary. Yours was: " + commander.getName(), true); - valid = false; - } - if (commanders.size() == 2) { - if (!commander.getAbilities().contains(PartnerAbility.getInstance())) { - boolean partnersWith = commander.getAbilities() - .stream() - .filter(PartnerWithAbility.class::isInstance) - .map(PartnerWithAbility.class::cast) - .map(PartnerWithAbility::getPartnerName) - .anyMatch(commanderNames::contains); - if (!partnersWith) { - addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander without Partner (" + commander.getName() + ')', true); - valid = false; - } - } - } - ManaUtil.collectColorIdentity(colorIdentity, commander.getColorIdentity()); - } - - // no needs in cards check on wrong commanders - if (!valid) { + protected boolean checkCommander(Card commander) { + if (!commander.hasCardTypeForDeckbuilding(CardType.CREATURE) && !commander.isLegendary()) { + addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "For Freeform Commander, the commander must be a creature or be legendary. Yours was: " + commander.getName(), true); return false; } - - for (Card card : deck.getCards()) { - if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) { - addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true); - valid = false; - } - } - for (Card card : deck.getSideboard()) { - if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) { - addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true); - valid = false; - } - } - // Check for companion legality - if (companion != null) { - Set cards = new HashSet<>(deck.getCards()); - cards.addAll(commanders); - for (Ability ability : companion.getAbilities()) { - if (ability instanceof CompanionAbility) { - CompanionAbility companionAbility = (CompanionAbility) ability; - if (!companionAbility.isLegal(cards, getDeckMinSize())) { - addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Commander Companion (deck invalid for companion)", true); - valid = false; - } - break; - } - } - } - return valid; + return true; } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Legacy.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Legacy.java index 195cfe17288..b92962f7713 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Legacy.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Legacy.java @@ -16,31 +16,18 @@ public class Legacy extends Constructed { setCodes.add(set.getCode()); } } - banned.add("Advantageous Proclamation"); - banned.add("Arcum's Astrolabe"); - banned.add("Amulet of Quoz"); banned.add("Ancestral Recall"); - banned.add("Backup Plan"); + banned.add("Arcum's Astrolabe"); banned.add("Balance"); banned.add("Bazaar of Baghdad"); banned.add("Black Lotus"); - banned.add("Brago's Favor"); - banned.add("Bronze Tablet"); banned.add("Channel"); - banned.add("Chaos Orb"); - banned.add("Cleanse"); - banned.add("Contract from Below"); - banned.add("Crusade"); - banned.add("Darkpact"); banned.add("Deathrite Shaman"); - banned.add("Demonic Attorney"); banned.add("Demonic Consultation"); banned.add("Demonic Tutor"); banned.add("Dig Through Time"); - banned.add("Double Stroke"); banned.add("Dreadhorde Arcanist"); banned.add("Earthcraft"); - banned.add("Falling Star"); banned.add("Fastbond"); banned.add("Flash"); banned.add("Frantic Search"); @@ -48,13 +35,7 @@ public class Legacy extends Constructed { banned.add("Goblin Recruiter"); banned.add("Gush"); banned.add("Hermit Druid"); - banned.add("Immediate Action"); banned.add("Imperial Seal"); - banned.add("Imprison"); - banned.add("Invoke Prejudice"); - banned.add("Iterative Analysis"); - banned.add("Jeweled Bird"); - banned.add("Jihad"); banned.add("Library of Alexandria"); banned.add("Lurrus of the Dream-Den"); banned.add("Mana Crypt"); @@ -62,47 +43,34 @@ public class Legacy extends Constructed { banned.add("Mana Vault"); banned.add("Memory Jar"); banned.add("Mental Misstep"); - banned.add("Mind Twist"); banned.add("Mind's Desire"); + banned.add("Mind Twist"); banned.add("Mishra's Workshop"); banned.add("Mox Emerald"); banned.add("Mox Jet"); banned.add("Mox Pearl"); banned.add("Mox Ruby"); banned.add("Mox Sapphire"); - banned.add("Muzzio's Preparations"); banned.add("Mystical Tutor"); banned.add("Necropotence"); banned.add("Oath of Druids"); banned.add("Oko, Thief of Crowns"); - banned.add("Power Play"); - banned.add("Pradesh Gypsies"); banned.add("Ragavan, Nimble Pilferer"); - banned.add("Rebirth"); - banned.add("Secret Summoning"); - banned.add("Secrets of Paradise"); banned.add("Sensei's Divining Top"); - banned.add("Sentinel Dispatch"); - banned.add("Shahrazad"); banned.add("Skullclamp"); banned.add("Sol Ring"); - banned.add("Stone-Throwing Devils"); banned.add("Strip Mine"); banned.add("Survival of the Fittest"); - banned.add("Tempest Efreet"); + banned.add("Timetwister"); banned.add("Time Vault"); banned.add("Time Walk"); - banned.add("Timetwister"); - banned.add("Timmerian Fiends"); banned.add("Tinker"); banned.add("Tolarian Academy"); banned.add("Treasure Cruise"); banned.add("Underworld Breach"); - banned.add("Unexpected Potential"); banned.add("Vampiric Tutor"); banned.add("Wheel of Fortune"); banned.add("Windfall"); - banned.add("Worldknit"); banned.add("Wrenn and Six"); banned.add("Yawgmoth's Bargain"); banned.add("Yawgmoth's Will"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/MTGO1v1Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/MTGO1v1Commander.java index 511d0d3f0e0..4f90d5de4e9 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/MTGO1v1Commander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/MTGO1v1Commander.java @@ -1,7 +1,6 @@ package mage.deck; /** - * * @author fireshoes */ public class MTGO1v1Commander extends Commander { @@ -9,7 +8,7 @@ public class MTGO1v1Commander extends Commander { public MTGO1v1Commander() { super("MTGO 1v1 Commander"); partnerAllowed = false; - + banned.add("Ancestral Recall"); banned.add("Back to Basics"); banned.add("Balance"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Modern.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Modern.java index f56006a3cd0..6d68d4f89de 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Modern.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Modern.java @@ -45,6 +45,7 @@ public class Modern extends Constructed { banned.add("Hogaak, Arisen Necropolis"); banned.add("Hypergenesis"); banned.add("Krark-Clan Ironworks"); + banned.add("Lurrus of the Dream-Den"); banned.add("Mental Misstep"); banned.add("Mox Opal"); banned.add("Mycosynth Lattice"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Oathbreaker.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Oathbreaker.java index 9a86f632844..31cbee16419 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Oathbreaker.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Oathbreaker.java @@ -4,6 +4,7 @@ import mage.abilities.Ability; import mage.abilities.keyword.PartnerAbility; import mage.abilities.keyword.PartnerWithAbility; import mage.cards.Card; +import mage.cards.decks.Constructed; import mage.cards.decks.Deck; import mage.cards.decks.DeckValidatorErrorType; import mage.constants.CardType; @@ -15,14 +16,13 @@ import java.util.*; /** * @author JayDi85 */ -public class Oathbreaker extends Vintage { +public class Oathbreaker extends Constructed { protected List bannedCommander = new ArrayList<>(); private static final Map pdAllowed = new HashMap<>(); public Oathbreaker() { - super(); - setName("Oathbreaker"); + super("Oathbreaker"); // banned = vintage + oathbreaker's list: https://oathbreakermtg.org/banned-list/ banned.add("Ad Nauseam"); @@ -31,21 +31,14 @@ public class Oathbreaker extends Vintage { banned.add("Biorhythm"); banned.add("Black Lotus"); banned.add("Channel"); - banned.add("Chaos Orb"); - banned.add("Cleanse"); - banned.add("Crusade"); banned.add("Dark Ritual"); banned.add("Doomsday"); banned.add("Emrakul, the Aeons Torn"); banned.add("Expropriate"); - banned.add("Falling Star"); banned.add("Fastbond"); banned.add("Gifts Ungiven"); banned.add("Griselbrand"); banned.add("High Tide"); - banned.add("Imprison"); - banned.add("Invoke Prejudice"); - banned.add("Jihad"); banned.add("Jeweled Lotus"); banned.add("Library of Alexandria"); banned.add("Limited Resources"); @@ -61,12 +54,9 @@ public class Oathbreaker extends Vintage { banned.add("Natural Order"); banned.add("Painter's Servant"); banned.add("Panoptic Mirror"); - banned.add("Pradesh Gypsies"); banned.add("Primal Surge"); banned.add("Saheeli, the Gifted"); - banned.add("Shahrazad"); banned.add("Sol Ring"); - banned.add("Stone-Throwing Devils"); banned.add("Sundering Titan"); banned.add("Sylvan Primordial"); banned.add("Time Vault"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394.java index 66d06ee8287..de9f72c486c 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394.java @@ -1,20 +1,16 @@ - package mage.deck; -import mage.cards.ExpansionSet; -import mage.cards.Sets; import mage.cards.decks.Constructed; -import mage.constants.SetType; /** * This class validates a deck for the Old School 93/94 format. - * + *

* This was originally made to follow the deck construction rules found at the * Old School Mtg blog found at: * http://oldschool-mtg.blogspot.com/p/banrestriction.html - * + *

* There is no mana burn in this version of old school. - * + *

* If there are any questions or corrections, feel free to contact me. * * @author Marthinwurer (at gmail.com) @@ -33,31 +29,6 @@ public class OldSchool9394 extends Constructed { setCodes.add(mage.sets.Legends.getInstance().getCode()); setCodes.add(mage.sets.TheDark.getInstance().getCode()); - // ante cards and conspiracies banned, with specifically mentioned ones called out. - banned.add("Advantageous Proclamation"); - banned.add("Amulet of Quoz"); - banned.add("Backup Plan"); - banned.add("Brago's Favor"); - banned.add("Bronze Tablet"); /// - banned.add("Contract from Below"); /// - banned.add("Darkpact"); /// - banned.add("Demonic Attorney"); /// - banned.add("Double Stroke"); - banned.add("Immediate Action"); - banned.add("Iterative Analysis"); - banned.add("Jeweled Bird"); /// - banned.add("Muzzio's Preparations"); - banned.add("Power Play"); - banned.add("Rebirth"); /// - banned.add("Secret Summoning"); - banned.add("Secrets of Paradise"); - banned.add("Sentinel Dispatch"); - banned.add("Shahrazad"); - banned.add("Tempest Efreet"); /// - banned.add("Timmerian Fiends"); - banned.add("Unexpected Potential"); - banned.add("Worldknit"); - restricted.add("Ancestral Recall"); restricted.add("Balance"); restricted.add("Black Lotus"); @@ -82,6 +53,5 @@ public class OldSchool9394 extends Constructed { restricted.add("Time Walk"); restricted.add("Timetwister"); restricted.add("Wheel of Fortune"); - } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394CFB.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394CFB.java index a9f38181ac9..4a2d0cb1f07 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394CFB.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394CFB.java @@ -29,30 +29,6 @@ public class OldSchool9394CFB extends Constructed { setCodes.add(mage.sets.TheDark.getInstance().getCode()); setCodes.add(mage.sets.FallenEmpires.getInstance().getCode()); - // ante cards and conspiracies banned, with specifically mentioned ones called out. - banned.add("Advantageous Proclamation"); - banned.add("Amulet of Quoz"); - banned.add("Backup Plan"); - banned.add("Brago's Favor"); - banned.add("Bronze Tablet"); /// - banned.add("Contract from Below"); /// - banned.add("Darkpact"); /// - banned.add("Demonic Attorney"); /// - banned.add("Double Stroke"); - banned.add("Immediate Action"); - banned.add("Iterative Analysis"); - banned.add("Jeweled Bird"); /// - banned.add("Muzzio's Preparations"); - banned.add("Power Play"); - banned.add("Rebirth"); /// - banned.add("Secret Summoning"); - banned.add("Secrets of Paradise"); - banned.add("Sentinel Dispatch"); - banned.add("Tempest Efreet"); /// - banned.add("Timmerian Fiends"); - banned.add("Unexpected Potential"); - banned.add("Worldknit"); - //Let Media Inserts Arena and Sewers of Estark being only cards playable banned.add("Acquire"); banned.add("Aeronaut Tinkerer"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394EC.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394EC.java index 49a5cf564a7..73e70d2b912 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394EC.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394EC.java @@ -29,31 +29,6 @@ public class OldSchool9394EC extends Constructed { setCodes.add(mage.sets.TheDark.getInstance().getCode()); setCodes.add(mage.sets.FallenEmpires.getInstance().getCode()); - // ante cards and conspiracies banned, with specifically mentioned ones called out. - banned.add("Advantageous Proclamation"); - banned.add("Amulet of Quoz"); - banned.add("Backup Plan"); - banned.add("Brago's Favor"); - banned.add("Bronze Tablet"); /// - banned.add("Contract from Below"); /// - banned.add("Darkpact"); /// - banned.add("Demonic Attorney"); /// - banned.add("Double Stroke"); - banned.add("Immediate Action"); - banned.add("Iterative Analysis"); - banned.add("Jeweled Bird"); /// - banned.add("Muzzio's Preparations"); - banned.add("Power Play"); - banned.add("Rebirth"); /// - banned.add("Secret Summoning"); - banned.add("Secrets of Paradise"); - banned.add("Sentinel Dispatch"); - banned.add("Shahrazad"); - banned.add("Tempest Efreet"); /// - banned.add("Timmerian Fiends"); - banned.add("Unexpected Potential"); - banned.add("Worldknit"); - //Let Media Inserts Arena and Sewers of Estark being only cards playable banned.add("Acquire"); banned.add("Aeronaut Tinkerer"); @@ -262,5 +237,4 @@ public class OldSchool9394EC extends Constructed { restricted.add("Timetwister"); restricted.add("Wheel of Fortune"); } - } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394EG.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394EG.java index 3ce11e196af..753ef772b85 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394EG.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394EG.java @@ -1,29 +1,25 @@ - package mage.deck; -import mage.cards.ExpansionSet; -import mage.cards.Sets; import mage.cards.decks.Constructed; -import mage.constants.SetType; /** * This class validates a deck for the Old School 93/94 format, specifically the * EudoGames Rules. - * + *

* This was originally made to follow the deck construction rules found at the * Old School Mtg blog found at: * http://oldschool-mtg.blogspot.com/p/banrestriction.html - * + *

* There is no mana burn in this version of old school. * * @author jmharmon */ public class OldSchool9394EG extends Constructed { - + public OldSchool9394EG() { super("Constructed - Old School 93/94 - EudoGames Rules"); - - // use the set instances to make sure that we get the correct set codes + + // use the set instances to make sure that we get the correct set codes setCodes.add(mage.sets.LimitedEditionAlpha.getInstance().getCode()); setCodes.add(mage.sets.LimitedEditionBeta.getInstance().getCode()); setCodes.add(mage.sets.UnlimitedEdition.getInstance().getCode()); @@ -34,32 +30,7 @@ public class OldSchool9394EG extends Constructed { setCodes.add(mage.sets.RevisedEdition.getInstance().getCode()); setCodes.add(mage.sets.FallenEmpires.getInstance().getCode()); setCodes.add(mage.sets.Chronicles.getInstance().getCode()); - - // ante cards and conspiracies banned, with specifically mentioned ones called out. - banned.add("Advantageous Proclamation"); - banned.add("Amulet of Quoz"); - banned.add("Backup Plan"); - banned.add("Brago's Favor"); - banned.add("Bronze Tablet"); /// - banned.add("Contract from Below"); /// - banned.add("Darkpact"); /// - banned.add("Demonic Attorney"); /// - banned.add("Double Stroke"); - banned.add("Immediate Action"); - banned.add("Iterative Analysis"); - banned.add("Jeweled Bird"); /// - banned.add("Muzzio's Preparations"); - banned.add("Power Play"); - banned.add("Rebirth"); /// - banned.add("Secret Summoning"); - banned.add("Secrets of Paradise"); - banned.add("Sentinel Dispatch"); - banned.add("Shahrazad"); - banned.add("Tempest Efreet"); /// - banned.add("Timmerian Fiends"); - banned.add("Unexpected Potential"); - banned.add("Worldknit"); - + restricted.add("Ancestral Recall"); restricted.add("Balance"); restricted.add("Black Lotus"); @@ -88,5 +59,4 @@ public class OldSchool9394EG extends Constructed { restricted.add("Timetwister"); restricted.add("Wheel of Fortune"); } - } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394Italian.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394Italian.java index c5e97d44b19..c160a13cdf2 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394Italian.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/OldSchool9394Italian.java @@ -1,28 +1,25 @@ package mage.deck; -import mage.cards.ExpansionSet; -import mage.cards.Sets; import mage.cards.decks.Constructed; -import mage.constants.SetType; /** * This class validates a deck for the Old School 93/94 format, specifically for * the Italian Rules. - * + *

* This was originally made to follow the deck construction rules found at the * Old School Mtg blog found at: * http://oldschool-mtg.blogspot.com/p/banrestriction.html - * + *

* There is no mana burn in this version of old school * * @author jmharmon */ -public class OldSchool9394Italian extends Constructed{ - +public class OldSchool9394Italian extends Constructed { + public OldSchool9394Italian() { super("Constructed - Old School 93/94 - Italian Rules"); - + // use the set instances to make sure that we get the correct set codes setCodes.add(mage.sets.LimitedEditionAlpha.getInstance().getCode()); setCodes.add(mage.sets.LimitedEditionBeta.getInstance().getCode()); @@ -32,32 +29,7 @@ public class OldSchool9394Italian extends Constructed{ setCodes.add(mage.sets.Legends.getInstance().getCode()); setCodes.add(mage.sets.TheDark.getInstance().getCode()); setCodes.add(mage.sets.RevisedEdition.getInstance().getCode()); - - // ante cards and conspiracies banned, with specifically mentioned ones called out. - banned.add("Advantageous Proclamation"); - banned.add("Amulet of Quoz"); - banned.add("Backup Plan"); - banned.add("Brago's Favor"); - banned.add("Bronze Tablet"); /// - banned.add("Contract from Below"); /// - banned.add("Darkpact"); /// - banned.add("Demonic Attorney"); /// - banned.add("Double Stroke"); - banned.add("Immediate Action"); - banned.add("Iterative Analysis"); - banned.add("Jeweled Bird"); /// - banned.add("Muzzio's Preparations"); - banned.add("Power Play"); - banned.add("Rebirth"); /// - banned.add("Secret Summoning"); - banned.add("Secrets of Paradise"); - banned.add("Sentinel Dispatch"); - banned.add("Shahrazad"); - banned.add("Tempest Efreet"); /// - banned.add("Timmerian Fiends"); - banned.add("Unexpected Potential"); - banned.add("Worldknit"); - + restricted.add("Ancestral Recall"); restricted.add("Balance"); restricted.add("Black Lotus"); @@ -82,6 +54,5 @@ public class OldSchool9394Italian extends Constructed{ restricted.add("Time Walk"); restricted.add("Timetwister"); restricted.add("Wheel of Fortune"); - } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java index 0b44ef683e8..af5dc6536da 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pauper.java @@ -29,10 +29,11 @@ public class Pauper extends Constructed { banned.add("Cloudpost"); banned.add("Cranial Plating"); banned.add("Daze"); + banned.add("Disciple of the Vault"); banned.add("Empty the Warrens"); - banned.add("Expedition Map"); banned.add("Fall from Favor"); banned.add("Frantic Search"); + banned.add("Galvanic Relay"); banned.add("Gitaxian Probe"); banned.add("Grapeshot"); banned.add("Gush"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java index 0e5289d4c75..49f01d483fb 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java @@ -1,33 +1,22 @@ package mage.deck; -import mage.abilities.Ability; -import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.keyword.CompanionAbility; -import mage.abilities.keyword.PartnerAbility; -import mage.abilities.keyword.PartnerWithAbility; -import mage.cards.Card; import mage.cards.ExpansionSet; import mage.cards.Sets; -import mage.cards.decks.Constructed; -import mage.cards.decks.Deck; import mage.cards.decks.DeckValidatorErrorType; import mage.cards.decks.PennyDreadfulLegalityUtil; -import mage.constants.CardType; -import mage.filter.FilterMana; -import mage.util.ManaUtil; -import java.util.*; +import java.util.HashMap; +import java.util.Map; /** * @author spjspj */ -public class PennyDreadfulCommander extends Constructed { +public class PennyDreadfulCommander extends AbstractCommander { - protected List bannedCommander = new ArrayList<>(); private static final Map pdAllowed = new HashMap<>(); public PennyDreadfulCommander() { - super("Penny Dreadful Commander", "Penny"); + super("Penny Dreadful Commander"); for (ExpansionSet set : Sets.getInstance().values()) { if (set.getSetType().isEternalLegal()) { setCodes.add(set.getCode()); @@ -36,168 +25,17 @@ public class PennyDreadfulCommander extends Constructed { } @Override - public int getDeckMinSize() { - return 98; - } - - @Override - public int getSideboardMinSize() { - return 1; - } - - @Override - public boolean validate(Deck deck) { - boolean valid = true; - errorsList.clear(); - FilterMana colorIdentity = new FilterMana(); - Set commanders = new HashSet<>(); - Card companion = null; - - if (deck.getSideboard().size() == 1) { - commanders.add(deck.getSideboard().iterator().next()); - } else if (deck.getSideboard().size() == 2) { - Iterator iter = deck.getSideboard().iterator(); - Card card1 = iter.next(); - Card card2 = iter.next(); - if (card1.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) { - companion = card1; - commanders.add(card2); - } else if (card2.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) { - companion = card2; - commanders.add(card1); - } else { - commanders.add(card1); - commanders.add(card2); - } - } else if (deck.getSideboard().size() == 3) { - Iterator iter = deck.getSideboard().iterator(); - Card card1 = iter.next(); - Card card2 = iter.next(); - Card card3 = iter.next(); - if (card1.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) { - companion = card1; - commanders.add(card2); - commanders.add(card3); - } else if (card2.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) { - companion = card2; - commanders.add(card1); - commanders.add(card3); - } else if (card3.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) { - companion = card3; - commanders.add(card1); - commanders.add(card2); - } else { - addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion"); - valid = false; - } - } else { - addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion"); - valid = false; - } - - if (companion != null && deck.getCards().size() + deck.getSideboard().size() != 101) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 101 + " cards (companion doesn't count for deck size): has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); - valid = false; - } else if (companion == null && deck.getCards().size() + deck.getSideboard().size() != 100) { - addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 100 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); - valid = false; - } - - Map counts = new HashMap<>(); - countCards(counts, deck.getCards()); - countCards(counts, deck.getSideboard()); - valid = checkCounts(1, counts) && valid; - + protected boolean checkBanned(Map counts) { if (pdAllowed.isEmpty()) { pdAllowed.putAll(PennyDreadfulLegalityUtil.getLegalCardList()); } - + boolean valid = true; for (String wantedCard : counts.keySet()) { if (!(pdAllowed.containsKey(wantedCard))) { addError(DeckValidatorErrorType.BANNED, wantedCard, "Banned", true); valid = false; } } - - Set commanderNames = new HashSet<>(); - for (Card commander : commanders) { - commanderNames.add(commander.getName()); - } - for (Card commander : commanders) { - if (bannedCommander.contains(commander.getName())) { - addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander banned (" + commander.getName() + ')', true); - valid = false; - } - if ((!commander.hasCardTypeForDeckbuilding(CardType.CREATURE) || !commander.isLegendary()) - && !commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance())) { - addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander invalid (" + commander.getName() + ')', true); - valid = false; - } - if (commanders.size() == 2) { - if (!commander.getAbilities().contains(PartnerAbility.getInstance())) { - boolean partnersWith = commander.getAbilities() - .stream() - .filter(PartnerWithAbility.class::isInstance) - .map(PartnerWithAbility.class::cast) - .map(PartnerWithAbility::getPartnerName) - .anyMatch(commanderNames::contains); - if (!partnersWith) { - addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander without Partner (" + commander.getName() + ')', true); - valid = false; - } - } - } - ManaUtil.collectColorIdentity(colorIdentity, commander.getColorIdentity()); - } - - // no needs in cards check on wrong commanders - if (!valid) { - return false; - } - - for (Card card : deck.getCards()) { - if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) { - addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true); - valid = false; - } - } - for (Card card : deck.getSideboard()) { - if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) { - addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true); - valid = false; - } - } - for (Card card : deck.getCards()) { - if (!isSetAllowed(card.getExpansionSetCode())) { - if (!legalSets(card)) { - addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true); - valid = false; - } - } - } - for (Card card : deck.getSideboard()) { - if (!isSetAllowed(card.getExpansionSetCode())) { - if (!legalSets(card)) { - addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true); - valid = false; - } - } - } - // Check for companion legality - if (companion != null) { - Set cards = new HashSet<>(deck.getCards()); - cards.addAll(commanders); - for (Ability ability : companion.getAbilities()) { - if (ability instanceof CompanionAbility) { - CompanionAbility companionAbility = (CompanionAbility) ability; - if (!companionAbility.isLegal(cards, getDeckMinSize())) { - addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Commander Companion (deck invalid for companion)", true); - valid = false; - } - break; - } - } - } return valid; } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pioneer.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pioneer.java index 77f3a4ced81..6daef5f9051 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pioneer.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Pioneer.java @@ -34,6 +34,7 @@ public class Pioneer extends Constructed { banned.add("Inverter of Truth"); banned.add("Kethis, the Hidden Hand"); banned.add("Leyline of Abundance"); + banned.add("Lurrus of the Dream-Den"); banned.add("Nexus of Fate"); banned.add("Oko, Thief of Crowns"); banned.add("Once Upon a Time"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Premodern.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Premodern.java index a73be72a95d..f15a06d9e7b 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Premodern.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Premodern.java @@ -3,7 +3,6 @@ package mage.deck; import mage.cards.decks.Constructed; /** - * * @author jmharmon */ @@ -44,10 +43,8 @@ public class Premodern extends Constructed { setCodes.add(mage.sets.Scourge.getInstance().getCode()); // Ban List - banned.add("Amulet of Quoz"); banned.add("Balance"); banned.add("Brainstorm"); - banned.add("Bronze Tablet"); banned.add("Channel"); banned.add("Demonic Consultation"); banned.add("Earthcraft"); @@ -56,25 +53,21 @@ public class Premodern extends Constructed { banned.add("Force of Will"); banned.add("Goblin Recruiter"); banned.add("Grim Monolith"); - banned.add("Jeweled Bird"); banned.add("Mana Vault"); banned.add("Memory Jar"); - banned.add("Mind Twist"); banned.add("Mind's Desire"); + banned.add("Mind Twist"); banned.add("Mystical Tutor"); banned.add("Necropotence"); - banned.add("Rebirth"); banned.add("Show and Tell"); banned.add("Strip Mine"); - banned.add("Tempest Efreet"); banned.add("Tendrils of Agony"); banned.add("Time Spiral"); - banned.add("Timmerian Fiends"); banned.add("Tolarian Academy"); banned.add("Vampiric Tutor"); banned.add("Windfall"); banned.add("Worldgorger Dragon"); - banned.add("Yawgmoth's Will"); banned.add("Yawgmoth's Bargain"); + banned.add("Yawgmoth's Will"); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java index 92f45d511ba..52d733412d2 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java @@ -59,7 +59,6 @@ public class TinyLeaders extends Constructed { banned.add("Mox Sapphire"); banned.add("Najeela, the Blade-Blossom"); banned.add("Necropotence"); - banned.add("Shahrazad"); banned.add("Sisay, Weatherlight Captain"); banned.add("Skullclamp"); banned.add("Sol Ring"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Vintage.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Vintage.java index 3a7f2662caf..1641ece3ac5 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Vintage.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Vintage.java @@ -16,39 +16,6 @@ public class Vintage extends Constructed { setCodes.add(set.getCode()); } } - banned.add("Advantageous Proclamation"); - banned.add("Amulet of Quoz"); - banned.add("Backup Plan"); - banned.add("Brago's Favor"); - banned.add("Bronze Tablet"); - banned.add("Chaos Orb"); - banned.add("Cleanse"); - banned.add("Crusade"); - banned.add("Contract from Below"); - banned.add("Darkpact"); - banned.add("Demonic Attorney"); - banned.add("Double Stroke"); - banned.add("Falling Star"); - banned.add("Immediate Action"); - banned.add("Imprison"); - banned.add("Invoke Prejudice"); - banned.add("Iterative Analysis"); - banned.add("Jeweled Bird"); - banned.add("Jihad"); - banned.add("Muzzio's Preparations"); - banned.add("Power Play"); - banned.add("Pradesh Gypsies"); - banned.add("Rebirth"); - banned.add("Secret Summoning"); - banned.add("Secrets of Paradise"); - banned.add("Sentinel Dispatch"); - banned.add("Shahrazad"); - banned.add("Stone-Throwing Devils"); - banned.add("Tempest Efreet"); - banned.add("Timmerian Fiends"); - banned.add("Unexpected Potential"); - banned.add("Worldknit"); - restricted.add("Ancestral Recall"); restricted.add("Balance"); restricted.add("Black Lotus"); diff --git a/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java b/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java index d2391aab2fc..3b9445e36e8 100644 --- a/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java +++ b/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java @@ -13,7 +13,7 @@ import java.util.Map; public class Limited extends DeckValidator { public Limited() { - super("Limited"); + super("Limited", null); } @Override diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java index 5b347cb2a92..770d3b0aaec 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java @@ -396,7 +396,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { && stackObject.getControllerId().equals(playerId)) { Target target = effect.getTarget(); if (!target.doneChosing()) { - for (UUID targetId : target.possibleTargets(stackObject.getSourceId(), stackObject.getControllerId(), game)) { + for (UUID targetId : target.possibleTargets(stackObject.getControllerId(), stackObject.getStackAbility(), game)) { Game sim = game.copy(); StackAbility newAbility = (StackAbility) stackObject.copy(); SearchEffect newEffect = getSearchEffect(newAbility); diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java index 4cff650ac63..ee208d00d68 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java @@ -124,8 +124,7 @@ public class SimulatedPlayer2 extends ComputerPlayer { // calculate the mana that can be used for the x part int numAvailable = getAvailableManaProducers(game).size() - ability.getManaCosts().manaValue(); - Card card = game.getCard(ability.getSourceId()); - if (card != null && numAvailable > 0) { + if (numAvailable > 0) { // check if variable mana costs is included and get the multiplier VariableManaCost variableManaCost = null; for (ManaCost cost : ability.getManaCostsToPay()) { @@ -159,7 +158,7 @@ public class SimulatedPlayer2 extends ComputerPlayer { if (varCost != null) { varCost.setPaid(); } - card.adjustTargets(newAbility, game); + newAbility.adjustTargets(game); // add the different possible target option for the specific X value if (!newAbility.getTargets().getUnchosen().isEmpty()) { addTargetOptions(options, newAbility, targetNum, game); diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java index d7deb819b41..8393ebf864a 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/ComputerPlayer.java @@ -122,12 +122,12 @@ public class ComputerPlayer extends PlayerImpl implements Player { } @Override - public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { - return choose(outcome, target, sourceId, game, null); + public boolean choose(Outcome outcome, Target target, Ability source, Game game) { + return choose(outcome, target, source, game, null); } @Override - public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map options) { + public boolean choose(Outcome outcome, Target target, Ability source, Game game, Map options) { if (log.isDebugEnabled()) { log.debug("choose: " + outcome.toString() + ':' + target.toString()); @@ -143,9 +143,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { && target.getAbilityController() != null) { abilityControllerId = target.getAbilityController(); } + UUID sourceId = source != null ? source.getSourceId() : null; boolean required = target.isRequired(sourceId, game); - Set possibleTargets = target.possibleTargets(sourceId, abilityControllerId, game); + Set possibleTargets = target.possibleTargets(abilityControllerId, source, game); if (possibleTargets.isEmpty() || target.getTargets().size() >= target.getNumberOfTargets()) { required = false; } @@ -160,7 +161,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } if (target.getOriginalTarget() instanceof TargetPlayer) { - return setTargetPlayer(outcome, target, null, sourceId, abilityControllerId, randomOpponentId, game, required); + return setTargetPlayer(outcome, target, null, abilityControllerId, randomOpponentId, game, required); } if (target.getOriginalTarget() instanceof TargetDiscard) { @@ -191,12 +192,12 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target.getOriginalTarget() instanceof TargetControlledPermanent) { List targets; TargetControlledPermanent origTarget = (TargetControlledPermanent) target.getOriginalTarget(); - targets = threats(abilityControllerId, sourceId, origTarget.getFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source, origTarget.getFilter(), game, target.getTargets()); if (!outcome.isGood()) { Collections.reverse(targets); } for (Permanent permanent : targets) { - if (origTarget.canTarget(abilityControllerId, permanent.getId(), sourceId, game, false) && !target.getTargets().contains(permanent.getId())) { + if (origTarget.canTarget(abilityControllerId, permanent.getId(), source, game, false) && !target.getTargets().contains(permanent.getId())) { target.add(permanent.getId(), game); return true; } @@ -217,18 +218,18 @@ public class ComputerPlayer extends PlayerImpl implements Player { List targets; if (outcome.isCanTargetAll()) { - targets = threats(null, sourceId, filter, game, target.getTargets()); + targets = threats(null, source, filter, game, target.getTargets()); } else { if (outcome.isGood()) { - targets = threats(abilityControllerId, sourceId, filter, game, target.getTargets()); + targets = threats(abilityControllerId, source, filter, game, target.getTargets()); } else { - targets = threats(randomOpponentId, sourceId, filter, game, target.getTargets()); + targets = threats(randomOpponentId, source, filter, game, target.getTargets()); } if (targets.isEmpty() && target.isRequired()) { if (!outcome.isGood()) { - targets = threats(abilityControllerId, sourceId, filter, game, target.getTargets()); + targets = threats(abilityControllerId, source, filter, game, target.getTargets()); } else { - targets = threats(randomOpponentId, sourceId, filter, game, target.getTargets()); + targets = threats(randomOpponentId, source, filter, game, target.getTargets()); } } } @@ -257,7 +258,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target.getOriginalTarget() instanceof TargetCardInHand || (target.getZone() == Zone.HAND && (target.getOriginalTarget() instanceof TargetCard))) { List cards = new ArrayList<>(); - for (UUID cardId : target.possibleTargets(sourceId, this.getId(), game)) { + for (UUID cardId : target.possibleTargets(this.getId(), source, game)) { Card card = game.getCard(cardId); if (card != null) { cards.add(card); @@ -278,9 +279,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { List targets; TargetAnyTarget origTarget = (TargetAnyTarget) target.getOriginalTarget(); if (outcome.isGood()) { - targets = threats(abilityControllerId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); } else { - targets = threats(randomOpponentId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); + targets = threats(randomOpponentId, source, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); } for (Permanent permanent : targets) { List alreadyTargetted = target.getTargets(); @@ -309,9 +310,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { List targets; TargetCreatureOrPlayer origTarget = (TargetCreatureOrPlayer) target.getOriginalTarget(); if (outcome.isGood()) { - targets = threats(abilityControllerId, sourceId, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets()); } else { - targets = threats(randomOpponentId, sourceId, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets()); + targets = threats(randomOpponentId, source, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets()); } for (Permanent permanent : targets) { List alreadyTargeted = target.getTargets(); @@ -339,8 +340,8 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target.getOriginalTarget() instanceof TargetPermanentOrPlayer) { List targets; TargetPermanentOrPlayer origTarget = (TargetPermanentOrPlayer) target.getOriginalTarget(); - List ownedTargets = threats(abilityControllerId, sourceId, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); - List opponentTargets = threats(randomOpponentId, sourceId, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); + List ownedTargets = threats(abilityControllerId, source, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); + List opponentTargets = threats(randomOpponentId, source, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); if (outcome.isGood()) { targets = ownedTargets; } else { @@ -463,7 +464,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target.getOriginalTarget() instanceof TargetSource) { Set targets; - targets = target.possibleTargets(sourceId, abilityControllerId, game); + targets = target.possibleTargets(abilityControllerId, source, game); for (UUID targetId : targets) { MageObject targetObject = game.getObject(targetId); if (targetObject != null) { @@ -517,7 +518,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } boolean required = target.isRequired(sourceId, game); - Set possibleTargets = target.possibleTargets(sourceId, abilityControllerId, game); + Set possibleTargets = target.possibleTargets(abilityControllerId, source, game); if (possibleTargets.isEmpty() || target.getTargets().size() >= target.getNumberOfTargets()) { required = false; } @@ -537,11 +538,11 @@ public class ComputerPlayer extends PlayerImpl implements Player { } if (target.getOriginalTarget() instanceof TargetPlayer) { - return setTargetPlayer(outcome, target, source, sourceId, abilityControllerId, randomOpponentId, game, required); + return setTargetPlayer(outcome, target, source, abilityControllerId, randomOpponentId, game, required); } // Angel of Serenity trigger - if (target.getOriginalTarget() instanceof TargetCardInGraveyardOrBattlefield) { + if (target.getOriginalTarget() instanceof TargetCardInGraveyardBattlefieldOrStack) { Cards cards = new CardsImpl(possibleTargets); List possibleCards = new ArrayList<>(cards.getCards(game)); for (Card card : possibleCards) { @@ -642,7 +643,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target.getOriginalTarget() instanceof TargetControlledPermanent) { TargetControlledPermanent origTarget = (TargetControlledPermanent) target.getOriginalTarget(); List targets; - targets = threats(abilityControllerId, sourceId, origTarget.getFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source, origTarget.getFilter(), game, target.getTargets()); if (!outcome.isGood()) { Collections.reverse(targets); } @@ -671,7 +672,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { + target.getOriginalTarget().getClass().getCanonicalName()); } - findBestPermanentTargets(outcome, abilityControllerId, sourceId, filter, + findBestPermanentTargets(outcome, abilityControllerId, sourceId, source, filter, game, target, goodList, badList, allList); // use good list all the time and add maximum targets @@ -700,9 +701,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { List targets; TargetCreatureOrPlayer origTarget = ((TargetCreatureOrPlayer) target.getOriginalTarget()); if (outcome.isGood()) { - targets = threats(abilityControllerId, sourceId, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets()); } else { - targets = threats(randomOpponentId, sourceId, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets()); + targets = threats(randomOpponentId, source, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets()); } if (targets.isEmpty()) { @@ -742,9 +743,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { List targets; TargetAnyTarget origTarget = ((TargetAnyTarget) target.getOriginalTarget()); if (outcome.isGood()) { - targets = threats(abilityControllerId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); } else { - targets = threats(randomOpponentId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); + targets = threats(randomOpponentId, source, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); } if (targets.isEmpty()) { @@ -785,9 +786,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { List targets; TargetPermanentOrPlayer origTarget = ((TargetPermanentOrPlayer) target.getOriginalTarget()); if (outcome.isGood()) { - targets = threats(abilityControllerId, source.getSourceId(), ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); } else { - targets = threats(randomOpponentId, source.getSourceId(), ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); + targets = threats(randomOpponentId, source, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); } if (targets.isEmpty()) { @@ -823,9 +824,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { // normal cycle (good for you, bad for opponents) // possible good/bad permanents if (outcome.isGood()) { - targets = threats(abilityControllerId, source.getSourceId(), ((FilterPermanentOrPlayer) target.getFilter()).getPermanentFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source, ((FilterPermanentOrPlayer) target.getFilter()).getPermanentFilter(), game, target.getTargets()); } else { - targets = threats(randomOpponentId, source.getSourceId(), ((FilterPermanentOrPlayer) target.getFilter()).getPermanentFilter(), game, target.getTargets()); + targets = threats(randomOpponentId, source, ((FilterPermanentOrPlayer) target.getFilter()).getPermanentFilter(), game, target.getTargets()); } // possible good/bad players @@ -930,12 +931,12 @@ public class ComputerPlayer extends PlayerImpl implements Player { List targets; boolean outcomeTargets = true; if (outcome.isGood()) { - targets = threats(abilityControllerId, source == null ? null : source.getSourceId(), origTarget.getPermanentFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source, origTarget.getPermanentFilter(), game, target.getTargets()); } else { - targets = threats(randomOpponentId, source == null ? null : source.getSourceId(), origTarget.getPermanentFilter(), game, target.getTargets()); + targets = threats(randomOpponentId, source, origTarget.getPermanentFilter(), game, target.getTargets()); } if (targets.isEmpty() && required) { - targets = threats(null, source == null ? null : source.getSourceId(), origTarget.getPermanentFilter(), game, target.getTargets()); + targets = threats(null, source, origTarget.getPermanentFilter(), game, target.getTargets()); Collections.reverse(targets); outcomeTargets = false; } @@ -976,24 +977,8 @@ public class ComputerPlayer extends PlayerImpl implements Player { } if (target.getOriginalTarget() instanceof TargetDefender) { - // TODO: Improve, now planeswalker is always chosen if it exits - List targets; - targets = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_PLANESWALKER, randomOpponentId, game); - if (targets != null && !targets.isEmpty()) { - for (Permanent planeswalker : targets) { - if (target.canTarget(abilityControllerId, planeswalker.getId(), source, game)) { - target.addTarget(planeswalker.getId(), source, game); - } - if (target.isChosen()) { - return true; - } - } - } - if (!target.isChosen()) { - if (target.canTarget(abilityControllerId, randomOpponentId, source, game)) { - target.addTarget(randomOpponentId, source, game); - } - } + UUID randomDefender = RandomUtil.randomFromCollection(possibleTargets); + target.addTarget(randomDefender, source, game); return target.isChosen(); } @@ -1024,7 +1009,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } List cards = new ArrayList<>(); - for (UUID uuid : target.possibleTargets(source.getSourceId(), source.getControllerId(), game)) { + for (UUID uuid : target.possibleTargets(source.getControllerId(), source, game)) { Card card = game.getCard(uuid); if (card != null && game.getState().getZone(card.getId()) == Zone.EXILED) { cards.add(card); @@ -1042,7 +1027,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target.getOriginalTarget() instanceof TargetActivatedAbility) { List stackObjects = new ArrayList<>(); - for (UUID uuid : target.possibleTargets(source.getSourceId(), source.getControllerId(), game)) { + for (UUID uuid : target.possibleTargets(source.getControllerId(), source, game)) { StackObject stackObject = game.getStack().getStackObject(uuid); if (stackObject != null) { stackObjects.add(stackObject); @@ -1058,7 +1043,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { return target.isChosen(); } - if (target.getOriginalTarget() instanceof TargetCardInGraveyardOrBattlefield) { + if (target.getOriginalTarget() instanceof TargetCardInGraveyardBattlefieldOrStack) { List cards = new ArrayList<>(); for (Player player : game.getPlayers().values()) { cards.addAll(player.getGraveyard().getCards(game)); @@ -1145,7 +1130,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { // permanents kill for (UUID opponentId : opponents) { - targets = threats(opponentId, sourceId, StaticFilters.FILTER_PERMANENT_CREATURE_OR_PLANESWALKER_A, game, target.getTargets()); + targets = threats(opponentId, source, StaticFilters.FILTER_PERMANENT_CREATURE_OR_PLANESWALKER_A, game, target.getTargets()); // planeswalker kill for (Permanent permanent : targets) { @@ -1172,9 +1157,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { // own permanents will be checked multiple times... that's ok for (UUID opponentId : opponents) { if (outcome.isGood()) { - targets = threats(getId(), sourceId, StaticFilters.FILTER_PERMANENT, game, target.getTargets()); + targets = threats(getId(), source, StaticFilters.FILTER_PERMANENT, game, target.getTargets()); } else { - targets = threats(opponentId, sourceId, StaticFilters.FILTER_PERMANENT, game, target.getTargets()); + targets = threats(opponentId, source, StaticFilters.FILTER_PERMANENT, game, target.getTargets()); } // planeswalkers @@ -1208,9 +1193,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (UUID opponentId : opponents) { if (!outcome.isGood()) { // bad on yourself, uses weakest targets - targets = threats(getId(), sourceId, StaticFilters.FILTER_PERMANENT, game, target.getTargets(), false); + targets = threats(getId(), source, StaticFilters.FILTER_PERMANENT, game, target.getTargets(), false); } else { - targets = threats(opponentId, sourceId, StaticFilters.FILTER_PERMANENT, game, target.getTargets(), false); + targets = threats(opponentId, source, StaticFilters.FILTER_PERMANENT, game, target.getTargets(), false); } // creatures - non killable (TODO: add extra skill checks like undestructeable) @@ -1668,7 +1653,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } // pay phyrexian life costs - if (cost instanceof PhyrexianManaCost) { + if (cost.isPhyrexian()) { return cost.pay(ability, game, ability, playerId, false, null) || approvingObject != null; } @@ -2005,7 +1990,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } // we still use playerId when getting cards even if they don't control the search - List cardChoices = new ArrayList<>(cards.getCards(target.getFilter(), source != null ? source.getSourceId() : null, playerId, game)); + List cardChoices = new ArrayList<>(cards.getCards(target.getFilter(), playerId, source, game)); while (!target.doneChosing()) { Card card = pickTarget(abilityControllerId, cardChoices, outcome, target, source, game); if (card != null) { @@ -2125,7 +2110,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { continue AvailableMode; } } - if (mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) { // and where targets are available + if (mode.getTargets().canChoose(source.getControllerId(), source, game)) { // and where targets are available return mode; } } @@ -2710,7 +2695,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { return worst; } - protected void findBestPermanentTargets(Outcome outcome, UUID abilityControllerId, UUID sourceId, FilterPermanent filter, Game game, Target target, + protected void findBestPermanentTargets(Outcome outcome, UUID abilityControllerId, UUID sourceId, Ability source, FilterPermanent filter, Game game, Target target, List goodList, List badList, List allList) { // searching for most valuable/powerfull permanents goodList.clear(); @@ -2719,7 +2704,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { List usedTargets = target.getTargets(); // search all - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, abilityControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, abilityControllerId, source, game)) { if (usedTargets.contains(permanent.getId())) { continue; } @@ -2767,19 +2752,19 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } - protected List threats(UUID playerId, UUID sourceId, FilterPermanent filter, Game game, List targets) { - return threats(playerId, sourceId, filter, game, targets, true); + protected List threats(UUID playerId, Ability source, FilterPermanent filter, Game game, List targets) { + return threats(playerId, source, filter, game, targets, true); } - protected List threats(UUID playerId, UUID sourceId, FilterPermanent filter, Game game, List targets, boolean mostValueableGoFirst) { + protected List threats(UUID playerId, Ability source, FilterPermanent filter, Game game, List targets, boolean mostValueableGoFirst) { // most valuable/powerfull permanents goes at first List threats; if (playerId == null) { - threats = game.getBattlefield().getActivePermanents(filter, this.getId(), sourceId, game); // all permanents within the range of the player + threats = game.getBattlefield().getActivePermanents(filter, this.getId(), source, game); // all permanents within the range of the player } else { FilterPermanent filterCopy = filter.copy(); filterCopy.add(new ControllerIdPredicate(playerId)); - threats = game.getBattlefield().getActivePermanents(filter, this.getId(), sourceId, game); + threats = game.getBattlefield().getActivePermanents(filter, this.getId(), source, game); } Iterator it = threats.iterator(); while (it.hasNext()) { // remove permanents already targeted @@ -2897,7 +2882,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { * * @param source null on choose and non-null on chooseTarget */ - private boolean setTargetPlayer(Outcome outcome, Target target, Ability source, UUID sourceId, UUID abilityControllerId, UUID randomOpponentId, Game game, boolean required) { + private boolean setTargetPlayer(Outcome outcome, Target target, Ability source, UUID abilityControllerId, UUID randomOpponentId, Game game, boolean required) { Outcome affectedOutcome; if (abilityControllerId == this.playerId) { // selects for itself @@ -2931,6 +2916,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { return false; } + UUID sourceId = source != null ? source.getSourceId() : null; if (target.getOriginalTarget() instanceof TargetPlayer) { if (affectedOutcome.isGood()) { if (source == null) { @@ -2997,26 +2983,12 @@ public class ComputerPlayer extends PlayerImpl implements Player { * @return */ private UUID getRandomOpponent(UUID abilityControllerId, Game game) { - UUID randomOpponentId = null; - Set opponents = game.getOpponents(abilityControllerId); - if (opponents.size() > 1) { - int rand = RandomUtil.nextInt(opponents.size()); - int count = 0; - for (UUID currentId : opponents) { - if (count == rand) { - randomOpponentId = currentId; - break; - } - } - } else if (opponents.size() == 1) { - randomOpponentId = game.getOpponents(abilityControllerId).iterator().next(); - } - return randomOpponentId; + return RandomUtil.randomFromCollection(game.getOpponents(abilityControllerId)); } @Override public SpellAbility chooseAbilityForCast(Card card, Game game, boolean noMana) { - Map useable = PlayerImpl.getCastableSpellAbilities(game, this.getId(), card, game.getState().getZone(card.getId()), noMana); + Map useable = PlayerImpl.getCastableSpellAbilities(game, this.getId(), card, game.getState().getZone(card.getId()), noMana); return (SpellAbility) useable.values().stream().findFirst().orElse(null); } diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java index f887ca55c93..4eb502940c3 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/src/mage/player/ai/SimulatedPlayerMCTS.java @@ -221,7 +221,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { } protected boolean chooseRandomTarget(Target target, Ability source, Game game) { - Set possibleTargets = target.possibleTargets(source == null ? null : source.getSourceId(), playerId, game); + Set possibleTargets = target.possibleTargets(playerId, source, game); if (possibleTargets.isEmpty()) { return false; } @@ -245,19 +245,19 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { } @Override - public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { + public boolean choose(Outcome outcome, Target target, Ability source, Game game) { if (this.isHuman()) { return chooseRandom(target, game); } - return super.choose(outcome, target, sourceId, game); + return super.choose(outcome, target, source, game); } @Override - public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map options) { + public boolean choose(Outcome outcome, Target target, Ability source, Game game, Map options) { if (this.isHuman()) { return chooseRandom(target, game); } - return super.choose(outcome, target, sourceId, game, options); + return super.choose(outcome, target, source, game, options); } @Override @@ -302,7 +302,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { @Override public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) { - Set possibleTargets = target.possibleTargets(source == null ? null : source.getSourceId(), playerId, game); + Set possibleTargets = target.possibleTargets(playerId, source, game); if (possibleTargets.isEmpty()) { return !target.isRequired(source); } diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java index 097c08ef3b7..18c518cbd21 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/src/mage/player/ai/ComputerPlayer2.java @@ -235,7 +235,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements Player { if (effect != null && ability.getControllerId().equals(playerId)) { Target target = effect.getTarget(); if (!target.doneChosing()) { - for (UUID targetId: target.possibleTargets(ability.getSourceId(), ability.getControllerId(), game)) { + for (UUID targetId: target.possibleTargets(ability.getControllerId(), ability.getStackAbility(), game)) { Game sim = game.copy(); StackAbility newAbility = (StackAbility) ability.copy(); SearchEffect newEffect = getSearchEffect((StackAbility) newAbility); diff --git a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java index d2528ce6c2b..89f4d072ddf 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java +++ b/Mage.Server.Plugins/Mage.Player.Human/src/mage/player/human/HumanPlayer.java @@ -498,12 +498,12 @@ public class HumanPlayer extends PlayerImpl { } @Override - public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { - return choose(outcome, target, sourceId, game, null); + public boolean choose(Outcome outcome, Target target, Ability source, Game game) { + return choose(outcome, target, source, game, null); } @Override - public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map options) { + public boolean choose(Outcome outcome, Target target, Ability source, Game game, Map options) { if (gameInCheckPlayableState(game)) { return true; } @@ -519,12 +519,12 @@ public class HumanPlayer extends PlayerImpl { } while (canRespond()) { - Set targetIds = target.possibleTargets(sourceId, abilityControllerId, game); + Set targetIds = target.possibleTargets(abilityControllerId, source, game); if (targetIds == null || targetIds.isEmpty()) { return target.getTargets().size() >= target.getNumberOfTargets(); } - boolean required = target.isRequired(sourceId, game); + boolean required = target.isRequired(source != null ? source.getSourceId() : null, game); if (target.getTargets().size() >= target.getNumberOfTargets()) { required = false; } @@ -535,7 +535,7 @@ public class HumanPlayer extends PlayerImpl { updateGameStatePriority("choose(5)", game); prepareForResponse(game); if (!isExecutingMacro()) { - game.fireSelectTargetEvent(getId(), new MessageToClient(target.getMessage(), getRelatedObjectName(sourceId, game)), targetIds, required, getOptions(target, options)); + game.fireSelectTargetEvent(getId(), new MessageToClient(target.getMessage(), getRelatedObjectName(source, game)), targetIds, required, getOptions(target, options)); } waitForResponse(game); @@ -554,14 +554,14 @@ public class HumanPlayer extends PlayerImpl { } if (target instanceof TargetPermanent) { - if (((TargetPermanent) target).canTarget(abilityControllerId, responseId, sourceId, game, false)) { + if (((TargetPermanent) target).canTarget(abilityControllerId, responseId, source, game, false)) { target.add(responseId, game); if (target.doneChosing()) { return true; } } } else { - MageObject object = game.getObject(sourceId); + MageObject object = game.getObject(source); if (object instanceof Ability) { if (target.canTarget(responseId, (Ability) object, game)) { if (target.getTargets().contains(responseId)) { // if already included remove it with @@ -617,7 +617,7 @@ public class HumanPlayer extends PlayerImpl { Map options = new HashMap<>(); while (canRespond()) { - Set possibleTargets = target.possibleTargets(source == null ? null : source.getSourceId(), abilityControllerId, game); + Set possibleTargets = target.possibleTargets(abilityControllerId, source, game); boolean required = target.isRequired(source != null ? source.getSourceId() : null, game); if (possibleTargets.isEmpty() || target.getTargets().size() >= target.getNumberOfTargets()) { @@ -845,7 +845,7 @@ public class HumanPlayer extends PlayerImpl { // 1. Select targets while (canRespond()) { - Set possibleTargets = target.possibleTargets(source == null ? null : source.getSourceId(), abilityControllerId, game); + Set possibleTargets = target.possibleTargets(abilityControllerId, source, game); boolean required = target.isRequired(source != null ? source.getSourceId() : null, game); if (possibleTargets.isEmpty() || target.getSize() >= target.getNumberOfTargets()) { @@ -979,7 +979,7 @@ public class HumanPlayer extends PlayerImpl { FilterCreatureForCombatBlock filter = filterCreatureForCombatBlock.copy(); filter.add(new ControllerIdPredicate(playerId)); // stop skip on any/zero permanents available - int possibleBlockersCount = game.getBattlefield().count(filter, null, playerId, game); + int possibleBlockersCount = game.getBattlefield().count(filter, playerId, null, game); boolean canStopOnAny = possibleBlockersCount != 0 && getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockersWithAnyPermanents(); boolean canStopOnZero = possibleBlockersCount == 0 && getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockersWithZeroPermanents(); quickStop = canStopOnAny || canStopOnZero; @@ -1482,7 +1482,7 @@ public class HumanPlayer extends PlayerImpl { // can't see lands as playable and must know the reason (if they click on land then they get that message) if (abilityToCast.getAbilityType() == AbilityType.SPELL) { Spell spell = game.getStack().getSpell(abilityToCast.getSourceId()); - boolean haveManaAbilities = object.getAbilities().stream().anyMatch(a -> a instanceof ManaAbility); + boolean haveManaAbilities = object.getAbilities().stream().anyMatch(ManaAbility.class::isInstance); if (spell != null && !spell.isResolving() && haveManaAbilities) { switch (spell.getCurrentActivatingManaAbilitiesStep()) { // if you used special mana ability like convoke then normal mana abilities will be restricted to use, see Convoke for details @@ -1605,9 +1605,9 @@ public class HumanPlayer extends PlayerImpl { } else if (responseId != null) { Permanent attacker = game.getPermanent(responseId); if (attacker != null) { - if (filterCreatureForCombat.match(attacker, null, playerId, game)) { + if (filterCreatureForCombat.match(attacker, playerId, null, game)) { selectDefender(game.getCombat().getDefenders(), attacker.getId(), game); - } else if (filterAttack.match(attacker, null, playerId, game) && game.getStack().isEmpty()) { + } else if (filterAttack.match(attacker, playerId, null, game) && game.getStack().isEmpty()) { removeAttackerIfPossible(game, attacker); } } @@ -1737,7 +1737,6 @@ public class HumanPlayer extends PlayerImpl { return true; } else { TargetDefender target = new TargetDefender(possibleDefender, attackerId); - target.setNotTarget(true); // player or planswalker hexproof does not prevent attacking a player if (forcedToAttack) { StringBuilder sb = new StringBuilder(target.getTargetName()); Permanent attacker = game.getPermanent(attackerId); @@ -1757,7 +1756,6 @@ public class HumanPlayer extends PlayerImpl { protected UUID selectDefenderForAllAttack(Set defenders, Game game) { TargetDefender target = new TargetDefender(defenders, null); - target.setNotTarget(true); // player or planswalker hexproof does not prevent attacking a player if (chooseTarget(Outcome.Damage, target, null, game)) { return getFixedResponseUUID(game); } @@ -1774,7 +1772,7 @@ public class HumanPlayer extends PlayerImpl { filter.add(new ControllerIdPredicate(defendingPlayerId)); // stop skip on any/zero permanents available - int possibleBlockersCount = game.getBattlefield().count(filter, null, playerId, game); + int possibleBlockersCount = game.getBattlefield().count(filter, playerId, source, game); boolean canStopOnAny = possibleBlockersCount != 0 && getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockersWithAnyPermanents(); boolean canStopOnZero = possibleBlockersCount == 0 && getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockersWithZeroPermanents(); @@ -1812,9 +1810,9 @@ public class HumanPlayer extends PlayerImpl { if (blocker != null) { boolean removeBlocker = false; // does not block yet and can block or can block more attackers - if (filter.match(blocker, null, playerId, game)) { + if (filter.match(blocker, playerId, source, game)) { selectCombatGroup(defendingPlayerId, blocker.getId(), game); - } else if (filterBlock.match(blocker, null, playerId, game) + } else if (filterBlock.match(blocker, playerId, source, game) && game.getStack().isEmpty()) { removeBlocker = true; } @@ -1894,7 +1892,7 @@ public class HumanPlayer extends PlayerImpl { prepareForResponse(game); if (!isExecutingMacro()) { // possible attackers to block - Set attackers = target.possibleTargets(null, playerId, game); + Set attackers = target.possibleTargets(playerId, null, game); Permanent blocker = game.getPermanent(blockerId); Set possibleTargets = new HashSet<>(); for (UUID attackerId : attackers) { @@ -1934,7 +1932,7 @@ public class HumanPlayer extends PlayerImpl { if (singleTargetName != null) { target.setTargetName(singleTargetName); } - choose(Outcome.Damage, target, source.getSourceId(), game); + choose(Outcome.Damage, target, source, game); if (targets.isEmpty() || targets.contains(target.getFirstTarget())) { int damageAmount = getAmount(0, remainingDamage, "Select amount", game); Permanent permanent = game.getPermanent(target.getFirstTarget()); @@ -2187,10 +2185,10 @@ public class HumanPlayer extends PlayerImpl { MageObject object = game.getObject(card.getId()); // must be object to find real abilities (example: commander) if (object != null) { String message = "Choose ability to cast" + (noMana ? " for FREE" : "") + "
" + object.getLogName(); - LinkedHashMap useableAbilities = PlayerImpl.getCastableSpellAbilities(game, playerId, object, game.getState().getZone(object.getId()), noMana); + LinkedHashMap useableAbilities = PlayerImpl.getCastableSpellAbilities(game, playerId, object, game.getState().getZone(object.getId()), noMana); if (useableAbilities != null && useableAbilities.size() == 1) { - return (SpellAbility) useableAbilities.values().iterator().next(); + return useableAbilities.values().iterator().next(); } else if (useableAbilities != null && !useableAbilities.isEmpty()) { @@ -2204,7 +2202,7 @@ public class HumanPlayer extends PlayerImpl { UUID responseId = getFixedResponseUUID(game); if (responseId != null) { if (useableAbilities.containsKey(responseId)) { - return (SpellAbility) useableAbilities.get(responseId); + return useableAbilities.get(responseId); } } } @@ -2224,7 +2222,7 @@ public class HumanPlayer extends PlayerImpl { if (modes.size() > 1) { // done option for up to choices boolean canEndChoice = modes.getSelectedModes().size() >= modes.getMinModes() || modes.isMayChooseNone(); - MageObject obj = game.getObject(source.getSourceId()); + MageObject obj = game.getObject(source); Map modeMap = new LinkedHashMap<>(); int modeIndex = 0; AvailableModes: @@ -2244,7 +2242,7 @@ public class HumanPlayer extends PlayerImpl { } } - if (mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) { // and needed targets have to be available + if (mode.getTargets().canChoose(source.getControllerId(), source, game)) { // and needed targets have to be available String modeText = mode.getEffects().getText(mode); if (obj != null) { modeText = modeText.replace("{this}", obj.getName()); diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/KhansExpandedCube.java b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/KhansExpandedCube.java new file mode 100644 index 00000000000..2115310b97e --- /dev/null +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/KhansExpandedCube.java @@ -0,0 +1,512 @@ +package mage.tournament.cubes; + +import mage.game.draft.DraftCube; + +/** + * @author TheBear132 + * This cube is taken from this article https://magic.wizards.com/en/articles/archive/magic-online/khans-expanded-cube-2019-07-23 + * If the cards are from any of the Tarkir sets, the preferred set will be set to that set + */ + +public class KhansExpandedCube extends DraftCube { + + public KhansExpandedCube() { + super("MTGO Khans Expanded Cube"); + + cubeCards.add(new DraftCube.CardIdentity("Herald of Anafenza", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Embodiment of Spring", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Bloodsoaked Champion", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Kolaghan Stormsinger", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Experiment One", "")); + cubeCards.add(new DraftCube.CardIdentity("Taigam, Ojutai Master", "")); + cubeCards.add(new DraftCube.CardIdentity("Chronomaton", "")); + cubeCards.add(new DraftCube.CardIdentity("Arid Mesa", "")); + cubeCards.add(new DraftCube.CardIdentity("Mardu Hateblade", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Enclave Cryptologist", "")); + cubeCards.add(new DraftCube.CardIdentity("Cruel Sadist", "")); + cubeCards.add(new DraftCube.CardIdentity("Monastery Swiftspear", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Gnarlwood Dryad", "")); + cubeCards.add(new DraftCube.CardIdentity("Ojutai, Soul of Winter", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Filigree Familiar", "")); + cubeCards.add(new DraftCube.CardIdentity("Ash Barrens", "")); + cubeCards.add(new DraftCube.CardIdentity("Mardu Woe-Reaper", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Deranged Assistant", "")); + cubeCards.add(new DraftCube.CardIdentity("Disowned Ancestor", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Abbot of Keral Keep", "")); + cubeCards.add(new DraftCube.CardIdentity("Patron of the Wild", "")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Silumgar", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Pilgrim's Eye", "")); + cubeCards.add(new DraftCube.CardIdentity("Battlefield Forge", "")); + cubeCards.add(new DraftCube.CardIdentity("Ainok Bond-Kin", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Elusive Spellfist", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Ruthless Ripper", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Firebrand Archer", "")); + cubeCards.add(new DraftCube.CardIdentity("Pelt Collector", "")); + cubeCards.add(new DraftCube.CardIdentity("Connive // Concoct", "")); + cubeCards.add(new DraftCube.CardIdentity("Skittering Surveyor", "")); + cubeCards.add(new DraftCube.CardIdentity("Blood Crypt", "")); + cubeCards.add(new DraftCube.CardIdentity("Daring Skyjek", "")); + cubeCards.add(new DraftCube.CardIdentity("Jeskai Elder", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Shambling Goblin", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Horde Ambusher", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Ainok Survivalist", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Dreadhorde Butcher", "")); + cubeCards.add(new DraftCube.CardIdentity("Awakened Amalgam", "")); + cubeCards.add(new DraftCube.CardIdentity("Bloodfell Caves", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Hidden Dragonslayer", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Jeskai Sage", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Battle Brawler", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Ire Shaman", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Broodhatch Nantuko", "")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Kolaghan", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Peace Strider", "")); + cubeCards.add(new DraftCube.CardIdentity("Bloodstained Mire", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Master of Pearls", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Plaxmanta", "")); + cubeCards.add(new DraftCube.CardIdentity("Kitesail Freebooter", "")); + cubeCards.add(new DraftCube.CardIdentity("Jeering Instigator", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Deadly Recluse", "")); + cubeCards.add(new DraftCube.CardIdentity("Ghor-Clan Rampager", "")); + cubeCards.add(new DraftCube.CardIdentity("Rampaging Monument", "")); + cubeCards.add(new DraftCube.CardIdentity("Blooming Marsh", "")); + cubeCards.add(new DraftCube.CardIdentity("Remorseful Cleric", "")); + cubeCards.add(new DraftCube.CardIdentity("Qarsi Deceiver", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Mardu Skullhunter", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Kiln Fiend", "")); + cubeCards.add(new DraftCube.CardIdentity("Decorated Champion", "")); + cubeCards.add(new DraftCube.CardIdentity("Atarka, World Render", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Solemn Simulacrum", "")); + cubeCards.add(new DraftCube.CardIdentity("Blossoming Sands", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Seeker of the Way", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Spellweaver Eternal", "")); + cubeCards.add(new DraftCube.CardIdentity("Silumgar Assassin", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Mogg War Marshal", "")); + cubeCards.add(new DraftCube.CardIdentity("Den Protector", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Knight of Autumn", "")); + cubeCards.add(new DraftCube.CardIdentity("Chamber Sentry", "")); + cubeCards.add(new DraftCube.CardIdentity("Botanical Sanctum", "")); + cubeCards.add(new DraftCube.CardIdentity("Soulfire Grand Master", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Stratus Dancer", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Skinthinner", "")); + cubeCards.add(new DraftCube.CardIdentity("Nef-Crop Entangler", "")); + cubeCards.add(new DraftCube.CardIdentity("Glade Watcher", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Dromoka, the Eternal", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Duplicant", "")); + cubeCards.add(new DraftCube.CardIdentity("Breeding Pool", "")); + cubeCards.add(new DraftCube.CardIdentity("Steward of Solidarity", "")); + cubeCards.add(new DraftCube.CardIdentity("Willbender", "")); + cubeCards.add(new DraftCube.CardIdentity("Sultai Emissary", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Skirk Marauder", "")); + cubeCards.add(new DraftCube.CardIdentity("Heir of the Wilds", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Chief of the Edge", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Animation Module", "")); + cubeCards.add(new DraftCube.CardIdentity("Caves of Koilos", "")); + cubeCards.add(new DraftCube.CardIdentity("Tithe Taker", "")); + cubeCards.add(new DraftCube.CardIdentity("Echo Tracer", "")); + cubeCards.add(new DraftCube.CardIdentity("Aphetto Exterminator", "")); + cubeCards.add(new DraftCube.CardIdentity("Thermo-Alchemist", "")); + cubeCards.add(new DraftCube.CardIdentity("Obsessive Skinner", "")); + cubeCards.add(new DraftCube.CardIdentity("Chief of the Scale", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Ghostfire Blade", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Concealed Courtyard", "")); + cubeCards.add(new DraftCube.CardIdentity("Wall of Omens", "")); + cubeCards.add(new DraftCube.CardIdentity("Riptide Entrancer", "")); + cubeCards.add(new DraftCube.CardIdentity("Blood-Chin Fanatic", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("War-Name Aspirant", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Rattleclaw Mystic", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Elenda, the Dusk Rose", "")); + cubeCards.add(new DraftCube.CardIdentity("Sylvok Lifestaff", "")); + cubeCards.add(new DraftCube.CardIdentity("Dismal Backwater", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Abzan Falconer", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Riptide Survivor", "")); + cubeCards.add(new DraftCube.CardIdentity("Graveblade Marauder", "")); + cubeCards.add(new DraftCube.CardIdentity("Crater Elemental", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Ilysian Caryatid", "")); + cubeCards.add(new DraftCube.CardIdentity("Mortify", "")); + cubeCards.add(new DraftCube.CardIdentity("Triangle of War", "")); + cubeCards.add(new DraftCube.CardIdentity("Evolving Wilds", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Arashin Foremost", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Aphetto Runecaster", "")); + cubeCards.add(new DraftCube.CardIdentity("Grim Haruspex", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Flamewake Phoenix", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Deathmist Raptor", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Start // Finish", "")); + cubeCards.add(new DraftCube.CardIdentity("Cranial Archive", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Flooded Strand", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Kor Sanctifiers", "")); + cubeCards.add(new DraftCube.CardIdentity("Gurmag Drowner", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Mardu Strike Leader", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Legion Warboss", "")); + cubeCards.add(new DraftCube.CardIdentity("Springbloom Druid", "")); + cubeCards.add(new DraftCube.CardIdentity("Utter End", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Dream Chisel", "")); + cubeCards.add(new DraftCube.CardIdentity("Frontier Bivouac", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Mardu Hordechief", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Kheru Spellsnatcher", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Necravolver", "")); + cubeCards.add(new DraftCube.CardIdentity("Bonecrusher Giant", "")); + cubeCards.add(new DraftCube.CardIdentity("Tuskguard Captain", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Castigate", "")); + cubeCards.add(new DraftCube.CardIdentity("Guild Globe", "")); + cubeCards.add(new DraftCube.CardIdentity("Godless Shrine", "")); + cubeCards.add(new DraftCube.CardIdentity("Monastery Mentor", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Master of the Veil", "")); + cubeCards.add(new DraftCube.CardIdentity("Bane of the Living", "")); + cubeCards.add(new DraftCube.CardIdentity("Reckless Bushwhacker", "")); + cubeCards.add(new DraftCube.CardIdentity("Anavolver", "")); + cubeCards.add(new DraftCube.CardIdentity("Obzedat's Aid", "")); + cubeCards.add(new DraftCube.CardIdentity("Leering Emblem", "")); + cubeCards.add(new DraftCube.CardIdentity("Grand Coliseum", "")); + cubeCards.add(new DraftCube.CardIdentity("Wingbeat Warrior", "")); + cubeCards.add(new DraftCube.CardIdentity("Mistfire Weaver", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Bellowing Saddlebrute", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Skirk Commando", "")); + cubeCards.add(new DraftCube.CardIdentity("Armorcraft Judge", "")); + cubeCards.add(new DraftCube.CardIdentity("Death Grasp", "")); + cubeCards.add(new DraftCube.CardIdentity("Prophetic Prism", "")); + cubeCards.add(new DraftCube.CardIdentity("Hallowed Fountain", "")); + cubeCards.add(new DraftCube.CardIdentity("Abzan Battle Priest", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Niblis of Frost", "")); + cubeCards.add(new DraftCube.CardIdentity("Gift of Doom", "")); + cubeCards.add(new DraftCube.CardIdentity("Smelt-Ward Minotaur", "")); + cubeCards.add(new DraftCube.CardIdentity("Goreclaw, Terror of Qal Sisma", "")); + cubeCards.add(new DraftCube.CardIdentity("Campaign of Vengeance", "")); + cubeCards.add(new DraftCube.CardIdentity("Stormrider Rig", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Hissing Quagmire", "")); + cubeCards.add(new DraftCube.CardIdentity("Aven Liberator", "")); + cubeCards.add(new DraftCube.CardIdentity("Talrand, Sky Summoner", "")); + cubeCards.add(new DraftCube.CardIdentity("Grinning Demon", "")); + cubeCards.add(new DraftCube.CardIdentity("Ashcloud Phoenix", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Nantuko Vigilante", "")); + cubeCards.add(new DraftCube.CardIdentity("Golgari Guildmage", "")); + cubeCards.add(new DraftCube.CardIdentity("Trip Noose", "")); + cubeCards.add(new DraftCube.CardIdentity("Inspiring Vantage", "")); + cubeCards.add(new DraftCube.CardIdentity("Daru Sanctifier", "")); + cubeCards.add(new DraftCube.CardIdentity("Chromeshell Crab", "")); + cubeCards.add(new DraftCube.CardIdentity("Haunted Cadaver", "")); + cubeCards.add(new DraftCube.CardIdentity("Atarka Efreet", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Serpentine Basilisk", "")); + cubeCards.add(new DraftCube.CardIdentity("Dreg Mangler", "")); + cubeCards.add(new DraftCube.CardIdentity("Arcane Encyclopedia", "")); + cubeCards.add(new DraftCube.CardIdentity("Jungle Hollow", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Dragonscale General", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Icefall Regent", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Haunted Dead", "")); + cubeCards.add(new DraftCube.CardIdentity("Battering Craghorn", "")); + cubeCards.add(new DraftCube.CardIdentity("Sultai Flayer", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Corpsejack Menace", "")); + cubeCards.add(new DraftCube.CardIdentity("Sickleslicer", "")); + cubeCards.add(new DraftCube.CardIdentity("Llanowar Wastes", "")); + cubeCards.add(new DraftCube.CardIdentity("High Sentinels of Arashin", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Ixidor, Reality Sculptor", "")); + cubeCards.add(new DraftCube.CardIdentity("Mer-Ek Nightblade", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Blistering Firecat", "")); + cubeCards.add(new DraftCube.CardIdentity("Surrak, the Hunt Caller", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Izoni, Thousand-Eyed", "")); + cubeCards.add(new DraftCube.CardIdentity("Bonehoard", "")); + cubeCards.add(new DraftCube.CardIdentity("Lumbering Falls", "")); + cubeCards.add(new DraftCube.CardIdentity("Ojutai Exemplars", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Ixidron", "")); + cubeCards.add(new DraftCube.CardIdentity("Thrasher Brute", "")); + cubeCards.add(new DraftCube.CardIdentity("Erratic Cyclops", "")); + cubeCards.add(new DraftCube.CardIdentity("Thelonite Hermit", "")); + cubeCards.add(new DraftCube.CardIdentity("Assassin's Trophy", "")); + cubeCards.add(new DraftCube.CardIdentity("Obelisk of Alara", "")); + cubeCards.add(new DraftCube.CardIdentity("Marsh Flats", "")); + cubeCards.add(new DraftCube.CardIdentity("Stonehorn Dignitary", "")); + cubeCards.add(new DraftCube.CardIdentity("Mischievous Quanar", "")); + cubeCards.add(new DraftCube.CardIdentity("Creakwood Ghoul", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Heelcutter", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Challenger Troll", "")); + cubeCards.add(new DraftCube.CardIdentity("Grisly Salvage", "")); + cubeCards.add(new DraftCube.CardIdentity("Misty Rainforest", "")); + cubeCards.add(new DraftCube.CardIdentity("Elite Scaleguard", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Soulblade Djinn", "")); + cubeCards.add(new DraftCube.CardIdentity("Rakshasa Gravecaller", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Mardu Heart-Piercer", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Conclave Naturalists", "")); + cubeCards.add(new DraftCube.CardIdentity("Find // Finality", "")); + cubeCards.add(new DraftCube.CardIdentity("Mystic Monastery", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Giant Killer", "")); + cubeCards.add(new DraftCube.CardIdentity("Vesuvan Shapeshifter", "")); + cubeCards.add(new DraftCube.CardIdentity("Noosegraf Mob", "")); + cubeCards.add(new DraftCube.CardIdentity("Caldera Hellion", "")); + cubeCards.add(new DraftCube.CardIdentity("Gigapede", "")); + cubeCards.add(new DraftCube.CardIdentity("Death Frenzy", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Needle Spires", "")); + cubeCards.add(new DraftCube.CardIdentity("Patron of the Valiant", "")); + cubeCards.add(new DraftCube.CardIdentity("Brine Elemental", "")); + cubeCards.add(new DraftCube.CardIdentity("Silent Specter", "")); + cubeCards.add(new DraftCube.CardIdentity("Charging Monstrosaur", "")); + cubeCards.add(new DraftCube.CardIdentity("Hystrodon", "")); + cubeCards.add(new DraftCube.CardIdentity("Deadbridge Chant", "")); + cubeCards.add(new DraftCube.CardIdentity("Nomad Outpost", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Wingmate Roc", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Quicksilver Dragon", "")); + cubeCards.add(new DraftCube.CardIdentity("Gurmag Angler", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Dragon-Style Twins", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Kessig Cagebreakers", "")); + cubeCards.add(new DraftCube.CardIdentity("Nyx Weaver", "")); + cubeCards.add(new DraftCube.CardIdentity("Opulent Palace", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Daru Lancer", "")); + cubeCards.add(new DraftCube.CardIdentity("Thousand Winds", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Tombstalker", "")); + cubeCards.add(new DraftCube.CardIdentity("Flamerush Rider", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Pine Walker", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Coiling Oracle", "")); + cubeCards.add(new DraftCube.CardIdentity("Overgrown Tomb", "")); + cubeCards.add(new DraftCube.CardIdentity("Exalted Angel", "")); + cubeCards.add(new DraftCube.CardIdentity("Dive Down", "")); + cubeCards.add(new DraftCube.CardIdentity("Necropolis Fiend", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Quakefoot Cyclops", "")); + cubeCards.add(new DraftCube.CardIdentity("Primal Whisperer", "")); + cubeCards.add(new DraftCube.CardIdentity("Icefeather Aven", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Polluted Delta", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Linvala, the Preserver", "")); + cubeCards.add(new DraftCube.CardIdentity("Opt", "")); + cubeCards.add(new DraftCube.CardIdentity("Ghastly Demise", "")); + cubeCards.add(new DraftCube.CardIdentity("Skarrgan Hellkite", "")); + cubeCards.add(new DraftCube.CardIdentity("Hooting Mandrills", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Mystic Snake", "")); + cubeCards.add(new DraftCube.CardIdentity("Prismatic Vista", "")); + cubeCards.add(new DraftCube.CardIdentity("Harm's Way", "")); + cubeCards.add(new DraftCube.CardIdentity("Stubborn Denial", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Moment of Craving", "")); + cubeCards.add(new DraftCube.CardIdentity("Firemaw Kavu", "")); + cubeCards.add(new DraftCube.CardIdentity("Root Elemental", "")); + cubeCards.add(new DraftCube.CardIdentity("Sagu Mauler", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Rugged Highlands", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Path to Exile", "")); + cubeCards.add(new DraftCube.CardIdentity("Disdainful Stroke", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Vicious Offering", "")); + cubeCards.add(new DraftCube.CardIdentity("Rockshard Elemental", "")); + cubeCards.add(new DraftCube.CardIdentity("Temur War Shaman", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Applied Biomancy", "")); + cubeCards.add(new DraftCube.CardIdentity("Sacred Foundry", "")); + cubeCards.add(new DraftCube.CardIdentity("Sheltering Light", "")); + cubeCards.add(new DraftCube.CardIdentity("Force Away", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Expunge", "")); + cubeCards.add(new DraftCube.CardIdentity("Bedlam Reveler", "")); + cubeCards.add(new DraftCube.CardIdentity("Hooded Hydra", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Ethereal Ambush", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Sandsteppe Citadel", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Adamant Will", "")); + cubeCards.add(new DraftCube.CardIdentity("Impulse", "")); + cubeCards.add(new DraftCube.CardIdentity("Murder", "")); + cubeCards.add(new DraftCube.CardIdentity("Weapon Surge", "")); + cubeCards.add(new DraftCube.CardIdentity("Venomspout Brackus", "")); + cubeCards.add(new DraftCube.CardIdentity("Incubation // Incongruity", "")); + cubeCards.add(new DraftCube.CardIdentity("Scalding Tarn", "")); + cubeCards.add(new DraftCube.CardIdentity("Artful Maneuver", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Jilt", "")); + cubeCards.add(new DraftCube.CardIdentity("Foul Renewal", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Burning Oil", "")); + cubeCards.add(new DraftCube.CardIdentity("Earthbrawn", "")); + cubeCards.add(new DraftCube.CardIdentity("Urban Evolution", "")); + cubeCards.add(new DraftCube.CardIdentity("Scoured Barrens", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Disenchant", "")); + cubeCards.add(new DraftCube.CardIdentity("Reality Shift", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Price of Fame", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Strike", "")); + cubeCards.add(new DraftCube.CardIdentity("Grapple with the Past", "")); + cubeCards.add(new DraftCube.CardIdentity("Secret Plans", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Shambling Vent", "")); + cubeCards.add(new DraftCube.CardIdentity("Feat of Resistance", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Think Twice", "")); + cubeCards.add(new DraftCube.CardIdentity("Murderous Cut", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Temur Battle Rage", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Winds of Qal Sisma", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Yavimaya's Embrace", "")); + cubeCards.add(new DraftCube.CardIdentity("Shivan Reef", "")); + cubeCards.add(new DraftCube.CardIdentity("Feeling of Dread", "")); + cubeCards.add(new DraftCube.CardIdentity("Twisted Reflection", "")); + cubeCards.add(new DraftCube.CardIdentity("Reach of Shadows", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Omen of the Forge", "")); + cubeCards.add(new DraftCube.CardIdentity("Crushing Canopy", "")); + cubeCards.add(new DraftCube.CardIdentity("Stormchaser Mage", "")); + cubeCards.add(new DraftCube.CardIdentity("Spirebluff Canal", "")); + cubeCards.add(new DraftCube.CardIdentity("Phalanx Tactics", "")); + cubeCards.add(new DraftCube.CardIdentity("Winds of Rebuke", "")); + cubeCards.add(new DraftCube.CardIdentity("Death Wind", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Brimstone Volley", "")); + cubeCards.add(new DraftCube.CardIdentity("Gnaw to the Bone", "")); + cubeCards.add(new DraftCube.CardIdentity("Bloodwater Entity", "")); + cubeCards.add(new DraftCube.CardIdentity("Steam Vents", "")); + cubeCards.add(new DraftCube.CardIdentity("Valorous Stance", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Forbidden Alchemy", "")); + cubeCards.add(new DraftCube.CardIdentity("Duress", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Geistblast", "")); + cubeCards.add(new DraftCube.CardIdentity("Thornado", "")); + cubeCards.add(new DraftCube.CardIdentity("Wee Dragonauts", "")); + cubeCards.add(new DraftCube.CardIdentity("Stomping Ground", "")); + cubeCards.add(new DraftCube.CardIdentity("Generous Gift", "")); + cubeCards.add(new DraftCube.CardIdentity("Phantasmal Form", "")); + cubeCards.add(new DraftCube.CardIdentity("Chainer's Edict", "")); + cubeCards.add(new DraftCube.CardIdentity("Risk Factor", "")); + cubeCards.add(new DraftCube.CardIdentity("Wild Hunger", "")); + cubeCards.add(new DraftCube.CardIdentity("Crackling Drake", "")); + cubeCards.add(new DraftCube.CardIdentity("Swiftwater Cliffs", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Radiant's Judgment", "")); + cubeCards.add(new DraftCube.CardIdentity("Repulse", "")); + cubeCards.add(new DraftCube.CardIdentity("Agonizing Remorse", "")); + cubeCards.add(new DraftCube.CardIdentity("Bolt Bend", "")); + cubeCards.add(new DraftCube.CardIdentity("Become Immense", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Hypersonic Dragon", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple Garden", "")); + cubeCards.add(new DraftCube.CardIdentity("Rally the Peasants", "")); + cubeCards.add(new DraftCube.CardIdentity("Sinister Sabotage", "")); + cubeCards.add(new DraftCube.CardIdentity("Morgue Theft", "")); + cubeCards.add(new DraftCube.CardIdentity("Burn Away", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Savage Swipe", "")); + cubeCards.add(new DraftCube.CardIdentity("Izzet Charm", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Abandon", "")); + cubeCards.add(new DraftCube.CardIdentity("Miraculous Recovery", "")); + cubeCards.add(new DraftCube.CardIdentity("Chemister's Insight", "")); + cubeCards.add(new DraftCube.CardIdentity("Mire Triton", "")); + cubeCards.add(new DraftCube.CardIdentity("Deem Worthy", "")); + cubeCards.add(new DraftCube.CardIdentity("Epic Confrontation", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Electrolyze", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Deceit", "")); + cubeCards.add(new DraftCube.CardIdentity("Oust", "")); + cubeCards.add(new DraftCube.CardIdentity("Commit // Memory", "")); + cubeCards.add(new DraftCube.CardIdentity("Doomfall", "")); + cubeCards.add(new DraftCube.CardIdentity("Flames of the Raze-Boar", "")); + cubeCards.add(new DraftCube.CardIdentity("Savage Punch", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Sonic Assault", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Enlightenment", "")); + cubeCards.add(new DraftCube.CardIdentity("Collective Effort", "")); + cubeCards.add(new DraftCube.CardIdentity("Icy Blast", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Heartless Pillage", "")); + cubeCards.add(new DraftCube.CardIdentity("Faithless Looting", "")); + cubeCards.add(new DraftCube.CardIdentity("Tracker's Instincts", "")); + cubeCards.add(new DraftCube.CardIdentity("Winterflame", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Epiphany", "")); + cubeCards.add(new DraftCube.CardIdentity("Slaughter the Strong", "")); + cubeCards.add(new DraftCube.CardIdentity("Dig Through Time", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Infest", "")); + cubeCards.add(new DraftCube.CardIdentity("Flame Slash", "")); + cubeCards.add(new DraftCube.CardIdentity("Winding Way", "")); + cubeCards.add(new DraftCube.CardIdentity("Prophetic Bolt", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Malady", "")); + cubeCards.add(new DraftCube.CardIdentity("End Hostilities", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Callous Dismissal", "")); + cubeCards.add(new DraftCube.CardIdentity("Parting Thoughts", "")); + cubeCards.add(new DraftCube.CardIdentity("Reckless Charge", "")); + cubeCards.add(new DraftCube.CardIdentity("Map the Wastes", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Honored Crop-Captain", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Malice", "")); + cubeCards.add(new DraftCube.CardIdentity("Fell the Mighty", "")); + cubeCards.add(new DraftCube.CardIdentity("Chart a Course", "")); + cubeCards.add(new DraftCube.CardIdentity("Wander in Death", "")); + cubeCards.add(new DraftCube.CardIdentity("Nightbird's Clutches", "")); + cubeCards.add(new DraftCube.CardIdentity("Voracious Hydra", "")); + cubeCards.add(new DraftCube.CardIdentity("Sunhome Guildmage", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Mystery", "")); + cubeCards.add(new DraftCube.CardIdentity("Myth Realized", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Strategic Planning", "")); + cubeCards.add(new DraftCube.CardIdentity("Moan of the Unhallowed", "")); + cubeCards.add(new DraftCube.CardIdentity("Roast", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Nissa's Judgment", "")); + cubeCards.add(new DraftCube.CardIdentity("Viashino Firstblade", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Plenty", "")); + cubeCards.add(new DraftCube.CardIdentity("Mastery of the Unseen", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Write into Being", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Smiting Helix", "")); + cubeCards.add(new DraftCube.CardIdentity("Tormenting Voice", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Spider Spawning", "")); + cubeCards.add(new DraftCube.CardIdentity("Firemane Avenger", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Silence", "")); + cubeCards.add(new DraftCube.CardIdentity("Silkwrap", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Set Adrift", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Vigor Mortis", "")); + cubeCards.add(new DraftCube.CardIdentity("Arc Lightning", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("See the Unwritten", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Foundry Champion", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple of Triumph", "")); + cubeCards.add(new DraftCube.CardIdentity("Suspension Field", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Treasure Cruise", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Crux of Fate", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Collective Defiance", "")); + cubeCards.add(new DraftCube.CardIdentity("Hardened Scales", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Integrity // Intervention", "")); + cubeCards.add(new DraftCube.CardIdentity("Fabled Passage", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightform", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Spontaneous Mutation", "")); + cubeCards.add(new DraftCube.CardIdentity("Dead Drop", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Repeating Barrage", "")); + cubeCards.add(new DraftCube.CardIdentity("Obscuring Aether", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Response // Resurgence", "")); + cubeCards.add(new DraftCube.CardIdentity("Thornwood Falls", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Stasis Snare", "")); + cubeCards.add(new DraftCube.CardIdentity("Riddleform", "")); + cubeCards.add(new DraftCube.CardIdentity("Debilitating Injury", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Rolling Temblor", "")); + cubeCards.add(new DraftCube.CardIdentity("Durable Handicraft", "")); + cubeCards.add(new DraftCube.CardIdentity("Ride Down", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Tranquil Cove", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Cast Out", "")); + cubeCards.add(new DraftCube.CardIdentity("Cloudform", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Raiders' Spoils", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Crater's Claws", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Trail of Mystery", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("War Flare", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Verdant Catacombs", "")); + cubeCards.add(new DraftCube.CardIdentity("Righteous Cause", "")); + cubeCards.add(new DraftCube.CardIdentity("Skywise Teachings", "Dragons of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Raiders' Wake", "")); + cubeCards.add(new DraftCube.CardIdentity("Rageform", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Colossal Majesty", "")); + cubeCards.add(new DraftCube.CardIdentity("Warleader's Helix", "")); + cubeCards.add(new DraftCube.CardIdentity("Wandering Fumarole", "")); + cubeCards.add(new DraftCube.CardIdentity("Mantis Rider", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Watery Grave", "")); + cubeCards.add(new DraftCube.CardIdentity("Shu Yun, the Silent Tempest", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Wind-Scarred Crag", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Elsha of the Infinite", "")); + cubeCards.add(new DraftCube.CardIdentity("Windswept Heath", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Warden of the Eye", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Wooded Foothills", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Efreet Weaponmaster", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Yavimaya Coast", "")); + cubeCards.add(new DraftCube.CardIdentity("Kykar, Wind's Fury", "")); + cubeCards.add(new DraftCube.CardIdentity("Jeskai Charm", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Flying Crane Technique", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Jeskai Ascendancy", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Alesha, Who Smiles at Death", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Butcher of the Horde", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Ankle Shanker", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Zurgo Helmsmasher", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Ponyback Brigade", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Crackling Doom", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Mardu Charm", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Mardu Ascendancy", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Fervent Charge", "")); + cubeCards.add(new DraftCube.CardIdentity("Anafenza, the Foremost", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Siege Rhino", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Armament Corps", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Ivorytusk Fortress", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Abzan Guide", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Abzan Charm", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Ready // Willing", "")); + cubeCards.add(new DraftCube.CardIdentity("Duneblast", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Abzan Ascendancy", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Sidisi, Brood Tyrant", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Rakshasa Vizier", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Sultai Soothsayer", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Abomination of Gudul", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Muldrotha, the Gravetide", "")); + cubeCards.add(new DraftCube.CardIdentity("Tasigur, the Golden Fang", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Sultai Charm", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Villainous Wealth", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Sultai Ascendancy", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Savage Knuckleblade", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Yasova Dragonclaw", "Fate Reforged")); + cubeCards.add(new DraftCube.CardIdentity("Avalanche Tusker", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Bear's Companion", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Surrak Dragonclaw", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Intet, the Dreamer", "")); + cubeCards.add(new DraftCube.CardIdentity("Snowhorn Rider", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Temur Charm", "Khans of Tarkir")); + cubeCards.add(new DraftCube.CardIdentity("Temur Ascendancy", "Khans of Tarkir")); + } +} diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/VintageCubeFebruary2022.java b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/VintageCubeFebruary2022.java new file mode 100644 index 00000000000..5c7c6ddf1d4 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/VintageCubeFebruary2022.java @@ -0,0 +1,552 @@ +package mage.tournament.cubes; + +import mage.game.draft.DraftCube; + +public class VintageCubeFebruary2022 extends DraftCube { + + public VintageCubeFebruary2022() { + super("MTGO Vintage Cube Februrary 2022"); + + cubeCards.add(new CardIdentity("Abbot of Keral Keep", "")); + cubeCards.add(new CardIdentity("Abrade", "")); + cubeCards.add(new CardIdentity("Academy Ruins", "")); + cubeCards.add(new CardIdentity("Acidic Slime", "")); + cubeCards.add(new CardIdentity("Adanto Vanguard", "")); + cubeCards.add(new CardIdentity("Adeline, Resplendent Cathar", "")); + cubeCards.add(new CardIdentity("Ancestral Recall", "")); + cubeCards.add(new CardIdentity("Ancestral Vision", "")); + cubeCards.add(new CardIdentity("Ancient Tomb", "")); + cubeCards.add(new CardIdentity("Animate Dead", "")); + cubeCards.add(new CardIdentity("Arbor Elf", "")); + cubeCards.add(new CardIdentity("Archangel Avacyn", "")); + cubeCards.add(new CardIdentity("Archon of Cruelty", "")); + cubeCards.add(new CardIdentity("Archon of Valor's Reach", "")); + cubeCards.add(new CardIdentity("Arid Mesa", "")); + cubeCards.add(new CardIdentity("Armageddon", "")); + cubeCards.add(new CardIdentity("Ashen Rider", "")); + cubeCards.add(new CardIdentity("Ashiok, Nightmare Weaver", "")); + cubeCards.add(new CardIdentity("Assassin's Trophy", "")); + cubeCards.add(new CardIdentity("Augur of Autumn", "")); + cubeCards.add(new CardIdentity("Avalanche Riders", "")); + cubeCards.add(new CardIdentity("Avenger of Zendikar", "")); + cubeCards.add(new CardIdentity("Azorius Signet", "")); + cubeCards.add(new CardIdentity("Badlands", "")); + cubeCards.add(new CardIdentity("Balance", "")); + cubeCards.add(new CardIdentity("Baleful Strix", "")); + cubeCards.add(new CardIdentity("Baneslayer Angel", "")); + cubeCards.add(new CardIdentity("Banishing Light", "")); + cubeCards.add(new CardIdentity("Baral, Chief of Compliance", "")); + cubeCards.add(new CardIdentity("Basalt Monolith", "")); + cubeCards.add(new CardIdentity("Batterskull", "")); + cubeCards.add(new CardIdentity("Bayou", "")); + cubeCards.add(new CardIdentity("Bazaar of Baghdad", "")); + cubeCards.add(new CardIdentity("Birds of Paradise", "")); + cubeCards.add(new CardIdentity("Birgi, God of Storytelling", "")); + cubeCards.add(new CardIdentity("Birthing Pod", "")); + cubeCards.add(new CardIdentity("Bitterblossom", "")); + cubeCards.add(new CardIdentity("Black Lotus", "")); + cubeCards.add(new CardIdentity("Blackcleave Cliffs", "")); + cubeCards.add(new CardIdentity("Blade Splicer", "")); + cubeCards.add(new CardIdentity("Blightsteel Colossus", "")); + cubeCards.add(new CardIdentity("Blood Crypt", "")); + cubeCards.add(new CardIdentity("Bloodchief's Thirst", "")); + cubeCards.add(new CardIdentity("Bloodghast", "")); + cubeCards.add(new CardIdentity("Bloodstained Mire", "")); + cubeCards.add(new CardIdentity("Bloodthirsty Adversary", "")); + cubeCards.add(new CardIdentity("Bloodtithe Harvester", "")); + cubeCards.add(new CardIdentity("Blooming Marsh", "")); + cubeCards.add(new CardIdentity("Bolas's Citadel", "")); + cubeCards.add(new CardIdentity("Bomat Courier", "")); + cubeCards.add(new CardIdentity("Bone Shredder", "")); + cubeCards.add(new CardIdentity("Bonecrusher Giant", "")); + cubeCards.add(new CardIdentity("Boros Signet", "")); + cubeCards.add(new CardIdentity("Boseiju, Who Endures", "")); + cubeCards.add(new CardIdentity("Botanical Sanctum", "")); + cubeCards.add(new CardIdentity("Braids, Cabal Minion", "")); + cubeCards.add(new CardIdentity("Brain Freeze", "")); + cubeCards.add(new CardIdentity("Brainstorm", "")); + cubeCards.add(new CardIdentity("Brazen Borrower", "")); + cubeCards.add(new CardIdentity("Breeding Pool", "")); + cubeCards.add(new CardIdentity("Bribery", "")); + cubeCards.add(new CardIdentity("Burst Lightning", "")); + cubeCards.add(new CardIdentity("Cabal Ritual", "")); + cubeCards.add(new CardIdentity("Cathar Commando", "")); + cubeCards.add(new CardIdentity("Celestial Colonnade", "")); + cubeCards.add(new CardIdentity("Chain Lightning", "")); + cubeCards.add(new CardIdentity("Chandra, Torch of Defiance", "")); + cubeCards.add(new CardIdentity("Channel", "")); + cubeCards.add(new CardIdentity("Char", "")); + cubeCards.add(new CardIdentity("Chart a Course", "")); + cubeCards.add(new CardIdentity("Chrome Mox", "")); + cubeCards.add(new CardIdentity("Circle of Dreams Druid", "")); + cubeCards.add(new CardIdentity("Coalition Relic", "")); + cubeCards.add(new CardIdentity("Coercive Portal", "")); + cubeCards.add(new CardIdentity("Collective Brutality", "")); + cubeCards.add(new CardIdentity("Concealed Courtyard", "")); + cubeCards.add(new CardIdentity("Condemn", "")); + cubeCards.add(new CardIdentity("Consecrated Sphinx", "")); + cubeCards.add(new CardIdentity("Containment Priest", "")); + cubeCards.add(new CardIdentity("Copperline Gorge", "")); + cubeCards.add(new CardIdentity("Council's Judgment", "")); + cubeCards.add(new CardIdentity("Counterspell", "")); + cubeCards.add(new CardIdentity("Courser of Kruphix", "")); + cubeCards.add(new CardIdentity("Craterhoof Behemoth", "")); + cubeCards.add(new CardIdentity("Creeping Tar Pit", "")); + cubeCards.add(new CardIdentity("Crop Rotation", "")); + cubeCards.add(new CardIdentity("Crucible of Worlds", "")); + cubeCards.add(new CardIdentity("Cryptbreaker", "")); + cubeCards.add(new CardIdentity("Cryptic Command", "")); + cubeCards.add(new CardIdentity("Cultivate", "")); + cubeCards.add(new CardIdentity("Custodi Lich", "")); + cubeCards.add(new CardIdentity("Dack Fayden", "")); + cubeCards.add(new CardIdentity("Damn", "")); + cubeCards.add(new CardIdentity("Damnation", "")); + cubeCards.add(new CardIdentity("Daretti, Ingenious Iconoclast", "")); + cubeCards.add(new CardIdentity("Daretti, Scrap Savant", "")); + cubeCards.add(new CardIdentity("Dark Confidant", "")); + cubeCards.add(new CardIdentity("Dark Depths", "")); + cubeCards.add(new CardIdentity("Dark Ritual", "")); + cubeCards.add(new CardIdentity("Darkslick Shores", "")); + cubeCards.add(new CardIdentity("Dauthi Voidwalker", "")); + cubeCards.add(new CardIdentity("Daze", "")); + cubeCards.add(new CardIdentity("Deathcap Glade", "")); + cubeCards.add(new CardIdentity("Deceiver Exarch", "")); + cubeCards.add(new CardIdentity("Demonic Tutor", "")); + cubeCards.add(new CardIdentity("Deranged Hermit", "")); + cubeCards.add(new CardIdentity("Deserted Beach", "")); + cubeCards.add(new CardIdentity("Desperate Ritual", "")); + cubeCards.add(new CardIdentity("Destructive Force", "")); + cubeCards.add(new CardIdentity("Devoted Druid", "")); + cubeCards.add(new CardIdentity("Dig Through Time", "")); + cubeCards.add(new CardIdentity("Dimir Signet", "")); + cubeCards.add(new CardIdentity("Dire Fleet Daredevil", "")); + cubeCards.add(new CardIdentity("Disenchant", "")); + cubeCards.add(new CardIdentity("Dismember", "")); + cubeCards.add(new CardIdentity("Dockside Extortionist", "")); + cubeCards.add(new CardIdentity("Dragon's Rage Channeler", "")); + cubeCards.add(new CardIdentity("Dreamroot Cascade", "")); + cubeCards.add(new CardIdentity("Duress", "")); + cubeCards.add(new CardIdentity("Eater of Virtue", "")); + cubeCards.add(new CardIdentity("Echo of Eons", "")); + cubeCards.add(new CardIdentity("Edric, Spymaster of Trest", "")); + cubeCards.add(new CardIdentity("Eidolon of the Great Revel", "")); + cubeCards.add(new CardIdentity("Elder Gargaroth", "")); + cubeCards.add(new CardIdentity("Elesh Norn, Grand Cenobite", "")); + cubeCards.add(new CardIdentity("Elite Spellbinder", "")); + cubeCards.add(new CardIdentity("Elspeth Conquers Death", "")); + cubeCards.add(new CardIdentity("Elspeth, Knight-Errant", "")); + cubeCards.add(new CardIdentity("Elspeth, Sun's Champion", "")); + cubeCards.add(new CardIdentity("Elvish Mystic", "")); + cubeCards.add(new CardIdentity("Elvish Reclaimer", "")); + cubeCards.add(new CardIdentity("Embereth Shieldbreaker", "")); + cubeCards.add(new CardIdentity("Empty the Warrens", "")); + cubeCards.add(new CardIdentity("Emrakul, the Aeons Torn", "")); + cubeCards.add(new CardIdentity("Emrakul, the Promised End", "")); + cubeCards.add(new CardIdentity("Emry, Lurker of the Loch", "")); + cubeCards.add(new CardIdentity("Endurance", "")); + cubeCards.add(new CardIdentity("Entomb", "")); + cubeCards.add(new CardIdentity("Ephemerate", "")); + cubeCards.add(new CardIdentity("Escape to the Wilds", "")); + cubeCards.add(new CardIdentity("Esper Sentinel", "")); + cubeCards.add(new CardIdentity("Eternal Witness", "")); + cubeCards.add(new CardIdentity("Eureka", "")); + cubeCards.add(new CardIdentity("Everflowing Chalice", "")); + cubeCards.add(new CardIdentity("Exhume", "")); + cubeCards.add(new CardIdentity("Expansion // Explosion", "")); + cubeCards.add(new CardIdentity("Expressive Iteration", "")); + cubeCards.add(new CardIdentity("Fable of the Mirror-Breaker", "")); + cubeCards.add(new CardIdentity("Fact or Fiction", "")); + cubeCards.add(new CardIdentity("Faithless Looting", "")); + cubeCards.add(new CardIdentity("Fallen Shinobi", "")); + cubeCards.add(new CardIdentity("Fastbond", "")); + cubeCards.add(new CardIdentity("Fatal Push", "")); + cubeCards.add(new CardIdentity("Fauna Shaman", "")); + cubeCards.add(new CardIdentity("Field of the Dead", "")); + cubeCards.add(new CardIdentity("Fiery Islet", "")); + cubeCards.add(new CardIdentity("Figure of Destiny", "")); + cubeCards.add(new CardIdentity("Finale of Devastation", "")); + cubeCards.add(new CardIdentity("Fireblast", "")); + cubeCards.add(new CardIdentity("Firebolt", "")); + cubeCards.add(new CardIdentity("Flickerwisp", "")); + cubeCards.add(new CardIdentity("Flooded Strand", "")); + cubeCards.add(new CardIdentity("Force of Negation", "")); + cubeCards.add(new CardIdentity("Force of Will", "")); + cubeCards.add(new CardIdentity("Fractured Identity", "")); + cubeCards.add(new CardIdentity("Frantic Search", "")); + cubeCards.add(new CardIdentity("Fury", "")); + cubeCards.add(new CardIdentity("Fyndhorn Elves", "")); + cubeCards.add(new CardIdentity("Gaea's Cradle", "")); + cubeCards.add(new CardIdentity("Garruk Relentless", "")); + cubeCards.add(new CardIdentity("Garruk Wildspeaker", "")); + cubeCards.add(new CardIdentity("Geist of Saint Traft", "")); + cubeCards.add(new CardIdentity("Gideon Blackblade", "")); + cubeCards.add(new CardIdentity("Gideon Jura", "")); + cubeCards.add(new CardIdentity("Gideon, Ally of Zendikar", "")); + cubeCards.add(new CardIdentity("Gilded Drake", "")); + cubeCards.add(new CardIdentity("Gilded Lotus", "")); + cubeCards.add(new CardIdentity("Gitaxian Probe", "")); + cubeCards.add(new CardIdentity("Giver of Runes", "")); + cubeCards.add(new CardIdentity("Glen Elendra Archmage", "")); + cubeCards.add(new CardIdentity("Goblin Bombardment", "")); + cubeCards.add(new CardIdentity("Goblin Electromancer", "")); + cubeCards.add(new CardIdentity("Goblin Guide", "")); + cubeCards.add(new CardIdentity("Goblin Rabblemaster", "")); + cubeCards.add(new CardIdentity("Goblin Welder", "")); + cubeCards.add(new CardIdentity("Godless Shrine", "")); + cubeCards.add(new CardIdentity("Goldspan Dragon", "")); + cubeCards.add(new CardIdentity("Golgari Signet", "")); + cubeCards.add(new CardIdentity("Golos, Tireless Pilgrim", "")); + cubeCards.add(new CardIdentity("Gonti, Lord of Luxury", "")); + cubeCards.add(new CardIdentity("Grave Titan", "")); + cubeCards.add(new CardIdentity("Green Sun's Zenith", "")); + cubeCards.add(new CardIdentity("Grief", "")); + cubeCards.add(new CardIdentity("Grim Lavamancer", "")); + cubeCards.add(new CardIdentity("Grim Monolith", "")); + cubeCards.add(new CardIdentity("Griselbrand", "")); + cubeCards.add(new CardIdentity("Grist, the Hunger Tide", "")); + cubeCards.add(new CardIdentity("Gruul Signet", "")); + cubeCards.add(new CardIdentity("Gush", "")); + cubeCards.add(new CardIdentity("Halana and Alena, Partners", "")); + cubeCards.add(new CardIdentity("Hallowed Fountain", "")); + cubeCards.add(new CardIdentity("Hangarback Walker", "")); + cubeCards.add(new CardIdentity("Haunted Ridge", "")); + cubeCards.add(new CardIdentity("Hazoret the Fervent", "")); + cubeCards.add(new CardIdentity("Heartbeat of Spring", "")); + cubeCards.add(new CardIdentity("Hellrider", "")); + cubeCards.add(new CardIdentity("Hero of Bladehold", "")); + cubeCards.add(new CardIdentity("Hero's Downfall", "")); + cubeCards.add(new CardIdentity("Hexdrinker", "")); + cubeCards.add(new CardIdentity("High Tide", "")); + cubeCards.add(new CardIdentity("Horizon Canopy", "")); + cubeCards.add(new CardIdentity("Hornet Queen", "")); + cubeCards.add(new CardIdentity("Hullbreaker Horror", "")); + cubeCards.add(new CardIdentity("Huntmaster of the Fells", "")); + cubeCards.add(new CardIdentity("Hydroid Krasis", "")); + cubeCards.add(new CardIdentity("Hymn to Tourach", "")); + cubeCards.add(new CardIdentity("Ignoble Hierarch", "")); + cubeCards.add(new CardIdentity("Imperial Recruiter", "")); + cubeCards.add(new CardIdentity("Imperial Seal", "")); + cubeCards.add(new CardIdentity("Incinerate", "")); + cubeCards.add(new CardIdentity("Infernal Grasp", "")); + cubeCards.add(new CardIdentity("Inferno Titan", "")); + cubeCards.add(new CardIdentity("Inkwell Leviathan", "")); + cubeCards.add(new CardIdentity("Inquisition of Kozilek", "")); + cubeCards.add(new CardIdentity("Inspiring Vantage", "")); + cubeCards.add(new CardIdentity("Intrepid Adversary", "")); + cubeCards.add(new CardIdentity("Iona, Shield of Emeria", "")); + cubeCards.add(new CardIdentity("Izzet Signet", "")); + cubeCards.add(new CardIdentity("Jace, the Mind Sculptor", "")); + cubeCards.add(new CardIdentity("Jace, Vryn's Prodigy", "")); + cubeCards.add(new CardIdentity("Jin-Gitaxias, Progress Tyrant", "")); + cubeCards.add(new CardIdentity("Jokulhaups", "")); + cubeCards.add(new CardIdentity("Joraga Treespeaker", "")); + cubeCards.add(new CardIdentity("Karakas", "")); + cubeCards.add(new CardIdentity("Karmic Guide", "")); + cubeCards.add(new CardIdentity("Karn Liberated", "")); + cubeCards.add(new CardIdentity("Karn, Scion of Urza", "")); + cubeCards.add(new CardIdentity("Kiki-Jiki, Mirror Breaker", "")); + cubeCards.add(new CardIdentity("Kitchen Finks", "")); + cubeCards.add(new CardIdentity("Knight of Autumn", "")); + cubeCards.add(new CardIdentity("Knight of the Reliquary", "")); + cubeCards.add(new CardIdentity("Kogla, the Titan Ape", "")); + cubeCards.add(new CardIdentity("Kolaghan's Command", "")); + cubeCards.add(new CardIdentity("Koth of the Hammer", "")); + cubeCards.add(new CardIdentity("Kroxa, Titan of Death's Hunger", "")); + cubeCards.add(new CardIdentity("Kuldotha Forgemaster", "")); + cubeCards.add(new CardIdentity("Laelia, the Blade Reforged", "")); + cubeCards.add(new CardIdentity("Land Tax", "")); + cubeCards.add(new CardIdentity("Lavaclaw Reaches", "")); + cubeCards.add(new CardIdentity("Leonin Relic-Warder", "")); + cubeCards.add(new CardIdentity("Leovold, Emissary of Trest", "")); + cubeCards.add(new CardIdentity("Library of Alexandria", "")); + cubeCards.add(new CardIdentity("Life from the Loam", "")); + cubeCards.add(new CardIdentity("Light Up the Stage", "")); + cubeCards.add(new CardIdentity("Lightning Bolt", "")); + cubeCards.add(new CardIdentity("Lightning Helix", "")); + cubeCards.add(new CardIdentity("Liliana of the Veil", "")); + cubeCards.add(new CardIdentity("Liliana, the Last Hope", "")); + cubeCards.add(new CardIdentity("Lion Sash", "")); + cubeCards.add(new CardIdentity("Lion's Eye Diamond", "")); + cubeCards.add(new CardIdentity("Living Death", "")); + cubeCards.add(new CardIdentity("Llanowar Elves", "")); + cubeCards.add(new CardIdentity("Lodestone Golem", "")); + cubeCards.add(new CardIdentity("Lotus Bloom", "")); + cubeCards.add(new CardIdentity("Lotus Petal", "")); + cubeCards.add(new CardIdentity("Lurrus of the Dream-Den", "")); + cubeCards.add(new CardIdentity("Lyra Dawnbringer", "")); + cubeCards.add(new CardIdentity("Maelstrom Pulse", "")); + cubeCards.add(new CardIdentity("Magus of the Order", "")); + cubeCards.add(new CardIdentity("Makeshift Mannequin", "")); + cubeCards.add(new CardIdentity("Mana Crypt", "")); + cubeCards.add(new CardIdentity("Mana Drain", "")); + cubeCards.add(new CardIdentity("Mana Flare", "")); + cubeCards.add(new CardIdentity("Mana Leak", "")); + cubeCards.add(new CardIdentity("Mana Tithe", "")); + cubeCards.add(new CardIdentity("Mana Vault", "")); + cubeCards.add(new CardIdentity("Manamorphose", "")); + cubeCards.add(new CardIdentity("Marsh Flats", "")); + cubeCards.add(new CardIdentity("Massacre Wurm", "")); + cubeCards.add(new CardIdentity("Memory Deluge", "")); + cubeCards.add(new CardIdentity("Memory Jar", "")); + cubeCards.add(new CardIdentity("Mesmeric Fiend", "")); + cubeCards.add(new CardIdentity("Metalworker", "")); + cubeCards.add(new CardIdentity("Mind Twist", "")); + cubeCards.add(new CardIdentity("Mind's Desire", "")); + cubeCards.add(new CardIdentity("Mindslaver", "")); + cubeCards.add(new CardIdentity("Mirari's Wake", "")); + cubeCards.add(new CardIdentity("Miscalculation", "")); + cubeCards.add(new CardIdentity("Mishra's Factory", "")); + cubeCards.add(new CardIdentity("Mishra's Workshop", "")); + cubeCards.add(new CardIdentity("Misty Rainforest", "")); + cubeCards.add(new CardIdentity("Monastery Mentor", "")); + cubeCards.add(new CardIdentity("Monastery Swiftspear", "")); + cubeCards.add(new CardIdentity("Mother of Runes", "")); + cubeCards.add(new CardIdentity("Mox Diamond", "")); + cubeCards.add(new CardIdentity("Mox Emerald", "")); + cubeCards.add(new CardIdentity("Mox Jet", "")); + cubeCards.add(new CardIdentity("Mox Pearl", "")); + cubeCards.add(new CardIdentity("Mox Ruby", "")); + cubeCards.add(new CardIdentity("Mox Sapphire", "")); + cubeCards.add(new CardIdentity("Mulldrifter", "")); + cubeCards.add(new CardIdentity("Murderous Rider", "")); + cubeCards.add(new CardIdentity("Murktide Regent", "")); + cubeCards.add(new CardIdentity("Mutavault", "")); + cubeCards.add(new CardIdentity("Myr Battlesphere", "")); + cubeCards.add(new CardIdentity("Mystic Confluence", "")); + cubeCards.add(new CardIdentity("Mystical Tutor", "")); + cubeCards.add(new CardIdentity("Nahiri, the Harbinger", "")); + cubeCards.add(new CardIdentity("Narset, Parter of Veils", "")); + cubeCards.add(new CardIdentity("Nashi, Moon Sage's Scion", "")); + cubeCards.add(new CardIdentity("Natural Order", "")); + cubeCards.add(new CardIdentity("Necromancy", "")); + cubeCards.add(new CardIdentity("Night's Whisper", "")); + cubeCards.add(new CardIdentity("Nighthawk Scavenger", "")); + cubeCards.add(new CardIdentity("Nissa, Vastwood Seer", "")); + cubeCards.add(new CardIdentity("Nissa, Who Shakes the World", "")); + cubeCards.add(new CardIdentity("Niv-Mizzet Reborn", "")); + cubeCards.add(new CardIdentity("Noble Hierarch", "")); + cubeCards.add(new CardIdentity("Nurturing Peatland", "")); + cubeCards.add(new CardIdentity("Oath of Druids", "")); + cubeCards.add(new CardIdentity("Oblivion Stone", "")); + cubeCards.add(new CardIdentity("Oko, Thief of Crowns", "")); + cubeCards.add(new CardIdentity("Olivia, Crimson Bride", "")); + cubeCards.add(new CardIdentity("Omnath, Locus of Creation", "")); + cubeCards.add(new CardIdentity("Oona's Prowler", "")); + cubeCards.add(new CardIdentity("Ophiomancer", "")); + cubeCards.add(new CardIdentity("Opposition", "")); + cubeCards.add(new CardIdentity("Oracle of Mul Daya", "")); + cubeCards.add(new CardIdentity("Orzhov Signet", "")); + cubeCards.add(new CardIdentity("Oust", "")); + cubeCards.add(new CardIdentity("Overgrown Farmland", "")); + cubeCards.add(new CardIdentity("Overgrown Tomb", "")); + cubeCards.add(new CardIdentity("Pack Rat", "")); + cubeCards.add(new CardIdentity("Palace Jailer", "")); + cubeCards.add(new CardIdentity("Palinchron", "")); + cubeCards.add(new CardIdentity("Parallax Wave", "")); + cubeCards.add(new CardIdentity("Past in Flames", "")); + cubeCards.add(new CardIdentity("Path to Exile", "")); + cubeCards.add(new CardIdentity("Pest Infestation", "")); + cubeCards.add(new CardIdentity("Pestermite", "")); + cubeCards.add(new CardIdentity("Phantasmal Image", "")); + cubeCards.add(new CardIdentity("Phyrexian Metamorph", "")); + cubeCards.add(new CardIdentity("Phyrexian Revoker", "")); + cubeCards.add(new CardIdentity("Pia and Kiran Nalaar", "")); + cubeCards.add(new CardIdentity("Plateau", "")); + cubeCards.add(new CardIdentity("Plow Under", "")); + cubeCards.add(new CardIdentity("Polluted Delta", "")); + cubeCards.add(new CardIdentity("Polukranos, World Eater", "")); + cubeCards.add(new CardIdentity("Ponder", "")); + cubeCards.add(new CardIdentity("Porcelain Legionnaire", "")); + cubeCards.add(new CardIdentity("Portent", "")); + cubeCards.add(new CardIdentity("Preordain", "")); + cubeCards.add(new CardIdentity("Primeval Titan", "")); + cubeCards.add(new CardIdentity("Prismatic Vista", "")); + cubeCards.add(new CardIdentity("Progenitus", "")); + cubeCards.add(new CardIdentity("Putrid Imp", "")); + cubeCards.add(new CardIdentity("Pyretic Ritual", "")); + cubeCards.add(new CardIdentity("Questing Beast", "")); + cubeCards.add(new CardIdentity("Ragavan, Nimble Pilferer", "")); + cubeCards.add(new CardIdentity("Raging Ravine", "")); + cubeCards.add(new CardIdentity("Rakdos Signet", "")); + cubeCards.add(new CardIdentity("Ramunap Excavator", "")); + cubeCards.add(new CardIdentity("Ravages of War", "")); + cubeCards.add(new CardIdentity("Ravenous Chupacabra", "")); + cubeCards.add(new CardIdentity("Razorverge Thicket", "")); + cubeCards.add(new CardIdentity("Reanimate", "")); + cubeCards.add(new CardIdentity("Reclamation Sage", "")); + cubeCards.add(new CardIdentity("Recruiter of the Guard", "")); + cubeCards.add(new CardIdentity("Recurring Nightmare", "")); + cubeCards.add(new CardIdentity("Red Elemental Blast", "")); + cubeCards.add(new CardIdentity("Regrowth", "")); + cubeCards.add(new CardIdentity("Relic of Progenitus", "")); + cubeCards.add(new CardIdentity("Remand", "")); + cubeCards.add(new CardIdentity("Repeal", "")); + cubeCards.add(new CardIdentity("Restoration Angel", "")); + cubeCards.add(new CardIdentity("Retrofitter Foundry", "")); + cubeCards.add(new CardIdentity("Rishadan Port", "")); + cubeCards.add(new CardIdentity("Rockfall Vale", "")); + cubeCards.add(new CardIdentity("Rofellos, Llanowar Emissary", "")); + cubeCards.add(new CardIdentity("Rotting Regisaur", "")); + cubeCards.add(new CardIdentity("Runaway Steam-Kin", "")); + cubeCards.add(new CardIdentity("Sacred Foundry", "")); + cubeCards.add(new CardIdentity("Sakura-Tribe Elder", "")); + cubeCards.add(new CardIdentity("Satoru Umezawa", "")); + cubeCards.add(new CardIdentity("Savannah", "")); + cubeCards.add(new CardIdentity("Scalding Tarn", "")); + cubeCards.add(new CardIdentity("Scavenging Ooze", "")); + cubeCards.add(new CardIdentity("Scrapheap Scrounger", "")); + cubeCards.add(new CardIdentity("Scrubland", "")); + cubeCards.add(new CardIdentity("Sea Gate Stormcaller", "")); + cubeCards.add(new CardIdentity("Seachrome Coast", "")); + cubeCards.add(new CardIdentity("Seasoned Pyromancer", "")); + cubeCards.add(new CardIdentity("Sedgemoor Witch", "")); + cubeCards.add(new CardIdentity("Seething Song", "")); + cubeCards.add(new CardIdentity("Selesnya Signet", "")); + cubeCards.add(new CardIdentity("Selfless Spirit", "")); + cubeCards.add(new CardIdentity("Sensei's Divining Top", "")); + cubeCards.add(new CardIdentity("Shallow Grave", "")); + cubeCards.add(new CardIdentity("Shark Typhoon", "")); + cubeCards.add(new CardIdentity("Shattered Sanctum", "")); + cubeCards.add(new CardIdentity("Shelldock Isle", "")); + cubeCards.add(new CardIdentity("Shipwreck Marsh", "")); + cubeCards.add(new CardIdentity("Show and Tell", "")); + cubeCards.add(new CardIdentity("Showdown of the Skalds", "")); + cubeCards.add(new CardIdentity("Shriekmaw", "")); + cubeCards.add(new CardIdentity("Silent Clearing", "")); + cubeCards.add(new CardIdentity("Silverblade Paladin", "")); + cubeCards.add(new CardIdentity("Simic Signet", "")); + cubeCards.add(new CardIdentity("Skullclamp", "")); + cubeCards.add(new CardIdentity("Skyclave Apparition", "")); + cubeCards.add(new CardIdentity("Skyclave Shade", "")); + cubeCards.add(new CardIdentity("Smokestack", "")); + cubeCards.add(new CardIdentity("Smuggler's Copter", "")); + cubeCards.add(new CardIdentity("Snapcaster Mage", "")); + cubeCards.add(new CardIdentity("Sneak Attack", "")); + cubeCards.add(new CardIdentity("Snuff Out", "")); + cubeCards.add(new CardIdentity("Sol Ring", "")); + cubeCards.add(new CardIdentity("Solitude", "")); + cubeCards.add(new CardIdentity("Soulfire Grand Master", "")); + cubeCards.add(new CardIdentity("Sower of Temptation", "")); + cubeCards.add(new CardIdentity("Spear of Heliod", "")); + cubeCards.add(new CardIdentity("Spectral Procession", "")); + cubeCards.add(new CardIdentity("Spell Pierce", "")); + cubeCards.add(new CardIdentity("Spellseeker", "")); + cubeCards.add(new CardIdentity("Sphinx of the Steel Wind", "")); + cubeCards.add(new CardIdentity("Spirebluff Canal", "")); + cubeCards.add(new CardIdentity("Spirit-Sister's Call", "")); + cubeCards.add(new CardIdentity("Splinter Twin", "")); + cubeCards.add(new CardIdentity("Steam Vents", "")); + cubeCards.add(new CardIdentity("Stomping Ground", "")); + cubeCards.add(new CardIdentity("Stoneforge Mystic", "")); + cubeCards.add(new CardIdentity("Stormcarved Coast", "")); + cubeCards.add(new CardIdentity("Strip Mine", "")); + cubeCards.add(new CardIdentity("Student of Warfare", "")); + cubeCards.add(new CardIdentity("Sulfuric Vortex", "")); + cubeCards.add(new CardIdentity("Sun Titan", "")); + cubeCards.add(new CardIdentity("Sunbaked Canyon", "")); + cubeCards.add(new CardIdentity("Sundering Titan", "")); + cubeCards.add(new CardIdentity("Sundown Pass", "")); + cubeCards.add(new CardIdentity("Survival of the Fittest", "")); + cubeCards.add(new CardIdentity("Suspicious Stowaway", "")); + cubeCards.add(new CardIdentity("Sword of Body and Mind", "")); + cubeCards.add(new CardIdentity("Sword of Feast and Famine", "")); + cubeCards.add(new CardIdentity("Sword of Fire and Ice", "")); + cubeCards.add(new CardIdentity("Swords to Plowshares", "")); + cubeCards.add(new CardIdentity("Sylvan Caryatid", "")); + cubeCards.add(new CardIdentity("Sylvan Library", "")); + cubeCards.add(new CardIdentity("Taiga", "")); + cubeCards.add(new CardIdentity("Tamiyo, Compleated Sage", "")); + cubeCards.add(new CardIdentity("Tangle Wire", "")); + cubeCards.add(new CardIdentity("Teferi, Hero of Dominaria", "")); + cubeCards.add(new CardIdentity("Teferi, Time Raveler", "")); + cubeCards.add(new CardIdentity("Temple Garden", "")); + cubeCards.add(new CardIdentity("Tendrils of Agony", "")); + cubeCards.add(new CardIdentity("Terastodon", "")); + cubeCards.add(new CardIdentity("Tezzeret the Seeker", "")); + cubeCards.add(new CardIdentity("Thalia, Guardian of Thraben", "")); + cubeCards.add(new CardIdentity("Thassa's Oracle", "")); + cubeCards.add(new CardIdentity("The Gitrog Monster", "")); + cubeCards.add(new CardIdentity("The Restoration of Eiganjo", "")); + cubeCards.add(new CardIdentity("The Scarab God", "")); + cubeCards.add(new CardIdentity("The Wandering Emperor", "")); + cubeCards.add(new CardIdentity("Thespian's Stage", "")); + cubeCards.add(new CardIdentity("Thieving Skydiver", "")); + cubeCards.add(new CardIdentity("Thirst for Discovery", "")); + cubeCards.add(new CardIdentity("Thoughtseize", "")); + cubeCards.add(new CardIdentity("Thousand-Year Storm", "")); + cubeCards.add(new CardIdentity("Thraben Inspector", "")); + cubeCards.add(new CardIdentity("Thragtusk", "")); + cubeCards.add(new CardIdentity("Thran Dynamo", "")); + cubeCards.add(new CardIdentity("Through the Breach", "")); + cubeCards.add(new CardIdentity("Thundermaw Hellkite", "")); + cubeCards.add(new CardIdentity("Tidehollow Sculler", "")); + cubeCards.add(new CardIdentity("Time Spiral", "")); + cubeCards.add(new CardIdentity("Time Walk", "")); + cubeCards.add(new CardIdentity("Time Warp", "")); + cubeCards.add(new CardIdentity("Timetwister", "")); + cubeCards.add(new CardIdentity("Tinker", "")); + cubeCards.add(new CardIdentity("Tireless Tracker", "")); + cubeCards.add(new CardIdentity("Tolarian Academy", "")); + cubeCards.add(new CardIdentity("Toski, Bearer of Secrets", "")); + cubeCards.add(new CardIdentity("Tovolar's Huntmaster", "")); + cubeCards.add(new CardIdentity("Toxic Deluge", "")); + cubeCards.add(new CardIdentity("Treachery", "")); + cubeCards.add(new CardIdentity("Treasure Cruise", "")); + cubeCards.add(new CardIdentity("Trinket Mage", "")); + cubeCards.add(new CardIdentity("Tropical Island", "")); + cubeCards.add(new CardIdentity("Tundra", "")); + cubeCards.add(new CardIdentity("Turnabout", "")); + cubeCards.add(new CardIdentity("Ugin, the Spirit Dragon", "")); + cubeCards.add(new CardIdentity("Ulamog, the Ceaseless Hunger", "")); + cubeCards.add(new CardIdentity("Ulamog, the Infinite Gyre", "")); + cubeCards.add(new CardIdentity("Umezawa's Jitte", "")); + cubeCards.add(new CardIdentity("Unburial Rites", "")); + cubeCards.add(new CardIdentity("Underground Sea", "")); + cubeCards.add(new CardIdentity("Underworld Breach", "")); + cubeCards.add(new CardIdentity("Unholy Heat", "")); + cubeCards.add(new CardIdentity("Upheaval", "")); + cubeCards.add(new CardIdentity("Uro, Titan of Nature's Wrath", "")); + cubeCards.add(new CardIdentity("Urza's Saga", "")); + cubeCards.add(new CardIdentity("Urza, Lord High Artificer", "")); + cubeCards.add(new CardIdentity("Usher of the Fallen", "")); + cubeCards.add(new CardIdentity("Utopia Sprawl", "")); + cubeCards.add(new CardIdentity("Vampire Hexmage", "")); + cubeCards.add(new CardIdentity("Vampiric Tutor", "")); + cubeCards.add(new CardIdentity("Vendilion Clique", "")); + cubeCards.add(new CardIdentity("Venser, Shaper Savant", "")); + cubeCards.add(new CardIdentity("Verdant Catacombs", "")); + cubeCards.add(new CardIdentity("Vindicate", "")); + cubeCards.add(new CardIdentity("Volcanic Island", "")); + cubeCards.add(new CardIdentity("Volrath's Stronghold", "")); + cubeCards.add(new CardIdentity("Voltaic Visionary", "")); + cubeCards.add(new CardIdentity("Vraska, Golgari Queen", "")); + cubeCards.add(new CardIdentity("Vryn Wingmare", "")); + cubeCards.add(new CardIdentity("Walking Ballista", "")); + cubeCards.add(new CardIdentity("Wall of Omens", "")); + cubeCards.add(new CardIdentity("Wall of Roots", "")); + cubeCards.add(new CardIdentity("Wasteland", "")); + cubeCards.add(new CardIdentity("Waterlogged Grove", "")); + cubeCards.add(new CardIdentity("Watery Grave", "")); + cubeCards.add(new CardIdentity("Wear // Tear", "")); + cubeCards.add(new CardIdentity("Wheel of Fortune", "")); + cubeCards.add(new CardIdentity("Wheel of Misfortune", "")); + cubeCards.add(new CardIdentity("Whisperwood Elemental", "")); + cubeCards.add(new CardIdentity("Windswept Heath", "")); + cubeCards.add(new CardIdentity("Winter Orb", "")); + cubeCards.add(new CardIdentity("Wishclaw Talisman", "")); + cubeCards.add(new CardIdentity("Woe Strider", "")); + cubeCards.add(new CardIdentity("Wooded Foothills", "")); + cubeCards.add(new CardIdentity("Woodfall Primus", "")); + cubeCards.add(new CardIdentity("Worldly Tutor", "")); + cubeCards.add(new CardIdentity("Worn Powerstone", "")); + cubeCards.add(new CardIdentity("Wrath of God", "")); + cubeCards.add(new CardIdentity("Wrenn and Six", "")); + cubeCards.add(new CardIdentity("Wurmcoil Engine", "")); + cubeCards.add(new CardIdentity("Yawgmoth's Bargain", "")); + cubeCards.add(new CardIdentity("Yawgmoth's Will", "")); + cubeCards.add(new CardIdentity("Yorion, Sky Nomad", "")); + cubeCards.add(new CardIdentity("Young Pyromancer", "")); + cubeCards.add(new CardIdentity("Zealous Conscripts", "")); + } +} + diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml index 98e89221bc2..13840ba7b4f 100644 --- a/Mage.Server/config/config.xml +++ b/Mage.Server/config/config.xml @@ -123,6 +123,7 @@ + @@ -153,6 +154,7 @@ + diff --git a/Mage.Server/release/config/config.xml b/Mage.Server/release/config/config.xml index b2b663f6b41..8b7709a0c7f 100644 --- a/Mage.Server/release/config/config.xml +++ b/Mage.Server/release/config/config.xml @@ -115,6 +115,7 @@ + @@ -145,6 +146,7 @@ + diff --git a/Mage.Sets/src/mage/cards/a/ALittleChat.java b/Mage.Sets/src/mage/cards/a/ALittleChat.java new file mode 100644 index 00000000000..ff344510382 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ALittleChat.java @@ -0,0 +1,35 @@ +package mage.cards.a; + +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.keyword.CasualtyAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ALittleChat extends CardImpl { + + public ALittleChat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); + + // Casualty 1 + this.addAbility(new CasualtyAbility(this, 1)); + + // Look at the top two cards of your library. Put one of them into your hand and the other on the bottom of your library. + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(2, 1, PutCards.HAND, PutCards.BOTTOM_ANY)); + } + + private ALittleChat(final ALittleChat card) { + super(card); + } + + @Override + public ALittleChat copy() { + return new ALittleChat(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AbandonReason.java b/Mage.Sets/src/mage/cards/a/AbandonReason.java index a34140c11b6..10e297ca4ec 100644 --- a/Mage.Sets/src/mage/cards/a/AbandonReason.java +++ b/Mage.Sets/src/mage/cards/a/AbandonReason.java @@ -12,6 +12,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.Outcome; import mage.target.common.TargetCreaturePermanent; /** @@ -25,6 +26,7 @@ public final class AbandonReason extends CardImpl { // Up to two target creatures each get +1/+0 and gain first strike until end of turn. Effect effect = new BoostTargetEffect(1, 0, Duration.EndOfTurn); + effect.setOutcome(Outcome.Benefit); effect.setText("Up to two target creatures each get +1/+0"); this.getSpellAbility().addEffect(effect); effect = new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn, "and gain first strike until end of turn"); @@ -32,7 +34,7 @@ public final class AbandonReason extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); // Madness {1}{R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{1}{R}"))); } private AbandonReason(final AbandonReason card) { diff --git a/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java b/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java index fc4253b964a..1c1bb693c25 100644 --- a/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java +++ b/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java @@ -3,6 +3,7 @@ package mage.cards.a; import java.util.HashMap; import java.util.Map; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; @@ -25,13 +26,17 @@ import mage.watchers.Watcher; */ public final class AbandonedSarcophagus extends CardImpl { + private static final FilterCard filter = new FilterCard("nonland cards with cycling"); + + static { + filter.add(Predicates.not(CardType.LAND.getPredicate())); + filter.add(new AbilityPredicate(CyclingAbility.class)); + } + public AbandonedSarcophagus(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // You may cast nonland cards with cycling from your graveyard. - FilterCard filter = new FilterCard("nonland cards with cycling"); - filter.add(Predicates.not(CardType.LAND.getPredicate())); - filter.add(new AbilityPredicate(CyclingAbility.class)); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayFromNotOwnHandZoneAllEffect(filter, Zone.GRAVEYARD, true, TargetController.YOU, Duration.WhileOnBattlefield) @@ -77,16 +82,20 @@ class AbandonedSarcophagusReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null) { - return controller.moveCards(permanent, Zone.EXILED, source, game); - } - Card card = game.getCard(event.getTargetId()); - if (card != null) { - return controller.moveCards(card, Zone.EXILED, source, game); - } + if (controller == null) { + return false; } + + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent != null) { + return controller.moveCards(permanent, Zone.EXILED, source, game); + } + + Card card = game.getCard(event.getTargetId()); + if (card != null) { + return controller.moveCards(card, Zone.EXILED, source, game); + } + return false; } @@ -97,32 +106,46 @@ class AbandonedSarcophagusReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - boolean cardWasCycledThisTurn = false; - boolean cardHasCycling = false; if (!(((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD)) { return false; } + Player controller = game.getPlayer(source.getControllerId()); - AbandonedSarcophagusWatcher watcher = game.getState().getWatcher(AbandonedSarcophagusWatcher.class); - Card card = game.getCard(event.getTargetId()); - if (card == null - || controller == null - || watcher == null - || !card.isOwnedBy(controller.getId())) { + if (controller == null) { return false; } + + Card card = game.getCard(event.getTargetId()); + if (card == null) { + return false; + } + if (!card.isOwnedBy(controller.getId())) { + return false; + } + + AbandonedSarcophagusWatcher watcher = game.getState().getWatcher(AbandonedSarcophagusWatcher.class); + if (watcher == null) { + return false; + } + + boolean cardHasCycling = false; for (Ability ability : card.getAbilities(game)) { if (ability instanceof CyclingAbility) { cardHasCycling = true; + break; } } + Cards cards = watcher.getCardsCycledThisTurn(controller.getId()); - for (Card c : cards.getCards(game)) { - if (c == card) { + boolean cardWasCycledThisTurn = false; + + for (Card cardCycledThisTurn : cards.getCards(game)) { + if (cardCycledThisTurn == card) { cardWasCycledThisTurn = true; watcher.getCardsCycledThisTurn(controller.getId()).remove(card); //remove reference to the card as it is no longer needed } } + return !cardWasCycledThisTurn && cardHasCycling; } } @@ -137,17 +160,26 @@ class AbandonedSarcophagusWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.CYCLE_CARD) { - Card card = game.getCard(event.getSourceId()); - Player controller = game.getPlayer(event.getPlayerId()); - if (card != null - && controller != null - && card.isOwnedBy(controller.getId())) { - Cards c = getCardsCycledThisTurn(event.getPlayerId()); - c.add(card); - cycledCardsThisTurn.put(event.getPlayerId(), c); - } + if (event.getType() != GameEvent.EventType.CYCLE_CARD) { + return; } + + Card card = game.getCard(event.getSourceId()); + if (card == null) { + return; + } + + Player controller = game.getPlayer(event.getPlayerId()); + if (controller == null) { + return; + } + if (!card.isOwnedBy(controller.getId())) { + return; + } + + Cards c = getCardsCycledThisTurn(event.getPlayerId()); + c.add(card); + cycledCardsThisTurn.put(event.getPlayerId(), c); } public Cards getCardsCycledThisTurn(UUID playerId) { diff --git a/Mage.Sets/src/mage/cards/a/Abeyance.java b/Mage.Sets/src/mage/cards/a/Abeyance.java index 5281148c49f..3f6e49e7cc2 100644 --- a/Mage.Sets/src/mage/cards/a/Abeyance.java +++ b/Mage.Sets/src/mage/cards/a/Abeyance.java @@ -68,7 +68,7 @@ class AbeyanceEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast instant or sorcery spells or activate abilities " + "that aren't mana abilities this turn (" + mageObject.getIdName() + ")."; diff --git a/Mage.Sets/src/mage/cards/a/AbhorrentOverlord.java b/Mage.Sets/src/mage/cards/a/AbhorrentOverlord.java index 57f88bca5f1..eb03cb26a99 100644 --- a/Mage.Sets/src/mage/cards/a/AbhorrentOverlord.java +++ b/Mage.Sets/src/mage/cards/a/AbhorrentOverlord.java @@ -14,7 +14,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.StaticFilters; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.HarpyToken; import java.util.UUID; @@ -34,7 +34,7 @@ public final class AbhorrentOverlord extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Abhorrent Overlord enters the battlefield, create a number of 1/1 black Harpy creature tokens with flying equal to your devotion to black. - Effect effect = new CreateTokenEffect(new AbhorrentOverlordHarpyToken(), DevotionCount.B); + Effect effect = new CreateTokenEffect(new HarpyToken(), DevotionCount.B); effect.setText("create a number of 1/1 black Harpy creature tokens with flying equal to your devotion to black. (Each {B} in the mana costs of permanents you control counts toward your devotion to black.)"); this.addAbility(new EntersBattlefieldTriggeredAbility(effect).addHint(DevotionCount.B.getHint())); @@ -51,25 +51,3 @@ public final class AbhorrentOverlord extends CardImpl { return new AbhorrentOverlord(this); } } - -class AbhorrentOverlordHarpyToken extends TokenImpl { - - AbhorrentOverlordHarpyToken() { - super("Harpy", "1/1 black Harpy creature tokens with flying"); - cardType.add(CardType.CREATURE); - color.setBlack(true); - subtype.add(SubType.HARPY); - power = new MageInt(1); - toughness = new MageInt(1); - - this.addAbility(FlyingAbility.getInstance()); - } - - private AbhorrentOverlordHarpyToken(final AbhorrentOverlordHarpyToken token) { - super(token); - } - - public AbhorrentOverlordHarpyToken copy() { - return new AbhorrentOverlordHarpyToken(this); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AbominationOfGudul.java b/Mage.Sets/src/mage/cards/a/AbominationOfGudul.java index 516ee4e8729..acab700c50f 100644 --- a/Mage.Sets/src/mage/cards/a/AbominationOfGudul.java +++ b/Mage.Sets/src/mage/cards/a/AbominationOfGudul.java @@ -35,7 +35,7 @@ public final class AbominationOfGudul extends CardImpl { this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(effect, true)); // Morph 2BGU - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{B}{G}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{B}{G}{U}"))); } private AbominationOfGudul(final AbominationOfGudul card) { diff --git a/Mage.Sets/src/mage/cards/a/Abrade.java b/Mage.Sets/src/mage/cards/a/Abrade.java index 697bfc9d969..6bec2a4cc02 100644 --- a/Mage.Sets/src/mage/cards/a/Abrade.java +++ b/Mage.Sets/src/mage/cards/a/Abrade.java @@ -25,8 +25,7 @@ public final class Abrade extends CardImpl { getSpellAbility().addTarget(new TargetCreaturePermanent()); // Destroy target artifact. - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetArtifactPermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/AbuJafar.java b/Mage.Sets/src/mage/cards/a/AbuJafar.java index 15d9931ddfa..0747eb9c3e8 100644 --- a/Mage.Sets/src/mage/cards/a/AbuJafar.java +++ b/Mage.Sets/src/mage/cards/a/AbuJafar.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.effects.common.DestroyAllEffect; @@ -9,28 +7,31 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.BlockedByIdPredicate; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; + +import java.util.UUID; /** - * * @author MarcoMarin */ public final class AbuJafar extends CardImpl { + private static final FilterPermanent filter + = new FilterCreaturePermanent("creatures blocking or blocked by it"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.EITHER); + } + public AbuJafar(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.power = new MageInt(0); this.toughness = new MageInt(1); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures blocking or blocked by it"); - filter.add(Predicates.or(new BlockedByIdPredicate(this.getId()), - new BlockingAttackerIdPredicate(this.getId()))); - - // When Abu Ja'far dies, destroy all creatures blocking or blocked by it. They can't be regenerated. + // When Abu Ja'far dies, destroy all creatures blocking or blocked by it. They can't be regenerated. this.addAbility(new DiesSourceTriggeredAbility(new DestroyAllEffect(filter, true), false)); } diff --git a/Mage.Sets/src/mage/cards/a/AbunasChant.java b/Mage.Sets/src/mage/cards/a/AbunasChant.java index 60014da754f..22e990edba4 100644 --- a/Mage.Sets/src/mage/cards/a/AbunasChant.java +++ b/Mage.Sets/src/mage/cards/a/AbunasChant.java @@ -28,8 +28,7 @@ public final class AbunasChant extends CardImpl { //You gain 5 life; this.getSpellAbility().addEffect(new GainLifeEffect(5)); //or prevent the next 5 damage that would be dealt to target creature this turn. - Mode mode = new Mode(); - mode.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, 5)); + Mode mode = new Mode(new PreventDamageToTargetEffect(Duration.EndOfTurn, 5)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().getModes().addMode(mode); // Entwine {2} diff --git a/Mage.Sets/src/mage/cards/a/Abundance.java b/Mage.Sets/src/mage/cards/a/Abundance.java index 2e4522f30d4..a7a1f9fed52 100644 --- a/Mage.Sets/src/mage/cards/a/Abundance.java +++ b/Mage.Sets/src/mage/cards/a/Abundance.java @@ -64,7 +64,7 @@ class AbundanceReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(event.getPlayerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { FilterCard filter = new FilterCard(); if (controller.chooseUse(Outcome.Detriment, "Choose card type:", @@ -79,7 +79,7 @@ class AbundanceReplacementEffect extends ReplacementEffectImpl { Card selectedCard = null; for (Card card : controller.getLibrary().getCards(game)) { toReveal.add(card); - if (filter.match(card, source.getSourceId(), source.getControllerId(), game)) { + if (filter.match(card, source.getControllerId(), source, game)) { selectedCard = card; break; } diff --git a/Mage.Sets/src/mage/cards/a/AbzanCharm.java b/Mage.Sets/src/mage/cards/a/AbzanCharm.java index 577ebe8ea8a..fbd888d447c 100644 --- a/Mage.Sets/src/mage/cards/a/AbzanCharm.java +++ b/Mage.Sets/src/mage/cards/a/AbzanCharm.java @@ -38,14 +38,12 @@ public final class AbzanCharm extends CardImpl { this.getSpellAbility().addEffect(new ExileTargetEffect()); // *You draw two cards and you lose 2 life - Mode mode = new Mode(); - mode.addEffect(new DrawCardSourceControllerEffect(2)); + Mode mode = new Mode(new DrawCardSourceControllerEffect(2)); mode.addEffect(new LoseLifeSourceControllerEffect(2)); this.getSpellAbility().addMode(mode); // *Distribute two +1/+1 counters among one or two target creatures. - mode = new Mode(); - mode.addEffect(new DistributeCountersEffect(CounterType.P1P1, 2, false, "one or two target creatures")); + mode = new Mode(new DistributeCountersEffect(CounterType.P1P1, 2, false, "one or two target creatures")); mode.addTarget(new TargetCreaturePermanentAmount(2)); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/a/AbzanGuide.java b/Mage.Sets/src/mage/cards/a/AbzanGuide.java index 16b0df19ffb..4f64e3f24fc 100644 --- a/Mage.Sets/src/mage/cards/a/AbzanGuide.java +++ b/Mage.Sets/src/mage/cards/a/AbzanGuide.java @@ -28,7 +28,7 @@ public final class AbzanGuide extends CardImpl { // Lifelink this.addAbility(LifelinkAbility.getInstance()); // Morph {2}{W}{B}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{W}{B}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{W}{B}{G}"))); } private AbzanGuide(final AbzanGuide card) { diff --git a/Mage.Sets/src/mage/cards/a/AcademicProbation.java b/Mage.Sets/src/mage/cards/a/AcademicProbation.java index 229bc44c342..5c99e662b25 100644 --- a/Mage.Sets/src/mage/cards/a/AcademicProbation.java +++ b/Mage.Sets/src/mage/cards/a/AcademicProbation.java @@ -37,8 +37,7 @@ public final class AcademicProbation extends CardImpl { this.getSpellAbility().addEffect(new OpponentsCantCastChosenUntilNextTurnEffect().setText("opponents can't cast spells with the chosen name until your next turn")); // • Choose target nonland permanent. Until your next turn, it can't attack or block, and its activated abilities can't be activated. - Mode restrictMode = new Mode(); - restrictMode.addEffect(new AcademicProbationRestrictionEffect()); + Mode restrictMode = new Mode(new AcademicProbationRestrictionEffect()); restrictMode.addTarget(new TargetNonlandPermanent()); this.getSpellAbility().addMode(restrictMode); } diff --git a/Mage.Sets/src/mage/cards/a/AcademyResearchers.java b/Mage.Sets/src/mage/cards/a/AcademyResearchers.java index b6646bf014e..0aaa9bbba05 100644 --- a/Mage.Sets/src/mage/cards/a/AcademyResearchers.java +++ b/Mage.Sets/src/mage/cards/a/AcademyResearchers.java @@ -73,7 +73,7 @@ class AcademyResearchersEffect extends OneShotEffect { if (controller != null && academyResearchers != null) { filterCardInHand.add(new AuraCardCanAttachToPermanentId(academyResearchers.getId())); TargetCardInHand target = new TargetCardInHand(0, 1, filterCardInHand); - if (controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCardInPlay, target, source, game)) { Card auraInHand = game.getCard(target.getFirstTarget()); if (auraInHand != null) { game.getState().setValue("attachTo:" + auraInHand.getId(), academyResearchers); diff --git a/Mage.Sets/src/mage/cards/a/AcademyRuins.java b/Mage.Sets/src/mage/cards/a/AcademyRuins.java index 4a5bf489d83..71f1b35cff6 100644 --- a/Mage.Sets/src/mage/cards/a/AcademyRuins.java +++ b/Mage.Sets/src/mage/cards/a/AcademyRuins.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; @@ -13,17 +11,18 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SuperType; import mage.constants.Zone; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Plopman */ public final class AcademyRuins extends CardImpl { public AcademyRuins(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); addSuperType(SuperType.LEGENDARY); // {T}: Add {C}. @@ -31,7 +30,7 @@ public final class AcademyRuins extends CardImpl { // {1}{U}, {T}: Put target artifact card from your graveyard on top of your library. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutOnLibraryTargetEffect(true), new ManaCostsImpl("{1}{U}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AccessDenied.java b/Mage.Sets/src/mage/cards/a/AccessDenied.java new file mode 100644 index 00000000000..0776f2cd386 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AccessDenied.java @@ -0,0 +1,65 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.token.ThopterColorlessToken; +import mage.game.stack.StackObject; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AccessDenied extends CardImpl { + + public AccessDenied(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}{U}"); + + // Counter target spell. Create X 1/1 colorless Thopter artifact creature tokens with flying, where X is that spell's mana value. + this.getSpellAbility().addEffect(new AccessDeniedEffect()); + this.getSpellAbility().addTarget(new TargetSpell()); + } + + private AccessDenied(final AccessDenied card) { + super(card); + } + + @Override + public AccessDenied copy() { + return new AccessDenied(this); + } +} + +class AccessDeniedEffect extends OneShotEffect { + + AccessDeniedEffect() { + super(Outcome.Benefit); + staticText = "counter target spell. Create X 1/1 colorless Thopter " + + "artifact creature tokens with flying, where X is that spell's mana value"; + } + + private AccessDeniedEffect(final AccessDeniedEffect effect) { + super(effect); + } + + @Override + public AccessDeniedEffect copy() { + return new AccessDeniedEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + StackObject stackObject = game.getStack().getStackObject(targetPointer.getFirst(game, source)); + if (stackObject != null) { + game.getStack().counter(source.getFirstTarget(), source, game); + return new ThopterColorlessToken().putOntoBattlefield(stackObject.getManaValue(), game, source); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AcclaimedContender.java b/Mage.Sets/src/mage/cards/a/AcclaimedContender.java index 9ffedd21655..51003c288d8 100644 --- a/Mage.Sets/src/mage/cards/a/AcclaimedContender.java +++ b/Mage.Sets/src/mage/cards/a/AcclaimedContender.java @@ -5,14 +5,13 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; @@ -56,9 +55,8 @@ public final class AcclaimedContender extends CardImpl { // When Acclaimed Contender enters the battlefield, if you control another Knight, look at the top five cards of your library. You may reveal a Knight, Aura, Equipment, or legendary artifact card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. this.addAbility(new ConditionalInterveningIfTriggeredAbility( new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), filter2, Zone.LIBRARY, false, - true, false, Zone.HAND, true, false, false - ).setBackInRandomOrder(true)), condition, "When {this} enters the battlefield, " + + 5, 1, filter2, PutCards.HAND, PutCards.BOTTOM_RANDOM + )), condition, "When {this} enters the battlefield, " + "if you control another Knight, look at the top five cards of your library. " + "You may reveal a Knight, Aura, Equipment, or legendary artifact card from among them " + "and put it into your hand. Put the rest on the bottom of your library in a random order." diff --git a/Mage.Sets/src/mage/cards/a/AccursedWitch.java b/Mage.Sets/src/mage/cards/a/AccursedWitch.java index bf88d81b5e9..a6ad8937615 100644 --- a/Mage.Sets/src/mage/cards/a/AccursedWitch.java +++ b/Mage.Sets/src/mage/cards/a/AccursedWitch.java @@ -84,8 +84,7 @@ class AccursedWitchReturnTransformedEffect extends OneShotEffect { } game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); - UUID secondFaceId = card.getSecondCardFace().getId(); - game.getState().setValue("attachTo:" + secondFaceId, attachTo.getId()); + game.getState().setValue("attachTo:" + source.getSourceId(), attachTo.getId()); if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { attachTo.addAttachment(card.getId(), source, game); } diff --git a/Mage.Sets/src/mage/cards/a/AcererakTheArchlich.java b/Mage.Sets/src/mage/cards/a/AcererakTheArchlich.java index 6ea9dee4c1e..19f34cfbf69 100644 --- a/Mage.Sets/src/mage/cards/a/AcererakTheArchlich.java +++ b/Mage.Sets/src/mage/cards/a/AcererakTheArchlich.java @@ -103,7 +103,7 @@ class AcererakTheArchlichEffect extends OneShotEffect { } TargetPermanent target = new TargetControlledCreaturePermanent(0, 1); target.setNotTarget(true); - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + player.choose(Outcome.Sacrifice, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null && permanent.sacrifice(source, game)) { tokens--; diff --git a/Mage.Sets/src/mage/cards/a/AchHansRun.java b/Mage.Sets/src/mage/cards/a/AchHansRun.java index 619615a29a3..e8b9c2e6ec0 100644 --- a/Mage.Sets/src/mage/cards/a/AchHansRun.java +++ b/Mage.Sets/src/mage/cards/a/AchHansRun.java @@ -78,7 +78,7 @@ class AchHansRunEffect extends OneShotEffect { if (!controller.searchLibrary(target, source, game)) { return false; } - Card card = controller.getLibrary().remove(target.getFirstTarget(), game); + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card == null || !controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { return false; } diff --git a/Mage.Sets/src/mage/cards/a/AcidSpewerDragon.java b/Mage.Sets/src/mage/cards/a/AcidSpewerDragon.java index 81047f0d9ed..e7c3488df2b 100644 --- a/Mage.Sets/src/mage/cards/a/AcidSpewerDragon.java +++ b/Mage.Sets/src/mage/cards/a/AcidSpewerDragon.java @@ -43,7 +43,7 @@ public final class AcidSpewerDragon extends CardImpl { this.addAbility(DeathtouchAbility.getInstance()); // Megamorph {5}{B}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{5}{B}{B}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{5}{B}{B}"), true)); // When Acid-Spewer Dragon is turned face up, put a +1/+1 counter on each other Dragon creature you control. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter), false, false)); diff --git a/Mage.Sets/src/mage/cards/a/AcidicSliver.java b/Mage.Sets/src/mage/cards/a/AcidicSliver.java index 12826a9efd1..b808edb913f 100644 --- a/Mage.Sets/src/mage/cards/a/AcidicSliver.java +++ b/Mage.Sets/src/mage/cards/a/AcidicSliver.java @@ -38,7 +38,7 @@ public final class AcidicSliver extends CardImpl { ability.addTarget(new TargetAnyTarget()); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(ability, - Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, + Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS, "All Slivers have \"{2}, Sacrifice this permanent: This permanent deals 2 damage to any target.\""))); } diff --git a/Mage.Sets/src/mage/cards/a/AcidicSoil.java b/Mage.Sets/src/mage/cards/a/AcidicSoil.java index ea0ac39142d..be950588e28 100644 --- a/Mage.Sets/src/mage/cards/a/AcidicSoil.java +++ b/Mage.Sets/src/mage/cards/a/AcidicSoil.java @@ -50,7 +50,7 @@ class AcidicSoilEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - List permanents = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), source, game); for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { diff --git a/Mage.Sets/src/mage/cards/a/AcolyteOfAffliction.java b/Mage.Sets/src/mage/cards/a/AcolyteOfAffliction.java index 58791c6deb2..b206f0338b7 100644 --- a/Mage.Sets/src/mage/cards/a/AcolyteOfAffliction.java +++ b/Mage.Sets/src/mage/cards/a/AcolyteOfAffliction.java @@ -73,7 +73,7 @@ class AcolyteOfAfflictionEffect extends OneShotEffect { } player.moveCards(player.getLibrary().getTopCards(game, 2), Zone.GRAVEYARD, source, game); TargetCard target = new TargetCardInYourGraveyard(0, 1, filter, true); - if (!player.choose(Outcome.ReturnToHand, target, source.getSourceId(), game)) { + if (!player.choose(Outcome.ReturnToHand, target, source, game)) { return true; } Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/a/AcquisitionOctopus.java b/Mage.Sets/src/mage/cards/a/AcquisitionOctopus.java index e49d61f6490..1d55d604dd8 100644 --- a/Mage.Sets/src/mage/cards/a/AcquisitionOctopus.java +++ b/Mage.Sets/src/mage/cards/a/AcquisitionOctopus.java @@ -80,6 +80,6 @@ class AcquisitionOctopusTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "When {this} or equipped creature deals combat damage to a player, draw a card."; + return "Whenever {this} or equipped creature deals combat damage to a player, draw a card."; } } diff --git a/Mage.Sets/src/mage/cards/a/AcrobaticManeuver.java b/Mage.Sets/src/mage/cards/a/AcrobaticManeuver.java index 15313ce5fd1..c505455aa14 100644 --- a/Mage.Sets/src/mage/cards/a/AcrobaticManeuver.java +++ b/Mage.Sets/src/mage/cards/a/AcrobaticManeuver.java @@ -22,10 +22,10 @@ public final class AcrobaticManeuver extends CardImpl { // Exile target creature you control, then return that card to the battlefield under its owner's control. this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); this.getSpellAbility().addEffect(new ExileTargetForSourceEffect()); - this.getSpellAbility().addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false)); + this.getSpellAbility().addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false).concatBy(",")); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private AcrobaticManeuver(final AcrobaticManeuver card) { diff --git a/Mage.Sets/src/mage/cards/a/ActOfAuthority.java b/Mage.Sets/src/mage/cards/a/ActOfAuthority.java index 0001376bc54..d288540ba90 100644 --- a/Mage.Sets/src/mage/cards/a/ActOfAuthority.java +++ b/Mage.Sets/src/mage/cards/a/ActOfAuthority.java @@ -54,7 +54,7 @@ class ActOfAuthorityEffect extends OneShotEffect { this.staticText = "you may exile target artifact or enchantment. If you do, its controller gains control of {this}"; } - public ActOfAuthorityEffect(final ActOfAuthorityEffect effect) { + private ActOfAuthorityEffect(final ActOfAuthorityEffect effect) { super(effect); } @@ -66,29 +66,32 @@ class ActOfAuthorityEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (targetPermanent != null && new ExileTargetEffect().apply(game, source)) { - Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); - if (sourcePermanent != null) { - ContinuousEffect effect = new ActOfAuthorityGainControlEffect(Duration.Custom, targetPermanent.getControllerId()); - effect.setTargetPointer(new FixedTarget(sourcePermanent, game)); - game.addEffect(effect, source); - } - return true; - } - return false; + if (targetPermanent == null) { return false; } + + ExileTargetEffect exileTargetEffect = new ExileTargetEffect(); + if (!exileTargetEffect.apply(game, source)) { return false; } + + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + if (sourcePermanent == null) { return true; } + + ContinuousEffect effect = new ActOfAuthorityGainControlEffect(Duration.Custom, targetPermanent.getControllerId()); + effect.setTargetPointer(new FixedTarget(sourcePermanent, game)); + game.addEffect(effect, source); + return true; } } +// TODO: These and it's duplicates can probably be replaced by a gain control of effect class ActOfAuthorityGainControlEffect extends ContinuousEffectImpl { - UUID controller; + private final UUID controller; public ActOfAuthorityGainControlEffect(Duration duration, UUID controller) { super(duration, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); this.controller = controller; } - public ActOfAuthorityGainControlEffect(final ActOfAuthorityGainControlEffect effect) { + private ActOfAuthorityGainControlEffect(final ActOfAuthorityGainControlEffect effect) { super(effect); this.controller = effect.controller; } @@ -100,14 +103,16 @@ class ActOfAuthorityGainControlEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (targetPointer != null) { + Permanent permanent; + if (targetPointer == null) { + permanent = game.getPermanent(source.getFirstTarget()); + } else { permanent = game.getPermanent(targetPointer.getFirst(game, source)); } - if (permanent != null) { - return permanent.changeControllerId(controller, game, source); - } - return false; + + if (permanent == null) { return false; } + + return permanent.changeControllerId(controller, game, source); } @Override diff --git a/Mage.Sets/src/mage/cards/a/ActiveVolcano.java b/Mage.Sets/src/mage/cards/a/ActiveVolcano.java index fe765fcf52a..2bfe9897f98 100644 --- a/Mage.Sets/src/mage/cards/a/ActiveVolcano.java +++ b/Mage.Sets/src/mage/cards/a/ActiveVolcano.java @@ -36,8 +36,7 @@ public final class ActiveVolcano extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent(filterBlue)); // or return target Island to its owner's hand. - Mode mode = new Mode(); - mode.addEffect(new ReturnToHandTargetEffect()); + Mode mode = new Mode(new ReturnToHandTargetEffect()); mode.addTarget(new TargetPermanent(filterIsland)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java b/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java index beded6f827f..b7efc2fde8a 100644 --- a/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java +++ b/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java @@ -84,18 +84,17 @@ class AdarkarValkyrieEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent != null) { - DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(new MageObjectReference(permanent, game)); - game.addDelayedTriggeredAbility(delayedAbility, source); - return true; - } - return false; + if (permanent == null) { return false; } + + DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(new MageObjectReference(permanent, game)); + game.addDelayedTriggeredAbility(delayedAbility, source); + return true; } } class AdarkarValkyrieDelayedTriggeredAbility extends DelayedTriggeredAbility { - protected MageObjectReference mor; + private final MageObjectReference mor; public AdarkarValkyrieDelayedTriggeredAbility(MageObjectReference mor) { super(new ReturnToBattlefieldUnderYourControlTargetEffect(), Duration.EndOfTurn); @@ -119,14 +118,17 @@ class AdarkarValkyrieDelayedTriggeredAbility extends DelayedTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (((ZoneChangeEvent) event).isDiesEvent() - && mor.refersTo(((ZoneChangeEvent) event).getTarget(), game) - && game.getState().getZone(event.getTargetId()) == Zone.GRAVEYARD) { // must be in the graveyard - getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); - return true; + if (!((ZoneChangeEvent) event).isDiesEvent()) { return false; } - } - return false; + if (!mor.refersTo(((ZoneChangeEvent) event).getTarget(), game)) { return false; } + + // TODO: Must it? Why? + // Must be in the graveyard + if (game.getState().getZone(event.getTargetId()) != Zone.GRAVEYARD) { return false; } + + getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); + + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java b/Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java index f2f120e6945..0cc9aac12e7 100644 --- a/Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java +++ b/Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java @@ -91,7 +91,7 @@ class DamagedByPiratesWatcher extends Watcher { } public boolean damagedByEnoughPirates(UUID sourceId) { - return damageSourceIds.keySet().contains(sourceId) && damageSourceIds.get(sourceId).size() > 2; + return damageSourceIds.containsKey(sourceId) && damageSourceIds.get(sourceId).size() > 2; } @Override diff --git a/Mage.Sets/src/mage/cards/a/AdunOakenshield.java b/Mage.Sets/src/mage/cards/a/AdunOakenshield.java index a50becf6298..e3ebbb16dec 100644 --- a/Mage.Sets/src/mage/cards/a/AdunOakenshield.java +++ b/Mage.Sets/src/mage/cards/a/AdunOakenshield.java @@ -1,24 +1,22 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author shieldal */ public final class AdunOakenshield extends CardImpl { @@ -33,7 +31,7 @@ public final 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 ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), 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/AdventureAwaits.java b/Mage.Sets/src/mage/cards/a/AdventureAwaits.java index ec7fc5b76c9..52d331b8222 100644 --- a/Mage.Sets/src/mage/cards/a/AdventureAwaits.java +++ b/Mage.Sets/src/mage/cards/a/AdventureAwaits.java @@ -1,16 +1,14 @@ package mage.cards.a; import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.Mode; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.*; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInLibrary; import java.util.UUID; @@ -22,7 +20,8 @@ public final class AdventureAwaits extends CardImpl { public AdventureAwaits(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); - // Look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. If you don't put a card into your hand this way, draw a card. + // Look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. If you don't put a card into your hand this way, draw a card. this.getSpellAbility().addEffect(new AdventureAwaitsEffect()); } @@ -36,14 +35,10 @@ public final class AdventureAwaits extends CardImpl { } } -class AdventureAwaitsEffect extends OneShotEffect { +class AdventureAwaitsEffect extends LookLibraryAndPickControllerEffect { AdventureAwaitsEffect() { - super(Outcome.Benefit); - staticText = "Look at the top five cards of your library. " + - "You may reveal a creature card from among them and put it into your hand. " + - "Put the rest on the bottom of your library in a random order. " + - "If you didn't put a card into your hand this way, draw a card."; + super(5, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_RANDOM); } private AdventureAwaitsEffect(final AdventureAwaitsEffect effect) { @@ -56,25 +51,16 @@ class AdventureAwaitsEffect extends OneShotEffect { } @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 5)); - TargetCard target = new TargetCardInLibrary(0, 1, StaticFilters.FILTER_CARD_CREATURE); - player.choose(outcome, cards, target, game); - Card card = game.getCard(target.getFirstTarget()); - if (card != null && player.chooseUse(outcome, "Put " + card.getName() + " into your hand?", - "Otherwise draw a card", "Put into hand", "Draw a card", source, game - )) { - player.moveCards(card, Zone.HAND, source, game); - cards.remove(card); - player.putCardsOnBottomOfLibrary(cards, game, source, false); - } else { - player.putCardsOnBottomOfLibrary(cards, game, source, false); + public boolean actionWithPickedCards(Game game, Ability source, Player player, Cards pickedCards, Cards otherCards) { + super.actionWithPickedCards(game, source, player, pickedCards, otherCards); + if (pickedCards.isEmpty()) { player.drawCards(1, source, game); } return true; } + + @Override + public String getText(Mode mode) { + return super.getText(mode).concat(". If you didn't put a card into your hand this way, draw a card"); + } } diff --git a/Mage.Sets/src/mage/cards/a/AdventurousImpulse.java b/Mage.Sets/src/mage/cards/a/AdventurousImpulse.java index afcafa4f6f3..4b447bd211e 100644 --- a/Mage.Sets/src/mage/cards/a/AdventurousImpulse.java +++ b/Mage.Sets/src/mage/cards/a/AdventurousImpulse.java @@ -1,14 +1,12 @@ - package mage.cards.a; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; /** * @@ -16,18 +14,14 @@ import mage.filter.predicate.Predicates; */ public final class AdventurousImpulse extends CardImpl { - private static final FilterCard filter = new FilterCard("a creature or land card"); - - static { - filter.add(Predicates.or(CardType.CREATURE.getPredicate(), CardType.LAND.getPredicate())); - } - public AdventurousImpulse(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{G}"); - //Look at the top three cards of your library. You may reveal a creature or land card from among them and put it into your hand. Put the rest on the bottom of your library in any order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(3), false, StaticValue.get(1), filter, false)); - + // Look at the top three cards of your library. + // You may reveal a creature or land card from among them and put it into your hand. + // Put the rest on the bottom of your library in any order. + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + 3, 1, StaticFilters.FILTER_CARD_CREATURE_OR_LAND, PutCards.HAND, PutCards.BOTTOM_ANY)); } private AdventurousImpulse(final AdventurousImpulse card) { diff --git a/Mage.Sets/src/mage/cards/a/AdviceFromTheFae.java b/Mage.Sets/src/mage/cards/a/AdviceFromTheFae.java index d998ff65bd6..a4cd6e707c4 100644 --- a/Mage.Sets/src/mage/cards/a/AdviceFromTheFae.java +++ b/Mage.Sets/src/mage/cards/a/AdviceFromTheFae.java @@ -1,37 +1,36 @@ - package mage.cards.a; -import java.util.Objects; -import java.util.Set; import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.StaticFilters; import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; /** * - * @author jeffwadsworth + * @author awjackson */ public final class AdviceFromTheFae extends CardImpl { public AdviceFromTheFae(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2/U}{2/U}{2/U}"); - // ({2U} can be paid with any two mana or with {U}. This card's converted mana cost is 6.) - // Look at the top five cards of your library. If you control more creatures than each other player, put two of those cards into your hand. Otherwise, put one of them into your hand. Then put the rest on the bottom of your library in any order. - this.getSpellAbility().addEffect(new AdviceFromTheFaeEffect()); - + // Look at the top five cards of your library. If you control more creatures than each other player, + // put two of those cards into your hand. Otherwise, put one of them into your hand. + // Then put the rest on the bottom of your library in any order. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new LookLibraryAndPickControllerEffect(5, 2, PutCards.HAND, PutCards.BOTTOM_ANY), + new LookLibraryAndPickControllerEffect(5, 1, PutCards.HAND, PutCards.BOTTOM_ANY), + AdviceFromTheFaeCondition.instance, "Look at the top five cards of your library. " + + "If you control more creatures than each other player, put two of those cards into your hand. " + + "Otherwise, put one of them into your hand. Then put the rest on the bottom of your library in any order." + )); } private AdviceFromTheFae(final AdviceFromTheFae card) { @@ -44,52 +43,23 @@ public final class AdviceFromTheFae extends CardImpl { } } -class AdviceFromTheFaeEffect extends OneShotEffect { - - public AdviceFromTheFaeEffect() { - super(Outcome.DrawCard); - this.staticText = "Look at the top five cards of your library. If you control more creatures than each other player, put two of those cards into your hand. Otherwise, put one of them into your hand. Then put the rest on the bottom of your library in any order"; - } - - public AdviceFromTheFaeEffect(final AdviceFromTheFaeEffect effect) { - super(effect); - } - - @Override - public AdviceFromTheFaeEffect copy() { - return new AdviceFromTheFaeEffect(this); - } +enum AdviceFromTheFaeCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); - if (controller != null && mageObject != null) { - Set topCards = controller.getLibrary().getTopCards(game, 5); - Cards cardsFromLibrary = new CardsImpl(); - for (Card card : topCards) { - cardsFromLibrary.add(card); + int max = 0; + UUID controllerId = source.getControllerId(); + for (UUID playerId : game.getState().getPlayersInRange(controllerId, game)) { + if (!playerId.equals(controllerId)) { + max = Math.max(max, game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game)); } - controller.lookAtCards(mageObject.getIdName(), cardsFromLibrary, game); - int max = 0; - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(new ControllerIdPredicate(playerId)); - if (!Objects.equals(playerId, controller.getId())) { - if (max < game.getBattlefield().countAll(filter, playerId, game)) { - max = game.getBattlefield().countAll(filter, playerId, game); - } - } - } - boolean moreCreatures = game.getBattlefield().countAll(new FilterControlledCreaturePermanent(), controller.getId(), game) > max; - TargetCard target = new TargetCard(moreCreatures ? 2 : 1, Zone.LIBRARY, new FilterCard()); - if (controller.choose(Outcome.DrawCard, cardsFromLibrary, target, game)) { - cardsFromLibrary.removeAll(target.getTargets()); - controller.moveCards(new CardsImpl(target.getTargets()), Zone.HAND, source, game); - } - controller.putCardsOnBottomOfLibrary(cardsFromLibrary, game, source, true); - return true; } - return false; + return game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, controllerId, game) > max; + } + + @Override + public String toString() { + return "you control more creatures than each other player"; } } diff --git a/Mage.Sets/src/mage/cards/a/AerialModification.java b/Mage.Sets/src/mage/cards/a/AerialModification.java index f31af209783..83aacbb8bf2 100644 --- a/Mage.Sets/src/mage/cards/a/AerialModification.java +++ b/Mage.Sets/src/mage/cards/a/AerialModification.java @@ -24,7 +24,7 @@ import mage.target.TargetPermanent; */ public final class AerialModification extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("creature or vehicle"); + private static final FilterPermanent filter = new FilterPermanent("creature or Vehicle"); static { filter.add(Predicates.or(CardType.CREATURE.getPredicate(), diff --git a/Mage.Sets/src/mage/cards/a/AerialSurveyor.java b/Mage.Sets/src/mage/cards/a/AerialSurveyor.java new file mode 100644 index 00000000000..b96d633b7e6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AerialSurveyor.java @@ -0,0 +1,115 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.common.LandsYouControlHint; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterBasicLandCard; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.permanent.DefendingPlayerControlsPredicate; +import mage.game.Controllable; +import mage.game.Game; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class AerialSurveyor extends CardImpl { + + private static final FilterCard filter = new FilterBasicLandCard(SubType.PLAINS); + + public AerialSurveyor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{W}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Aerial Surveyor attacks, if defending player controls more lands than you, search your library for a basic Plains card, put it onto the battlefield tapped, then shuffle. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new AttacksTriggeredAbility( + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true) + ), AerialSurveyorCondition.instance, "Whenever {this} attacks, if defending player " + + "controls more lands than you, search your library for a basic Plains card, " + + "put it onto the battlefield tapped, then shuffle." + ).addHint(LandsYouControlHint.instance).addHint(AerialSurveyorHint.instance)); + + // Crew 2 + this.addAbility(new CrewAbility(2)); + } + + private AerialSurveyor(final AerialSurveyor card) { + super(card); + } + + @Override + public AerialSurveyor copy() { + return new AerialSurveyor(this); + } +} + +enum AerialSurveyorCondition implements Condition { + instance; + private static final FilterPermanent filter = new FilterLandPermanent(); + + static { + filter.add(DefendingPlayerControlsPredicate.instance); + } + + @Override + public boolean apply(Game game, Ability source) { + return game.getBattlefield().count( + filter, source.getControllerId(), source, game + ) > game.getBattlefield().count( + StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, + source.getControllerId(), source, game + ); + } +} + +enum AerialSurveyorHint implements Hint { + instance; + + @Override + public String getText(Game game, Ability ability) { + return game.getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_LAND, + ability.getControllerId(), + ability, game + ).stream() + .map(Controllable::getControllerId) + .filter(game.getOpponents(ability.getControllerId())::contains) + .collect(Collectors.toMap(Function.identity(), u -> 1, Integer::sum)) + .entrySet() + .stream() + .filter(entry -> game.getPlayer(entry.getKey()) != null) + .map(entry -> "Lands " + game.getPlayer(entry.getKey()).getName() + " controls: " + entry.getValue()) + .collect(Collectors.joining("
")); + } + + @Override + public AerialSurveyorHint copy() { + return instance; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AerieBowmasters.java b/Mage.Sets/src/mage/cards/a/AerieBowmasters.java index f6bbbf1e108..e84f91122d2 100644 --- a/Mage.Sets/src/mage/cards/a/AerieBowmasters.java +++ b/Mage.Sets/src/mage/cards/a/AerieBowmasters.java @@ -28,7 +28,7 @@ public final class AerieBowmasters extends CardImpl { this.addAbility(ReachAbility.getInstance()); // Megamorph {5}{G} (You may cast this card face down as a 2/2 creature for {3}. Turn it face up at any time for its megamorph cost and put a +1/+1 counter on it.)) - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{5}{G}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{5}{G}"), true)); } diff --git a/Mage.Sets/src/mage/cards/a/AetherChaser.java b/Mage.Sets/src/mage/cards/a/AetherChaser.java index b6fa2065f94..7e13cf0556a 100644 --- a/Mage.Sets/src/mage/cards/a/AetherChaser.java +++ b/Mage.Sets/src/mage/cards/a/AetherChaser.java @@ -36,8 +36,7 @@ public final class AetherChaser extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(2))); // Whenever Aether Chaser attacks, you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token. - this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2)), false, - "Whenever {this} attacks you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token.")); + this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2)))); } private AetherChaser(final AetherChaser card) { diff --git a/Mage.Sets/src/mage/cards/a/AetherFigment.java b/Mage.Sets/src/mage/cards/a/AetherFigment.java index 90847b3dc68..3a3258f5709 100644 --- a/Mage.Sets/src/mage/cards/a/AetherFigment.java +++ b/Mage.Sets/src/mage/cards/a/AetherFigment.java @@ -37,7 +37,7 @@ public final class AetherFigment extends CardImpl { Ability ability = new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), KickedCondition.instance, - "If {this} was kicked, it enters the battlefield with two +1/+1 counters on it", + "If {this} was kicked, it enters the battlefield with two +1/+1 counters on it.", ""); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AetherGust.java b/Mage.Sets/src/mage/cards/a/AetherGust.java index dbff727bf7a..438586ef456 100644 --- a/Mage.Sets/src/mage/cards/a/AetherGust.java +++ b/Mage.Sets/src/mage/cards/a/AetherGust.java @@ -1,19 +1,15 @@ package mage.cards.a; +import mage.MageObject; import mage.ObjectColor; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.filter.common.FilterSpellOrPermanent; import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; -import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetSpellOrPermanent; import java.util.UUID; @@ -25,7 +21,7 @@ public final class AetherGust extends CardImpl { private static final FilterSpellOrPermanent filter = new FilterSpellOrPermanent("spell or permanent that's red or green"); - private static final Predicate predicate = Predicates.or( + private static final Predicate predicate = Predicates.or( new ColorPredicate(ObjectColor.RED), new ColorPredicate(ObjectColor.GREEN) ); @@ -39,8 +35,11 @@ public final class AetherGust extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Choose target spell or permanent that's red or green. Its owner puts it on the top or bottom of their library. - this.getSpellAbility().addEffect(new AetherGustEffect()); - this.getSpellAbility().addTarget(new TargetSpellOrPermanent(1, 1, filter, false)); + this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect( + "choose target spell or permanent that's red or green. " + + "Its owner puts it on the top or bottom of their library" + )); + this.getSpellAbility().addTarget(new TargetSpellOrPermanent(filter)); } private AetherGust(final AetherGust card) { @@ -52,34 +51,3 @@ public final class AetherGust extends CardImpl { return new AetherGust(this); } } - -class AetherGustEffect extends OneShotEffect { - - AetherGustEffect() { - super(Outcome.Removal); - staticText = "Choose target spell or permanent that's red or green. " + - "Its owner puts it on the top or bottom of their library."; - } - - private AetherGustEffect(final AetherGustEffect effect) { - super(effect); - } - - @Override - public AetherGustEffect copy() { - return new AetherGustEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget())); - if (player == null) { - return false; - } - if (player.chooseUse(Outcome.Detriment, "Put the targeted object on the top or bottom of your library?", - "", "Top", "Bottom", source, game)) { - return new PutOnLibraryTargetEffect(true).apply(game, source); - } - return new PutOnLibraryTargetEffect(false).apply(game, source); - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/AetherHerder.java b/Mage.Sets/src/mage/cards/a/AetherHerder.java index dfb7b51e861..63653549124 100644 --- a/Mage.Sets/src/mage/cards/a/AetherHerder.java +++ b/Mage.Sets/src/mage/cards/a/AetherHerder.java @@ -34,8 +34,7 @@ public final class AetherHerder extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(2))); // Whenever Aether Herder attacks, you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token. - this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2)), false, - "Whenever {this} attacks you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token.")); + this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2)))); } private AetherHerder(final AetherHerder card) { diff --git a/Mage.Sets/src/mage/cards/a/AetherInspector.java b/Mage.Sets/src/mage/cards/a/AetherInspector.java index 6ba31ee9731..6ea57c07011 100644 --- a/Mage.Sets/src/mage/cards/a/AetherInspector.java +++ b/Mage.Sets/src/mage/cards/a/AetherInspector.java @@ -36,8 +36,7 @@ public final class AetherInspector extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(2))); // Whenever Aether Inspector attacks, you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token. - this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2)), false, - "Whenever {this} attacks you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token.")); + this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2)))); } private AetherInspector(final AetherInspector card) { diff --git a/Mage.Sets/src/mage/cards/a/AetherMembrane.java b/Mage.Sets/src/mage/cards/a/AetherMembrane.java index ed335085ff1..0e856ced535 100644 --- a/Mage.Sets/src/mage/cards/a/AetherMembrane.java +++ b/Mage.Sets/src/mage/cards/a/AetherMembrane.java @@ -3,9 +3,8 @@ package mage.cards.a; import java.util.UUID; import mage.MageInt; -import mage.abilities.common.BlocksSourceTriggeredAbility; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.DefenderAbility; @@ -34,9 +33,11 @@ public final class AetherMembrane extends CardImpl { this.addAbility(ReachAbility.getInstance()); // Whenever Aether Membrane blocks a creature, return that creature to its owner's hand at end of combat. - Effect effect = new ReturnToHandTargetEffect(); - effect.setText("return that creature to its owner's hand at end of combat"); - this.addAbility(new BlocksSourceTriggeredAbility(new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(effect)), false, true)); + this.addAbility(new BlocksCreatureTriggeredAbility( + new CreateDelayedTriggeredAbilityEffect( + new AtTheEndOfCombatDelayedTriggeredAbility(new ReturnToHandTargetEffect()) + ).setText("return that creature to its owner's hand at end of combat") + )); } private AetherMembrane(final AetherMembrane card) { diff --git a/Mage.Sets/src/mage/cards/a/AetherShockwave.java b/Mage.Sets/src/mage/cards/a/AetherShockwave.java index 6ef5a01f7e9..d8e233994cd 100644 --- a/Mage.Sets/src/mage/cards/a/AetherShockwave.java +++ b/Mage.Sets/src/mage/cards/a/AetherShockwave.java @@ -31,8 +31,7 @@ public final class AetherShockwave extends CardImpl { // Choose one - Tap all Spirits; or tap all non-Spirit creatures. this.getSpellAbility().addEffect(new TapAllEffect(filterSpirit)); - Mode mode = new Mode(); - mode.addEffect(new TapAllEffect(filterNonSpirit)); + Mode mode = new Mode(new TapAllEffect(filterNonSpirit)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/AetherSwooper.java b/Mage.Sets/src/mage/cards/a/AetherSwooper.java index ad7cf1aab47..5aa40c707dd 100644 --- a/Mage.Sets/src/mage/cards/a/AetherSwooper.java +++ b/Mage.Sets/src/mage/cards/a/AetherSwooper.java @@ -37,8 +37,7 @@ public final class AetherSwooper extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(2))); // Whenever Aether Swooper attacks, you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token. - this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2)), false, - "Whenever {this} attacks you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token.")); + this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2)))); } private AetherSwooper(final AetherSwooper card) { diff --git a/Mage.Sets/src/mage/cards/a/AetherVial.java b/Mage.Sets/src/mage/cards/a/AetherVial.java index b5a9f24d614..10866abda9a 100644 --- a/Mage.Sets/src/mage/cards/a/AetherVial.java +++ b/Mage.Sets/src/mage/cards/a/AetherVial.java @@ -90,7 +90,7 @@ class AetherVialEffect extends OneShotEffect { } TargetCardInHand target = new TargetCardInHand(filter); - if (controller.choose(this.outcome, target, source.getSourceId(), game)) { + if (controller.choose(this.outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { return controller.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/a/AetherWeb.java b/Mage.Sets/src/mage/cards/a/AetherWeb.java index ab7aef23932..e635c846f5f 100644 --- a/Mage.Sets/src/mage/cards/a/AetherWeb.java +++ b/Mage.Sets/src/mage/cards/a/AetherWeb.java @@ -1,34 +1,32 @@ package mage.cards.a; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + import java.util.UUID; -import mage.abilities.StaticAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.common.continuous.BoostEnchantedEffect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.keyword.ReachAbility; -import mage.constants.*; -import mage.abilities.keyword.FlashAbility; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.common.TargetCreaturePermanent; -import mage.abilities.Ability; -import mage.abilities.effects.common.AttachEffect; -import mage.target.TargetPermanent; -import mage.abilities.keyword.EnchantAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; - /** - * * @author noahg */ public final class AetherWeb extends CardImpl { public AetherWeb(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); - + this.subtype.add(SubType.AURA); // Flash @@ -38,15 +36,15 @@ public final class AetherWeb extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Enchanted creature gets +1/+1, has reach, and can block creatures with shadow as though they didn't have shadow. - StaticAbility staticAbility = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 1) - .setText("Enchanted creature gets +1/+1, has reach, and can block creatures with shadow as though they didn't have shadow.")); - staticAbility.addEffect(new GainAbilityAttachedEffect(ReachAbility.getInstance(), AttachmentType.AURA).setText("")); - staticAbility.addEffect(new AetherWebEffect()); - this.addAbility(staticAbility); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(1, 1)); + ability.addEffect(new GainAbilityAttachedEffect( + ReachAbility.getInstance(), AttachmentType.AURA + ).setText(", has reach")); + ability.addEffect(new AetherWebEffect()); + this.addAbility(ability); } private AetherWeb(final AetherWeb card) { @@ -63,7 +61,7 @@ class AetherWebEffect extends AsThoughEffectImpl { public AetherWebEffect() { super(AsThoughEffectType.BLOCK_SHADOW, Duration.WhileOnBattlefield, Outcome.Benefit); - staticText = ""; + staticText = ", and can block creatures with shadow as though they didn't have shadow"; } public AetherWebEffect(final AetherWebEffect effect) { @@ -85,4 +83,4 @@ class AetherWebEffect extends AsThoughEffectImpl { Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); return sourcePermanent != null && sourceId.equals(sourcePermanent.getAttachedTo()); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/a/AetherbornMarauder.java b/Mage.Sets/src/mage/cards/a/AetherbornMarauder.java index b2925e58532..6f252704e5e 100644 --- a/Mage.Sets/src/mage/cards/a/AetherbornMarauder.java +++ b/Mage.Sets/src/mage/cards/a/AetherbornMarauder.java @@ -78,12 +78,12 @@ class AetherbornMarauderEffect extends OneShotEffect { filter.add(AnotherPredicate.instance); filter.add(CounterType.P1P1.getPredicate()); boolean firstRun = true; - while (game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0) { + while (game.getBattlefield().count(filter, source.getControllerId(), source, game) > 0) { if (controller.chooseUse(outcome, "Move " + (firstRun ? "any" : "more") + " +1/+1 counters from other permanents you control to " + sourceObject.getLogName() + '?', source, game)) { firstRun = false; TargetControlledPermanent target = new TargetControlledPermanent(filter); target.setNotTarget(true); - if (target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), game)) { + if (target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), source, game)) { Permanent fromPermanent = game.getPermanent(target.getFirstTarget()); if (fromPermanent != null) { int numberOfCounters = fromPermanent.getCounters(game).getCount(CounterType.P1P1); diff --git a/Mage.Sets/src/mage/cards/a/AetherflameWall.java b/Mage.Sets/src/mage/cards/a/AetherflameWall.java index d9ab65b70cd..8ae22cb4824 100644 --- a/Mage.Sets/src/mage/cards/a/AetherflameWall.java +++ b/Mage.Sets/src/mage/cards/a/AetherflameWall.java @@ -12,19 +12,17 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import java.util.UUID; /** - * * @author noahg */ public final class AetherflameWall extends CardImpl { public AetherflameWall(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); - + this.subtype.add(SubType.WALL); this.power = new MageInt(0); this.toughness = new MageInt(4); @@ -33,10 +31,13 @@ public final class AetherflameWall extends CardImpl { this.addAbility(DefenderAbility.getInstance()); // Aetherflame Wall can block creatures with shadow as though they didn’t have shadow. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CanBlockAsThoughtItHadShadowEffect(Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(new CanBlockAsThoughtItHadShadowEffect(Duration.WhileOnBattlefield) + .setText("{this} can block creatures with shadow as though they didn't have shadow"))); // {R}: Aetherflame Wall gets +1/+0 until end of turn. - this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl("{R}"))); + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl<>("{R}") + )); } private AetherflameWall(final AetherflameWall card) { diff --git a/Mage.Sets/src/mage/cards/a/AetherfluxReservoir.java b/Mage.Sets/src/mage/cards/a/AetherfluxReservoir.java index 4dc5ac6b8fd..99f02213fd2 100644 --- a/Mage.Sets/src/mage/cards/a/AetherfluxReservoir.java +++ b/Mage.Sets/src/mage/cards/a/AetherfluxReservoir.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; @@ -10,31 +8,30 @@ import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.hint.ValueHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.game.Game; import mage.target.common.TargetAnyTarget; import mage.watchers.common.CastSpellLastTurnWatcher; +import java.util.UUID; + /** - * * @author emerald000 */ public final class AetherfluxReservoir extends CardImpl { public AetherfluxReservoir(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // Whenever you cast a spell, you gain 1 life for each spell you've cast this turn. - Ability abilityGainLife = new SpellCastControllerTriggeredAbility(new GainLifeEffect(new AetherfluxReservoirDynamicValue()), false); - abilityGainLife.addHint(new ValueHint("You've cast spells this turn", new AetherfluxReservoirDynamicValue())); - this.addAbility(abilityGainLife); + this.addAbility(new SpellCastControllerTriggeredAbility(new GainLifeEffect( + AetherfluxReservoirDynamicValue.instance, "you gain 1 life for each spell you've cast this turn" + ), false)); // Pay 50 life: Aetherflux Reservoir deals 50 damage to any target. - Ability abilityPayLife = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(50), new PayLifeCost(50)); + Ability abilityPayLife = new SimpleActivatedAbility(new DamageTargetEffect(50), new PayLifeCost(50)); abilityPayLife.addTarget(new TargetAnyTarget()); this.addAbility(abilityPayLife); } @@ -49,20 +46,20 @@ public final class AetherfluxReservoir extends CardImpl { } } -class AetherfluxReservoirDynamicValue implements DynamicValue { +enum AetherfluxReservoirDynamicValue implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); - if(watcher != null) { - return watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(sourceAbility.getControllerId()); - } - return 0; + return game + .getState() + .getWatcher(CastSpellLastTurnWatcher.class) + .getAmountOfSpellsPlayerCastOnCurrentTurn(sourceAbility.getControllerId()); } @Override public AetherfluxReservoirDynamicValue copy() { - return new AetherfluxReservoirDynamicValue(); + return this; } @Override @@ -74,5 +71,4 @@ class AetherfluxReservoirDynamicValue implements DynamicValue { public String getMessage() { return "spell you've cast this turn"; } - } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/Aetherling.java b/Mage.Sets/src/mage/cards/a/Aetherling.java index 6e7020a9580..ff6d6b5f8a0 100644 --- a/Mage.Sets/src/mage/cards/a/Aetherling.java +++ b/Mage.Sets/src/mage/cards/a/Aetherling.java @@ -29,7 +29,7 @@ public final class Aetherling extends CardImpl { this.toughness = new MageInt(5); // {U}: Exile Aetherling. Return it to the battlefield under its owner's control at the beginning of the next end step. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true), new ManaCostsImpl("{U}"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(), new ManaCostsImpl("{U}"))); // {U}: Aetherling can't be blocked this turn this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CantBeBlockedSourceEffect(Duration.EndOfTurn), new ManaCostsImpl("{U}"))); // {1}: Aetherling gets +1/-1 until end of turn. diff --git a/Mage.Sets/src/mage/cards/a/AethermagesTouch.java b/Mage.Sets/src/mage/cards/a/AethermagesTouch.java index 027b033d4c0..ad47780bb23 100644 --- a/Mage.Sets/src/mage/cards/a/AethermagesTouch.java +++ b/Mage.Sets/src/mage/cards/a/AethermagesTouch.java @@ -60,7 +60,7 @@ class AethermagesTouchEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 4)); if (!cards.isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/a/Aetherplasm.java b/Mage.Sets/src/mage/cards/a/Aetherplasm.java index 9636bde5c7f..3e9f4592edd 100644 --- a/Mage.Sets/src/mage/cards/a/Aetherplasm.java +++ b/Mage.Sets/src/mage/cards/a/Aetherplasm.java @@ -3,7 +3,7 @@ package mage.cards.a; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.BlocksSourceTriggeredAbility; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.costs.common.ReturnToHandFromBattlefieldSourceCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DoIfCostPaid; @@ -34,8 +34,11 @@ public final class Aetherplasm extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - // Whenever Aetherplasm blocks a creature, you may return Aetherplasm to its owner's hand. If you do, you may put a creature card from your hand onto the battlefield blocking that creature. - this.addAbility(new BlocksSourceTriggeredAbility(new DoIfCostPaid(new AetherplasmEffect(), new ReturnToHandFromBattlefieldSourceCost()), false, true)); + // Whenever Aetherplasm blocks a creature, you may return Aetherplasm to its owner's hand. + // If you do, you may put a creature card from your hand onto the battlefield blocking that creature. + this.addAbility(new BlocksCreatureTriggeredAbility(new DoIfCostPaid( + new AetherplasmEffect(), new ReturnToHandFromBattlefieldSourceCost() + ))); } private Aetherplasm(final Aetherplasm card) { @@ -67,7 +70,7 @@ class AetherplasmEffect extends OneShotEffect { } if (player.chooseUse(Outcome.PutCardInPlay, "Put a creature card from your hand onto the battlefield?", source, game)) { TargetCardInHand target = new TargetCardInHand(StaticFilters.FILTER_CARD_CREATURE_A); - if (player.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { + if (player.choose(Outcome.PutCardInPlay, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { Permanent blockedCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); diff --git a/Mage.Sets/src/mage/cards/a/Aetherspouts.java b/Mage.Sets/src/mage/cards/a/Aetherspouts.java index 6d8a9d09412..1cb48164069 100644 --- a/Mage.Sets/src/mage/cards/a/Aetherspouts.java +++ b/Mage.Sets/src/mage/cards/a/Aetherspouts.java @@ -44,11 +44,13 @@ public final class Aetherspouts extends CardImpl { /* 7/18/2014 The owner of each attacking creature chooses whether to put it on the top or bottom - of their library. The active player (the player whose turn it is) makes all of - their choices first, followed by each other player in turn order. + of their library. + The active player (the player whose turn it is) makes all of their choices first, + followed by each other player in turn order. + 7/18/2014 If an effect puts two or more cards on the top or bottom of a library at the same time, - the owner of those cards may arrange them in any order. That library's owner doesn't reveal - the order in which the cards go into their library. + the owner of those cards may arrange them in any order. + That library's owner doesn't reveal the order in which the cards go into their library. */ class AetherspoutsEffect extends OneShotEffect { @@ -57,7 +59,7 @@ class AetherspoutsEffect extends OneShotEffect { this.staticText = "For each attacking creature, its owner puts it on the top or bottom of their library"; } - public AetherspoutsEffect(final AetherspoutsEffect effect) { + private AetherspoutsEffect(final AetherspoutsEffect effect) { super(effect); } @@ -70,107 +72,107 @@ class AetherspoutsEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { game.getPlayerList(); Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - PlayerList playerList = game.getPlayerList().copy(); - playerList.setCurrent(game.getActivePlayerId()); - Player player = game.getPlayer(game.getActivePlayerId()); - Player activePlayer = player; - do { - List permanentsToTop = new ArrayList<>(); - List permanentsToBottom = new ArrayList<>(); - for (Permanent permanent : game.getState().getBattlefield().getActivePermanents(new FilterAttackingCreature(), player.getId(), source.getSourceId(), game)) { - if (permanent.isOwnedBy(player.getId())) { - if (player.chooseUse(outcome, "Put " + permanent.getLogName() + " to the top? (else it goes to bottom)", source, game)) { - permanentsToTop.add(permanent); - game.informPlayers(permanent.getLogName() + " goes to the top of " + player.getLogName() + "'s library"); - } else { - permanentsToBottom.add(permanent); - game.informPlayers(permanent.getLogName() + " goes to the bottom of " + player.getLogName() + "'s library"); - } - } - } - // cards to top - Cards cards = new CardsImpl(); - List toLibrary = new ArrayList<>(); - for (Permanent permanent : permanentsToTop) { - if (permanent instanceof PermanentToken) { - toLibrary.add(permanent); - } else { - Card card = game.getCard(permanent.getId()); - if (card != null) { - cards.add(card); - } - } - } - TargetCard target = new TargetCard(Zone.BATTLEFIELD, new FilterCard("order to put on the top of library (last choosen will be the top most)")); - while (cards.size() > 1) { - if (!player.canRespond()) { - return false; - } - player.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { - toLibrary.add(permanent); - } - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { - toLibrary.add(permanent); - } - } - // move all permanents to lib at the same time - for (Permanent permanent : toLibrary) { - player.moveCardToLibraryWithInfo(permanent, source, game, Zone.BATTLEFIELD, true, false); - } - // cards to bottom - cards.clear(); - toLibrary.clear(); - for (Permanent permanent : permanentsToBottom) { - if (permanent instanceof PermanentToken) { - toLibrary.add(permanent); - } else { - Card card = game.getCard(permanent.getId()); - if (card != null) { - cards.add(card); - } - } - } - target = new TargetCard(Zone.BATTLEFIELD, new FilterCard("order to put on bottom of library (last choosen will be bottommost card)")); - while (player.canRespond() && cards.size() > 1) { - player.choose(Outcome.Neutral, cards, target, game); + if (controller == null) { return false; } - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { - toLibrary.add(permanent); - } + PlayerList playerList = game.getState().getPlayersInRange(controller.getId(), game); + playerList.setCurrent(game.getActivePlayerId()); + Player player = game.getPlayer(game.getActivePlayerId()); + Player activePlayer = player; + do { + List permanentsToTop = new ArrayList<>(); + List permanentsToBottom = new ArrayList<>(); + for (Permanent permanent : game.getState().getBattlefield().getActivePermanents(new FilterAttackingCreature(), player.getId(), source, game)) { + if (permanent.isOwnedBy(player.getId())) { + if (player.chooseUse(outcome, "Put " + permanent.getLogName() + " to the top? (else it goes to bottom)", source, game)) { + permanentsToTop.add(permanent); + game.informPlayers(permanent.getLogName() + " goes to the top of " + player.getLogName() + "'s library"); + } else { + permanentsToBottom.add(permanent); + game.informPlayers(permanent.getLogName() + " goes to the bottom of " + player.getLogName() + "'s library"); } - target.clearChosen(); } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); + } + // cards to top + Cards cards = new CardsImpl(); + List toLibrary = new ArrayList<>(); + for (Permanent permanent : permanentsToTop) { + if (permanent instanceof PermanentToken) { + toLibrary.add(permanent); + } else { + Card card = game.getCard(permanent.getId()); + if (card != null) { + cards.add(card); + } + } + } + TargetCard target = new TargetCard(Zone.BATTLEFIELD, new FilterCard("order to put on the top of library (last choosen will be the top most)")); + while (cards.size() > 1) { + if (!player.canRespond()) { + return false; + } + player.choose(Outcome.Neutral, cards, target, game); + Card card = cards.get(target.getFirstTarget(), game); + if (card != null) { + cards.remove(card); Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { toLibrary.add(permanent); } } - // move all permanents to lib at the same time - for (Permanent permanent : toLibrary) { - player.moveCardToLibraryWithInfo(permanent, source, game, Zone.BATTLEFIELD, false, false); + target.clearChosen(); + } + if (cards.size() == 1) { + Card card = cards.get(cards.iterator().next(), game); + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) { + toLibrary.add(permanent); } - player = playerList.getNext(game, false); - } while (player != null && !player.getId().equals(game.getActivePlayerId()) && activePlayer.canRespond()); - return true; - } - return false; + } + // move all permanents to lib at the same time + for (Permanent permanent : toLibrary) { + player.moveCardToLibraryWithInfo(permanent, source, game, Zone.BATTLEFIELD, true, false); + } + // cards to bottom + cards.clear(); + toLibrary.clear(); + for (Permanent permanent : permanentsToBottom) { + if (permanent instanceof PermanentToken) { + toLibrary.add(permanent); + } else { + Card card = game.getCard(permanent.getId()); + if (card != null) { + cards.add(card); + } + } + } + target = new TargetCard(Zone.BATTLEFIELD, new FilterCard("order to put on bottom of library (last choosen will be bottommost card)")); + while (player.canRespond() && cards.size() > 1) { + player.choose(Outcome.Neutral, cards, target, game); + + Card card = cards.get(target.getFirstTarget(), game); + if (card != null) { + cards.remove(card); + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) { + toLibrary.add(permanent); + } + } + target.clearChosen(); + } + if (cards.size() == 1) { + Card card = cards.get(cards.iterator().next(), game); + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) { + toLibrary.add(permanent); + } + } + // move all permanents to lib at the same time + for (Permanent permanent : toLibrary) { + player.moveCardToLibraryWithInfo(permanent, source, game, Zone.BATTLEFIELD, false, false); + } + player = playerList.getNext(game, false); + } while (player != null && !player.getId().equals(game.getActivePlayerId()) && activePlayer.canRespond()); + + return true; } } diff --git a/Mage.Sets/src/mage/cards/a/AetherstreamLeopard.java b/Mage.Sets/src/mage/cards/a/AetherstreamLeopard.java index e10a8848419..7c63853017f 100644 --- a/Mage.Sets/src/mage/cards/a/AetherstreamLeopard.java +++ b/Mage.Sets/src/mage/cards/a/AetherstreamLeopard.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -16,8 +14,9 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; +import java.util.UUID; + /** - * * @author fireshoes */ public final class AetherstreamLeopard extends CardImpl { @@ -36,8 +35,9 @@ public final class AetherstreamLeopard extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(1))); // Whenever Aetherstream Leopard attacks, you may pay {E}. If you do, it gets +2/+0 until end of turn. - this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new BoostSourceEffect(2, 0, Duration.EndOfTurn), new PayEnergyCost(1)), false, - "Whenever {this} attacks you may pay {E}. If you do, it gets +2/+0 until end of turn.")); + this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new BoostSourceEffect( + 2, 0, Duration.EndOfTurn + ).setText("it gets +2/+0 until end of turn"), new PayEnergyCost(1)))); } private AetherstreamLeopard(final AetherstreamLeopard card) { diff --git a/Mage.Sets/src/mage/cards/a/Aethertow.java b/Mage.Sets/src/mage/cards/a/Aethertow.java index f126ce78317..f9af151c47c 100644 --- a/Mage.Sets/src/mage/cards/a/Aethertow.java +++ b/Mage.Sets/src/mage/cards/a/Aethertow.java @@ -31,7 +31,7 @@ public final class Aethertow extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); // Conspire - this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE)); + this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.ONE)); } private Aethertow(final Aethertow card) { diff --git a/Mage.Sets/src/mage/cards/a/AetherworksMarvel.java b/Mage.Sets/src/mage/cards/a/AetherworksMarvel.java index 5669bb4ebd0..6f39ece334e 100644 --- a/Mage.Sets/src/mage/cards/a/AetherworksMarvel.java +++ b/Mage.Sets/src/mage/cards/a/AetherworksMarvel.java @@ -1,8 +1,5 @@ package mage.cards.a; -import java.util.Set; -import java.util.UUID; -import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.common.PutIntoGraveFromBattlefieldAllTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -10,20 +7,22 @@ import mage.abilities.costs.common.PayEnergyCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.GetEnergyCountersControllerEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SuperType; import mage.constants.Zone; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.common.FilterNonlandCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author emerald000 */ public final class AetherworksMarvel extends CardImpl { @@ -35,13 +34,13 @@ public final class AetherworksMarvel extends CardImpl { // Whenever a permanent you control is put into a graveyard, you get {E}. this.addAbility(new PutIntoGraveFromBattlefieldAllTriggeredAbility( new GetEnergyCountersControllerEffect(1), false, - new FilterControlledPermanent("a permanent you control"), false)); + StaticFilters.FILTER_CONTROLLED_A_PERMANENT, false + )); // {T}, Pay {E}{E}{E}{E}{E}{E}: Look at the top six cards of your library. // You may cast a card from among them without paying its mana cost. // Put the rest on the bottom of your library in a random order. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new AetherworksMarvelEffect(), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(new AetherworksMarvelEffect(), new TapSourceCost()); ability.addCost(new PayEnergyCost(6)); this.addAbility(ability); } @@ -78,26 +77,13 @@ class AetherworksMarvelEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Set cardsSet = controller.getLibrary().getTopCards(game, 6); - Cards cards = new CardsImpl(cardsSet); - TargetCard target = new TargetCardInLibrary(0, 1, - new FilterNonlandCard("card to cast without paying its mana cost")); - if (controller.choose(Outcome.PlayForFree, cards, target, game)) { - Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - if (cardWasCast) { - cards.remove(card); - } - } - } - controller.putCardsOnBottomOfLibrary(cards, game, source, false); - return true; + if (controller == null) { + return false; } - return false; + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 6)); + CardUtil.castSpellWithAttributesForFree(controller, source, game, cards, StaticFilters.FILTER_CARD); + cards.retainZone(Zone.LIBRARY, game); + controller.putCardsOnBottomOfLibrary(cards, game, source, false); + return true; } } diff --git a/Mage.Sets/src/mage/cards/a/Afterburn.java b/Mage.Sets/src/mage/cards/a/Afterburn.java index a97a2861afa..a1925110676 100644 --- a/Mage.Sets/src/mage/cards/a/Afterburn.java +++ b/Mage.Sets/src/mage/cards/a/Afterburn.java @@ -30,8 +30,7 @@ public final class Afterburn extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Remove target creature from combat. - Mode mode = new Mode(); - mode.addEffect(new RemoveFromCombatTargetEffect()); + Mode mode = new Mode(new RemoveFromCombatTargetEffect()); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/AgadeemOccultist.java b/Mage.Sets/src/mage/cards/a/AgadeemOccultist.java index 99b3654a0e5..f96262b5a87 100644 --- a/Mage.Sets/src/mage/cards/a/AgadeemOccultist.java +++ b/Mage.Sets/src/mage/cards/a/AgadeemOccultist.java @@ -81,8 +81,8 @@ class AgadeemOccultistEffect extends OneShotEffect { TargetCardInOpponentsGraveyard target = new TargetCardInOpponentsGraveyard(1, 1, filter); if (controller != null) { - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) - && controller.choose(Outcome.GainControl, target, source.getSourceId(), game)) { + if (target.canChoose(source.getControllerId(), source, game) + && controller.choose(Outcome.GainControl, target, source, game)) { if (!target.getTargets().isEmpty()) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/a/AgadeemsAwakening.java b/Mage.Sets/src/mage/cards/a/AgadeemsAwakening.java index eb16de9bef9..75944abd326 100644 --- a/Mage.Sets/src/mage/cards/a/AgadeemsAwakening.java +++ b/Mage.Sets/src/mage/cards/a/AgadeemsAwakening.java @@ -100,8 +100,8 @@ class AgadeemsAwakeningTarget extends TargetCardInYourGraveyard { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set possibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); Set cmcs = this.getTargets() .stream() .map(game::getCard) diff --git a/Mage.Sets/src/mage/cards/a/AgelessSentinels.java b/Mage.Sets/src/mage/cards/a/AgelessSentinels.java index 341854f825b..07e0d68aac2 100644 --- a/Mage.Sets/src/mage/cards/a/AgelessSentinels.java +++ b/Mage.Sets/src/mage/cards/a/AgelessSentinels.java @@ -35,9 +35,9 @@ public final class AgelessSentinels extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Ageless Sentinels blocks, it becomes a Bird Giant, and it loses defender. - Ability ability = new BlocksSourceTriggeredAbility(new AgelessSentinelsEffect(), false, false, true); + Ability ability = new BlocksSourceTriggeredAbility(new AgelessSentinelsEffect()).setTriggerPhrase("When {this} blocks, "); Effect effect = new LoseAbilitySourceEffect(DefenderAbility.getInstance(), Duration.WhileOnBattlefield); - effect.setText(", and it loses defender"); + effect.setText(", and it loses defender. (It's no longer a Wall. This effect lasts indefinitely.)"); ability.addEffect(effect); this.addAbility(ability); } @@ -50,37 +50,37 @@ public final class AgelessSentinels extends CardImpl { public AgelessSentinels copy() { return new AgelessSentinels(this); } +} - private class AgelessSentinelsEffect extends ContinuousEffectImpl { +class AgelessSentinelsEffect extends ContinuousEffectImpl { - public AgelessSentinelsEffect() { - super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.BecomeCreature); - staticText = "it becomes a Bird Giant"; + public AgelessSentinelsEffect() { + super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.BecomeCreature); + staticText = "it becomes a Bird Giant"; + } + + private AgelessSentinelsEffect(final AgelessSentinelsEffect effect) { + super(effect); + } + + @Override + public AgelessSentinelsEffect copy() { + return new AgelessSentinelsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + return false; } + permanent.removeAllCreatureTypes(game); + permanent.addSubType(game, SubType.BIRD, SubType.GIANT); + return true; + } - public AgelessSentinelsEffect(final AgelessSentinelsEffect effect) { - super(effect); - } - - @Override - public AgelessSentinelsEffect copy() { - return new AgelessSentinelsEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent == null) { - return false; - } - permanent.removeAllCreatureTypes(game); - permanent.addSubType(game, SubType.BIRD, SubType.GIANT); - return true; - } - - @Override - public boolean hasLayer(Layer layer) { - return layer == Layer.TypeChangingEffects_4; - } + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.TypeChangingEffects_4; } } diff --git a/Mage.Sets/src/mage/cards/a/AgitatorAnt.java b/Mage.Sets/src/mage/cards/a/AgitatorAnt.java index cda362b3783..02541574c22 100644 --- a/Mage.Sets/src/mage/cards/a/AgitatorAnt.java +++ b/Mage.Sets/src/mage/cards/a/AgitatorAnt.java @@ -86,12 +86,12 @@ class AgitatorAntEffect extends OneShotEffect { } TargetPermanent targetPermanent = new TargetControlledCreaturePermanent(0, 1); targetPermanent.setNotTarget(true); - player.choose(Outcome.BoostCreature, targetPermanent, source.getSourceId(), game); + player.choose(Outcome.BoostCreature, targetPermanent, source, game); Permanent permanent = game.getPermanent(targetPermanent.getFirstTarget()); if (permanent == null || !permanent.addCounters(CounterType.P1P1.createInstance(2), player.getId(), source, game)) { continue; } - new GoadTargetEffect().setTargetPointer(new FixedTarget(permanent, game)).apply(game, source); + game.addEffect(new GoadTargetEffect().setTargetPointer(new FixedTarget(permanent, game)), source); } return true; } diff --git a/Mage.Sets/src/mage/cards/a/AidFromTheCowl.java b/Mage.Sets/src/mage/cards/a/AidFromTheCowl.java index adfcd640ca9..82d0f16613f 100644 --- a/Mage.Sets/src/mage/cards/a/AidFromTheCowl.java +++ b/Mage.Sets/src/mage/cards/a/AidFromTheCowl.java @@ -25,7 +25,7 @@ import mage.watchers.common.RevoltWatcher; public final class AidFromTheCowl extends CardImpl { private static final String ruleText = "Revolt — At the beginning of your end step, if a permanent you controlled left the battlefield this turn, " - + "reveal the top card of your library. If it's a permanent card, you may put it onto the battlefield. Otherwise, put it on the bottom of your library."; + + "reveal the top card of your library. If it's a permanent card, you may put it onto the battlefield. Otherwise, you may put it on the bottom of your library."; public AidFromTheCowl(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}{G}"); @@ -65,7 +65,7 @@ class AidFromTheCowlEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/a/AidTheFallen.java b/Mage.Sets/src/mage/cards/a/AidTheFallen.java index 5e676ec87b8..4b9d5b3c70c 100644 --- a/Mage.Sets/src/mage/cards/a/AidTheFallen.java +++ b/Mage.Sets/src/mage/cards/a/AidTheFallen.java @@ -1,7 +1,7 @@ package mage.cards.a; import mage.abilities.Mode; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -27,13 +27,13 @@ public final class AidTheFallen extends CardImpl { this.getSpellAbility().getModes().setMaxModes(2); // • Return target creature card from your graveyard to your hand. - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard( StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD ).withChooseHint("returns a creature card to your hand")); // • Return target planeswalker card from your graveyard to your hand. - Mode mode = new Mode(new ReturnToHandTargetEffect()); + Mode mode = new Mode(new ReturnFromGraveyardToHandTargetEffect()); mode.addTarget(new TargetCardInYourGraveyard(filter) .withChooseHint("returns a planeswalker card to your hand")); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/a/AinokGuide.java b/Mage.Sets/src/mage/cards/a/AinokGuide.java index fd5c6707ce0..3ce99a028dc 100644 --- a/Mage.Sets/src/mage/cards/a/AinokGuide.java +++ b/Mage.Sets/src/mage/cards/a/AinokGuide.java @@ -35,8 +35,7 @@ public final class AinokGuide extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())); // * Search your library for a basic land card, reveal it, then shuffle your library and put that card on top of it. - Mode mode = new Mode(); - mode.addEffect(new SearchLibraryPutOnLibraryEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true, true)); + Mode mode = new Mode(new SearchLibraryPutOnLibraryEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true, true)); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/AinokSurvivalist.java b/Mage.Sets/src/mage/cards/a/AinokSurvivalist.java index 6e7db4e32b8..58e059e30c9 100644 --- a/Mage.Sets/src/mage/cards/a/AinokSurvivalist.java +++ b/Mage.Sets/src/mage/cards/a/AinokSurvivalist.java @@ -37,7 +37,7 @@ public final class AinokSurvivalist extends CardImpl { this.toughness = new MageInt(1); // Megamorph {1}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{G}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{G}"), true)); // When Ainok Survivalist is turned face up, destroy target artifact or enchantment an opponent controls. Effect effect = new DestroyTargetEffect(); diff --git a/Mage.Sets/src/mage/cards/a/AinokTracker.java b/Mage.Sets/src/mage/cards/a/AinokTracker.java index 96105d9b3e1..7c0f9ce5bba 100644 --- a/Mage.Sets/src/mage/cards/a/AinokTracker.java +++ b/Mage.Sets/src/mage/cards/a/AinokTracker.java @@ -28,7 +28,7 @@ public final class AinokTracker extends CardImpl { // First Strike this.addAbility(FirstStrikeAbility.getInstance()); // Morph 4R - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{R}"))); } private AinokTracker(final AinokTracker card) { diff --git a/Mage.Sets/src/mage/cards/a/AirdropAeronauts.java b/Mage.Sets/src/mage/cards/a/AirdropAeronauts.java index a60bbe3aef9..d62249d4086 100644 --- a/Mage.Sets/src/mage/cards/a/AirdropAeronauts.java +++ b/Mage.Sets/src/mage/cards/a/AirdropAeronauts.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -16,8 +14,9 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.watchers.common.RevoltWatcher; +import java.util.UUID; + /** - * * @author Styxo */ public final class AirdropAeronauts extends CardImpl { @@ -34,10 +33,10 @@ public final class AirdropAeronauts extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Revolt — When Airdrop Aeronauts enters the battlefield, if a permanent you controlled left the battlefield this turn, you gain 5 life. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( - new GainLifeEffect(5), false), RevoltCondition.instance, - "Revolt — When {this} enters the battlefield, if a permanent you controlled left" - + " the battlefield this turn, you gain 5 life." + Ability ability = new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new GainLifeEffect(5), false), + RevoltCondition.instance, "When {this} enters the battlefield, " + + "if a permanent you controlled left the battlefield this turn, you gain 5 life." ); ability.setAbilityWord(AbilityWord.REVOLT); this.addAbility(ability, new RevoltWatcher()); diff --git a/Mage.Sets/src/mage/cards/a/AjaniAdversaryOfTyrants.java b/Mage.Sets/src/mage/cards/a/AjaniAdversaryOfTyrants.java index c6efc37d169..fcdc8d17509 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniAdversaryOfTyrants.java +++ b/Mage.Sets/src/mage/cards/a/AjaniAdversaryOfTyrants.java @@ -1,27 +1,27 @@ package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.constants.SubType; -import mage.constants.SuperType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.counters.CounterType; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.command.emblems.AjaniAdversaryOfTyrantsEmblem; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInYourGraveyard; -import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class AjaniAdversaryOfTyrants extends CardImpl { @@ -38,11 +38,11 @@ public final class AjaniAdversaryOfTyrants extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.AJANI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Put a +1/+1 counter on each of up to two target creatures. Ability ability = new LoyaltyAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), 1); - ability.addTarget(new TargetCreaturePermanent(0, 2)); + ability.addTarget(new TargetPermanent(0, 2, StaticFilters.FILTER_PERMANENT_CREATURES)); this.addAbility(ability); // −2: Return target creature card with converted mana cost 2 or less from your graveyard to the battlefield. diff --git a/Mage.Sets/src/mage/cards/a/AjaniCallerOfThePride.java b/Mage.Sets/src/mage/cards/a/AjaniCallerOfThePride.java index 22cf714c4bf..67d51825f00 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniCallerOfThePride.java +++ b/Mage.Sets/src/mage/cards/a/AjaniCallerOfThePride.java @@ -4,7 +4,6 @@ package mage.cards.a; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.ControllerLifeCount; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; @@ -34,7 +33,7 @@ public final class AjaniCallerOfThePride extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.AJANI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Put a +1/+1 counter on up to one target creature. Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); effect.setText("Put a +1/+1 counter on up to one target creature"); diff --git a/Mage.Sets/src/mage/cards/a/AjaniGoldmane.java b/Mage.Sets/src/mage/cards/a/AjaniGoldmane.java index 6efe3fc8d75..d779587b675 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniGoldmane.java +++ b/Mage.Sets/src/mage/cards/a/AjaniGoldmane.java @@ -1,13 +1,7 @@ - package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.Effects; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -15,17 +9,17 @@ import mage.abilities.effects.common.counter.AddCountersAllEffect; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.counters.CounterType; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterCreaturePermanent; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.permanent.token.TokenImpl; -import mage.players.Player; +import mage.filter.StaticFilters; +import mage.game.permanent.token.AvatarToken; + +import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public final class AjaniGoldmane extends CardImpl { @@ -35,20 +29,24 @@ public final class AjaniGoldmane extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.AJANI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: You gain 2 life. this.addAbility(new LoyaltyAbility(new GainLifeEffect(2), 1)); // -1: Put a +1/+1 counter on each creature you control. Those creatures gain vigilance until end of turn. - Effects effects1 = new Effects(); - effects1.add(new AddCountersAllEffect(CounterType.P1P1.createInstance(), new FilterControlledCreaturePermanent())); - effects1.add(new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn, new FilterCreaturePermanent())); - this.addAbility(new LoyaltyAbility(effects1, -1)); + Ability ability = new LoyaltyAbility(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), + StaticFilters.FILTER_CONTROLLED_CREATURE + ), -1); + ability.addEffect(new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("Those creatures gain vigilance until end of turn")); + this.addAbility(ability); // -6: Create a white Avatar creature token. It has "This creature's power and toughness are each equal to your life total." this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new AvatarToken()), -6)); - } private AjaniGoldmane(final AjaniGoldmane card) { @@ -59,54 +57,4 @@ public final class AjaniGoldmane extends CardImpl { public AjaniGoldmane copy() { return new AjaniGoldmane(this); } - -} - -class AvatarToken extends TokenImpl { - - public AvatarToken() { - super("Avatar", "white Avatar creature token with \"This creature's power and toughness are each equal to your life total.\""); - cardType.add(CardType.CREATURE); - subtype.add(SubType.AVATAR); - color.setWhite(true); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AvatarTokenEffect())); - } - public AvatarToken(final AvatarToken token) { - super(token); - } - - public AvatarToken copy() { - return new AvatarToken(this); - } -} - -class AvatarTokenEffect extends ContinuousEffectImpl { - - public AvatarTokenEffect() { - super(Duration.WhileOnBattlefield, Layer.PTChangingEffects_7, SubLayer.SetPT_7b, Outcome.BoostCreature); - } - - public AvatarTokenEffect(final AvatarTokenEffect effect) { - super(effect); - } - - @Override - public AvatarTokenEffect copy() { - return new AvatarTokenEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent token = game.getPermanent(source.getSourceId()); - if (token != null) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - token.getPower().setValue(controller.getLife()); - token.getToughness().setValue(controller.getLife()); - return true; - } - } - return false; - } - } diff --git a/Mage.Sets/src/mage/cards/a/AjaniInspiringLeader.java b/Mage.Sets/src/mage/cards/a/AjaniInspiringLeader.java index 87c510e8f3a..e7eeb863bb9 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniInspiringLeader.java +++ b/Mage.Sets/src/mage/cards/a/AjaniInspiringLeader.java @@ -2,7 +2,6 @@ package mage.cards.a; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -31,7 +30,7 @@ public final class AjaniInspiringLeader extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.AJANI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +2: You gain 2 life. Put two +1/+1 counters on up to one target creature. Ability ability = new LoyaltyAbility(new GainLifeEffect(2), 2); diff --git a/Mage.Sets/src/mage/cards/a/AjaniMentorOfHeroes.java b/Mage.Sets/src/mage/cards/a/AjaniMentorOfHeroes.java index f4cb427e1e9..f3c9a18acd4 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniMentorOfHeroes.java +++ b/Mage.Sets/src/mage/cards/a/AjaniMentorOfHeroes.java @@ -4,9 +4,9 @@ package mage.cards.a; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.counter.DistributeCountersEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -14,7 +14,6 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.TargetController; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.common.FilterCreaturePermanent; @@ -43,15 +42,16 @@ public final class AjaniMentorOfHeroes extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.AJANI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Distribute three +1/+1 counters among one, two, or three target creatures you control Ability ability = new LoyaltyAbility(new DistributeCountersEffect(CounterType.P1P1, 3, false, "one, two, or three target creatures you control"), 1); ability.addTarget(new TargetCreaturePermanentAmount(3, filter)); this.addAbility(ability); - // +1: Look at the top four cards of your library. You may reveal an Aura, creature, or planeswalker card from among them and put that card into your hand. Put the rest on the bottom of your library in any order. - this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect(4, 1, filterCard, true, false, Zone.HAND, true), 1)); + // +1: Look at the top four cards of your library. You may reveal an Aura, creature, or planeswalker card + // from among them and put it into your hand. Put the rest on the bottom of your library in any order. + this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect(4, 1, filterCard, PutCards.HAND, PutCards.BOTTOM_ANY), 1)); // -8: You gain 100 life. this.addAbility(new LoyaltyAbility(new GainLifeEffect(100), -8)); diff --git a/Mage.Sets/src/mage/cards/a/AjaniSteadfast.java b/Mage.Sets/src/mage/cards/a/AjaniSteadfast.java index c951d1b4f02..4d843009533 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniSteadfast.java +++ b/Mage.Sets/src/mage/cards/a/AjaniSteadfast.java @@ -3,7 +3,6 @@ package mage.cards.a; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -44,7 +43,7 @@ public final class AjaniSteadfast extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.AJANI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Until end of turn, up to one target creature gets +1/+1 and gains first strike, vigilance, and lifelink. Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); diff --git a/Mage.Sets/src/mage/cards/a/AjaniStrengthOfThePride.java b/Mage.Sets/src/mage/cards/a/AjaniStrengthOfThePride.java index d0f076bbe36..b8154b1c060 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniStrengthOfThePride.java +++ b/Mage.Sets/src/mage/cards/a/AjaniStrengthOfThePride.java @@ -2,7 +2,6 @@ package mage.cards.a; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -32,7 +31,7 @@ public final class AjaniStrengthOfThePride extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.AJANI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: You gain life equal to the number of creatures you control plus the number of planeswalkers you control. this.addAbility(new LoyaltyAbility(new GainLifeEffect( diff --git a/Mage.Sets/src/mage/cards/a/AjaniTheGreathearted.java b/Mage.Sets/src/mage/cards/a/AjaniTheGreathearted.java index 837660006db..e30d19de341 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniTheGreathearted.java +++ b/Mage.Sets/src/mage/cards/a/AjaniTheGreathearted.java @@ -2,7 +2,6 @@ package mage.cards.a; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -38,7 +37,7 @@ public final class AjaniTheGreathearted extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.AJANI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Creatures you control have vigilance. this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( @@ -52,7 +51,7 @@ public final class AjaniTheGreathearted extends CardImpl { // -2: Put a +1/+1 counter on each creature you control and a loyalty counter on each other planeswalker you control. Ability ability = new LoyaltyAbility(new AddCountersAllEffect( - CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURES + CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE ), -2); ability.addEffect(new AddCountersAllEffect( CounterType.LOYALTY.createInstance(), filter diff --git a/Mage.Sets/src/mage/cards/a/AjaniUnyielding.java b/Mage.Sets/src/mage/cards/a/AjaniUnyielding.java index 50a5472824e..786318a9df8 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniUnyielding.java +++ b/Mage.Sets/src/mage/cards/a/AjaniUnyielding.java @@ -3,7 +3,6 @@ package mage.cards.a; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.ExileAndGainLifeEqualPowerTargetEffect; import mage.abilities.effects.common.RevealLibraryPutIntoHandEffect; import mage.abilities.effects.common.counter.AddCountersAllEffect; @@ -41,7 +40,7 @@ public final class AjaniUnyielding extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.AJANI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +2: Reveal the top three cards of your library. Put all nonland permanent cards revealed this way into your hand and the rest on the bottom of your library in any order. this.addAbility(new LoyaltyAbility(new RevealLibraryPutIntoHandEffect(3, nonlandPermanentFilter, Zone.LIBRARY), 2)); @@ -53,7 +52,7 @@ public final class AjaniUnyielding extends CardImpl { // -9: Put five +1/+1 counters on each creature you control and five loyalty counters on each other planeswalker you control. LoyaltyAbility ajaniAbility3 = new LoyaltyAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(5), new FilterControlledCreaturePermanent()), -9); - ajaniAbility3.addEffect(new AddCountersAllEffect(CounterType.LOYALTY.createInstance(5), planeswalkerFilter)); + ajaniAbility3.addEffect(new AddCountersAllEffect(CounterType.LOYALTY.createInstance(5), planeswalkerFilter).setText("and five loyalty counters on each other planeswalker you control")); this.addAbility(ajaniAbility3); } diff --git a/Mage.Sets/src/mage/cards/a/AjaniValiantProtector.java b/Mage.Sets/src/mage/cards/a/AjaniValiantProtector.java index 5e8025bcb75..1bff23aab26 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniValiantProtector.java +++ b/Mage.Sets/src/mage/cards/a/AjaniValiantProtector.java @@ -3,7 +3,6 @@ package mage.cards.a; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.ControllerLifeCount; import mage.abilities.effects.Effect; import mage.abilities.effects.common.RevealCardsFromLibraryUntilEffect; @@ -32,7 +31,7 @@ public final class AjaniValiantProtector extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.AJANI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +2: Put two +1/+1 counters on up to one target creature. Ability ability = new LoyaltyAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)), 2); diff --git a/Mage.Sets/src/mage/cards/a/AjaniVengeant.java b/Mage.Sets/src/mage/cards/a/AjaniVengeant.java index 57eee39eda4..84d4f64875d 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniVengeant.java +++ b/Mage.Sets/src/mage/cards/a/AjaniVengeant.java @@ -3,7 +3,6 @@ package mage.cards.a; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effects; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DestroyAllControlledTargetEffect; @@ -36,7 +35,7 @@ public final class AjaniVengeant extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.AJANI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Target permanent doesn't untap during its controller's next untap step. LoyaltyAbility ability1 = new LoyaltyAbility(new DontUntapInControllersNextUntapStepTargetEffect(), 1); @@ -46,7 +45,7 @@ public final class AjaniVengeant extends CardImpl { // −2: Ajani Vengeant deals 3 damage to any target and you gain 3 life. Effects effects1 = new Effects(); effects1.add(new DamageTargetEffect(3)); - effects1.add(new GainLifeEffect(3)); + effects1.add(new GainLifeEffect(3).concatBy("and")); LoyaltyAbility ability2 = new LoyaltyAbility(effects1, -2); ability2.addTarget(new TargetAnyTarget()); this.addAbility(ability2); diff --git a/Mage.Sets/src/mage/cards/a/AjaniWiseCounselor.java b/Mage.Sets/src/mage/cards/a/AjaniWiseCounselor.java index e7fd5f8837b..33feec0fdd1 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniWiseCounselor.java +++ b/Mage.Sets/src/mage/cards/a/AjaniWiseCounselor.java @@ -2,7 +2,6 @@ package mage.cards.a; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.ControllerLifeCount; import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.GainLifeEffect; @@ -29,7 +28,7 @@ public final class AjaniWiseCounselor extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.AJANI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +2: You gain 1 life for each creature you control. this.addAbility(new LoyaltyAbility(new GainLifeEffect(CreaturesYouControlCount.instance) diff --git a/Mage.Sets/src/mage/cards/a/AjanisInfluence.java b/Mage.Sets/src/mage/cards/a/AjanisInfluence.java index 94700f16dc7..fd10941fba3 100644 --- a/Mage.Sets/src/mage/cards/a/AjanisInfluence.java +++ b/Mage.Sets/src/mage/cards/a/AjanisInfluence.java @@ -2,13 +2,12 @@ package mage.cards.a; import java.util.UUID; import mage.ObjectColor; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.ColorPredicate; @@ -35,12 +34,7 @@ public final class AjanisInfluence extends CardImpl { // Look at the top five cards of your library. You may reveal a white card form among them and put it into your hand. Put the rest on the bottom of your library in a random order. this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), filter, - Zone.LIBRARY, false, true, false, Zone.HAND, true, false, false - ).setBackInRandomOrder(true).setText("Look at the top five cards of your library. " - + "You may reveal a white card from among them and put it into your hand. " - + "Put the rest on the bottom of your library in a random order.") - ); + 5, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM).concatBy("
")); } private AjanisInfluence(final AjanisInfluence card) { diff --git a/Mage.Sets/src/mage/cards/a/AkiriFearlessVoyager.java b/Mage.Sets/src/mage/cards/a/AkiriFearlessVoyager.java index a7583635ab4..c9dbd3ca820 100644 --- a/Mage.Sets/src/mage/cards/a/AkiriFearlessVoyager.java +++ b/Mage.Sets/src/mage/cards/a/AkiriFearlessVoyager.java @@ -142,11 +142,11 @@ class AkiriFearlessVoyagerEffect extends OneShotEffect { return false; } TargetPermanent target = new TargetPermanent(1, 1, filter, true); - if (!target.canChoose(source.getSourceId(), source.getControllerId(), game) + if (!target.canChoose(source.getControllerId(), source, game) || !player.chooseUse(outcome, "Unnattach an equipment from a creature you control?", source, game)) { return false; } - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Permanent equipment = game.getPermanent(target.getFirstTarget()); if (equipment == null) { return false; diff --git a/Mage.Sets/src/mage/cards/a/AkkiBattleSquad.java b/Mage.Sets/src/mage/cards/a/AkkiBattleSquad.java new file mode 100644 index 00000000000..846e9e22b71 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AkkiBattleSquad.java @@ -0,0 +1,53 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksCreatureYouControlTriggeredAbility; +import mage.abilities.effects.common.AdditionalCombatPhaseEffect; +import mage.abilities.effects.common.UntapAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.ModifiedPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AkkiBattleSquad extends CardImpl { + + private static final FilterControlledCreaturePermanent filter + = new FilterControlledCreaturePermanent("modified creatures you control"); + + static { + filter.add(ModifiedPredicate.instance); + } + + public AkkiBattleSquad(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.SAMURAI); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Whenever one or more modified creatures you control attack, untap all modified creatures you control. After this combat phase, there is an additional combat phase. This ability triggers only once each turn. + Ability ability = new AttacksCreatureYouControlTriggeredAbility( + new UntapAllEffect(filter), false, filter + ).setTriggerPhrase("Whenever one or more modified creatures you control attack, ").setTriggersOnce(true); + ability.addEffect(new AdditionalCombatPhaseEffect()); + this.addAbility(ability); + } + + private AkkiBattleSquad(final AkkiBattleSquad card) { + super(card); + } + + @Override + public AkkiBattleSquad copy() { + return new AkkiBattleSquad(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AkoumBattlesinger.java b/Mage.Sets/src/mage/cards/a/AkoumBattlesinger.java index b7fb362bb3c..36dedb10152 100644 --- a/Mage.Sets/src/mage/cards/a/AkoumBattlesinger.java +++ b/Mage.Sets/src/mage/cards/a/AkoumBattlesinger.java @@ -39,7 +39,7 @@ public final class AkoumBattlesinger extends CardImpl { // Haste this.addAbility(HasteAbility.getInstance()); // Whenever Akoum Battlesinger or another Ally enters the battlefield under your control, you may have Ally creatures you control get +1/+0 until end of turn. - this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new BoostControlledEffect(1, 0, Duration.EndOfTurn, filter, false), true)); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new BoostControlledEffect(1, 0, Duration.EndOfTurn, filter, false), true).setAbilityWord(null)); } private AkoumBattlesinger(final AkoumBattlesinger card) { diff --git a/Mage.Sets/src/mage/cards/a/AkoumBoulderfoot.java b/Mage.Sets/src/mage/cards/a/AkoumBoulderfoot.java index 5f986c84952..7e97709e670 100644 --- a/Mage.Sets/src/mage/cards/a/AkoumBoulderfoot.java +++ b/Mage.Sets/src/mage/cards/a/AkoumBoulderfoot.java @@ -27,7 +27,7 @@ public final class AkoumBoulderfoot extends CardImpl { this.power = new MageInt(4); this.toughness = new MageInt(5); - Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(1), false); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(1, "it"), false); Target target = new TargetAnyTarget(); ability.addTarget(target); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/AkoumHellkite.java b/Mage.Sets/src/mage/cards/a/AkoumHellkite.java index 9c61c25c58b..2d3cdfd6856 100644 --- a/Mage.Sets/src/mage/cards/a/AkoumHellkite.java +++ b/Mage.Sets/src/mage/cards/a/AkoumHellkite.java @@ -58,7 +58,7 @@ class AkoumHellkiteTriggeredAbility extends TriggeredAbilityImpl { super(Zone.BATTLEFIELD, new AkoumHellkiteDamageEffect()); } - public AkoumHellkiteTriggeredAbility(final AkoumHellkiteTriggeredAbility ability) { + private AkoumHellkiteTriggeredAbility(final AkoumHellkiteTriggeredAbility ability) { super(ability); } @@ -75,19 +75,21 @@ class AkoumHellkiteTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null - && permanent.isLand(game) - && permanent.isControlledBy(getControllerId())) { - Permanent sourcePermanent = game.getPermanent(getSourceId()); - if (sourcePermanent != null) { - for (Effect effect : getEffects()) { - if (effect instanceof AkoumHellkiteDamageEffect) { - effect.setTargetPointer(new FixedTarget(permanent, game)); - } - return true; - } + if (permanent == null) { return false; } + + if (!permanent.isLand(game) || !permanent.isControlledBy(getControllerId())) { return false; } + + Permanent sourcePermanent = game.getPermanent(getSourceId()); + if (sourcePermanent == null) { return false; } + + for (Effect effect : getEffects()) { + if (effect instanceof AkoumHellkiteDamageEffect) { + effect.setTargetPointer(new FixedTarget(permanent, game)); + return true; } + } + // The Hellkit somehow lost it's damage effect but not it's landfall ability return false; } @@ -116,24 +118,22 @@ class AkoumHellkiteDamageEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent land = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); + if (land == null) { return false; } + + int damage = land.hasSubtype(SubType.MOUNTAIN, game) ? 2 : 1; + + // Get target for damange Player player = game.getPlayer(source.getFirstTarget()); - if (land != null && player != null) { - if (land.hasSubtype(SubType.MOUNTAIN, game)) { - player.damage(2, source.getSourceId(), source, game); - } else { - player.damage(1, source.getSourceId(), source, game); - } - return true; - } Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (land != null && permanent != null) { - if (land.hasSubtype(SubType.MOUNTAIN, game)) { - permanent.damage(2, source.getSourceId(), source, game); - } else { - permanent.damage(1, source.getSourceId(), source, game); - } - return true; + if (player == null && permanent == null) { return false; } + + if (player != null) { + // Target is a player + player.damage(damage, source.getSourceId(), source, game); + } else { + // Target is a permanent + permanent.damage(damage, source.getSourceId(), source, game); } - return false; + return true; } } diff --git a/Mage.Sets/src/mage/cards/a/AkroanHorse.java b/Mage.Sets/src/mage/cards/a/AkroanHorse.java index ea9789aebed..2e741b5ea85 100644 --- a/Mage.Sets/src/mage/cards/a/AkroanHorse.java +++ b/Mage.Sets/src/mage/cards/a/AkroanHorse.java @@ -37,8 +37,10 @@ public final class AkroanHorse extends CardImpl { // Defender this.addAbility(DefenderAbility.getInstance()); + // When Akroan Horse enters the battlefield, an opponent gains control of it. this.addAbility(new EntersBattlefieldTriggeredAbility(new AkroanHorseChangeControlEffect(), false)); + // At the beginning of your upkeep, each opponent create a 1/1 white Soldier creature token. this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new AkroanHorseCreateTokenEffect(), TargetController.YOU, false)); } @@ -60,7 +62,7 @@ class AkroanHorseChangeControlEffect extends OneShotEffect { this.staticText = "an opponent gains control of it"; } - public AkroanHorseChangeControlEffect(final AkroanHorseChangeControlEffect effect) { + private AkroanHorseChangeControlEffect(final AkroanHorseChangeControlEffect effect) { super(effect); } @@ -88,7 +90,7 @@ class AkroanHorseChangeControlEffect extends OneShotEffect { class AkroanHorseGainControlEffect extends ContinuousEffectImpl { - UUID controller; + private final UUID controller; public AkroanHorseGainControlEffect(Duration duration, UUID controller) { super(duration, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); @@ -107,14 +109,18 @@ class AkroanHorseGainControlEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (targetPointer != null) { + Permanent permanent; + + if (targetPointer == null) { + permanent = game.getPermanent(source.getFirstTarget()); + } else { permanent = game.getPermanent(targetPointer.getFirst(game, source)); } - if (permanent != null) { - return permanent.changeControllerId(controller, game, source); - } - return false; + + if (permanent == null) { return false; } + + return permanent.changeControllerId(controller, game, source); + } @Override @@ -130,7 +136,7 @@ class AkroanHorseCreateTokenEffect extends OneShotEffect { this.staticText = "each opponent creates a 1/1 white Soldier creature token"; } - public AkroanHorseCreateTokenEffect(final AkroanHorseCreateTokenEffect effect) { + private AkroanHorseCreateTokenEffect(final AkroanHorseCreateTokenEffect effect) { super(effect); } diff --git a/Mage.Sets/src/mage/cards/a/AkromaAngelOfFury.java b/Mage.Sets/src/mage/cards/a/AkromaAngelOfFury.java index 84b6c198062..538292d545b 100644 --- a/Mage.Sets/src/mage/cards/a/AkromaAngelOfFury.java +++ b/Mage.Sets/src/mage/cards/a/AkromaAngelOfFury.java @@ -41,7 +41,7 @@ public final class AkromaAngelOfFury extends CardImpl { // {R}: Akroma, Angel of Fury gets +1/+0 until end of turn. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1,0, Duration.EndOfTurn), new ManaCostsImpl("{R}"))); // Morph {3}{R}{R}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{R}{R}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{R}{R}{R}"))); } private AkromaAngelOfFury(final AkromaAngelOfFury card) { diff --git a/Mage.Sets/src/mage/cards/a/AkromaVisionOfIxidor.java b/Mage.Sets/src/mage/cards/a/AkromaVisionOfIxidor.java index b3f27fa3cdc..0e86ee06aa8 100644 --- a/Mage.Sets/src/mage/cards/a/AkromaVisionOfIxidor.java +++ b/Mage.Sets/src/mage/cards/a/AkromaVisionOfIxidor.java @@ -104,9 +104,9 @@ class AkromaVisionOfIxidorEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { for (Permanent permanent : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game )) { - Abilities abilities = permanent.getAbilities(game); + Abilities abilities = permanent.getAbilities(game); int count = classes .stream() .map(clazz -> abilities.stream().anyMatch(clazz::isInstance)) diff --git a/Mage.Sets/src/mage/cards/a/AlabasterPotion.java b/Mage.Sets/src/mage/cards/a/AlabasterPotion.java index 4877d3acebc..1462eaca09c 100644 --- a/Mage.Sets/src/mage/cards/a/AlabasterPotion.java +++ b/Mage.Sets/src/mage/cards/a/AlabasterPotion.java @@ -25,8 +25,7 @@ public final class AlabasterPotion extends CardImpl { // Choose one - Target player gains X life; or prevent the next X damage that would be dealt to any target this turn. this.getSpellAbility().addEffect(new GainLifeTargetEffect(ManacostVariableValue.REGULAR)); this.getSpellAbility().addTarget(new TargetPlayer()); - Mode mode = new Mode(); - mode.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, false, true, ManacostVariableValue.REGULAR)); + Mode mode = new Mode(new PreventDamageToTargetEffect(Duration.EndOfTurn, false, true, ManacostVariableValue.REGULAR)); mode.addTarget(new TargetAnyTarget()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/AlabornZealot.java b/Mage.Sets/src/mage/cards/a/AlabornZealot.java index ee4c93ca251..9c84b4a111f 100644 --- a/Mage.Sets/src/mage/cards/a/AlabornZealot.java +++ b/Mage.Sets/src/mage/cards/a/AlabornZealot.java @@ -1,16 +1,15 @@ - package mage.cards.a; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.BlocksSourceTriggeredAbility; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.effects.common.DestroySourceEffect; import mage.abilities.effects.common.DestroyTargetEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; /** * @@ -27,8 +26,11 @@ public final class AlabornZealot extends CardImpl { this.toughness = new MageInt(1); // When Alaborn Zealot blocks a creature, destroy that creature and Alaborn Zealot. - Ability ability = new BlocksSourceTriggeredAbility(new DestroyTargetEffect().setText("destroy that creature"), false, true, true); + TriggeredAbility ability = new BlocksCreatureTriggeredAbility( + new DestroyTargetEffect().setText("destroy that creature") + ); ability.addEffect(new DestroySourceEffect().setText("and {this}")); + ability.setTriggerPhrase("When {this} blocks a creature, "); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AlchemistsGreeting.java b/Mage.Sets/src/mage/cards/a/AlchemistsGreeting.java index e87883fed1f..6f401139368 100644 --- a/Mage.Sets/src/mage/cards/a/AlchemistsGreeting.java +++ b/Mage.Sets/src/mage/cards/a/AlchemistsGreeting.java @@ -24,7 +24,7 @@ public final class AlchemistsGreeting extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Madness {1}{R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{1}{R}"))); } private AlchemistsGreeting(final AlchemistsGreeting card) { diff --git a/Mage.Sets/src/mage/cards/a/AlertHeedbonder.java b/Mage.Sets/src/mage/cards/a/AlertHeedbonder.java index 8e77c371bdd..02eb1bdb7cf 100644 --- a/Mage.Sets/src/mage/cards/a/AlertHeedbonder.java +++ b/Mage.Sets/src/mage/cards/a/AlertHeedbonder.java @@ -44,7 +44,9 @@ public final class AlertHeedbonder extends CardImpl { // At the beginning of your end step, you gain 1 life for each creature you control with vigilance. this.addAbility(new BeginningOfEndStepTriggeredAbility( - new GainLifeEffect(xValue), TargetController.YOU, false + new GainLifeEffect(xValue) + .setText("you gain 1 life for each creature you control with vigilance"), + TargetController.YOU, false )); } diff --git a/Mage.Sets/src/mage/cards/a/AleshasVanguard.java b/Mage.Sets/src/mage/cards/a/AleshasVanguard.java index 019b3b39153..8a452e8c09f 100644 --- a/Mage.Sets/src/mage/cards/a/AleshasVanguard.java +++ b/Mage.Sets/src/mage/cards/a/AleshasVanguard.java @@ -23,7 +23,7 @@ public final class AleshasVanguard extends CardImpl { this.toughness = new MageInt(3); // Dash {2}{B} - this.addAbility(new DashAbility(this, "{2}{B}")); + this.addAbility(new DashAbility("{2}{B}")); } private AleshasVanguard(final AleshasVanguard card) { diff --git a/Mage.Sets/src/mage/cards/a/AlhammarretHighArbiter.java b/Mage.Sets/src/mage/cards/a/AlhammarretHighArbiter.java index 165adfccda2..f49af6d9d42 100644 --- a/Mage.Sets/src/mage/cards/a/AlhammarretHighArbiter.java +++ b/Mage.Sets/src/mage/cards/a/AlhammarretHighArbiter.java @@ -138,7 +138,7 @@ class AlhammarretHighArbiterCantCastEffect extends ContinuousRuleModifyingEffect @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You may not cast a card named " + cardName + " (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/a/AliFromCairo.java b/Mage.Sets/src/mage/cards/a/AliFromCairo.java index 2957af4ef7c..310a6b6428a 100644 --- a/Mage.Sets/src/mage/cards/a/AliFromCairo.java +++ b/Mage.Sets/src/mage/cards/a/AliFromCairo.java @@ -65,27 +65,26 @@ class AliFromCairoReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null - && (controller.getLife() > 0) &&(controller.getLife() - event.getAmount()) < 1 - && event.getPlayerId().equals(controller.getId()) - ) { - return true; - } - } - return false; + if (permanent == null) { return false; } + + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + + return (controller.getLife() > 0) && (controller.getLife() - event.getAmount()) < 1 + && event.getPlayerId().equals(controller.getId()); } @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - // 10/1/2008: The ability doesn't change how much damage is dealt; - // it just changes how much life that damage makes you lose. - // An effect such as Spirit Link will see the full amount of damage being dealt. - event.setAmount(controller.getLife() - 1); - } + if (controller == null) { return false; } + + // 10/1/2008: The ability doesn't change how much damage is dealt; + // it just changes how much life that damage makes you lose. + // An effect such as Spirit Link will see the full amount of damage being dealt. + event.setAmount(controller.getLife() - 1); + + // TODO: Is this supposed to be false? Seem suspicious return false; } } diff --git a/Mage.Sets/src/mage/cards/a/AlibouAncientWitness.java b/Mage.Sets/src/mage/cards/a/AlibouAncientWitness.java index 3fc6f9f0f98..c640759be20 100644 --- a/Mage.Sets/src/mage/cards/a/AlibouAncientWitness.java +++ b/Mage.Sets/src/mage/cards/a/AlibouAncientWitness.java @@ -91,7 +91,7 @@ class AlibouAncientWitnessEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int xValue = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int xValue = game.getBattlefield().count(filter, source.getControllerId(), source, game); if (xValue < 1) { return false; } diff --git a/Mage.Sets/src/mage/cards/a/AlignedHedronNetwork.java b/Mage.Sets/src/mage/cards/a/AlignedHedronNetwork.java index cfde81c4070..6658b9c9e5e 100644 --- a/Mage.Sets/src/mage/cards/a/AlignedHedronNetwork.java +++ b/Mage.Sets/src/mage/cards/a/AlignedHedronNetwork.java @@ -70,20 +70,20 @@ class AlignedHedronNetworkExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false;} + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { return false; } + // If Whale leaves the battlefield before its triggered ability resolves, // the target creature won't be exiled. - if (controller != null && permanent != null) { - Set toExile = new LinkedHashSet<>(); - for (Permanent creature : game.getBattlefield().getActivePermanents(filter, controller.getId(), source.getSourceId(), game)) { - toExile.add(creature); - } - if (!toExile.isEmpty()) { - controller.moveCardsToExile(toExile, source, game, true, CardUtil.getCardExileZoneId(game, source), permanent.getIdName()); - new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility()).apply(game, source); - } - return true; - } - return false; + Set toExile = new LinkedHashSet<>(game.getBattlefield().getActivePermanents(filter, controller.getId(), source, game)); + if (toExile.isEmpty()) { return false; } + + controller.moveCardsToExile(toExile, source, game, true, CardUtil.getCardExileZoneId(game, source), permanent.getIdName()); + new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility()).apply(game, source); + + return true; + } } diff --git a/Mage.Sets/src/mage/cards/a/AliveWell.java b/Mage.Sets/src/mage/cards/a/AliveWell.java index d2b9468f9ed..5c10da767e4 100644 --- a/Mage.Sets/src/mage/cards/a/AliveWell.java +++ b/Mage.Sets/src/mage/cards/a/AliveWell.java @@ -66,7 +66,7 @@ class WellEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - int life = 2 * game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int life = 2 * game.getBattlefield().count(filter, source.getControllerId(), source, game); player.gainLife(life, game, source); } return true; diff --git a/Mage.Sets/src/mage/cards/a/AllHallowsEve.java b/Mage.Sets/src/mage/cards/a/AllHallowsEve.java index eb9db02f159..1b6e2b12496 100644 --- a/Mage.Sets/src/mage/cards/a/AllHallowsEve.java +++ b/Mage.Sets/src/mage/cards/a/AllHallowsEve.java @@ -9,6 +9,7 @@ import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileSpellEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; @@ -34,10 +35,18 @@ public final class AllHallowsEve extends CardImpl { this.getSpellAbility().addEffect(new ExileSpellEffect()); this.getSpellAbility().addEffect(new AddCountersSourceEffect( CounterType.SCREAM.createInstance(), StaticValue.get(2), true, true - ).setText("with 2 scream counters on it")); + ).setText("with two scream counters on it")); - // At the beginning of your upkeep, if All Hallow's Eve is exiled with a scream counter on it, remove a scream counter from it. If there are no more scream counters on it, put it into your graveyard and each player returns all creature cards from their graveyard to the battlefield. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfUpkeepTriggeredAbility(Zone.EXILED, new AllHallowsEveEffect(), TargetController.YOU, false), AllHallowsEveCondition.instance, "At the beginning of your upkeep, if {this} is exiled with a scream counter on it, remove a scream counter from it. If there are no more scream counters on it, put it into your graveyard and each player returns all creature cards from their graveyard to the battlefield.")); + // At the beginning of your upkeep, if All Hallow's Eve is exiled with a scream counter on it, remove a scream counter from it. + // If there are no more scream counters on it, put it into your graveyard and each player returns all creature cards from their graveyard to the battlefield. + Ability ability = new BeginningOfUpkeepTriggeredAbility( + Zone.EXILED, + new RemoveCounterSourceEffect(CounterType.SCREAM.createInstance(1)), + TargetController.YOU, + false + ); + ability.addEffect(new AllHallowsEveEffect()); + this.addAbility(ability); } private AllHallowsEve(final AllHallowsEve card) { @@ -50,23 +59,12 @@ public final class AllHallowsEve extends CardImpl { } } -enum AllHallowsEveCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - MageObject sourceObject = source.getSourceObjectIfItStillExists(game); - return sourceObject != null - && game.getState().getZone(source.getSourceId()) == Zone.EXILED - && sourceObject instanceof Card - && ((Card) sourceObject).getMainCard().getCounters(game).getCount(CounterType.SCREAM) > 0; - } -} - class AllHallowsEveEffect extends OneShotEffect { AllHallowsEveEffect() { super(Outcome.PutCreatureInPlay); + staticText = "If there are no more scream counters on it, put it into your graveyard " + + "and each player returns all creature cards from their graveyard to the battlefield."; } private AllHallowsEveEffect(final AllHallowsEveEffect effect) { @@ -80,13 +78,15 @@ class AllHallowsEveEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Card card = (Card) source.getSourceObject(game); + Card allHallowsEveCard = (Card) source.getSourceObject(game); + if (allHallowsEveCard == null) { return false; } Player controller = game.getPlayer(source.getControllerId()); - if (card == null || controller == null) { - return false; - } - controller.moveCards(card, Zone.GRAVEYARD, source, game); - Cards cards = new CardsImpl(); + if (controller == null) { return false; } + + if (allHallowsEveCard.getCounters(game).getCount(CounterType.SCREAM) > 0) { return false; } + + controller.moveCards(allHallowsEveCard, Zone.GRAVEYARD, source, game); + Cards allCreatureCardsInGraveyards = new CardsImpl(); game.getState() .getPlayersInRange(source.getControllerId(), game) .stream() @@ -96,8 +96,9 @@ class AllHallowsEveEffect extends OneShotEffect { .map(g -> g.getCards(game)) .flatMap(Collection::stream) .filter(card1 -> card1.isCreature(game)) - .forEach(cards::add); - controller.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null); + .forEach(allCreatureCardsInGraveyards::add); + + controller.moveCards(allCreatureCardsInGraveyards.getCards(game), Zone.BATTLEFIELD, source, game, false, false, true, null); return true; } } diff --git a/Mage.Sets/src/mage/cards/a/AllSeeingArbiter.java b/Mage.Sets/src/mage/cards/a/AllSeeingArbiter.java new file mode 100644 index 00000000000..009e012464f --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AllSeeingArbiter.java @@ -0,0 +1,95 @@ +package mage.cards.a; + +import java.util.HashSet; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DiscardCardControllerTriggeredAbility; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.Card; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetOpponentsCreaturePermanent; + +/** + * + * @author weirddan455 + */ +public final class AllSeeingArbiter extends CardImpl { + + public AllSeeingArbiter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}"); + + this.subtype.add(SubType.AVATAR); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever All-Seeing Arbiter enters the battlefield or attacks, draw two cards, then discard a card. + this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new DrawDiscardControllerEffect(2, 1))); + + // Whenever you discard a card, target creature an opponent controls gets -X/-0 until your next turn, where X is the number of different mana values among cards in your graveyard. + Ability ability = new DiscardCardControllerTriggeredAbility(new BoostTargetEffect( + AllSeeingArbiterValue.instance, StaticValue.get(0), Duration.UntilYourNextTurn, true + ), false); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private AllSeeingArbiter(final AllSeeingArbiter card) { + super(card); + } + + @Override + public AllSeeingArbiter copy() { + return new AllSeeingArbiter(this); + } +} + +enum AllSeeingArbiterValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Player controller = game.getPlayer(sourceAbility.getControllerId()); + if (controller == null) { + return 0; + } + HashSet manaValues = new HashSet<>(); + for (UUID cardId : controller.getGraveyard()) { + Card card = game.getCard(cardId); + if (card != null) { + manaValues.add(card.getManaValue()); + } + } + return -manaValues.size(); + } + + @Override + public AllSeeingArbiterValue copy() { + return this; + } + + @Override + public String toString() { + return "-X"; + } + + @Override + public String getMessage() { + return "the number of different mana values among cards in your graveyard"; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AlleyEvasion.java b/Mage.Sets/src/mage/cards/a/AlleyEvasion.java index d7a65af78d6..af4449fefb0 100644 --- a/Mage.Sets/src/mage/cards/a/AlleyEvasion.java +++ b/Mage.Sets/src/mage/cards/a/AlleyEvasion.java @@ -26,8 +26,7 @@ public final class AlleyEvasion extends CardImpl { this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); // Return target creature you control to its owner's hand. - Mode mode = new Mode(); - mode.addEffect(new ReturnToHandTargetEffect()); + Mode mode = new Mode(new ReturnToHandTargetEffect()); mode.addTarget(new TargetControlledCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/AlliedStrategies.java b/Mage.Sets/src/mage/cards/a/AlliedStrategies.java index c91c6d71cf6..b7aa8b37b59 100644 --- a/Mage.Sets/src/mage/cards/a/AlliedStrategies.java +++ b/Mage.Sets/src/mage/cards/a/AlliedStrategies.java @@ -21,7 +21,7 @@ public final class AlliedStrategies extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{U}"); // Domain - Target player draws a card for each basic land type among lands they control. - this.getSpellAbility().addEffect(new DrawCardTargetEffect(new DomainValue(true))); + this.getSpellAbility().addEffect(new DrawCardTargetEffect(DomainValue.TARGET)); this.getSpellAbility().addTarget(new TargetPlayer()); this.getSpellAbility().setAbilityWord(AbilityWord.DOMAIN); this.getSpellAbility().addHint(DomainHint.instance); diff --git a/Mage.Sets/src/mage/cards/a/AllureOfTheUnknown.java b/Mage.Sets/src/mage/cards/a/AllureOfTheUnknown.java index ec7bd69d8f7..662e298721f 100644 --- a/Mage.Sets/src/mage/cards/a/AllureOfTheUnknown.java +++ b/Mage.Sets/src/mage/cards/a/AllureOfTheUnknown.java @@ -12,9 +12,9 @@ import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetOpponent; +import mage.util.CardUtil; import java.util.UUID; -import mage.ApprovingObject; /** * @author TheElk801 @@ -69,7 +69,7 @@ class AllureOfTheUnknownEffect extends OneShotEffect { return player.moveCards(cards, Zone.HAND, source, game); } TargetOpponent targetOpponent = new TargetOpponent(true); - if (!player.choose(outcome, targetOpponent, source.getSourceId(), game)) { + if (!player.choose(outcome, targetOpponent, source, game)) { return false; } Player opponent = game.getPlayer(targetOpponent.getFirstTarget()); @@ -85,12 +85,7 @@ class AllureOfTheUnknownEffect extends OneShotEffect { cards.remove(card); } player.moveCards(cards, Zone.HAND, source, game); - if (opponent.chooseUse(outcome, "Cast the exiled card without paying its mana cost?", source, game)) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - opponent.cast(opponent.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - } + CardUtil.castSpellWithAttributesForFree(opponent, source, game, card); return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/a/Alms.java b/Mage.Sets/src/mage/cards/a/Alms.java index db16df42257..bf6b4c84e4e 100644 --- a/Mage.Sets/src/mage/cards/a/Alms.java +++ b/Mage.Sets/src/mage/cards/a/Alms.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.ExileTopCardOfGraveyardCost; @@ -11,21 +9,23 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Zone; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class Alms extends CardImpl { public Alms(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); // {1}, Exile the top card of your graveyard: Prevent the next 1 damage that would be dealt to target creature this turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageToTargetEffect(Duration.EndOfTurn, 1), new GenericManaCost(1)); - ability.addCost(new ExileTopCardOfGraveyardCost(1)); + Ability ability = new SimpleActivatedAbility( + new PreventDamageToTargetEffect(Duration.EndOfTurn, 1), new GenericManaCost(1) + ); + ability.addCost(new ExileTopCardOfGraveyardCost()); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AlmsOfTheVein.java b/Mage.Sets/src/mage/cards/a/AlmsOfTheVein.java index 4a8a016a147..54136ba48d3 100644 --- a/Mage.Sets/src/mage/cards/a/AlmsOfTheVein.java +++ b/Mage.Sets/src/mage/cards/a/AlmsOfTheVein.java @@ -25,7 +25,7 @@ public final class AlmsOfTheVein extends CardImpl { this.getSpellAbility().addTarget(new TargetOpponent()); // Madness {B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{B}"))); } private AlmsOfTheVein(final AlmsOfTheVein card) { diff --git a/Mage.Sets/src/mage/cards/a/AlpineHoundmaster.java b/Mage.Sets/src/mage/cards/a/AlpineHoundmaster.java index fa9269902e5..13cab130e38 100644 --- a/Mage.Sets/src/mage/cards/a/AlpineHoundmaster.java +++ b/Mage.Sets/src/mage/cards/a/AlpineHoundmaster.java @@ -1,25 +1,24 @@ package mage.cards.a; import mage.MageInt; -import mage.MageObject; -import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.cards.*; -import mage.constants.*; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.common.FilterAttackingCreature; import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.game.Game; -import mage.players.Player; -import mage.target.common.TargetCardInLibrary; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.target.common.TargetCardWithDifferentNameInLibrary; import java.util.UUID; @@ -29,9 +28,15 @@ import java.util.UUID; public final class AlpineHoundmaster extends CardImpl { private static final FilterAttackingCreature filter = new FilterAttackingCreature("other attacking creatures"); + private static final FilterCard filter2 + = new FilterCard("card named Alpine Watchdog and/or a card named Igneous Cur"); static { filter.add(AnotherPredicate.instance); + filter2.add(Predicates.or( + new NamePredicate("Alpine Watchdog"), + new NamePredicate("Igneous Cur") + )); } private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter, null); @@ -45,10 +50,14 @@ public final class AlpineHoundmaster extends CardImpl { this.toughness = new MageInt(2); // When Alpine Houndmaster enters the battlefield, you may search your library for a card named Alpine Watchdog and/or a card named Igneous Cur, reveal them, put them into your hand, then shuffle your library. - this.addAbility(new EntersBattlefieldTriggeredAbility(new AlpineHoundmasterEffect(), true)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect( + new TargetCardWithDifferentNameInLibrary(0, 2, filter2), true, true + ).setText("search your library for a card named Alpine Watchdog and/or a card named Igneous Cur, reveal them, put them into your hand, then shuffle"), true)); // Whenever Alpine Houndmaster attacks, it gets +X/+0 until end of turn, where X is the number of other attacking creatures. - this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(xValue, StaticValue.get(0), Duration.EndOfTurn, true, "it"), false)); + this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect( + xValue, StaticValue.get(0), Duration.EndOfTurn, true, "it" + ), false)); } private AlpineHoundmaster(final AlpineHoundmaster card) { @@ -60,78 +69,3 @@ public final class AlpineHoundmaster extends CardImpl { return new AlpineHoundmaster(this); } } - -class AlpineHoundmasterEffect extends OneShotEffect { - - AlpineHoundmasterEffect() { - super(Outcome.Benefit); - staticText = "search your library for a card named Alpine Watchdog and/or a card named Igneous Cur, " + - "reveal them, put them into your hand, then shuffle"; - } - - private AlpineHoundmasterEffect(final AlpineHoundmasterEffect effect) { - super(effect); - } - - @Override - public AlpineHoundmasterEffect copy() { - return new AlpineHoundmasterEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - TargetCardInLibrary target = new AlpineHoundmasterTarget(); - player.searchLibrary(target, source, game); - Cards cards = new CardsImpl(target.getTargets()); - player.revealCards(source, cards, game); - player.moveCards(cards, Zone.HAND, source, game); - player.shuffleLibrary(source, game); - return true; - } -} - -class AlpineHoundmasterTarget extends TargetCardInLibrary { - - private static final FilterCard filter - = new FilterCard("card named Alpine Watchdog and/or a card named Igneous Cur"); - - static { - filter.add(Predicates.or( - new NamePredicate("Alpine Watchdog"), - new NamePredicate("Igneous Cur") - )); - } - - AlpineHoundmasterTarget() { - super(0, 2, filter); - } - - private AlpineHoundmasterTarget(final AlpineHoundmasterTarget target) { - super(target); - } - - @Override - public AlpineHoundmasterTarget copy() { - return new AlpineHoundmasterTarget(this); - } - - @Override - public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (!super.canTarget(controllerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - if (card == null) { - return false; - } - return this.getTargets() - .stream() - .map(game::getCard) - .map(MageObject::getName) - .noneMatch(card.getName()::equals); - } -} diff --git a/Mage.Sets/src/mage/cards/a/AlrundGodOfTheCosmos.java b/Mage.Sets/src/mage/cards/a/AlrundGodOfTheCosmos.java index 35b4748f591..73f77296623 100644 --- a/Mage.Sets/src/mage/cards/a/AlrundGodOfTheCosmos.java +++ b/Mage.Sets/src/mage/cards/a/AlrundGodOfTheCosmos.java @@ -50,7 +50,7 @@ public final class AlrundGodOfTheCosmos extends ModalDoubleFacesCard { // Alrund gets +1/+1 for each card in your hand and each foretold card you own in exile. Effect effect = new BoostSourceEffect(AlrundGodOfTheCosmosValue.instance, AlrundGodOfTheCosmosValue.instance, Duration.EndOfGame); - effect.setText("Alrund gets +1/+1 for each card in your hand and each foretold card you own in exile."); + effect.setText("{this} gets +1/+1 for each card in your hand and each foretold card you own in exile."); Ability ability = new SimpleStaticAbility(effect); this.getLeftHalfCard().addAbility(ability); @@ -89,7 +89,7 @@ class AlrundGodOfTheCosmosEffect extends OneShotEffect { public AlrundGodOfTheCosmosEffect() { super(Outcome.Neutral); - staticText = ", then reveal the top two cards of your library. Put all cards revealed this way of the chosen type into your hand and the rest on the bottom of your library in any order"; + staticText = ", then reveal the top two cards of your library. Put all cards of the chosen type revealed this way into your hand and the rest on the bottom of your library in any order"; } public AlrundGodOfTheCosmosEffect(final AlrundGodOfTheCosmosEffect effect) { diff --git a/Mage.Sets/src/mage/cards/a/AlrundsEpiphany.java b/Mage.Sets/src/mage/cards/a/AlrundsEpiphany.java index 9a3b9216d56..bf9a33a0930 100644 --- a/Mage.Sets/src/mage/cards/a/AlrundsEpiphany.java +++ b/Mage.Sets/src/mage/cards/a/AlrundsEpiphany.java @@ -7,7 +7,7 @@ import mage.abilities.keyword.ForetellAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.game.permanent.token.OwlToken; +import mage.game.permanent.token.BlueBirdToken; import java.util.UUID; @@ -20,7 +20,7 @@ public final class AlrundsEpiphany extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{5}{U}{U}"); // Create two 1/1 blue Bird creature tokens with flying. Take an extra turn after this one. Exile Alrund's Epiphany. - this.getSpellAbility().addEffect(new CreateTokenEffect(new OwlToken(), 2)); + this.getSpellAbility().addEffect(new CreateTokenEffect(new BlueBirdToken(), 2)); this.getSpellAbility().addEffect(new AddExtraTurnControllerEffect()); this.getSpellAbility().addEffect(new ExileSpellEffect()); diff --git a/Mage.Sets/src/mage/cards/a/AltarOfTheGoyf.java b/Mage.Sets/src/mage/cards/a/AltarOfTheGoyf.java index a590ba3de37..35d094861fc 100644 --- a/Mage.Sets/src/mage/cards/a/AltarOfTheGoyf.java +++ b/Mage.Sets/src/mage/cards/a/AltarOfTheGoyf.java @@ -36,7 +36,7 @@ public final class AltarOfTheGoyf extends CardImpl { CardTypesInGraveyardCount.ALL, Duration.EndOfTurn, true ).setText("it gets +X/+X until end of turn, where X is " + - "the number of card types among cards in all graveyards.")).addHint(CardTypesInGraveyardHint.ALL)); + "the number of card types among cards in all graveyards."), true, false).addHint(CardTypesInGraveyardHint.ALL)); // Lhurgoyf creatures you control have trample. this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( diff --git a/Mage.Sets/src/mage/cards/a/AltarOfTheLost.java b/Mage.Sets/src/mage/cards/a/AltarOfTheLost.java index 8b674e5c8e1..a014e2343e6 100644 --- a/Mage.Sets/src/mage/cards/a/AltarOfTheLost.java +++ b/Mage.Sets/src/mage/cards/a/AltarOfTheLost.java @@ -71,8 +71,8 @@ class AltarOfTheLostManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { MageObject object = game.getObject(source.getSourceId()); - if (game != null && game.inCheckPlayableState()) { - if (object instanceof Card && game.getState().getZone(source.getSourceId()).equals(Zone.GRAVEYARD)) { + if (game.inCheckPlayableState()) { + if (object instanceof Card && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) { for (Ability ability : ((Card) object).getAbilities(game)) { if (ability instanceof FlashbackAbility) { return true; diff --git a/Mage.Sets/src/mage/cards/a/AmbuscadeShaman.java b/Mage.Sets/src/mage/cards/a/AmbuscadeShaman.java index 65390caee24..5fe3acac163 100644 --- a/Mage.Sets/src/mage/cards/a/AmbuscadeShaman.java +++ b/Mage.Sets/src/mage/cards/a/AmbuscadeShaman.java @@ -35,7 +35,7 @@ public final class AmbuscadeShaman extends CardImpl { )); // Dash {3}{B} (You may cast this spell for its dash cost. If you do, it gains haste, and it's returned from the battlefield to its owner's hand at the beginning of the next end step.)); - this.addAbility(new DashAbility(this, "{3}{B}")); + this.addAbility(new DashAbility("{3}{B}")); } private AmbuscadeShaman(final AmbuscadeShaman card) { diff --git a/Mage.Sets/src/mage/cards/a/AminatouTheFateshifter.java b/Mage.Sets/src/mage/cards/a/AminatouTheFateshifter.java index 9125e8fc0f8..6d346dc5f56 100644 --- a/Mage.Sets/src/mage/cards/a/AminatouTheFateshifter.java +++ b/Mage.Sets/src/mage/cards/a/AminatouTheFateshifter.java @@ -3,7 +3,6 @@ package mage.cards.a; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetForSourceEffect; @@ -46,7 +45,7 @@ public class AminatouTheFateshifter extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.AMINATOU); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Draw a card, then put a card from your hand on top of your library. Ability ability = new LoyaltyAbility(new AminatouPlusEffect(), +1); @@ -106,7 +105,7 @@ class AminatouPlusEffect extends OneShotEffect { private boolean putOnLibrary(Player player, Ability source, Game game) { TargetCardInHand target = new TargetCardInHand(); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.ReturnToHand, target, source, game); Card card = player.getHand().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/a/AminatousAugury.java b/Mage.Sets/src/mage/cards/a/AminatousAugury.java index 53f6bb3a638..25cb90a5c7a 100644 --- a/Mage.Sets/src/mage/cards/a/AminatousAugury.java +++ b/Mage.Sets/src/mage/cards/a/AminatousAugury.java @@ -37,7 +37,8 @@ public class AminatousAugury extends CardImpl { public AminatousAugury(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{6}{U}{U}"); - // Exile the top eight cards of your library. You may put a land card from among them onto the battlefield. + // Exile the top eight cards of your library. + // You may put a land card from among them onto the battlefield. // Until end of turn, for each nonland card type, you may cast a card of that type from among the exiled cards // without paying its mana cost. this.getSpellAbility().addEffect(new AminatousAuguryEffect()); @@ -58,9 +59,10 @@ class AminatousAuguryEffect extends OneShotEffect { public AminatousAuguryEffect() { super(Outcome.PlayForFree); - staticText = "Exile the top eight cards of your library. You may put a land card from among them onto the" - + " battlefield. Until end of turn, for each nonland card type, you may cast a card of that type from" - + " among the exiled cards without paying its mana cost."; + staticText = "Exile the top eight cards of your library. " + + "You may put a land card from among them onto the battlefield. " + + "Until end of turn, for each nonland card type, " + + "you may cast a card of that type from among the exiled cards without paying its mana cost."; } public AminatousAuguryEffect(final AminatousAuguryEffect effect) { @@ -74,41 +76,42 @@ class AminatousAuguryEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { - // move cards from library to exile - controller.moveCardsToExile(controller.getLibrary().getTopCards(game, 8), source, game, true, source.getSourceId(), CardUtil.createObjectRealtedWindowTitle(source, game, null)); - ExileZone auguryExileZone = game.getExile().getExileZone(source.getSourceId()); - if (auguryExileZone == null) { - return true; - } - Cards cardsToCast = new CardsImpl(); - cardsToCast.addAll(auguryExileZone.getCards(game)); - // put a land card from among them onto the battlefield - TargetCard target = new TargetCard( - Zone.EXILED, - StaticFilters.FILTER_CARD_LAND_A - ); - if (cardsToCast.count(StaticFilters.FILTER_CARD_LAND, game) > 0) { - if (controller.chooseUse(Outcome.PutLandInPlay, "Put a land from among the exiled cards into play?", source, game)) { - if (controller.choose(Outcome.PutLandInPlay, cardsToCast, target, game)) { - Card card = cardsToCast.get(target.getFirstTarget(), game); - if (card != null) { - cardsToCast.remove(card); - controller.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null); - } - } + if (sourceObject == null) { return false; } + + // move cards from library to exile + controller.moveCardsToExile(controller.getLibrary().getTopCards(game, 8), source, game, true, source.getSourceId(), CardUtil.createObjectRealtedWindowTitle(source, game, null)); + ExileZone auguryExileZone = game.getExile().getExileZone(source.getSourceId()); + if (auguryExileZone == null) { return true; } + + Cards cardsToCast = new CardsImpl(); + cardsToCast.addAll(auguryExileZone.getCards(game)); + + // put a land card from among them onto the battlefield + TargetCard target = new TargetCard(Zone.EXILED, StaticFilters.FILTER_CARD_LAND_A); + + if (cardsToCast.count(StaticFilters.FILTER_CARD_LAND, game) == 0) { return true; } + + if (controller.chooseUse(Outcome.PutLandInPlay, "Put a land from among the exiled cards into play?", source, game)) { + if (controller.choose(Outcome.PutLandInPlay, cardsToCast, target, game)) { + Card card = cardsToCast.get(target.getFirstTarget(), game); + if (card != null) { + cardsToCast.remove(card); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null); } } - for (Card card : cardsToCast.getCards(StaticFilters.FILTER_CARD_NON_LAND, game)) { - AminatousAuguryCastFromExileEffect effect = new AminatousAuguryCastFromExileEffect(); - effect.setTargetPointer(new FixedTarget(card, game)); - game.addEffect(effect, source); - } } - return false; + + for (Card card : cardsToCast.getCards(StaticFilters.FILTER_CARD_NON_LAND, game)) { + AminatousAuguryCastFromExileEffect effect = new AminatousAuguryCastFromExileEffect(); + effect.setTargetPointer(new FixedTarget(card, game)); + game.addEffect(effect, source); + } + // TODO: I think this should be returning true + return true; } } @@ -136,51 +139,54 @@ class AminatousAuguryCastFromExileEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { Player player = game.getPlayer(affectedControllerId); - EnumSet usedCardTypes = EnumSet.noneOf(CardType.class); + if (player == null) { return false; } - if (game.getState().getValue(source.getSourceId().toString() + "cardTypes") != null) { + if (!affectedControllerId.equals(source.getControllerId())) { return false; } + + EnumSet usedCardTypes; + if (game.getState().getValue(source.getSourceId().toString() + "cardTypes") == null) { + // The effect has not been applied fully yet, so there are no previously cast times + usedCardTypes = EnumSet.noneOf(CardType.class); + } else { usedCardTypes = (EnumSet) game.getState().getValue(source.getSourceId().toString() + "cardTypes"); } - if (player != null - && objectId != null - && objectId.equals(getTargetPointer().getFirst(game, source)) - && affectedControllerId.equals(source.getControllerId())) { - Card card = game.getCard(objectId); - if (card != null - && game.getState().getZone(objectId) == Zone.EXILED) { - EnumSet unusedCardTypes = EnumSet.noneOf(CardType.class); - for (CardType cardT : card.getCardType(game)) { - if (!usedCardTypes.contains(cardT)) { - unusedCardTypes.add(cardT); - } - } - if (!unusedCardTypes.isEmpty()) { - if (!game.inCheckPlayableState()) { // some actions may not be done while the game only checks if a card can be cast - // Select the card type to consume and remove all not seleczted card types - if (unusedCardTypes.size() > 1) { - Choice choice = new ChoiceImpl(true); - choice.setMessage("Which card type do you want to consume?"); - Set choices = choice.getChoices(); - for (CardType cardType : unusedCardTypes) { - choices.add(cardType.toString()); - } - player.choose(Outcome.Detriment, choice, game); - for (Iterator iterator = unusedCardTypes.iterator(); iterator.hasNext();) { - CardType next = iterator.next(); - if (!next.toString().equals(choice.getChoice())) { - iterator.remove(); - } - } - usedCardTypes.add(CardType.fromString(choice.getChoice())); - } - usedCardTypes.addAll(unusedCardTypes); - game.getState().setValue(source.getSourceId().toString() + "cardTypes", usedCardTypes); - } - player.setCastSourceIdWithAlternateMana(objectId, null, card.getSpellAbility().getCosts()); - return true; - } + + if (objectId == null || !objectId.equals(getTargetPointer().getFirst(game, source))) { return false; } + + if (game.getState().getZone(objectId) != Zone.EXILED) { return false; } + + Card card = game.getCard(objectId); + if (card == null) { return false; } + + // Figure out which of the current card's types have not been cast before + EnumSet unusedCardTypes = EnumSet.noneOf(CardType.class); + for (CardType cardT : card.getCardType(game)) { + if (!usedCardTypes.contains(cardT)) { + unusedCardTypes.add(cardT); } } - return false; + + // The current card has only card types that have been cast before, so it can't be cast + if (unusedCardTypes.isEmpty()) { return false; } + + // some actions may not be done while the game only checks if a card can be cast + if (!game.inCheckPlayableState()) { + // Select the card type to consume and remove all not selected card types + if (unusedCardTypes.size() > 1) { + Choice choice = new ChoiceImpl(true); + choice.setMessage("Which card type do you want to consume?"); + Set choices = choice.getChoices(); + for (CardType cardType : unusedCardTypes) { + choices.add(cardType.toString()); + } + player.choose(Outcome.Detriment, choice, game); + unusedCardTypes.removeIf(next -> !next.toString().equals(choice.getChoice())); + usedCardTypes.add(CardType.fromString(choice.getChoice())); + } + usedCardTypes.addAll(unusedCardTypes); + game.getState().setValue(source.getSourceId().toString() + "cardTypes", usedCardTypes); + } + player.setCastSourceIdWithAlternateMana(objectId, null, card.getSpellAbility().getCosts()); + return true; } } diff --git a/Mage.Sets/src/mage/cards/a/AmuletOfSafekeeping.java b/Mage.Sets/src/mage/cards/a/AmuletOfSafekeeping.java index 00e7a996f11..92ff67533d3 100644 --- a/Mage.Sets/src/mage/cards/a/AmuletOfSafekeeping.java +++ b/Mage.Sets/src/mage/cards/a/AmuletOfSafekeeping.java @@ -82,7 +82,7 @@ class AmuletOfSafekeepingTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); if (event.getTargetId().equals(getControllerId()) - && filter.match(stackObject, getSourceId(), getControllerId(), game)) { + && filter.match(stackObject, getControllerId(), this, game)) { for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(stackObject.getId(), game)); } diff --git a/Mage.Sets/src/mage/cards/a/AmuletOfVigor.java b/Mage.Sets/src/mage/cards/a/AmuletOfVigor.java index 03058860c26..383366fa4f1 100644 --- a/Mage.Sets/src/mage/cards/a/AmuletOfVigor.java +++ b/Mage.Sets/src/mage/cards/a/AmuletOfVigor.java @@ -13,6 +13,7 @@ import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; import mage.util.GameLog; +import java.util.Optional; import java.util.UUID; /** @@ -75,10 +76,12 @@ class AmuletOfVigorTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { // that triggers depends on stack order, so make each trigger unique with extra info - String triggeredInfo = ""; - if (this.getEffects().get(0).getTargetPointer() != null) { - triggeredInfo = " Triggered permanent: " + this.getEffects().get(0).getTargetPointer().getData("triggeredName") + "."; - } - return "Whenever a permanent enters the battlefield tapped and under your control, untap it." + triggeredInfo; + return "Whenever a permanent enters the battlefield tapped and under your control, untap it." + + Optional + .of(this.getEffects().get(0).getTargetPointer()) + .map(targetPointer -> targetPointer.getData("triggeredName")) + .filter(s -> s != null && !s.isEmpty()) + .map(s -> " Triggered permanent: " + s) + .orElse(""); } } diff --git a/Mage.Sets/src/mage/cards/a/AnHavvaConstable.java b/Mage.Sets/src/mage/cards/a/AnHavvaConstable.java index 1daa50c5130..98d3da2f8a6 100644 --- a/Mage.Sets/src/mage/cards/a/AnHavvaConstable.java +++ b/Mage.Sets/src/mage/cards/a/AnHavvaConstable.java @@ -61,16 +61,17 @@ class AnHavvaConstableEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - MageObject mageObject = game.getObject(source.getSourceId()); - if (mageObject != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("green creatures"); - filter.add(new ColorPredicate(ObjectColor.GREEN)); - int number = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); - mageObject.getToughness().setValue(number + 1); - return true; - } - } - return false; + if (controller == null) { return false; } + + MageObject mageObject = game.getObject(source.getSourceId()); + if (mageObject == null) { return false; } + + FilterCreaturePermanent filter = new FilterCreaturePermanent("green creatures"); + filter.add(new ColorPredicate(ObjectColor.GREEN)); + int numberOfGreenCreatures = game.getBattlefield().count(filter, source.getSourceId(), source, game); + + mageObject.getToughness().setValue(1 + numberOfGreenCreatures); + + return true; } } diff --git a/Mage.Sets/src/mage/cards/a/AnHavvaInn.java b/Mage.Sets/src/mage/cards/a/AnHavvaInn.java index 0d81cc7e55a..ffab9055d57 100644 --- a/Mage.Sets/src/mage/cards/a/AnHavvaInn.java +++ b/Mage.Sets/src/mage/cards/a/AnHavvaInn.java @@ -59,7 +59,7 @@ class AnHavvaInnEffect extends OneShotEffect { if (player != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent("green creatures"); filter.add(new ColorPredicate(ObjectColor.GREEN)); - int greenCreatures = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int greenCreatures = game.getBattlefield().count(filter, source.getControllerId(), source, game); player.gainLife(greenCreatures+1, game, source); } return true; diff --git a/Mage.Sets/src/mage/cards/a/AnOfferYouCantRefuse.java b/Mage.Sets/src/mage/cards/a/AnOfferYouCantRefuse.java new file mode 100644 index 00000000000..37ee35918ea --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AnOfferYouCantRefuse.java @@ -0,0 +1,66 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.token.TreasureToken; +import mage.game.stack.Spell; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AnOfferYouCantRefuse extends CardImpl { + + public AnOfferYouCantRefuse(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); + + // Counter target noncreature spell. Its controller creates two Treasure tokens. + this.getSpellAbility().addEffect(new AnOfferYouCantRefuseEffect()); + this.getSpellAbility().addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_NON_CREATURE)); + } + + private AnOfferYouCantRefuse(final AnOfferYouCantRefuse card) { + super(card); + } + + @Override + public AnOfferYouCantRefuse copy() { + return new AnOfferYouCantRefuse(this); + } +} + +class AnOfferYouCantRefuseEffect extends OneShotEffect { + + AnOfferYouCantRefuseEffect() { + super(Outcome.Benefit); + staticText = "counter target noncreature spell. Its controller creates two Treasure tokens"; + } + + private AnOfferYouCantRefuseEffect(final AnOfferYouCantRefuseEffect effect) { + super(effect); + } + + @Override + public AnOfferYouCantRefuseEffect copy() { + return new AnOfferYouCantRefuseEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = game.getSpell(getTargetPointer().getFirst(game, source)); + if (spell == null) { + return false; + } + game.getStack().counter(spell.getId(), source, game);; + new TreasureToken().putOntoBattlefield(2, game, source, spell.getControllerId()); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/a/Anathemancer.java b/Mage.Sets/src/mage/cards/a/Anathemancer.java index be2db64c8e7..5785ab161bc 100644 --- a/Mage.Sets/src/mage/cards/a/Anathemancer.java +++ b/Mage.Sets/src/mage/cards/a/Anathemancer.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -14,33 +12,35 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.SuperType; -import mage.filter.common.FilterLandPermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author North */ public final class Anathemancer extends CardImpl { public Anathemancer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{R}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.WIZARD); - + this.power = new MageInt(2); this.toughness = new MageInt(2); // When Anathemancer enters the battlefield, it deals damage to target player equal to the number of nonbasic lands that player controls. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(new AnathemancerCount(), "it")); + EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility( + new DamageTargetEffect(AnathemancerCount.instance, "it") + .setText("it deals damage to target player equal to the number of nonbasic lands that player controls") + ); ability.addTarget(new TargetPlayer()); this.addAbility(ability); + // Unearth {5}{B}{R} - this.addAbility(new UnearthAbility(new ManaCostsImpl("{5}{B}{R}"))); + this.addAbility(new UnearthAbility(new ManaCostsImpl<>("{5}{B}{R}"))); } private Anathemancer(final Anathemancer card) { @@ -53,29 +53,29 @@ public final class Anathemancer extends CardImpl { } } -class AnathemancerCount implements DynamicValue { +enum AnathemancerCount implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { if (sourceAbility.getFirstTarget() == null) { return 0; } - - FilterLandPermanent filter = new FilterLandPermanent(); - filter.add(Predicates.not(SuperType.BASIC.getPredicate())); - filter.add(new ControllerIdPredicate(sourceAbility.getFirstTarget())); - - return game.getBattlefield().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + return game.getBattlefield().count( + StaticFilters.FILTER_LANDS_NONBASIC, + sourceAbility.getControllerId(), + sourceAbility, game + ); } @Override public AnathemancerCount copy() { - return new AnathemancerCount(); + return this; } @Override public String toString() { - return "1"; + return ""; } @Override diff --git a/Mage.Sets/src/mage/cards/a/AncestralMemories.java b/Mage.Sets/src/mage/cards/a/AncestralMemories.java index 031b0d8afdc..74f1b83ba39 100644 --- a/Mage.Sets/src/mage/cards/a/AncestralMemories.java +++ b/Mage.Sets/src/mage/cards/a/AncestralMemories.java @@ -1,12 +1,10 @@ package mage.cards.a; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import java.util.UUID; @@ -19,8 +17,7 @@ public final class AncestralMemories extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}{U}{U}"); // Look at the top seven cards of your library. Put two of them into your hand and the rest into your graveyard. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(7), false, StaticValue.get(2), - StaticFilters.FILTER_CARD, Zone.GRAVEYARD, false, false, false, Zone.HAND, false)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(7, 2, PutCards.HAND, PutCards.GRAVEYARD)); } private AncestralMemories(final AncestralMemories card) { @@ -31,4 +28,4 @@ public final class AncestralMemories extends CardImpl { public AncestralMemories copy() { return new AncestralMemories(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/a/AncestralVision.java b/Mage.Sets/src/mage/cards/a/AncestralVision.java index a87862eb530..ee92ec5bb4a 100644 --- a/Mage.Sets/src/mage/cards/a/AncestralVision.java +++ b/Mage.Sets/src/mage/cards/a/AncestralVision.java @@ -22,7 +22,7 @@ public final class AncestralVision extends CardImpl { this.color.setBlue(true); // Suspend 4-{U} - this.addAbility(new SuspendAbility(4, new ManaCostsImpl("U"), this)); + this.addAbility(new SuspendAbility(4, new ManaCostsImpl<>("{U}"), this)); // Target player draws three cards. this.getSpellAbility().addTarget(new TargetPlayer()); this.getSpellAbility().addEffect(new DrawCardTargetEffect(3)); diff --git a/Mage.Sets/src/mage/cards/a/AncientBrassDragon.java b/Mage.Sets/src/mage/cards/a/AncientBrassDragon.java new file mode 100644 index 00000000000..78fd2a68fdd --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AncientBrassDragon.java @@ -0,0 +1,88 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AncientBrassDragon extends CardImpl { + + public AncientBrassDragon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}"); + + this.subtype.add(SubType.ELDER); + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(7); + this.toughness = new MageInt(6); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Ancient Brass Dragon deals combat damage to a player, roll a d20. When you do, put any number of target creature cards with mana value X or less from graveyards onto the battlefield under your control, where X is the result. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new AncientBrassDragonEffect(), false)); + } + + private AncientBrassDragon(final AncientBrassDragon card) { + super(card); + } + + @Override + public AncientBrassDragon copy() { + return new AncientBrassDragon(this); + } +} + +class AncientBrassDragonEffect extends OneShotEffect { + + AncientBrassDragonEffect() { + super(Outcome.Benefit); + staticText = "roll a d20. When you do, put any number of target creature cards with mana value X " + + "or less from graveyards onto the battlefield under your control, where X is the result"; + } + + private AncientBrassDragonEffect(final AncientBrassDragonEffect effect) { + super(effect); + } + + @Override + public AncientBrassDragonEffect copy() { + return new AncientBrassDragonEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int result = player.rollDice(outcome, source, game, 20); + FilterCard filter = new FilterCreatureCard("creature cards with mana value " + result + " or less"); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, result)); + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect(), false + ); + ability.addTarget(new TargetCardInGraveyard(0, Integer.MAX_VALUE, filter)); + game.fireReflexiveTriggeredAbility(ability, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AncientStirrings.java b/Mage.Sets/src/mage/cards/a/AncientStirrings.java index b3ca0d48bec..137ad672c1b 100644 --- a/Mage.Sets/src/mage/cards/a/AncientStirrings.java +++ b/Mage.Sets/src/mage/cards/a/AncientStirrings.java @@ -1,14 +1,11 @@ - - package mage.cards.a; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.ColorlessPredicate; @@ -23,15 +20,12 @@ public final class AncientStirrings extends CardImpl { filter.add(ColorlessPredicate.instance); } - public AncientStirrings(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{G}"); // Look at the top five cards of your library. You may reveal a colorless card from among them and put it into your hand. // Then put the rest on the bottom of your library in any order. (Cards with no colored mana in their mana costs are colorless. Lands are also colorless.) - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(5), false, StaticValue.get(1), filter, Zone.LIBRARY, - false, true, false, Zone.HAND, true)); - + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(5, 1, filter, PutCards.HAND, PutCards.BOTTOM_ANY)); } private AncientStirrings(final AncientStirrings card) { @@ -42,5 +36,4 @@ public final class AncientStirrings extends CardImpl { public AncientStirrings copy() { return new AncientStirrings(this); } - } diff --git a/Mage.Sets/src/mage/cards/a/AngelOfCondemnation.java b/Mage.Sets/src/mage/cards/a/AngelOfCondemnation.java index d1740013eb4..37f3d1bdce0 100644 --- a/Mage.Sets/src/mage/cards/a/AngelOfCondemnation.java +++ b/Mage.Sets/src/mage/cards/a/AngelOfCondemnation.java @@ -8,7 +8,6 @@ import mage.abilities.common.delayed.OnLeaveReturnExiledToBattlefieldAbility; import mage.abilities.costs.common.ExertSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; @@ -56,15 +55,19 @@ public final class AngelOfCondemnation extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // {2}{W}, {T}: Exile another target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AngelOfCondemnationExileUntilEOTEffect(), new ManaCostsImpl<>("{2}{W}")); + Ability ability = new SimpleActivatedAbility( + new AngelOfCondemnationExileUntilEOTEffect(), new ManaCostsImpl<>("{2}{W}") + ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); // {2}{W}, {T}, Exert Angel of Condemnation: Exile another target creature until Angel of Condemnation leaves the battlefield. - Effect effect = new ExileUntilSourceLeavesEffect(""); - effect.setText("Exile another target creature until {this} leaves the battlefield"); - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{2}{W}")); + ability = new SimpleActivatedAbility( + new ExileUntilSourceLeavesEffect("") + .setText("Exile another target creature until {this} leaves the battlefield"), + new ManaCostsImpl<>("{2}{W}") + ); ability.addCost(new TapSourceCost()); ability.addCost(new ExertSourceCost()); ability.addTarget(new TargetCreaturePermanent(filter)); @@ -86,10 +89,11 @@ class AngelOfCondemnationExileUntilEOTEffect extends OneShotEffect { AngelOfCondemnationExileUntilEOTEffect() { super(Outcome.Detriment); - staticText = "exile another target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step"; + staticText = "exile another target creature. Return that card to the battlefield " + + "under its owner's control at the beginning of the next end step"; } - AngelOfCondemnationExileUntilEOTEffect(final AngelOfCondemnationExileUntilEOTEffect effect) { + private AngelOfCondemnationExileUntilEOTEffect(final AngelOfCondemnationExileUntilEOTEffect effect) { super(effect); } @@ -97,18 +101,17 @@ class AngelOfCondemnationExileUntilEOTEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (controller != null && permanent != null && sourcePermanent != null) { - if (controller.moveCardToExileWithInfo(permanent, source.getSourceId(), sourcePermanent.getIdName(), source, game, Zone.BATTLEFIELD, true)) { - //create delayed triggered ability - Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false); - effect.setText("return that card to the battlefield under its owner's control"); - effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game)); - game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source); - return true; - } + if (controller == null || permanent == null) { + return false; } - return false; + controller.moveCards(permanent, Zone.EXILED, source, game); + //create delayed triggered ability + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false) + .setText("return that card to the battlefield under its owner's control") + .setTargetPointer(new FixedTarget(source.getFirstTarget(), game)) + ), source); + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/a/AngelOfGlorysRise.java b/Mage.Sets/src/mage/cards/a/AngelOfGlorysRise.java index c8df87128b5..0b663bb191c 100644 --- a/Mage.Sets/src/mage/cards/a/AngelOfGlorysRise.java +++ b/Mage.Sets/src/mage/cards/a/AngelOfGlorysRise.java @@ -72,7 +72,7 @@ class AngelOfGlorysRiseEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Set toExile = new HashSet<>(game.getBattlefield() - .getActivePermanents(new FilterCreaturePermanent(SubType.ZOMBIE, "Zombie"), source.getControllerId(), source.getSourceId(), game)); + .getActivePermanents(new FilterCreaturePermanent(SubType.ZOMBIE, "Zombie"), source.getControllerId(), source, game)); controller.moveCards(toExile, Zone.EXILED, source, game); FilterCreatureCard filterHuman = new FilterCreatureCard(); filterHuman.add(SubType.HUMAN.getPredicate()); diff --git a/Mage.Sets/src/mage/cards/a/AngelOfSerenity.java b/Mage.Sets/src/mage/cards/a/AngelOfSerenity.java index 57d4f570450..f57e5744962 100644 --- a/Mage.Sets/src/mage/cards/a/AngelOfSerenity.java +++ b/Mage.Sets/src/mage/cards/a/AngelOfSerenity.java @@ -13,7 +13,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.target.common.TargetCardInGraveyardOrBattlefield; +import mage.target.common.TargetCardInGraveyardBattlefieldOrStack; import java.util.UUID; import mage.filter.common.FilterCreatureCard; @@ -49,7 +49,7 @@ public final class AngelOfSerenity extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility( new ExileTargetForSourceEffect().setText(rule), true ); - ability.addTarget(new TargetCardInGraveyardOrBattlefield( + ability.addTarget(new TargetCardInGraveyardBattlefieldOrStack( 0, 3, filterCreatureCard, filterCreaturePermanent )); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/AngelOfSuffering.java b/Mage.Sets/src/mage/cards/a/AngelOfSuffering.java new file mode 100644 index 00000000000..f9e1a194ec9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AngelOfSuffering.java @@ -0,0 +1,86 @@ +package mage.cards.a; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; + +/** + * + * @author weirddan455 + */ +public final class AngelOfSuffering extends CardImpl { + + public AngelOfSuffering(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + + this.subtype.add(SubType.NIGHTMARE); + this.subtype.add(SubType.ANGEL); + this.power = new MageInt(5); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // If damage would be dealt to you, prevent that damage and mill twice that many cards. + this.addAbility(new SimpleStaticAbility(new AngelOfSufferingEffect())); + } + + private AngelOfSuffering(final AngelOfSuffering card) { + super(card); + } + + @Override + public AngelOfSuffering copy() { + return new AngelOfSuffering(this); + } +} + +class AngelOfSufferingEffect extends ReplacementEffectImpl { + + public AngelOfSufferingEffect() { + super(Duration.WhileOnBattlefield, Outcome.PreventDamage); + this.staticText = "If damage would be dealt to you, prevent that damage and mill twice that many cards"; + } + + private AngelOfSufferingEffect(final AngelOfSufferingEffect effect) { + super(effect); + } + + @Override + public AngelOfSufferingEffect copy() { + return new AngelOfSufferingEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + int cardsToMill = event.getAmount() * 2; + game.preventDamage(event, source, game, Integer.MAX_VALUE); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + controller.millCards(cardsToMill, source, game); + } + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_PLAYER; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return event.getTargetId().equals(source.getControllerId()); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AngelheartVial.java b/Mage.Sets/src/mage/cards/a/AngelheartVial.java index e3dd5ea119e..c02b3c43049 100644 --- a/Mage.Sets/src/mage/cards/a/AngelheartVial.java +++ b/Mage.Sets/src/mage/cards/a/AngelheartVial.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleActivatedAbility; @@ -21,14 +20,15 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class AngelheartVial extends CardImpl { public AngelheartVial(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{5}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); // Whenever you're dealt damage, you may put that many charge counters on Angelheart Vial. this.addAbility(new AngelheartVialTriggeredAbility()); @@ -36,8 +36,8 @@ public final class AngelheartVial extends CardImpl { // {2}, {tap}, Remove four charge counters from Angelheart Vial: You gain 2 life and draw a card. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(2), new GenericManaCost(2)); ability.addCost(new TapSourceCost()); - ability.addCost(new RemoveCountersSourceCost(new RemoveCountersSourceCost(CounterType.CHARGE.createInstance(4)))); - ability.addEffect(new DrawCardSourceControllerEffect(1)); + ability.addCost(new RemoveCountersSourceCost(CounterType.CHARGE.createInstance(4))); + ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); this.addAbility(ability); } @@ -82,7 +82,7 @@ class AngelheartVialTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever you are dealt damage, you may put that many charge counters on {this}."; + return "Whenever you're dealt damage, you may put that many charge counters on {this}."; } } diff --git a/Mage.Sets/src/mage/cards/a/AngelicExaltation.java b/Mage.Sets/src/mage/cards/a/AngelicExaltation.java index ef1494214ff..fa1459097ca 100644 --- a/Mage.Sets/src/mage/cards/a/AngelicExaltation.java +++ b/Mage.Sets/src/mage/cards/a/AngelicExaltation.java @@ -24,7 +24,7 @@ public final class AngelicExaltation extends CardImpl { CreaturesYouControlCount.instance, CreaturesYouControlCount.instance, Duration.EndOfTurn, true - ).setText("it gets +X/+X until end of turn, where X is the number of creatures you control")).addHint(CreaturesYouControlHint.instance)); + ).setText("it gets +X/+X until end of turn, where X is the number of creatures you control"), true, false).addHint(CreaturesYouControlHint.instance)); } private AngelicExaltation(final AngelicExaltation card) { diff --git a/Mage.Sets/src/mage/cards/a/AngelicObserver.java b/Mage.Sets/src/mage/cards/a/AngelicObserver.java new file mode 100644 index 00000000000..b2722037366 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AngelicObserver.java @@ -0,0 +1,57 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AngelicObserver extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledPermanent(SubType.CITIZEN, "Citizen you control"); + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + private static final Hint hint = new ValueHint("Citizens you control", xValue); + + public AngelicObserver(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}"); + + this.subtype.add(SubType.ANGEL); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // This spell costs {1} less to cast for each Citizen you control. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, + new SpellCostReductionForEachSourceEffect(1, xValue).setCanWorksOnStackOnly(true) + ).setRuleAtTheTop(true).addHint(hint)); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + } + + private AngelicObserver(final AngelicObserver card) { + super(card); + } + + @Override + public AngelicObserver copy() { + return new AngelicObserver(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AngelicSleuth.java b/Mage.Sets/src/mage/cards/a/AngelicSleuth.java new file mode 100644 index 00000000000..a67e6ce6b3c --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AngelicSleuth.java @@ -0,0 +1,55 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.LeavesBattlefieldAllTriggeredAbility; +import mage.abilities.effects.keyword.InvestigateEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.permanent.CounterAnyPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AngelicSleuth extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent("another permanent you control"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(CounterAnyPredicate.instance); + } + + public AngelicSleuth(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.ANGEL); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever another permanent you control leaves the battlefield, if it had counters on it, investigate. + this.addAbility(new LeavesBattlefieldAllTriggeredAbility( + new InvestigateEffect().setText("if it had counters on it, investigate"), filter, false + )); + } + + private AngelicSleuth(final AngelicSleuth card) { + super(card); + } + + @Override + public AngelicSleuth copy() { + return new AngelicSleuth(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AnglerTurtle.java b/Mage.Sets/src/mage/cards/a/AnglerTurtle.java index dc12033da69..88ff0c06993 100644 --- a/Mage.Sets/src/mage/cards/a/AnglerTurtle.java +++ b/Mage.Sets/src/mage/cards/a/AnglerTurtle.java @@ -6,9 +6,9 @@ import mage.abilities.effects.common.combat.AttacksIfAbleAllEffect; import mage.abilities.keyword.HexproofAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.common.FilterCreaturePermanent; -import mage.watchers.common.AttackedThisTurnWatcher; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; import java.util.UUID; @@ -17,12 +17,6 @@ import java.util.UUID; */ public final class AnglerTurtle extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public AnglerTurtle(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}"); this.subtype.add(SubType.TURTLE); @@ -33,8 +27,7 @@ public final class AnglerTurtle extends CardImpl { this.addAbility(HexproofAbility.getInstance()); // Creatures your opponents control attack each combat if able - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AttacksIfAbleAllEffect(filter, Duration.WhileOnBattlefield)), - new AttackedThisTurnWatcher()); + this.addAbility(new SimpleStaticAbility(new AttacksIfAbleAllEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES))); } private AnglerTurtle(final AnglerTurtle card) { diff --git a/Mage.Sets/src/mage/cards/a/AngrathCaptainOfChaos.java b/Mage.Sets/src/mage/cards/a/AngrathCaptainOfChaos.java index 9827fa66844..57c302b73f5 100644 --- a/Mage.Sets/src/mage/cards/a/AngrathCaptainOfChaos.java +++ b/Mage.Sets/src/mage/cards/a/AngrathCaptainOfChaos.java @@ -1,7 +1,6 @@ package mage.cards.a; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.keyword.AmassEffect; @@ -26,7 +25,7 @@ public final class AngrathCaptainOfChaos extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ANGRATH); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Creatures you control have menace. this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( diff --git a/Mage.Sets/src/mage/cards/a/AngrathMinotaurPirate.java b/Mage.Sets/src/mage/cards/a/AngrathMinotaurPirate.java index 69a0669e360..33a1590efc4 100644 --- a/Mage.Sets/src/mage/cards/a/AngrathMinotaurPirate.java +++ b/Mage.Sets/src/mage/cards/a/AngrathMinotaurPirate.java @@ -2,7 +2,6 @@ package mage.cards.a; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effects; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageAllControlledTargetEffect; @@ -37,7 +36,7 @@ public final class AngrathMinotaurPirate extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ANGRATH); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +2: Angrath, Minotaur Pirate deals 1 damage to target opponent and each creature that player controls. Effects effects1 = new Effects(); diff --git a/Mage.Sets/src/mage/cards/a/AngrathTheFlameChained.java b/Mage.Sets/src/mage/cards/a/AngrathTheFlameChained.java index 294fdd7e7aa..b9de629fde2 100644 --- a/Mage.Sets/src/mage/cards/a/AngrathTheFlameChained.java +++ b/Mage.Sets/src/mage/cards/a/AngrathTheFlameChained.java @@ -5,7 +5,6 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.LoseLifeOpponentsEffect; @@ -41,7 +40,7 @@ public final class AngrathTheFlameChained extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ANGRATH); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Each opponent discards a card and loses 2 life. LoyaltyAbility ability = new LoyaltyAbility(new DiscardEachPlayerEffect(TargetController.OPPONENT), 1); diff --git a/Mage.Sets/src/mage/cards/a/AnimalMagnetism.java b/Mage.Sets/src/mage/cards/a/AnimalMagnetism.java index 87bb6c250f6..8fba5e3f25f 100644 --- a/Mage.Sets/src/mage/cards/a/AnimalMagnetism.java +++ b/Mage.Sets/src/mage/cards/a/AnimalMagnetism.java @@ -57,7 +57,7 @@ class AnimalMagnetismEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && controller != null) { Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5)); if (!cards.isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/a/AnimateDead.java b/Mage.Sets/src/mage/cards/a/AnimateDead.java index 8094e7da870..7398061be83 100644 --- a/Mage.Sets/src/mage/cards/a/AnimateDead.java +++ b/Mage.Sets/src/mage/cards/a/AnimateDead.java @@ -94,7 +94,7 @@ class AnimateDeadReAttachEffect extends OneShotEffect { if (controller != null && animateDead != null) { Card cardInGraveyard = game.getCard(animateDead.getAttachedTo()); - if (cardInGraveyard == null) { + if (cardInGraveyard == null || game.getState().getZone(cardInGraveyard.getId()) != Zone.GRAVEYARD) { return true; } // put card into play from Graveyard @@ -105,6 +105,7 @@ class AnimateDeadReAttachEffect extends OneShotEffect { FilterCreaturePermanent filter = new FilterCreaturePermanent("enchant creature put onto the battlefield with Animate Dead"); filter.add(new PermanentIdPredicate(cardInGraveyard.getId())); Target target = new TargetCreaturePermanent(filter); + target.setNotTarget(true); // Bug #7772 target.addTarget(enchantedCreature.getId(), source, game); animateDead.getSpellAbility().getTargets().clear(); animateDead.getSpellAbility().getTargets().add(target); @@ -225,6 +226,7 @@ class AnimateDeadChangeAbilityEffect extends ContinuousEffectImpl implements Sou for (Ability ability : permanent.getAbilities()) { if (ability instanceof EnchantAbility) { abilityToRemove = ability; + ability.getTargets().clear(); } } permanent.removeAbility(abilityToRemove, source.getSourceId(), game); @@ -258,6 +260,7 @@ class AnimateDeadAttachToPermanentEffect extends ContinuousEffectImpl { FilterCreaturePermanent filter = new FilterCreaturePermanent("enchant creature put onto the battlefield with Animate Dead"); filter.add(new PermanentIdPredicate(getTargetPointer().getFirst(game, source))); Target target = new TargetCreaturePermanent(filter); + target.setNotTarget(true); // Bug #7772 target.addTarget(((FixedTarget) getTargetPointer()).getTarget(), source, game); animateDead.getSpellAbility().getTargets().clear(); animateDead.getSpellAbility().getTargets().add(target); diff --git a/Mage.Sets/src/mage/cards/a/AnimistsAwakening.java b/Mage.Sets/src/mage/cards/a/AnimistsAwakening.java index 840b92bf263..911a2f264d6 100644 --- a/Mage.Sets/src/mage/cards/a/AnimistsAwakening.java +++ b/Mage.Sets/src/mage/cards/a/AnimistsAwakening.java @@ -56,7 +56,7 @@ class AnimistsAwakeningEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } @@ -66,7 +66,7 @@ class AnimistsAwakeningEffect extends OneShotEffect { if (!cards.isEmpty()) { controller.revealCards(sourceObject.getIdName(), cards, game); Set toBattlefield = new LinkedHashSet<>(); - for (Card card : cards.getCards(new FilterLandCard(), source.getSourceId(), source.getControllerId(), game)) { + for (Card card : cards.getCards(new FilterLandCard(), source.getControllerId(), source, game)) { cards.remove(card); toBattlefield.add(card); } diff --git a/Mage.Sets/src/mage/cards/a/AnimusOfNightsReach.java b/Mage.Sets/src/mage/cards/a/AnimusOfNightsReach.java index e6126818263..fae6c4995c3 100644 --- a/Mage.Sets/src/mage/cards/a/AnimusOfNightsReach.java +++ b/Mage.Sets/src/mage/cards/a/AnimusOfNightsReach.java @@ -52,8 +52,8 @@ public final class AnimusOfNightsReach extends CardImpl { // Whenever Animus of Night's Reach attacks, it gets +X/+0 until end of turn, where X is the number of creature cards in defending player's graveyard. this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect( - xValue, StaticValue.get(0), Duration.EndOfTurn, true) - ).addHint(AnimusOfNightsReachHint.instance)); + xValue, StaticValue.get(0), Duration.EndOfTurn, true + ).setText("it gets +X/+0 until end of turn, where X is the number of creature cards in defending player's graveyard")).addHint(AnimusOfNightsReachHint.instance)); } private AnimusOfNightsReach(final AnimusOfNightsReach card) { diff --git a/Mage.Sets/src/mage/cards/a/AnjesRavager.java b/Mage.Sets/src/mage/cards/a/AnjesRavager.java index 72ef6d7bbbe..c9c7d416c4f 100644 --- a/Mage.Sets/src/mage/cards/a/AnjesRavager.java +++ b/Mage.Sets/src/mage/cards/a/AnjesRavager.java @@ -39,7 +39,7 @@ public final class AnjesRavager extends CardImpl { this.addAbility(ability); // Madness {1}{R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{1}{R}"))); } private AnjesRavager(final AnjesRavager card) { diff --git a/Mage.Sets/src/mage/cards/a/Antagonize.java b/Mage.Sets/src/mage/cards/a/Antagonize.java new file mode 100644 index 00000000000..464f5854ad5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/Antagonize.java @@ -0,0 +1,33 @@ +package mage.cards.a; + +import java.util.UUID; + +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author weirddan455 + */ +public final class Antagonize extends CardImpl { + + public Antagonize(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); + + // Target creature gets +4/+3 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(4, 3)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private Antagonize(final Antagonize card) { + super(card); + } + + @Override + public Antagonize copy() { + return new Antagonize(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/Anticipate.java b/Mage.Sets/src/mage/cards/a/Anticipate.java index 5883d7eef07..3e3bc99c5d3 100644 --- a/Mage.Sets/src/mage/cards/a/Anticipate.java +++ b/Mage.Sets/src/mage/cards/a/Anticipate.java @@ -1,12 +1,10 @@ package mage.cards.a; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import java.util.UUID; @@ -19,11 +17,7 @@ public final class Anticipate extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Look at the top three cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(3), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.LIBRARY, false, false - ).setText("look at the top three cards of your library. " + - "Put one of them into your hand and the rest on the bottom of your library in any order")); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.BOTTOM_ANY)); } private Anticipate(final Anticipate card) { diff --git a/Mage.Sets/src/mage/cards/a/AnuridBrushhopper.java b/Mage.Sets/src/mage/cards/a/AnuridBrushhopper.java index 1668edee293..c509e050fa2 100644 --- a/Mage.Sets/src/mage/cards/a/AnuridBrushhopper.java +++ b/Mage.Sets/src/mage/cards/a/AnuridBrushhopper.java @@ -29,7 +29,7 @@ public final class AnuridBrushhopper extends CardImpl { // Discard two cards: Exile Anurid Brushhopper. Return it to the battlefield under its owner's control at the beginning of the next end step. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true), + new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(), new DiscardTargetCost(new TargetCardInHand(2, new FilterCard("two cards"))))); } diff --git a/Mage.Sets/src/mage/cards/a/AnuridScavenger.java b/Mage.Sets/src/mage/cards/a/AnuridScavenger.java index e72f7b67e57..5f4c455c57d 100644 --- a/Mage.Sets/src/mage/cards/a/AnuridScavenger.java +++ b/Mage.Sets/src/mage/cards/a/AnuridScavenger.java @@ -69,7 +69,7 @@ class AnuridScavengerCost extends CostImpl { public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { - if (targets.choose(Outcome.Removal, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.Removal, controllerId, source.getSourceId(), source, game)) { for (UUID targetId: targets.get(0).getTargets()) { Card card = game.getCard(targetId); if (card == null || game.getState().getZone(targetId) != Zone.GRAVEYARD) { @@ -85,7 +85,7 @@ class AnuridScavengerCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/a/AphettoAlchemist.java b/Mage.Sets/src/mage/cards/a/AphettoAlchemist.java index 2ae8d0bdefb..aee72367d65 100644 --- a/Mage.Sets/src/mage/cards/a/AphettoAlchemist.java +++ b/Mage.Sets/src/mage/cards/a/AphettoAlchemist.java @@ -45,7 +45,7 @@ public final class AphettoAlchemist extends CardImpl { this.addAbility(ability); // Morph {U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{U}"))); } private AphettoAlchemist(final AphettoAlchemist card) { diff --git a/Mage.Sets/src/mage/cards/a/AphettoExterminator.java b/Mage.Sets/src/mage/cards/a/AphettoExterminator.java index 1ba67e66b23..36b883b4286 100644 --- a/Mage.Sets/src/mage/cards/a/AphettoExterminator.java +++ b/Mage.Sets/src/mage/cards/a/AphettoExterminator.java @@ -30,7 +30,7 @@ public final class AphettoExterminator extends CardImpl { this.toughness = new MageInt(1); // Morph {3}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{B}"))); // When Aphetto Exterminator is turned face up, target creature gets -3/-3 until end of turn. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new BoostTargetEffect(-3,-3,Duration.EndOfTurn)); diff --git a/Mage.Sets/src/mage/cards/a/ApocalypseHydra.java b/Mage.Sets/src/mage/cards/a/ApocalypseHydra.java index 210ad5e4cdd..bdca251a3ff 100644 --- a/Mage.Sets/src/mage/cards/a/ApocalypseHydra.java +++ b/Mage.Sets/src/mage/cards/a/ApocalypseHydra.java @@ -1,4 +1,3 @@ - package mage.cards.a; import mage.MageInt; @@ -16,7 +15,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; @@ -40,7 +38,9 @@ public final class ApocalypseHydra extends CardImpl { this.addAbility(new EntersBattlefieldAbility(new ApocalypseHydraEffect())); // {1}{R}, Remove a +1/+1 counter from Apocalypse Hydra: Apocalypse Hydra deals 1 damage to any target. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl("{1}{R}")); + Ability ability = new SimpleActivatedAbility( + new DamageTargetEffect(1, "it"), new ManaCostsImpl<>("{1}{R}") + ); ability.addCost(new RemoveCountersSourceCost(CounterType.P1P1.createInstance())); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/AppealAuthority.java b/Mage.Sets/src/mage/cards/a/AppealAuthority.java index a87b598f0a5..5b357e366c6 100644 --- a/Mage.Sets/src/mage/cards/a/AppealAuthority.java +++ b/Mage.Sets/src/mage/cards/a/AppealAuthority.java @@ -14,10 +14,9 @@ import mage.cards.SplitCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SpellAbilityType; -import mage.constants.TargetController; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; import java.util.UUID; @@ -43,11 +42,9 @@ public final class AppealAuthority extends SplitCard { getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); // Tap up to two target creatures your opponents control. Creatures you control gain vigilance until end of turn. getRightHalfCard().getSpellAbility().addEffect(new TapTargetEffect()); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponents control"); - filter.add(TargetController.OPPONENT.getControllerPredicate()); - getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2, filter, false)); + getRightHalfCard().getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent(0, 2)); getRightHalfCard().getSpellAbility().addEffect(new GainAbilityControlledEffect(VigilanceAbility.getInstance(), - Duration.EndOfTurn, new FilterControlledCreaturePermanent("creatures"))); + Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES)); } diff --git a/Mage.Sets/src/mage/cards/a/AquamorphEntity.java b/Mage.Sets/src/mage/cards/a/AquamorphEntity.java index 0eddd538a38..87f34fe9c98 100644 --- a/Mage.Sets/src/mage/cards/a/AquamorphEntity.java +++ b/Mage.Sets/src/mage/cards/a/AquamorphEntity.java @@ -16,7 +16,6 @@ import mage.constants.*; import mage.game.Game; import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; @@ -39,7 +38,7 @@ public final class AquamorphEntity extends CardImpl { this.addAbility(ability); // Morph {2}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{U}"))); } private AquamorphEntity(final AquamorphEntity card) { @@ -128,7 +127,7 @@ class AquamorphEntityReplacementEffect extends ReplacementEffectImpl { break; } game.addEffect(new SetPowerToughnessSourceEffect(power, toughness, Duration.Custom, SubLayer.SetPT_7b), source); - return true; + return false; } @Override diff --git a/Mage.Sets/src/mage/cards/a/AquitectsWill.java b/Mage.Sets/src/mage/cards/a/AquitectsWill.java index 2076f905aba..c1f9df1e485 100644 --- a/Mage.Sets/src/mage/cards/a/AquitectsWill.java +++ b/Mage.Sets/src/mage/cards/a/AquitectsWill.java @@ -4,12 +4,9 @@ import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.BecomesBasicLandTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.abilities.mana.BlueManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -19,10 +16,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetLandPermanent; -import java.util.List; -import java.util.Set; import java.util.UUID; -import java.util.stream.Collectors; /** * @author ilcartographer @@ -60,10 +54,10 @@ public final class AquitectsWill extends CardImpl { } } -class AquitectsWillEffect extends ContinuousEffectImpl { +class AquitectsWillEffect extends BecomesBasicLandTargetEffect { AquitectsWillEffect() { - super(Duration.EndOfGame, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); + super(Duration.Custom, false, false, SubType.ISLAND); staticText = "That land is an Island in addition to its other types for as long as it has a flood counter on it"; } @@ -79,25 +73,10 @@ class AquitectsWillEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { Permanent land = game.getPermanent(this.targetPointer.getFirst(game, source)); - if (land == null - || land.getCounters(game).getCount(CounterType.FLOOD) < 1) { + if (land == null || land.getCounters(game).getCount(CounterType.FLOOD) < 1) { discard(); return false; } - // The land is an island intrinsically so the ability is added at layer 4, not layer 6 - land.addSubType(game, SubType.ISLAND); - if (!land.getAbilities(game).containsClass(BlueManaAbility.class)) { - land.addAbility(new BlueManaAbility(), source.getSourceId(), game); - } - return true; - } - - @Override - public Set isDependentTo(List allEffectsInLayer) { - return allEffectsInLayer - .stream() - .filter(effect -> effect.getDependencyTypes().contains(DependencyType.BecomeIsland)) - .map(Effect::getId) - .collect(Collectors.toSet()); + return super.apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/a/ArashinWarBeast.java b/Mage.Sets/src/mage/cards/a/ArashinWarBeast.java index e4b1b4f351c..21fe3683bf5 100644 --- a/Mage.Sets/src/mage/cards/a/ArashinWarBeast.java +++ b/Mage.Sets/src/mage/cards/a/ArashinWarBeast.java @@ -82,7 +82,7 @@ class ArashinWarBeastTriggeredAbility extends TriggeredAbilityImpl { ((DamagedEvent) event).isCombatDamage() && !usedForCombatDamageStep) { Permanent creature = game.getPermanentOrLKIBattlefield(event.getTargetId()); - if (creature == null || !filter.match(creature, getSourceId(), getControllerId(), game)) { + if (creature == null || !filter.match(creature, getControllerId(), this, game)) { return false; } // trigger only once per combat damage step diff --git a/Mage.Sets/src/mage/cards/a/AraumiOfTheDeadTide.java b/Mage.Sets/src/mage/cards/a/AraumiOfTheDeadTide.java index 2a54189e348..3bdd5b9c706 100644 --- a/Mage.Sets/src/mage/cards/a/AraumiOfTheDeadTide.java +++ b/Mage.Sets/src/mage/cards/a/AraumiOfTheDeadTide.java @@ -96,7 +96,7 @@ class AraumiOfTheDeadTideCost extends CostImpl { int oppCount = game.getOpponents(controllerId).size(); TargetCard target = new TargetCardInYourGraveyard(oppCount, StaticFilters.FILTER_CARD); target.setNotTarget(true); - player.choose(Outcome.Exile, target, source.getSourceId(), game); + player.choose(Outcome.Exile, target, source, game); Cards cards = new CardsImpl(target.getTargets()); if (cards.size() < oppCount) { return paid; diff --git a/Mage.Sets/src/mage/cards/a/ArcSpitter.java b/Mage.Sets/src/mage/cards/a/ArcSpitter.java new file mode 100644 index 00000000000..ebae0b59be8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArcSpitter.java @@ -0,0 +1,57 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArcSpitter extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creature that's blocking it"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.BLOCKING); + } + + public ArcSpitter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature has "{1}: This creature deals 1 damage to target creature that's blocking it." + Ability ability = new SimpleActivatedAbility( + new DamageTargetEffect(1, "this creature"), new GenericManaCost(1) + ); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect(ability, AttachmentType.EQUIPMENT))); + + // Equip {1} + this.addAbility(new EquipAbility(1)); + } + + private ArcSpitter(final ArcSpitter card) { + super(card); + } + + @Override + public ArcSpitter copy() { + return new ArcSpitter(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java b/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java index 5b054570126..f9a6967e801 100644 --- a/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java +++ b/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java @@ -102,13 +102,14 @@ class ArcaneAdaptationEffect extends ContinuousEffectImpl { // commander in command zone for (CommandObject commandObject : game.getState().getCommand()) { if (commandObject instanceof Commander) { - Card card = game.getCard(((Commander) commandObject).getId()); + Card card = game.getCard((commandObject).getId()); if (card != null && card.isOwnedBy(controller.getId()) && card.isCreature(game) && !card.hasSubtype(subType, game)) { game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType); } } } + // TODO: Why is this not using the for-in loop like all the others? // creature spells you control for (Iterator iterator = game.getStack().iterator(); iterator.hasNext(); ) { StackObject stackObject = iterator.next(); diff --git a/Mage.Sets/src/mage/cards/a/ArcaneBombardment.java b/Mage.Sets/src/mage/cards/a/ArcaneBombardment.java new file mode 100644 index 00000000000..b20f51a8923 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArcaneBombardment.java @@ -0,0 +1,158 @@ +package mage.cards.a; + +import mage.ApprovingObject; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.filter.StaticFilters; +import mage.filter.common.FilterInstantOrSorcerySpell; +import mage.game.ExileZone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.util.CardUtil; +import mage.util.RandomUtil; +import mage.watchers.Watcher; +import org.apache.log4j.Logger; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArcaneBombardment extends CardImpl { + + private static final FilterSpell filter + = new FilterInstantOrSorcerySpell("your first instant or sorcery spell each turn"); + + static { + filter.add(ArcaneBombardmentWatcher::checkSpell); + } + + public ArcaneBombardment(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{R}{R}"); + + // Whenever you cast your first instant or sorcery spell each turn, exile an instant or sorcery card at random from your graveyard. Then copy each card exiled with Arcane Bombardment. You may cast any number of the copies without paying their mana costs. + this.addAbility(new SpellCastControllerTriggeredAbility( + new ArcaneBombardmentEffect(), filter, false + ), new ArcaneBombardmentWatcher()); + } + + private ArcaneBombardment(final ArcaneBombardment card) { + super(card); + } + + @Override + public ArcaneBombardment copy() { + return new ArcaneBombardment(this); + } +} + +class ArcaneBombardmentEffect extends OneShotEffect { + + ArcaneBombardmentEffect() { + super(Outcome.Benefit); + staticText = "exile an instant or sorcery card at random from your graveyard. Then copy each " + + "card exiled with {this}. You may cast any number of the copies without paying their mana costs"; + } + + private ArcaneBombardmentEffect(final ArcaneBombardmentEffect effect) { + super(effect); + } + + @Override + public ArcaneBombardmentEffect copy() { + return new ArcaneBombardmentEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + UUID exileId = CardUtil.getExileZoneId(game, source); + Card toExile = RandomUtil.randomFromCollection( + player.getGraveyard().getCards(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, game) + ); + if (toExile != null) { + player.moveCardsToExile( + toExile, source, game, true, + exileId, CardUtil.getSourceName(game, source) + ); + } + ExileZone exileZone = game.getExile().getExileZone(exileId); + if (exileZone == null || exileZone.isEmpty()) { + return false; + } + + Cards copies = new CardsImpl(); + for (Card card : exileZone.getCards(game)) { + Card copiedCard = game.copyCard(card, source, source.getControllerId()); + game.getExile().add(source.getSourceId(), "", copiedCard); + game.getState().setZone(copiedCard.getId(), Zone.EXILED); + copies.add(copiedCard); + } + for (Card copiedCard : copies.getCards(game)) { + if (!player.chooseUse(outcome, "Cast the copied card?", source, game)) { + continue; + } + if (copiedCard.getSpellAbility() != null) { + game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), Boolean.TRUE); + player.cast( + player.chooseAbilityForCast(copiedCard, game, true), + game, true, new ApprovingObject(source, game) + ); + game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), null); + } else { + Logger.getLogger(ArcaneBombardmentEffect.class).error("Arcane Bombardment: " + + "spell ability == null " + copiedCard.getName()); + } + } + return true; + } +} + +class ArcaneBombardmentWatcher extends Watcher { + + private final Map playerMap = new HashMap<>(); + + ArcaneBombardmentWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.SPELL_CAST) { + return; + } + Spell spell = game.getSpell(event.getTargetId()); + if (spell != null && spell.isInstantOrSorcery(game)) { + playerMap.compute(spell.getControllerId(), CardUtil::setOrIncrementValue); + } + } + + @Override + public void reset() { + super.reset(); + playerMap.clear(); + } + + static boolean checkSpell(StackObject input, Game game) { + return game + .getState() + .getWatcher(ArcaneBombardmentWatcher.class) + .playerMap + .getOrDefault(input.getControllerId(), 0) < 2; + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArcaneEndeavor.java b/Mage.Sets/src/mage/cards/a/ArcaneEndeavor.java index 70f26c348c8..2d2cd938152 100644 --- a/Mage.Sets/src/mage/cards/a/ArcaneEndeavor.java +++ b/Mage.Sets/src/mage/cards/a/ArcaneEndeavor.java @@ -1,17 +1,19 @@ package mage.cards.a; import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.Outcome; import mage.filter.FilterCard; import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.players.Player; +import mage.util.CardUtil; import java.util.List; import java.util.UUID; @@ -40,10 +42,6 @@ public final class ArcaneEndeavor extends CardImpl { class ArcaneEndeavorEffect extends OneShotEffect { - private static final FilterCard filter = new FilterInstantOrSorceryCard( - "instant or sorcery card with mana value %mv or less from your hand" - ); - ArcaneEndeavorEffect() { super(Outcome.Benefit); staticText = "roll two d8 and choose one result. Draw cards equal to that result. " + @@ -82,7 +80,9 @@ class ArcaneEndeavorEffect extends OneShotEffect { second = firstResult; } player.drawCards(first, source, game); - new CastWithoutPayingManaCostEffect(StaticValue.get(second), filter).apply(game, source); + FilterCard filter = new FilterInstantOrSorceryCard(); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, second + 1)); + CardUtil.castSpellWithAttributesForFree(player, source, game, new CardsImpl(player.getHand()), filter); return true; } } diff --git a/Mage.Sets/src/mage/cards/a/ArcaneInfusion.java b/Mage.Sets/src/mage/cards/a/ArcaneInfusion.java index 33cb5d8ca39..e8ab05a63a6 100644 --- a/Mage.Sets/src/mage/cards/a/ArcaneInfusion.java +++ b/Mage.Sets/src/mage/cards/a/ArcaneInfusion.java @@ -1,14 +1,12 @@ package mage.cards.a; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.FlashbackAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.TimingRule; -import mage.constants.Zone; import mage.filter.StaticFilters; import java.util.UUID; @@ -23,13 +21,7 @@ public final class ArcaneInfusion extends CardImpl { // Look at the top four cards of your library. You may reveal an instant or sorcery card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(1), - StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, Zone.LIBRARY, - false, true, false, Zone.HAND, - true, false, false - ).setBackInRandomOrder(true).setText("Look at the top four cards of your library. " + - "You may reveal an instant or sorcery card from among them and put it into your hand. " + - "Put the rest on the bottom of your library in a random order.")); + 4, 1, StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, PutCards.HAND, PutCards.BOTTOM_RANDOM)); // Flashback {3}{U}{R} this.addAbility(new FlashbackAbility(this, new ManaCostsImpl<>("{3}{U}{R}"))); diff --git a/Mage.Sets/src/mage/cards/a/ArcaneInvestigator.java b/Mage.Sets/src/mage/cards/a/ArcaneInvestigator.java index e863a6de6f2..4c499ef1578 100644 --- a/Mage.Sets/src/mage/cards/a/ArcaneInvestigator.java +++ b/Mage.Sets/src/mage/cards/a/ArcaneInvestigator.java @@ -3,16 +3,14 @@ package mage.cards.a; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.RollDieWithResultTableEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import java.util.UUID; @@ -39,11 +37,7 @@ public final class ArcaneInvestigator extends CardImpl { effect.addTableEntry(1, 9, new DrawCardSourceControllerEffect(1)); // 10-20 | Look at the top three cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order. - effect.addTableEntry(10, 20, new LookLibraryAndPickControllerEffect( - StaticValue.get(3), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.LIBRARY, false, false - ).setText("look at the top three cards of your library. Put one of them " + - "into your hand and the rest on the bottom of your library in any order")); + effect.addTableEntry(10, 20, new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.BOTTOM_ANY)); } private ArcaneInvestigator(final ArcaneInvestigator card) { diff --git a/Mage.Sets/src/mage/cards/a/ArcaneLighthouse.java b/Mage.Sets/src/mage/cards/a/ArcaneLighthouse.java index 9a675800525..4e6d558320c 100644 --- a/Mage.Sets/src/mage/cards/a/ArcaneLighthouse.java +++ b/Mage.Sets/src/mage/cards/a/ArcaneLighthouse.java @@ -15,9 +15,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; /** * @@ -25,13 +22,6 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class ArcaneLighthouse extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public ArcaneLighthouse(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.LAND},""); @@ -39,11 +29,11 @@ public final class ArcaneLighthouse extends CardImpl { this.addAbility(new ColorlessManaAbility()); // {1}, {tap}: Until end of turn, creatures your opponents control lose hexproof and shroud and can't have hexproof or shroud. - Effect effect = new CreaturesCantGetOrHaveAbilityEffect(HexproofAbility.getInstance(), Duration.EndOfTurn, filter); + Effect effect = new CreaturesCantGetOrHaveAbilityEffect(HexproofAbility.getInstance(), Duration.EndOfTurn); effect.setText("Until end of turn, creatures your opponents control lose hexproof"); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new GenericManaCost(1)); + Ability ability = new SimpleActivatedAbility(effect, new GenericManaCost(1)); ability.addCost(new TapSourceCost()); - effect = new CreaturesCantGetOrHaveAbilityEffect(ShroudAbility.getInstance(), Duration.EndOfTurn, filter); + effect = new CreaturesCantGetOrHaveAbilityEffect(ShroudAbility.getInstance(), Duration.EndOfTurn); effect.setText("and shroud and can't have hexproof or shroud"); ability.addEffect(effect); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/ArcanistsOwl.java b/Mage.Sets/src/mage/cards/a/ArcanistsOwl.java index cd73ab26557..66b1f2b7c19 100644 --- a/Mage.Sets/src/mage/cards/a/ArcanistsOwl.java +++ b/Mage.Sets/src/mage/cards/a/ArcanistsOwl.java @@ -2,14 +2,13 @@ package mage.cards.a; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterArtifactOrEnchantmentCard; @@ -32,16 +31,11 @@ public final class ArcanistsOwl extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - // When Arcanist's Owl enters the battlefield, look at the top four cards of your library. You may reveal an artifact or enchantment card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. + // When Arcanist's Owl enters the battlefield, look at the top four cards of your library. + // You may reveal an artifact or enchantment card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. this.addAbility(new EntersBattlefieldTriggeredAbility( - new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(1), filter, - Zone.LIBRARY, false, true, false, Zone.HAND, - true, false, false - ).setBackInRandomOrder(true).setText("look at the top four cards of your library. " + - "You may reveal an artifact or enchantment card from among them and put it into your hand. " + - "Put the rest on the bottom of your library in a random order.") - )); + new LookLibraryAndPickControllerEffect(4, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM))); } private ArcanistsOwl(final ArcanistsOwl card) { diff --git a/Mage.Sets/src/mage/cards/a/Arcbond.java b/Mage.Sets/src/mage/cards/a/Arcbond.java index 8e3f19ea1bf..06ae06950e5 100644 --- a/Mage.Sets/src/mage/cards/a/Arcbond.java +++ b/Mage.Sets/src/mage/cards/a/Arcbond.java @@ -130,7 +130,7 @@ class ArcbondEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { int damage = (Integer) this.getValue("damage"); UUID sourceId = (UUID) this.getValue("sourceId"); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && damage > 0 && sourceId != null) { Permanent targetObject = game.getPermanentOrLKIBattlefield(sourceId); if (targetObject != null) { diff --git a/Mage.Sets/src/mage/cards/a/ArcboundReclaimer.java b/Mage.Sets/src/mage/cards/a/ArcboundReclaimer.java index 67511908118..d1908d6da0f 100644 --- a/Mage.Sets/src/mage/cards/a/ArcboundReclaimer.java +++ b/Mage.Sets/src/mage/cards/a/ArcboundReclaimer.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -14,24 +12,25 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ArcboundReclaimer extends CardImpl { public ArcboundReclaimer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); this.subtype.add(SubType.GOLEM); this.power = new MageInt(0); this.toughness = new MageInt(0); // Remove a +1/+1 counter from Arcbound Reclaimer: Put target artifact card from your graveyard on top of your library. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutOnLibraryTargetEffect(true),new RemoveCountersSourceCost(CounterType.P1P1.createInstance())); - ability.addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutOnLibraryTargetEffect(true), new RemoveCountersSourceCost(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); // Modular 2 diff --git a/Mage.Sets/src/mage/cards/a/ArchaeomancersMap.java b/Mage.Sets/src/mage/cards/a/ArchaeomancersMap.java index 39918d13917..9f97adf0fab 100644 --- a/Mage.Sets/src/mage/cards/a/ArchaeomancersMap.java +++ b/Mage.Sets/src/mage/cards/a/ArchaeomancersMap.java @@ -72,10 +72,10 @@ enum ArchaeomancersMapCondition implements Condition { UUID playerId = (UUID) source.getEffects().get(0).getValue("permanentEnteringControllerId"); return playerId != null && game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, - source.getSourceId(), playerId, game + playerId, source, game ) > game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, - source.getSourceId(), source.getControllerId(), game + source.getControllerId(), source, game ); } } diff --git a/Mage.Sets/src/mage/cards/a/Archaeomender.java b/Mage.Sets/src/mage/cards/a/Archaeomender.java index 7d796a45047..5b26300f4ad 100644 --- a/Mage.Sets/src/mage/cards/a/Archaeomender.java +++ b/Mage.Sets/src/mage/cards/a/Archaeomender.java @@ -8,8 +8,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.FilterCard; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; @@ -19,9 +18,6 @@ import java.util.UUID; */ public final class Archaeomender extends CardImpl { - private static final FilterCard filter - = new FilterArtifactCard("artifact card from your graveyard"); - public Archaeomender(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); @@ -32,7 +28,7 @@ public final class Archaeomender extends CardImpl { // When Archaeomender enters the battlefield, return target artifact card from your graveyard to your hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); - ability.addTarget(new TargetCardInYourGraveyard(filter)); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/ArchdemonOfGreed.java b/Mage.Sets/src/mage/cards/a/ArchdemonOfGreed.java index b8127b27631..6fcb910e12a 100644 --- a/Mage.Sets/src/mage/cards/a/ArchdemonOfGreed.java +++ b/Mage.Sets/src/mage/cards/a/ArchdemonOfGreed.java @@ -84,8 +84,8 @@ public final class ArchdemonOfGreed extends CardImpl { if (player != null) { TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, false); // if they can pay the cost, then they must pay - if (target.canChoose(source.getSourceId(), player.getId(), game)) { - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + if (target.canChoose(player.getId(), source, game)) { + player.choose(Outcome.Sacrifice, target, source, game); Permanent humanSacrifice = game.getPermanent(target.getFirstTarget()); if (humanSacrifice != null) { // sacrifice the chosen card diff --git a/Mage.Sets/src/mage/cards/a/ArchdemonOfUnx.java b/Mage.Sets/src/mage/cards/a/ArchdemonOfUnx.java index 1738f21e67a..5c6d7df33f2 100644 --- a/Mage.Sets/src/mage/cards/a/ArchdemonOfUnx.java +++ b/Mage.Sets/src/mage/cards/a/ArchdemonOfUnx.java @@ -43,7 +43,7 @@ public final class ArchdemonOfUnx extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // At the beginning of your upkeep, sacrifice a non-Zombie creature, then create a 2/2 black Zombie creature token. Ability ability = new BeginningOfUpkeepTriggeredAbility(new SacrificeControllerEffect(filter, 1, ""), TargetController.YOU, false); - ability.addEffect(new CreateTokenEffect(new ZombieToken())); + ability.addEffect(new CreateTokenEffect(new ZombieToken()).concatBy(", then")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/ArchetypeOfAggression.java b/Mage.Sets/src/mage/cards/a/ArchetypeOfAggression.java index fec03ff2bfe..b4f43b9eb7a 100644 --- a/Mage.Sets/src/mage/cards/a/ArchetypeOfAggression.java +++ b/Mage.Sets/src/mage/cards/a/ArchetypeOfAggression.java @@ -1,4 +1,3 @@ - package mage.cards.a; import java.util.UUID; @@ -9,9 +8,10 @@ import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; /** * @@ -19,12 +19,6 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class ArchetypeOfAggression extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public ArchetypeOfAggression(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT,CardType.CREATURE},"{1}{R}{R}"); this.subtype.add(SubType.HUMAN); @@ -34,10 +28,9 @@ public final class ArchetypeOfAggression extends CardImpl { this.toughness = new MageInt(2); // Creatures you control have trample. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES))); + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES))); // Creatures your opponents control lose trample and can't have or gain trample. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CreaturesCantGetOrHaveAbilityEffect(TrampleAbility.getInstance(), Duration.WhileOnBattlefield, filter))); - + this.addAbility(new SimpleStaticAbility(new CreaturesCantGetOrHaveAbilityEffect(TrampleAbility.getInstance(), Duration.WhileOnBattlefield))); } private ArchetypeOfAggression(final ArchetypeOfAggression card) { diff --git a/Mage.Sets/src/mage/cards/a/ArchetypeOfCourage.java b/Mage.Sets/src/mage/cards/a/ArchetypeOfCourage.java index b3cd4e35725..fbd8f744448 100644 --- a/Mage.Sets/src/mage/cards/a/ArchetypeOfCourage.java +++ b/Mage.Sets/src/mage/cards/a/ArchetypeOfCourage.java @@ -1,4 +1,3 @@ - package mage.cards.a; import java.util.UUID; @@ -9,9 +8,10 @@ import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; /** * @@ -19,11 +19,6 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class ArchetypeOfCourage extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public ArchetypeOfCourage(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT,CardType.CREATURE},"{1}{W}{W}"); this.subtype.add(SubType.HUMAN); @@ -33,9 +28,9 @@ public final class ArchetypeOfCourage extends CardImpl { this.toughness = new MageInt(2); // Creatures you control have first strike. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES))); + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES))); // Creatures your opponents control lose first strike and can't have or gain first strike. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CreaturesCantGetOrHaveAbilityEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield, filter))); + this.addAbility(new SimpleStaticAbility(new CreaturesCantGetOrHaveAbilityEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield))); } private ArchetypeOfCourage(final ArchetypeOfCourage card) { diff --git a/Mage.Sets/src/mage/cards/a/ArchetypeOfEndurance.java b/Mage.Sets/src/mage/cards/a/ArchetypeOfEndurance.java index 96ba77e85b2..450ddc74333 100644 --- a/Mage.Sets/src/mage/cards/a/ArchetypeOfEndurance.java +++ b/Mage.Sets/src/mage/cards/a/ArchetypeOfEndurance.java @@ -1,4 +1,3 @@ - package mage.cards.a; import java.util.UUID; @@ -9,9 +8,10 @@ import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.HexproofAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; /** * @@ -19,12 +19,6 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class ArchetypeOfEndurance extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public ArchetypeOfEndurance(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT,CardType.CREATURE},"{6}{G}{G}"); this.subtype.add(SubType.BOAR); @@ -33,11 +27,9 @@ public final class ArchetypeOfEndurance extends CardImpl { this.toughness = new MageInt(5); // Creatures you control have hexproof. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(HexproofAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES))); - + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect(HexproofAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES))); // Creatures your opponents control lose hexproof and can't have or gain hexproof. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CreaturesCantGetOrHaveAbilityEffect(HexproofAbility.getInstance(), Duration.WhileOnBattlefield, filter))); - + this.addAbility(new SimpleStaticAbility(new CreaturesCantGetOrHaveAbilityEffect(HexproofAbility.getInstance(), Duration.WhileOnBattlefield))); } private ArchetypeOfEndurance(final ArchetypeOfEndurance card) { diff --git a/Mage.Sets/src/mage/cards/a/ArchetypeOfFinality.java b/Mage.Sets/src/mage/cards/a/ArchetypeOfFinality.java index 19fcf7cb95a..2fdb4edfd69 100644 --- a/Mage.Sets/src/mage/cards/a/ArchetypeOfFinality.java +++ b/Mage.Sets/src/mage/cards/a/ArchetypeOfFinality.java @@ -1,4 +1,3 @@ - package mage.cards.a; import java.util.UUID; @@ -9,9 +8,10 @@ import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.DeathtouchAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; /** * @@ -19,12 +19,6 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class ArchetypeOfFinality extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public ArchetypeOfFinality(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT,CardType.CREATURE},"{4}{B}{B}"); this.subtype.add(SubType.GORGON); @@ -33,10 +27,9 @@ public final class ArchetypeOfFinality extends CardImpl { this.toughness = new MageInt(3); // Creatures you control have deathtouch. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(DeathtouchAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES))); + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect(DeathtouchAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES))); // Creatures your opponents control lose deathtouch and can't have or gain deathtouch. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CreaturesCantGetOrHaveAbilityEffect(DeathtouchAbility.getInstance(), Duration.WhileOnBattlefield, filter))); - + this.addAbility(new SimpleStaticAbility(new CreaturesCantGetOrHaveAbilityEffect(DeathtouchAbility.getInstance(), Duration.WhileOnBattlefield))); } private ArchetypeOfFinality(final ArchetypeOfFinality card) { diff --git a/Mage.Sets/src/mage/cards/a/ArchetypeOfImagination.java b/Mage.Sets/src/mage/cards/a/ArchetypeOfImagination.java index 69081991faa..2dab503b87e 100644 --- a/Mage.Sets/src/mage/cards/a/ArchetypeOfImagination.java +++ b/Mage.Sets/src/mage/cards/a/ArchetypeOfImagination.java @@ -1,4 +1,3 @@ - package mage.cards.a; import java.util.UUID; @@ -9,9 +8,10 @@ import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; /** * @@ -19,11 +19,6 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class ArchetypeOfImagination extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public ArchetypeOfImagination(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT,CardType.CREATURE},"{4}{U}{U}"); this.subtype.add(SubType.HUMAN); @@ -33,10 +28,9 @@ public final class ArchetypeOfImagination extends CardImpl { this.toughness = new MageInt(2); // Creatures you control have flying. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES))); + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES))); // Creatures your opponents control lose flying and can't have or gain flying. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CreaturesCantGetOrHaveAbilityEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield, filter))); - + this.addAbility(new SimpleStaticAbility(new CreaturesCantGetOrHaveAbilityEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield))); } private ArchetypeOfImagination(final ArchetypeOfImagination card) { diff --git a/Mage.Sets/src/mage/cards/a/ArchfiendOfDepravity.java b/Mage.Sets/src/mage/cards/a/ArchfiendOfDepravity.java index 76864cb6176..52b712d9714 100644 --- a/Mage.Sets/src/mage/cards/a/ArchfiendOfDepravity.java +++ b/Mage.Sets/src/mage/cards/a/ArchfiendOfDepravity.java @@ -73,7 +73,7 @@ class ArchfiendOfDepravityEffect extends OneShotEffect { List creaturesToSacrifice = new ArrayList<>(); TargetControlledPermanent target = new TargetControlledPermanent(0, 2, new FilterControlledCreaturePermanent("creatures to keep"), true); if (opponent.chooseTarget(outcome, target, source, game)) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), opponent.getId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), opponent.getId(), source, game)) { if (permanent != null && !target.getTargets().contains(permanent.getId())) { creaturesToSacrifice.add(permanent); } diff --git a/Mage.Sets/src/mage/cards/a/ArchfiendOfSorrows.java b/Mage.Sets/src/mage/cards/a/ArchfiendOfSorrows.java index 3a9433eb44d..1f1d41839bd 100644 --- a/Mage.Sets/src/mage/cards/a/ArchfiendOfSorrows.java +++ b/Mage.Sets/src/mage/cards/a/ArchfiendOfSorrows.java @@ -11,8 +11,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.common.FilterOpponentsCreaturePermanent; +import mage.filter.StaticFilters; import java.util.UUID; @@ -21,9 +20,6 @@ import java.util.UUID; */ public final class ArchfiendOfSorrows extends CardImpl { - private static final FilterCreaturePermanent filter - = new FilterOpponentsCreaturePermanent("creatures your opponents control"); - public ArchfiendOfSorrows(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}"); @@ -36,7 +32,7 @@ public final class ArchfiendOfSorrows extends CardImpl { // When Archfiend of Sorrows enters the battlefield, creatures your opponents control get -2/-2 until end of turn. this.addAbility(new EntersBattlefieldTriggeredAbility(new BoostAllEffect( - -2, -2, Duration.EndOfTurn, filter, false + -2, -2, Duration.EndOfTurn, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, false ))); // Unearth {3}{B}{B} diff --git a/Mage.Sets/src/mage/cards/a/ArchfiendOfSpite.java b/Mage.Sets/src/mage/cards/a/ArchfiendOfSpite.java index a25c3ab7d03..6ff9b34ee2a 100644 --- a/Mage.Sets/src/mage/cards/a/ArchfiendOfSpite.java +++ b/Mage.Sets/src/mage/cards/a/ArchfiendOfSpite.java @@ -42,7 +42,7 @@ public final class ArchfiendOfSpite extends CardImpl { this.addAbility(new ArchfiendOfSpiteAbility()); // Madness {3}{B}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{3}{B}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{3}{B}{B}"))); } diff --git a/Mage.Sets/src/mage/cards/a/Archipelagore.java b/Mage.Sets/src/mage/cards/a/Archipelagore.java index 55a15bdb0db..276ce4a252b 100644 --- a/Mage.Sets/src/mage/cards/a/Archipelagore.java +++ b/Mage.Sets/src/mage/cards/a/Archipelagore.java @@ -34,7 +34,7 @@ public final class Archipelagore extends CardImpl { // Whenever this creature mutates, tap up to X target creatures, where X is the number of times this creature has mutated. Those creatures don't untap during their controller's next untap step. Ability ability = new MutatesSourceTriggeredAbility(new TapTargetEffect( - "up to X target creatures, where X is the number of times this creature has mutated." + "tap up to X target creatures, where X is the number of times this creature has mutated." )); ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("Those creatures")); ability.setTargetAdjuster(ArchipelagoreAdjuster.instance); diff --git a/Mage.Sets/src/mage/cards/a/ArchmagesCharm.java b/Mage.Sets/src/mage/cards/a/ArchmagesCharm.java index 51509613010..d74e8e6f61a 100644 --- a/Mage.Sets/src/mage/cards/a/ArchmagesCharm.java +++ b/Mage.Sets/src/mage/cards/a/ArchmagesCharm.java @@ -44,7 +44,7 @@ public final class ArchmagesCharm extends CardImpl { this.getSpellAbility().addMode(mode); // • Gain control of target nonland permanent with converted mana cost 1 or less. - mode = new Mode(new GainControlTargetEffect(Duration.EndOfGame, true)); + mode = new Mode(new GainControlTargetEffect(Duration.Custom, true)); mode.addTarget(new TargetPermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/ArcticFoxes.java b/Mage.Sets/src/mage/cards/a/ArcticFoxes.java index d6b86a7d425..c75d0b58019 100644 --- a/Mage.Sets/src/mage/cards/a/ArcticFoxes.java +++ b/Mage.Sets/src/mage/cards/a/ArcticFoxes.java @@ -68,6 +68,6 @@ enum ArcticFoxesCondition implements Condition { if (defenderId == null) { return false; } - return game.getBattlefield().contains(filter, source.getSourceId(), defenderId, game, 1); + return game.getBattlefield().contains(filter, source.getSourceId(), defenderId, source, game, 1); } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/ArcticNishoba.java b/Mage.Sets/src/mage/cards/a/ArcticNishoba.java index 72f96426914..873ae4e4690 100644 --- a/Mage.Sets/src/mage/cards/a/ArcticNishoba.java +++ b/Mage.Sets/src/mage/cards/a/ArcticNishoba.java @@ -37,9 +37,8 @@ public final class ArcticNishoba extends CardImpl { // Cumulative upkeep {G} or {W} this.addAbility(new CumulativeUpkeepAbility(new OrCost( - new ManaCostsImpl("{G}"), - new ManaCostsImpl("{W}"), - "{G} or {W}" + "{G} or {W}", new ManaCostsImpl("{G}"), + new ManaCostsImpl("{W}") ))); // When Arctic Nishoba dies, you gain 2 life for each age counter on it. diff --git a/Mage.Sets/src/mage/cards/a/ArdennIntrepidArchaeologist.java b/Mage.Sets/src/mage/cards/a/ArdennIntrepidArchaeologist.java index fbd5b292ad1..4f8f9e25d32 100644 --- a/Mage.Sets/src/mage/cards/a/ArdennIntrepidArchaeologist.java +++ b/Mage.Sets/src/mage/cards/a/ArdennIntrepidArchaeologist.java @@ -88,7 +88,7 @@ class ArdennIntrepidArchaeologistEffect extends OneShotEffect { return false; } TargetPermanent target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); for (UUID targetId : target.getTargets()) { if (player != null) { player.addAttachment(targetId, source, game); diff --git a/Mage.Sets/src/mage/cards/a/ArdentDustspeaker.java b/Mage.Sets/src/mage/cards/a/ArdentDustspeaker.java index 1d8f14d44ba..a5317238953 100644 --- a/Mage.Sets/src/mage/cards/a/ArdentDustspeaker.java +++ b/Mage.Sets/src/mage/cards/a/ArdentDustspeaker.java @@ -79,7 +79,7 @@ class ArdentDustspeakerCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/a/ArgivianArchaeologist.java b/Mage.Sets/src/mage/cards/a/ArgivianArchaeologist.java index 11f24f71e17..2c9f9b63623 100644 --- a/Mage.Sets/src/mage/cards/a/ArgivianArchaeologist.java +++ b/Mage.Sets/src/mage/cards/a/ArgivianArchaeologist.java @@ -1,41 +1,37 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class ArgivianArchaeologist extends CardImpl { - - private static final FilterArtifactCard filter = new FilterArtifactCard("artifact card from your graveyard"); public ArgivianArchaeologist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ARTIFICER); this.power = new MageInt(1); this.toughness = new MageInt(1); // {W}{W}, {tap}: Return target artifact card from your graveyard to your hand. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{W}{W}")); + Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl("{W}{W}")); ability.addCost(new TapSourceCost()); - Target target = new TargetCardInYourGraveyard(filter); + Target target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD); ability.addTarget(target); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/ArgivianRestoration.java b/Mage.Sets/src/mage/cards/a/ArgivianRestoration.java index 9b555630301..81fa3ecb752 100644 --- a/Mage.Sets/src/mage/cards/a/ArgivianRestoration.java +++ b/Mage.Sets/src/mage/cards/a/ArgivianRestoration.java @@ -4,7 +4,7 @@ import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffec import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; @@ -19,7 +19,7 @@ public final class ArgivianRestoration extends CardImpl { // Return target artifact card from your graveyard to the battlefield. this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); } private ArgivianRestoration(final ArgivianRestoration card) { diff --git a/Mage.Sets/src/mage/cards/a/ArlinnKord.java b/Mage.Sets/src/mage/cards/a/ArlinnKord.java index 96f3e33cc21..1c9db9b355a 100644 --- a/Mage.Sets/src/mage/cards/a/ArlinnKord.java +++ b/Mage.Sets/src/mage/cards/a/ArlinnKord.java @@ -3,7 +3,6 @@ package mage.cards.a; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; @@ -34,7 +33,7 @@ public final class ArlinnKord extends CardImpl { this.secondSideCardClazz = ArlinnEmbracedByTheMoon.class; - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Until end of turn, up to one target creature gets +2/+2 and gains vigilance and haste. Effect effect = new BoostTargetEffect(2, 2, Duration.EndOfTurn); diff --git a/Mage.Sets/src/mage/cards/a/ArlinnTheMoonsFury.java b/Mage.Sets/src/mage/cards/a/ArlinnTheMoonsFury.java index f6ce1f507a5..3488bbb9a9c 100644 --- a/Mage.Sets/src/mage/cards/a/ArlinnTheMoonsFury.java +++ b/Mage.Sets/src/mage/cards/a/ArlinnTheMoonsFury.java @@ -3,7 +3,6 @@ package mage.cards.a; import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.mana.BasicManaEffect; import mage.abilities.keyword.HasteAbility; @@ -28,7 +27,7 @@ public final class ArlinnTheMoonsFury extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ARLINN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); this.color.setRed(true); this.color.setGreen(true); this.nightCard = true; diff --git a/Mage.Sets/src/mage/cards/a/ArlinnThePacksHope.java b/Mage.Sets/src/mage/cards/a/ArlinnThePacksHope.java index 7a7a2ccf999..14d73c31ae3 100644 --- a/Mage.Sets/src/mage/cards/a/ArlinnThePacksHope.java +++ b/Mage.Sets/src/mage/cards/a/ArlinnThePacksHope.java @@ -2,7 +2,6 @@ package mage.cards.a; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect; @@ -33,7 +32,7 @@ public final class ArlinnThePacksHope extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ARLINN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); this.secondSideCardClazz = mage.cards.a.ArlinnTheMoonsFury.class; // Daybound diff --git a/Mage.Sets/src/mage/cards/a/ArlinnVoiceOfThePack.java b/Mage.Sets/src/mage/cards/a/ArlinnVoiceOfThePack.java index 0f671dc4c70..3b7defc7915 100644 --- a/Mage.Sets/src/mage/cards/a/ArlinnVoiceOfThePack.java +++ b/Mage.Sets/src/mage/cards/a/ArlinnVoiceOfThePack.java @@ -2,7 +2,6 @@ package mage.cards.a; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.CreateTokenEffect; @@ -28,7 +27,7 @@ public final class ArlinnVoiceOfThePack extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ARLINN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(7)); + this.setStartingLoyalty(7); // Each creature you control that's a Wolf or Werewolf enters the battlefield with an additional +1/+1 counter on it. this.addAbility(new SimpleStaticAbility(new ArlinnVoiceOfThePackReplacementEffect())); @@ -51,7 +50,7 @@ class ArlinnVoiceOfThePackReplacementEffect extends ReplacementEffectImpl { ArlinnVoiceOfThePackReplacementEffect() { super(Duration.WhileOnBattlefield, Outcome.BoostCreature); - staticText = "Each creature you control that's a Wolf or Werewolf " + + staticText = "Each creature you control that's a Wolf or a Werewolf " + "enters the battlefield with an additional +1/+1 counter on it"; } diff --git a/Mage.Sets/src/mage/cards/a/ArmadilloCloak.java b/Mage.Sets/src/mage/cards/a/ArmadilloCloak.java index c3b369eba50..90fdb9290ac 100644 --- a/Mage.Sets/src/mage/cards/a/ArmadilloCloak.java +++ b/Mage.Sets/src/mage/cards/a/ArmadilloCloak.java @@ -5,7 +5,7 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DealsDamageAttachedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.NumericSetToEffectValues; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.GainLifeEffect; @@ -44,7 +44,7 @@ public final class ArmadilloCloak extends CardImpl { this.addAbility(ability); // Whenever enchanted creature deals damage, you gain that much life. - this.addAbility(new DealsDamageAttachedTriggeredAbility(Zone.BATTLEFIELD, new GainLifeEffect(new NumericSetToEffectValues("that much", "damage")), false)); + this.addAbility(new DealsDamageAttachedTriggeredAbility(Zone.BATTLEFIELD, new GainLifeEffect(SavedDamageValue.MUCH), false)); } diff --git a/Mage.Sets/src/mage/cards/a/ArmedAndArmored.java b/Mage.Sets/src/mage/cards/a/ArmedAndArmored.java index 29e95ca5bef..d101a746b06 100644 --- a/Mage.Sets/src/mage/cards/a/ArmedAndArmored.java +++ b/Mage.Sets/src/mage/cards/a/ArmedAndArmored.java @@ -108,12 +108,12 @@ class ArmedAndArmoredEquipEffect extends OneShotEffect { if (!dwarves.isEmpty() && !equipment.isEmpty()) { TargetPermanent target = new TargetPermanent(0, 1, dwarfFilter, true); target.withChooseHint("dwarf to be equipped"); - controller.choose(outcome, target, source.getId(), game); + controller.choose(outcome, target, source, game); Permanent dwarf = game.getPermanent(target.getFirstTarget()); if (dwarf != null) { target = new TargetPermanent(0, Integer.MAX_VALUE, equipmentFilter, true); target.withChooseHint("equip to " + dwarf.getLogName()); - controller.choose(outcome, target, source.getId(), game); + controller.choose(outcome, target, source, game); for (UUID targetId : target.getTargets()) { dwarf.addAttachment(targetId, source, game); game.informPlayers(game.getPermanent(targetId).getLogName() + " was attached to " + dwarf.getLogName()); diff --git a/Mage.Sets/src/mage/cards/a/ArmguardFamiliar.java b/Mage.Sets/src/mage/cards/a/ArmguardFamiliar.java index baf092ccf72..33a58c83abe 100644 --- a/Mage.Sets/src/mage/cards/a/ArmguardFamiliar.java +++ b/Mage.Sets/src/mage/cards/a/ArmguardFamiliar.java @@ -37,6 +37,7 @@ public final class ArmguardFamiliar extends CardImpl { ability.addEffect(new GainAbilityAttachedEffect( new WardAbility(new GenericManaCost(2)), AttachmentType.EQUIPMENT ).setText("and has ward {2}")); + this.addAbility(ability); // Reconfigure {4} this.addAbility(new ReconfigureAbility("{4}")); diff --git a/Mage.Sets/src/mage/cards/a/ArmixFiligreeThrasher.java b/Mage.Sets/src/mage/cards/a/ArmixFiligreeThrasher.java index 705e4b4a35f..4e1745fe5de 100644 --- a/Mage.Sets/src/mage/cards/a/ArmixFiligreeThrasher.java +++ b/Mage.Sets/src/mage/cards/a/ArmixFiligreeThrasher.java @@ -1,12 +1,14 @@ package mage.cards.a; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.dynamicvalue.AdditiveDynamicValue; import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.effects.Effect; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; import mage.abilities.effects.common.DoWhenCostPaid; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.keyword.PartnerAbility; @@ -19,8 +21,6 @@ import mage.constants.SuperType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.DefendingPlayerControlsPredicate; -import mage.game.Game; -import mage.players.Player; import mage.target.TargetPermanent; import java.util.UUID; @@ -36,6 +36,11 @@ public final class ArmixFiligreeThrasher extends CardImpl { filter.add(DefendingPlayerControlsPredicate.instance); } + private static final DynamicValue xValue = new SignInversionDynamicValue(new AdditiveDynamicValue( + new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACTS), + new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_ARTIFACT) + )); + public ArmixFiligreeThrasher(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{B}"); @@ -46,11 +51,8 @@ public final class ArmixFiligreeThrasher extends CardImpl { // Whenever Armix, Filigree Thrasher attacks, you may discard a card. When you do, target creature defending player controls gets -X/-X until end of turn, where X is the number of artifacts you control plus the number of artifact cards in your graveyard. ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( - new BoostTargetEffect( - ArmixFiligreeThrasherValue.instance, - ArmixFiligreeThrasherValue.instance, - Duration.EndOfTurn, true - ), false, "target creature defending player controls gets -X/-X until end of turn, " + + new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn, true), false, + "target creature defending player controls gets -X/-X until end of turn, " + "where X is the number of artifacts you control plus the number of artifact cards in your graveyard" ); ability.addTarget(new TargetPermanent(filter)); @@ -71,32 +73,3 @@ public final class ArmixFiligreeThrasher extends CardImpl { return new ArmixFiligreeThrasher(this); } } - -enum ArmixFiligreeThrasherValue implements DynamicValue { - instance; - - @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - Player player = game.getPlayer(sourceAbility.getControllerId()); - if (player == null) { - return 0; - } - return -(player.getGraveyard().count( - StaticFilters.FILTER_CARD_ARTIFACT, player.getId(), game - ) + game.getBattlefield().count( - StaticFilters.FILTER_PERMANENT_ARTIFACT, - sourceAbility.getSourceId(), - sourceAbility.getControllerId(), game - )); - } - - @Override - public ArmixFiligreeThrasherValue copy() { - return instance; - } - - @Override - public String getMessage() { - return ""; - } -} diff --git a/Mage.Sets/src/mage/cards/a/ArmorSliver.java b/Mage.Sets/src/mage/cards/a/ArmorSliver.java index 51b621bb65f..d3b81dcb084 100644 --- a/Mage.Sets/src/mage/cards/a/ArmorSliver.java +++ b/Mage.Sets/src/mage/cards/a/ArmorSliver.java @@ -30,7 +30,7 @@ public final class ArmorSliver extends CardImpl { this.toughness = new MageInt(2); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect( new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(0, 1, Duration.EndOfTurn).setText("this creature gets +0/+1 until end of turn"), - new GenericManaCost(2)), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, false))); + new GenericManaCost(2)), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS, false))); } private ArmorSliver(final ArmorSliver card) { diff --git a/Mage.Sets/src/mage/cards/a/ArmoredAscension.java b/Mage.Sets/src/mage/cards/a/ArmoredAscension.java index 01bcb46fc69..dbef7ce772a 100644 --- a/Mage.Sets/src/mage/cards/a/ArmoredAscension.java +++ b/Mage.Sets/src/mage/cards/a/ArmoredAscension.java @@ -1,12 +1,13 @@ - package mage.cards.a; -import java.util.UUID; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -16,8 +17,9 @@ import mage.filter.common.FilterLandPermanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com, North */ public final class ArmoredAscension extends CardImpl { @@ -29,8 +31,11 @@ public final class ArmoredAscension extends CardImpl { filter.add(TargetController.YOU.getControllerPredicate()); } + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + private static final Hint hint = new ValueHint("Plains you control", xValue); + public ArmoredAscension(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); this.subtype.add(SubType.AURA); @@ -41,10 +46,13 @@ public final class ArmoredAscension extends CardImpl { this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Enchanted creature gets +1/+1 for each Plains you control and has flying. - PermanentsOnBattlefieldCount amount = new PermanentsOnBattlefieldCount(filter, 1); - SimpleStaticAbility ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(amount, amount, Duration.WhileOnBattlefield)); - ability.addEffect(new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA)); - this.addAbility(ability); + SimpleStaticAbility ability = new SimpleStaticAbility( + new BoostEnchantedEffect(xValue, xValue, Duration.WhileOnBattlefield) + ); + ability.addEffect(new GainAbilityAttachedEffect( + FlyingAbility.getInstance(), AttachmentType.AURA + ).setText("and has flying")); + this.addAbility(ability.addHint(hint)); } private ArmoredAscension(final ArmoredAscension card) { diff --git a/Mage.Sets/src/mage/cards/a/ArmoredSkyhunter.java b/Mage.Sets/src/mage/cards/a/ArmoredSkyhunter.java index a4d57dfa177..9c20073645b 100644 --- a/Mage.Sets/src/mage/cards/a/ArmoredSkyhunter.java +++ b/Mage.Sets/src/mage/cards/a/ArmoredSkyhunter.java @@ -100,7 +100,7 @@ class ArmoredSkyhunterEffect extends OneShotEffect { } TargetPermanent targetPermanent = new TargetControlledCreaturePermanent(0, 1); targetCard.setNotTarget(true); - player.choose(outcome, targetPermanent, source.getSourceId(), game); + player.choose(outcome, targetPermanent, source, game); Permanent permanent = game.getPermanent(targetPermanent.getFirstTarget()); if (permanent != null) { permanent.addAttachment(equipment.getId(), source, game); diff --git a/Mage.Sets/src/mage/cards/a/ArmoryAutomaton.java b/Mage.Sets/src/mage/cards/a/ArmoryAutomaton.java index db3852831e7..8ea11d805a0 100644 --- a/Mage.Sets/src/mage/cards/a/ArmoryAutomaton.java +++ b/Mage.Sets/src/mage/cards/a/ArmoryAutomaton.java @@ -88,7 +88,7 @@ class ArmoryAutomatonEffect extends OneShotEffect { while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.Benefit, "Select and attach a target Equipment?", source, game)) { Target targetEquipment = new TargetPermanent(currentFilter); targetEquipment.setRequired(false); - if (player.choose(Outcome.Benefit, targetEquipment, source.getSourceId(), game) && targetEquipment.getFirstTarget() != null) { + if (player.choose(Outcome.Benefit, targetEquipment, source, game) && targetEquipment.getFirstTarget() != null) { currentFilter.add(Predicates.not(new PermanentIdPredicate(targetEquipment.getFirstTarget()))); // exclude selected for next time Permanent aura = game.getPermanent(targetEquipment.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/a/ArniBrokenbrow.java b/Mage.Sets/src/mage/cards/a/ArniBrokenbrow.java index b7531af26b7..c930da96a01 100644 --- a/Mage.Sets/src/mage/cards/a/ArniBrokenbrow.java +++ b/Mage.Sets/src/mage/cards/a/ArniBrokenbrow.java @@ -69,7 +69,7 @@ class ArniBrokenbrowEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (controller == null || mageObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/a/ArrogantWurm.java b/Mage.Sets/src/mage/cards/a/ArrogantWurm.java index 4ca3d3b0482..19c1cc99d18 100644 --- a/Mage.Sets/src/mage/cards/a/ArrogantWurm.java +++ b/Mage.Sets/src/mage/cards/a/ArrogantWurm.java @@ -28,7 +28,7 @@ public final class ArrogantWurm extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Madness {2}{G} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{2}{G}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{2}{G}"))); } private ArrogantWurm(final ArrogantWurm card) { diff --git a/Mage.Sets/src/mage/cards/a/ArsenalThresher.java b/Mage.Sets/src/mage/cards/a/ArsenalThresher.java index 168f8b8e264..a9d3f5eb3ae 100644 --- a/Mage.Sets/src/mage/cards/a/ArsenalThresher.java +++ b/Mage.Sets/src/mage/cards/a/ArsenalThresher.java @@ -14,7 +14,7 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.common.FilterArtifactCard; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -75,12 +75,12 @@ class ArsenalThresherEffect extends OneShotEffect { } Permanent arsenalThresher = game.getPermanentEntering(source.getSourceId()); FilterArtifactCard filter = new FilterArtifactCard(); - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); if (controller.chooseUse(Outcome.Benefit, "Reveal other artifacts in your hand?", source, game)) { Cards cards = new CardsImpl(); - if (controller.getHand().count(filter, source.getSourceId(), source.getControllerId(), game) > 0) { + if (controller.getHand().count(filter, source.getControllerId(), source, game) > 0) { TargetCardInHand target = new TargetCardInHand(0, Integer.MAX_VALUE, filter); - if (controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.Benefit, target, source, game)) { for (UUID uuid : target.getTargets()) { cards.add(controller.getHand().get(uuid, game)); } diff --git a/Mage.Sets/src/mage/cards/a/ArterialAlchemy.java b/Mage.Sets/src/mage/cards/a/ArterialAlchemy.java index 9fc51df6f9d..0750354b54e 100644 --- a/Mage.Sets/src/mage/cards/a/ArterialAlchemy.java +++ b/Mage.Sets/src/mage/cards/a/ArterialAlchemy.java @@ -74,7 +74,7 @@ class ArterialAlchemyEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { for (Permanent permanent : game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game )) { switch (layer) { case TypeChangingEffects_4: diff --git a/Mage.Sets/src/mage/cards/m/MindFlayerTheShadow.java b/Mage.Sets/src/mage/cards/a/ArvinoxTheMindFlail.java similarity index 80% rename from Mage.Sets/src/mage/cards/m/MindFlayerTheShadow.java rename to Mage.Sets/src/mage/cards/a/ArvinoxTheMindFlail.java index a409f0d1d69..8b84f951fa8 100644 --- a/Mage.Sets/src/mage/cards/m/MindFlayerTheShadow.java +++ b/Mage.Sets/src/mage/cards/a/ArvinoxTheMindFlail.java @@ -1,4 +1,4 @@ -package mage.cards.m; +package mage.cards.a; import mage.MageInt; import mage.abilities.Ability; @@ -27,7 +27,7 @@ import java.util.UUID; /** * @author TheElk801 plus everyone who worked on Gonti */ -public final class MindFlayerTheShadow extends CardImpl { +public final class ArvinoxTheMindFlail extends CardImpl { private static final FilterPermanent filter = new FilterControlledPermanent(); @@ -38,7 +38,7 @@ public final class MindFlayerTheShadow extends CardImpl { private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); private static final Hint hint = new ValueHint("Permanents you control but don't own", xValue); - public MindFlayerTheShadow(UUID ownerId, CardSetInfo setInfo) { + public ArvinoxTheMindFlail(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{4}{B}{B}{B}"); this.addSuperType(SuperType.LEGENDARY); @@ -53,23 +53,23 @@ public final class MindFlayerTheShadow extends CardImpl { // At the beginning of your end step, exile the bottom card of each opponent's library face down. For as long as those cards remain exiled, you may look at them, you may cast permanent spells from among them, and you may spend mana as though it were mana of any color to cast those spells. this.addAbility(new BeginningOfEndStepTriggeredAbility( - new MindFlayerTheShadowExileEffect(), TargetController.YOU, false + new ArvinoxTheMindFlailExileEffect(), TargetController.YOU, false )); } - private MindFlayerTheShadow(final MindFlayerTheShadow card) { + private ArvinoxTheMindFlail(final ArvinoxTheMindFlail card) { super(card); } @Override - public MindFlayerTheShadow copy() { - return new MindFlayerTheShadow(this); + public ArvinoxTheMindFlail copy() { + return new ArvinoxTheMindFlail(this); } } -class MindFlayerTheShadowExileEffect extends OneShotEffect { +class ArvinoxTheMindFlailExileEffect extends OneShotEffect { - MindFlayerTheShadowExileEffect() { + ArvinoxTheMindFlailExileEffect() { super(Outcome.Benefit); staticText = "exile the bottom card of each opponent's library face down. " + "For as long as those cards remain exiled, you may look at them, " @@ -77,13 +77,13 @@ class MindFlayerTheShadowExileEffect extends OneShotEffect { + "and you may spend mana as though it were mana of any color to cast those spells"; } - private MindFlayerTheShadowExileEffect(final MindFlayerTheShadowExileEffect effect) { + private ArvinoxTheMindFlailExileEffect(final ArvinoxTheMindFlailExileEffect effect) { super(effect); } @Override - public MindFlayerTheShadowExileEffect copy() { - return new MindFlayerTheShadowExileEffect(this); + public ArvinoxTheMindFlailExileEffect copy() { + return new ArvinoxTheMindFlailExileEffect(this); } @Override @@ -108,21 +108,21 @@ class MindFlayerTheShadowExileEffect extends OneShotEffect { cards.getCards(game).stream().forEach(card -> card.setFaceDown(true, game)); for (Card card : cards.getCards(game)) { card.setFaceDown(true, game); - game.addEffect(new MindFlayerTheShadowCastFromExileEffect().setTargetPointer(new FixedTarget(card, game)), source); - game.addEffect(new MindFlayerTheShadowSpendAnyManaEffect().setTargetPointer(new FixedTarget(card, game)), source); - game.addEffect(new MindFlayerTheShadowLookEffect(source.getControllerId()).setTargetPointer(new FixedTarget(card, game)), source); + game.addEffect(new ArvinoxTheMindFlailCastFromExileEffect().setTargetPointer(new FixedTarget(card, game)), source); + game.addEffect(new ArvinoxTheMindFlailSpendAnyManaEffect().setTargetPointer(new FixedTarget(card, game)), source); + game.addEffect(new ArvinoxTheMindFlailLookEffect(source.getControllerId()).setTargetPointer(new FixedTarget(card, game)), source); } return true; } } -class MindFlayerTheShadowCastFromExileEffect extends AsThoughEffectImpl { +class ArvinoxTheMindFlailCastFromExileEffect extends AsThoughEffectImpl { - public MindFlayerTheShadowCastFromExileEffect() { + public ArvinoxTheMindFlailCastFromExileEffect() { super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit); } - private MindFlayerTheShadowCastFromExileEffect(final MindFlayerTheShadowCastFromExileEffect effect) { + private ArvinoxTheMindFlailCastFromExileEffect(final ArvinoxTheMindFlailCastFromExileEffect effect) { super(effect); } @@ -132,8 +132,8 @@ class MindFlayerTheShadowCastFromExileEffect extends AsThoughEffectImpl { } @Override - public MindFlayerTheShadowCastFromExileEffect copy() { - return new MindFlayerTheShadowCastFromExileEffect(this); + public ArvinoxTheMindFlailCastFromExileEffect copy() { + return new ArvinoxTheMindFlailCastFromExileEffect(this); } @Override @@ -161,14 +161,14 @@ class MindFlayerTheShadowCastFromExileEffect extends AsThoughEffectImpl { } } -class MindFlayerTheShadowSpendAnyManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { +class ArvinoxTheMindFlailSpendAnyManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { - public MindFlayerTheShadowSpendAnyManaEffect() { + public ArvinoxTheMindFlailSpendAnyManaEffect() { super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.Custom, Outcome.Benefit); staticText = "you may spend mana as though it were mana of any color to cast it"; } - private MindFlayerTheShadowSpendAnyManaEffect(final MindFlayerTheShadowSpendAnyManaEffect effect) { + private ArvinoxTheMindFlailSpendAnyManaEffect(final ArvinoxTheMindFlailSpendAnyManaEffect effect) { super(effect); } @@ -178,8 +178,8 @@ class MindFlayerTheShadowSpendAnyManaEffect extends AsThoughEffectImpl implement } @Override - public MindFlayerTheShadowSpendAnyManaEffect copy() { - return new MindFlayerTheShadowSpendAnyManaEffect(this); + public ArvinoxTheMindFlailSpendAnyManaEffect copy() { + return new ArvinoxTheMindFlailSpendAnyManaEffect(this); } @Override @@ -206,17 +206,17 @@ class MindFlayerTheShadowSpendAnyManaEffect extends AsThoughEffectImpl implement } } -class MindFlayerTheShadowLookEffect extends AsThoughEffectImpl { +class ArvinoxTheMindFlailLookEffect extends AsThoughEffectImpl { private final UUID authorizedPlayerId; - public MindFlayerTheShadowLookEffect(UUID authorizedPlayerId) { + public ArvinoxTheMindFlailLookEffect(UUID authorizedPlayerId) { super(AsThoughEffectType.LOOK_AT_FACE_DOWN, Duration.EndOfGame, Outcome.Benefit); this.authorizedPlayerId = authorizedPlayerId; staticText = "You may look at the cards exiled with {this}"; } - private MindFlayerTheShadowLookEffect(final MindFlayerTheShadowLookEffect effect) { + private ArvinoxTheMindFlailLookEffect(final ArvinoxTheMindFlailLookEffect effect) { super(effect); this.authorizedPlayerId = effect.authorizedPlayerId; } @@ -227,8 +227,8 @@ class MindFlayerTheShadowLookEffect extends AsThoughEffectImpl { } @Override - public MindFlayerTheShadowLookEffect copy() { - return new MindFlayerTheShadowLookEffect(this); + public ArvinoxTheMindFlailLookEffect copy() { + return new ArvinoxTheMindFlailLookEffect(this); } @Override diff --git a/Mage.Sets/src/mage/cards/a/AryelKnightOfWindgrace.java b/Mage.Sets/src/mage/cards/a/AryelKnightOfWindgrace.java index 5c493e33179..59d17c42819 100644 --- a/Mage.Sets/src/mage/cards/a/AryelKnightOfWindgrace.java +++ b/Mage.Sets/src/mage/cards/a/AryelKnightOfWindgrace.java @@ -95,7 +95,7 @@ class AryelTapXTargetCost extends VariableCostImpl { @Override public int getMaxValue(Ability source, Game game) { - return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + return game.getBattlefield().count(filter, source.getControllerId(), source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/a/AsForetold.java b/Mage.Sets/src/mage/cards/a/AsForetold.java index d80d0d64748..e4b281fa86d 100644 --- a/Mage.Sets/src/mage/cards/a/AsForetold.java +++ b/Mage.Sets/src/mage/cards/a/AsForetold.java @@ -69,7 +69,7 @@ class SpellWithManaCostLessThanOrEqualToCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && !object.isLand(game) && object.getManaValue() <= counters; diff --git a/Mage.Sets/src/mage/cards/a/AscendantAcolyte.java b/Mage.Sets/src/mage/cards/a/AscendantAcolyte.java new file mode 100644 index 00000000000..464c364c675 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AscendantAcolyte.java @@ -0,0 +1,89 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DoubleCountersSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AscendantAcolyte extends CardImpl { + + public AscendantAcolyte(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MONK); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Ascendant Acolyte enters the battlefield with a +1/+1 counter on it for each +1/+1 counter among other creatures you control. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect( + CounterType.P1P1.createInstance(), AscendantAcolyteValue.instance, true + ), "with a +1/+1 counter on it for each +1/+1 counter among other creatures you control").addHint(AscendantAcolyteValue.getHint())); + + // At the beginning of your upkeep, double the number of +1/+1 counters on Ascendant Acolyte. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new DoubleCountersSourceEffect(CounterType.P1P1), TargetController.YOU, false + )); + } + + private AscendantAcolyte(final AscendantAcolyte card) { + super(card); + } + + @Override + public AscendantAcolyte copy() { + return new AscendantAcolyte(this); + } +} + +enum AscendantAcolyteValue implements DynamicValue { + instance; + private static final Hint hint = new ValueHint( + "Total +1/+1 counters on other creatures you control", instance + ); + + public static Hint getHint() { + return hint; + } + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return game.getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, + sourceAbility.getControllerId(), + sourceAbility, game + ).stream() + .mapToInt(permanent -> permanent.getCounters(game).getCount(CounterType.P1P1)) + .sum(); + } + + @Override + public AscendantAcolyteValue copy() { + return this; + } + + @Override + public String getMessage() { + return ""; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/AscendingAven.java b/Mage.Sets/src/mage/cards/a/AscendingAven.java index 2122b9be66a..1770a937c28 100644 --- a/Mage.Sets/src/mage/cards/a/AscendingAven.java +++ b/Mage.Sets/src/mage/cards/a/AscendingAven.java @@ -30,7 +30,7 @@ public final class AscendingAven extends CardImpl { // Ascending Aven can block only creatures with flying. this.addAbility(new CanBlockOnlyFlyingAbility()); // Morph {2}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{U}"))); } private AscendingAven(final AscendingAven card) { diff --git a/Mage.Sets/src/mage/cards/a/AscentOfTheWorthy.java b/Mage.Sets/src/mage/cards/a/AscentOfTheWorthy.java index c8c9b689e43..60d61305991 100644 --- a/Mage.Sets/src/mage/cards/a/AscentOfTheWorthy.java +++ b/Mage.Sets/src/mage/cards/a/AscentOfTheWorthy.java @@ -87,10 +87,10 @@ class AscentOfTheWorthyEffect extends OneShotEffect { } TargetPermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (!target.canChoose(source.getControllerId(), source, game)) { return false; } - player.choose(outcome, target, source.getControllerId(), game); + player.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent == null) { return false; diff --git a/Mage.Sets/src/mage/cards/a/AshasFavor.java b/Mage.Sets/src/mage/cards/a/AshasFavor.java index 7962eeda7fb..29895a32691 100644 --- a/Mage.Sets/src/mage/cards/a/AshasFavor.java +++ b/Mage.Sets/src/mage/cards/a/AshasFavor.java @@ -1,8 +1,5 @@ - - package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; @@ -13,33 +10,42 @@ import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class AshasFavor extends CardImpl { - public AshasFavor (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}"); + public AshasFavor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); this.subtype.add(SubType.AURA); - TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.AURA))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(VigilanceAbility.getInstance(), AttachmentType.AURA))); + Ability ability = new SimpleStaticAbility(new GainAbilityAttachedEffect( + FlyingAbility.getInstance(), AttachmentType.AURA + )); + ability.addEffect(new GainAbilityAttachedEffect( + FirstStrikeAbility.getInstance(), AttachmentType.AURA + ).setText(", first strike")); + ability.addEffect(new GainAbilityAttachedEffect( + VigilanceAbility.getInstance(), AttachmentType.AURA + ).setText(", and vigilance")); + this.addAbility(ability); } - public AshasFavor (final AshasFavor card) { + public AshasFavor(final AshasFavor card) { super(card); } @@ -47,5 +53,4 @@ public final class AshasFavor extends CardImpl { public AshasFavor copy() { return new AshasFavor(this); } - } diff --git a/Mage.Sets/src/mage/cards/a/AshayaSoulOfTheWild.java b/Mage.Sets/src/mage/cards/a/AshayaSoulOfTheWild.java index 010985ee806..64bf0edd602 100644 --- a/Mage.Sets/src/mage/cards/a/AshayaSoulOfTheWild.java +++ b/Mage.Sets/src/mage/cards/a/AshayaSoulOfTheWild.java @@ -77,7 +77,7 @@ class AshayaSoulOfTheWildEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { for (Permanent permanent : game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game )) { if (!permanent.isLand(game)) { permanent.addCardType(game, CardType.LAND); diff --git a/Mage.Sets/src/mage/cards/a/AshcloudPhoenix.java b/Mage.Sets/src/mage/cards/a/AshcloudPhoenix.java index 6ec21a04e2a..988585ad7bc 100644 --- a/Mage.Sets/src/mage/cards/a/AshcloudPhoenix.java +++ b/Mage.Sets/src/mage/cards/a/AshcloudPhoenix.java @@ -39,7 +39,7 @@ public final class AshcloudPhoenix extends CardImpl { this.addAbility(new DiesSourceTriggeredAbility(new AshcloudPhoenixEffect())); // Morph {4}{R}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{4}{R}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl<>("{4}{R}{R}"))); // When Ashcloud Phoenix is turned face up, it deals 2 damage to each player. Effect effect = new DamagePlayersEffect(2, TargetController.ANY); diff --git a/Mage.Sets/src/mage/cards/a/AshesOfTheFallen.java b/Mage.Sets/src/mage/cards/a/AshesOfTheFallen.java index 0dfd2a82906..2f90d505899 100644 --- a/Mage.Sets/src/mage/cards/a/AshesOfTheFallen.java +++ b/Mage.Sets/src/mage/cards/a/AshesOfTheFallen.java @@ -66,7 +66,7 @@ class AshesOfTheFallenEffect extends ContinuousEffectImpl { } } } else { - discard();; + discard(); } return true; } diff --git a/Mage.Sets/src/mage/cards/a/AshiokDreamRender.java b/Mage.Sets/src/mage/cards/a/AshiokDreamRender.java index ac680020c0d..abfd27ec50e 100644 --- a/Mage.Sets/src/mage/cards/a/AshiokDreamRender.java +++ b/Mage.Sets/src/mage/cards/a/AshiokDreamRender.java @@ -3,7 +3,6 @@ package mage.cards.a; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.common.ExileGraveyardAllPlayersEffect; @@ -29,7 +28,7 @@ public final class AshiokDreamRender extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ASHIOK); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Spells and abilities your opponents control can't cause their controller to search their library. this.addAbility(new SimpleStaticAbility(new AshiokDreamRenderEffect())); @@ -74,7 +73,7 @@ class AshiokDreamRenderEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't search libraries (" + mageObject.getLogName() + " in play)."; } diff --git a/Mage.Sets/src/mage/cards/a/AshiokNightmareMuse.java b/Mage.Sets/src/mage/cards/a/AshiokNightmareMuse.java index 6c783fb101d..1260aad0644 100644 --- a/Mage.Sets/src/mage/cards/a/AshiokNightmareMuse.java +++ b/Mage.Sets/src/mage/cards/a/AshiokNightmareMuse.java @@ -1,24 +1,26 @@ package mage.cards.a; -import java.util.UUID; -import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.*; import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.card.FaceDownPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.AshiokNightmareMuseToken; import mage.players.Player; -import mage.target.common.TargetCardInExile; import mage.target.common.TargetCardInHand; import mage.target.common.TargetNonlandPermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** * @author TheElk801 @@ -30,7 +32,7 @@ public final class AshiokNightmareMuse extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ASHIOK); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Create a 2/3 blue and black Nightmare creature token with "Whenever this creature attacks or blocks, each opponent exiles the top two cards of their library." this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new AshiokNightmareMuseToken()), 1)); @@ -96,6 +98,7 @@ class AshiokNightmareMuseCastEffect extends OneShotEffect { static { filter.add(TargetController.OPPONENT.getOwnerPredicate()); + filter.add(Predicates.not(FaceDownPredicate.instance)); } AshiokNightmareMuseCastEffect() { @@ -118,25 +121,10 @@ class AshiokNightmareMuseCastEffect extends OneShotEffect { if (controller == null) { return false; } - TargetCardInExile target = new TargetCardInExile(0, 3, filter, null); - target.setNotTarget(true); - if (!controller.chooseTarget(outcome, target, source, game)) { // method is fine, controller is still choosing the card - return false; - } - for (UUID targetId : target.getTargets()) { - if (targetId != null) { - Card chosenCard = game.getCard(targetId); - if (chosenCard != null - && game.getState().getZone(chosenCard.getId()) == Zone.EXILED // must be exiled - && game.getOpponents(controller.getId()).contains(chosenCard.getOwnerId()) // must be owned by an opponent - && controller.chooseUse(outcome, "Cast " + chosenCard.getName() + " without paying its mana cost?", source, game)) { - game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(chosenCard, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), null); - } - } - } + CardUtil.castMultipleWithAttributeForFree( + controller, source, game, new CardsImpl(game.getExile().getCards(filter, game)), + StaticFilters.FILTER_CARD, 3 + ); return true; } } diff --git a/Mage.Sets/src/mage/cards/a/AshiokNightmareWeaver.java b/Mage.Sets/src/mage/cards/a/AshiokNightmareWeaver.java index e52d6911130..eb4fd3b2afd 100644 --- a/Mage.Sets/src/mage/cards/a/AshiokNightmareWeaver.java +++ b/Mage.Sets/src/mage/cards/a/AshiokNightmareWeaver.java @@ -1,14 +1,11 @@ - package mage.cards.a; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; -import mage.abilities.costs.Cost; +import mage.abilities.costs.VariableCostImpl; import mage.abilities.costs.common.PayVariableLoyaltyCost; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.AddCardSubTypeTargetEffect; import mage.cards.*; import mage.constants.*; import mage.filter.FilterCard; @@ -35,7 +32,7 @@ public final class AshiokNightmareWeaver extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ASHIOK); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +2: Exile the top three cards of target opponent's library. LoyaltyAbility ability = new LoyaltyAbility(new AshiokNightmareWeaverExileEffect(), 2); @@ -80,15 +77,14 @@ class AshiokNightmareWeaverExileEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player opponent = game.getPlayer(this.getTargetPointer().getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (sourceObject != null && opponent != null && controller != null) { - UUID exileZone = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); - if (exileZone != null) { - controller.moveCardsToExile(opponent.getLibrary().getTopCards(game, 3), source, game, true, exileZone, sourceObject.getIdName()); - return true; - } + if (opponent == null || controller == null) { + return false; } - return false; + controller.moveCardsToExile( + opponent.getLibrary().getTopCards(game, 3), source, game, true, + CardUtil.getExileZoneId(game, source), CardUtil.getSourceName(game, source) + ); + return true; } } @@ -111,65 +107,34 @@ class AshiokNightmareWeaverPutIntoPlayEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (sourceObject == null || controller == null) { + if (controller == null) { return false; } - int cmc = 0; - for (Cost cost : source.getCosts()) { - if (cost instanceof PayVariableLoyaltyCost) { - cmc = ((PayVariableLoyaltyCost) cost).getAmount(); - } - } + int cmc = CardUtil.castStream( + source.getCosts().stream(), PayVariableLoyaltyCost.class + ).mapToInt(VariableCostImpl::getAmount).sum(); - FilterCard filter = new FilterCreatureCard("creature card with mana value {" + cmc + "} exiled with " + sourceObject.getIdName()); + FilterCard filter = new FilterCreatureCard("creature card with mana value " + cmc); filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, cmc)); - Target target = new TargetCardInExile(filter, CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter())); + Target target = new TargetCardInExile(filter, CardUtil.getExileZoneId(game, source)); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - if (controller.chooseTarget(Outcome.PutCreatureInPlay, target, source, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null - && controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { - ContinuousEffectImpl effect = new AshiokNightmareWeaverAddTypeEffect(); - effect.setTargetPointer(new FixedTarget(permanent, game)); - game.addEffect(effect, source); - } - } - } - } - return true; - } -} - -class AshiokNightmareWeaverAddTypeEffect extends ContinuousEffectImpl { - - public AshiokNightmareWeaverAddTypeEffect() { - super(Duration.Custom, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Neutral); - staticText = "That creature is a Nightmare in addition to its other types"; - } - - public AshiokNightmareWeaverAddTypeEffect(final AshiokNightmareWeaverAddTypeEffect effect) { - super(effect); - } - - @Override - public AshiokNightmareWeaverAddTypeEffect copy() { - return new AshiokNightmareWeaverAddTypeEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent creature = game.getPermanent(this.getTargetPointer().getFirst(game, source)); - if (creature == null) { - this.used = true; + if (!target.canChoose(controller.getId(), source, game)) { return false; } - creature.addSubType(game, SubType.NIGHTMARE); + controller.chooseTarget(Outcome.PutCreatureInPlay, target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return true; + } + controller.moveCards(card, Zone.BATTLEFIELD, source, game); + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) { + game.addEffect(new AddCardSubTypeTargetEffect( + SubType.NIGHTMARE, Duration.EndOfTurn + ).setTargetPointer(new FixedTarget(permanent, game)), source); + } return true; } } @@ -193,34 +158,23 @@ class AshiokNightmareWeaverExileAllEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (sourceObject == null || controller == null) { - return false; - } - UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); - if (exileId == null) { + if (controller == null) { return false; } + Cards cards = new CardsImpl(); for (UUID opponentId : game.getOpponents(source.getControllerId())) { Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - Cards cards = new CardsImpl(opponent.getHand()); - for (UUID cardId : cards) { - Card card = game.getCard(cardId); - if (card != null) { - controller.moveCardToExileWithInfo(card, exileId, sourceObject.getIdName(), source, game, Zone.HAND, true); - } - } - cards.clear(); - cards.addAll(opponent.getGraveyard()); - for (UUID cardId : cards) { - Card card = game.getCard(cardId); - if (card != null) { - controller.moveCardToExileWithInfo(card, exileId, sourceObject.getIdName(), source, game, Zone.GRAVEYARD, true); - } - } + if (opponent == null) { + continue; } + cards.addAll(opponent.getHand()); + cards.addAll(opponent.getGraveyard()); } + controller.moveCardsToExile( + cards.getCards(game), source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); return true; } } diff --git a/Mage.Sets/src/mage/cards/a/AshiokSculptorOfFears.java b/Mage.Sets/src/mage/cards/a/AshiokSculptorOfFears.java index ec9e24c8fd1..a2feb015812 100644 --- a/Mage.Sets/src/mage/cards/a/AshiokSculptorOfFears.java +++ b/Mage.Sets/src/mage/cards/a/AshiokSculptorOfFears.java @@ -2,7 +2,6 @@ package mage.cards.a; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.MillCardsEachPlayerEffect; @@ -34,7 +33,7 @@ public final class AshiokSculptorOfFears extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ASHIOK); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +2: Draw a card. Each player puts the top two cards of their library into their graveyard. Ability ability = new LoyaltyAbility( diff --git a/Mage.Sets/src/mage/cards/a/AspectOfWolf.java b/Mage.Sets/src/mage/cards/a/AspectOfWolf.java index 8eb1359d2d1..3c1326272b9 100644 --- a/Mage.Sets/src/mage/cards/a/AspectOfWolf.java +++ b/Mage.Sets/src/mage/cards/a/AspectOfWolf.java @@ -66,7 +66,7 @@ enum AspectOfWolfValue implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { int forestCount = game.getBattlefield().count( - filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game + filter, sourceAbility.getControllerId(), sourceAbility, game ); return forestCount / 2 + (up ? forestCount % 2 : 0); } diff --git a/Mage.Sets/src/mage/cards/a/AssembleTheLegion.java b/Mage.Sets/src/mage/cards/a/AssembleTheLegion.java index d996c592ef6..a1cb98ada51 100644 --- a/Mage.Sets/src/mage/cards/a/AssembleTheLegion.java +++ b/Mage.Sets/src/mage/cards/a/AssembleTheLegion.java @@ -25,7 +25,7 @@ public final class AssembleTheLegion extends CardImpl { // At the beginning of your upkeep, put a muster counter on Assemble the Legion. Then create a 1/1 red and white Soldier creature token with haste for each muster counter on Assemble the Legion. Ability ability = new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.MUSTER.createInstance()), TargetController.YOU, false); - ability.addEffect(new CreateTokenEffect(new SoldierTokenWithHaste(), new CountersSourceCount(CounterType.MUSTER))); + ability.addEffect(new CreateTokenEffect(new SoldierTokenWithHaste(), new CountersSourceCount(CounterType.MUSTER)).concatBy("Then")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AssemblyHall.java b/Mage.Sets/src/mage/cards/a/AssemblyHall.java index 83960e895e8..b9a5055a3a3 100644 --- a/Mage.Sets/src/mage/cards/a/AssemblyHall.java +++ b/Mage.Sets/src/mage/cards/a/AssemblyHall.java @@ -70,7 +70,7 @@ class AssemblyHallEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || controller.getHand().isEmpty() || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/a/AsylumVisitor.java b/Mage.Sets/src/mage/cards/a/AsylumVisitor.java index f2b1087ce34..b2011832780 100644 --- a/Mage.Sets/src/mage/cards/a/AsylumVisitor.java +++ b/Mage.Sets/src/mage/cards/a/AsylumVisitor.java @@ -41,7 +41,7 @@ public final class AsylumVisitor extends CardImpl { this.addAbility(ability); // Madness {1}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{1}{B}"))); } private AsylumVisitor(final AsylumVisitor card) { diff --git a/Mage.Sets/src/mage/cards/a/AtalyaSamiteMaster.java b/Mage.Sets/src/mage/cards/a/AtalyaSamiteMaster.java index a86d36f13c0..473912b2e47 100644 --- a/Mage.Sets/src/mage/cards/a/AtalyaSamiteMaster.java +++ b/Mage.Sets/src/mage/cards/a/AtalyaSamiteMaster.java @@ -54,8 +54,7 @@ public final class AtalyaSamiteMaster extends CardImpl { ability.addTarget(new TargetCreaturePermanent()); // or you gain X life - Mode mode = new Mode(); - mode.addEffect(new GainLifeEffect(ManacostVariableValue.REGULAR).setText("You gain X life. Spend only white mana on X.")); + Mode mode = new Mode(new GainLifeEffect(ManacostVariableValue.REGULAR).setText("You gain X life. Spend only white mana on X.")); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/AtarkaEfreet.java b/Mage.Sets/src/mage/cards/a/AtarkaEfreet.java index d639798fdf8..94b2ee5a42a 100644 --- a/Mage.Sets/src/mage/cards/a/AtarkaEfreet.java +++ b/Mage.Sets/src/mage/cards/a/AtarkaEfreet.java @@ -29,7 +29,7 @@ public final class AtarkaEfreet extends CardImpl { this.toughness = new MageInt(1); // Megamorph {2}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{R}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{R}"), true)); // When Atarka Efreet is turned face up, it deals 1 damage to any target. Effect effect = new DamageTargetEffect(1, "it"); diff --git a/Mage.Sets/src/mage/cards/a/AtarkaWorldRender.java b/Mage.Sets/src/mage/cards/a/AtarkaWorldRender.java index 4eb29bcf77f..219303f4980 100644 --- a/Mage.Sets/src/mage/cards/a/AtarkaWorldRender.java +++ b/Mage.Sets/src/mage/cards/a/AtarkaWorldRender.java @@ -82,7 +82,7 @@ class AtarkaWorldRenderEffect extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { Permanent attacker = game.getPermanent(event.getSourceId()); if (attacker != null - && filter.match(attacker, sourceId, controllerId, game)) { + && filter.match(attacker, controllerId, this, game)) { for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(attacker.getId(), game)); } diff --git a/Mage.Sets/src/mage/cards/a/AtarkasCommand.java b/Mage.Sets/src/mage/cards/a/AtarkasCommand.java index 5b999d8b3da..066aec87c35 100644 --- a/Mage.Sets/src/mage/cards/a/AtarkasCommand.java +++ b/Mage.Sets/src/mage/cards/a/AtarkasCommand.java @@ -34,20 +34,17 @@ public final class AtarkasCommand extends CardImpl { this.getSpellAbility().addEffect(new CantGainLifeAllEffect(Duration.EndOfTurn, TargetController.OPPONENT)); // or Atarka's Command deals 3 damage to each opponent; - Mode mode = new Mode(); - mode.addEffect(new DamagePlayersEffect(3, TargetController.OPPONENT)); + Mode mode = new Mode(new DamagePlayersEffect(3, TargetController.OPPONENT)); this.getSpellAbility().addMode(mode); // or You may put a land card from your hand onto the battlefield; - mode = new Mode(); - mode.addEffect(new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_LAND_A)); + mode = new Mode(new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_LAND_A)); this.getSpellAbility().addMode(mode); // or Creatures you control get +1/+1 and gain reach until the end of turn. - mode = new Mode(); Effect effect = new BoostControlledEffect(1, 1, Duration.EndOfTurn); effect.setText("Creatures you control get +1/+1"); - mode.addEffect(effect); + mode = new Mode(effect); effect = new GainAbilityControlledEffect(ReachAbility.getInstance(), Duration.EndOfTurn); effect.setText("and gain reach until the end of turn"); mode.addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/a/AtemsisAllSeeing.java b/Mage.Sets/src/mage/cards/a/AtemsisAllSeeing.java index 7f110b7c056..465e9eca161 100644 --- a/Mage.Sets/src/mage/cards/a/AtemsisAllSeeing.java +++ b/Mage.Sets/src/mage/cards/a/AtemsisAllSeeing.java @@ -1,6 +1,7 @@ package mage.cards.a; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.DealsDamageToOpponentTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -38,7 +39,7 @@ public final class AtemsisAllSeeing extends CardImpl { // {2}{U}, {T}: Draw two cards, then discard a card. Ability ability = new SimpleActivatedAbility( - new DrawDiscardControllerEffect(2, 1), new ManaCostsImpl("{2}{U}") + new DrawDiscardControllerEffect(2, 1), new ManaCostsImpl<>("{2}{U}") ); ability.addCost(new TapSourceCost()); this.addAbility(ability); @@ -88,7 +89,7 @@ class AtemsisAllSeeingEffect extends OneShotEffect { .getHand() .getCards(game) .stream() - .map(card -> card.getManaValue()) + .map(MageObject::getManaValue) .distinct() .count() > 5) { opponent.lost(game); diff --git a/Mage.Sets/src/mage/cards/a/AthreosGodOfPassage.java b/Mage.Sets/src/mage/cards/a/AthreosGodOfPassage.java index d7fc7e9a137..10764d4ef63 100644 --- a/Mage.Sets/src/mage/cards/a/AthreosGodOfPassage.java +++ b/Mage.Sets/src/mage/cards/a/AthreosGodOfPassage.java @@ -144,7 +144,7 @@ class AthreosDiesCreatureTriggeredAbility extends TriggeredAbilityImpl { if (!zEvent.isDiesEvent()) { return false; } - if (zEvent.getTarget() == null || !filter.match(zEvent.getTarget(), sourceId, controllerId, game)) { + if (zEvent.getTarget() == null || !filter.match(zEvent.getTarget(), controllerId, this, game)) { return false; } for (Effect effect : this.getEffects()) { diff --git a/Mage.Sets/src/mage/cards/a/AtsushiTheBlazingSky.java b/Mage.Sets/src/mage/cards/a/AtsushiTheBlazingSky.java index 803b7100895..84c2e721ca4 100644 --- a/Mage.Sets/src/mage/cards/a/AtsushiTheBlazingSky.java +++ b/Mage.Sets/src/mage/cards/a/AtsushiTheBlazingSky.java @@ -41,7 +41,7 @@ public final class AtsushiTheBlazingSky extends CardImpl { // When Atsushi, the Blazing Sky dies, choose one — // • Exile the top two cards of your library. Until the end of your next turn, you may play those cards. Ability ability = new DiesSourceTriggeredAbility(new ExileTopXMayPlayUntilEndOfTurnEffect( - 3, false, Duration.UntilEndOfYourNextTurn + 2, false, Duration.UntilEndOfYourNextTurn ), false); // • Create three Treasure tokens. diff --git a/Mage.Sets/src/mage/cards/a/AttendedSocialite.java b/Mage.Sets/src/mage/cards/a/AttendedSocialite.java new file mode 100644 index 00000000000..a224987a1a7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AttendedSocialite.java @@ -0,0 +1,39 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.AllianceAbility; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AttendedSocialite extends CardImpl { + + public AttendedSocialite(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Alliance — Whenever another creature enters the battlefield under your control, Attended Socialite gets +1/+1 until end of turn. + this.addAbility(new AllianceAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn))); + } + + private AttendedSocialite(final AttendedSocialite card) { + super(card); + } + + @Override + public AttendedSocialite copy() { + return new AttendedSocialite(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AudaciousSwap.java b/Mage.Sets/src/mage/cards/a/AudaciousSwap.java new file mode 100644 index 00000000000..73e6e205f88 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AudaciousSwap.java @@ -0,0 +1,98 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.CasualtyAbility; +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.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AudaciousSwap extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("nonenchantment permanent"); + + static { + filter.add(Predicates.not(CardType.ENCHANTMENT.getPredicate())); + } + + public AudaciousSwap(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}"); + + // Casualty 2 + this.addAbility(new CasualtyAbility(this, 2)); + + // The owner of target nonenchantment permanent shuffles it into their library, then exiles the top card of their library. If it's a land card, they put it onto the battlefield. Otherwise, they may cast it without paying its mana cost. + this.getSpellAbility().addEffect(new AudaciousSwapEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + private AudaciousSwap(final AudaciousSwap card) { + super(card); + } + + @Override + public AudaciousSwap copy() { + return new AudaciousSwap(this); + } +} + +class AudaciousSwapEffect extends OneShotEffect { + + AudaciousSwapEffect() { + super(Outcome.Benefit); + staticText = "the owner of target nonenchantment permanent shuffles it into their library, then " + + "exiles the top card of their library. If it's a land card, they put it onto the battlefield. " + + "Otherwise, they may cast it without paying its mana cost"; + } + + private AudaciousSwapEffect(final AudaciousSwapEffect effect) { + super(effect); + } + + @Override + public AudaciousSwapEffect copy() { + return new AudaciousSwapEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + return false; + } + Player player = game.getPlayer(permanent.getOwnerId()); + if (player == null) { + return false; + } + player.putCardsOnTopOfLibrary(permanent, game, source, false); + player.shuffleLibrary(source, game); + Card card = player.getLibrary().getFromTop(game); + if (card == null) { + return true; + } + player.moveCards(card, Zone.EXILED, source, game); + if (!card.isLand(game)) { + CardUtil.castSpellWithAttributesForFree(player, source, game, card); + return true; + } + if (player.chooseUse(Outcome.PutLandInPlay, "Put " + card.getName() + " onto the battlefield?", source, game)) { + player.moveCards(card, Zone.BATTLEFIELD, source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AugurOfBolas.java b/Mage.Sets/src/mage/cards/a/AugurOfBolas.java index ded15a1cb91..61f0f9e82b7 100644 --- a/Mage.Sets/src/mage/cards/a/AugurOfBolas.java +++ b/Mage.Sets/src/mage/cards/a/AugurOfBolas.java @@ -1,36 +1,22 @@ package mage.cards.a; import mage.MageInt; -import mage.MageObject; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +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.common.FilterInstantOrSorceryCard; -import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; +import mage.filter.StaticFilters; -import java.util.Set; import java.util.UUID; /** - * @author jeffwadsworth + * @author awjackson */ public final class AugurOfBolas extends CardImpl { - private static final FilterCard filter = new FilterCard("an instant or sorcery card"); - - static { - filter.add(Predicates.or(CardType.INSTANT.getPredicate(), CardType.SORCERY.getPredicate())); - } - public AugurOfBolas(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.MERFOLK); @@ -39,8 +25,11 @@ public final class AugurOfBolas extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(3); - // When Augur of Bolas enters the battlefield, look at the top three cards of your library. You may reveal an instant or sorcery card from among them and put it into your hand. Put the rest on the bottom of your library in any order. - this.addAbility(new EntersBattlefieldTriggeredAbility(new AugurOfBolasEffect())); + // When Augur of Bolas enters the battlefield, look at the top three cards of your library. + // You may reveal an instant or sorcery card from among them and put it into your hand. + // Put the rest on the bottom of your library in any order. + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 3, 1, StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, PutCards.HAND, PutCards.BOTTOM_ANY))); } private AugurOfBolas(final AugurOfBolas card) { @@ -52,57 +41,3 @@ public final class AugurOfBolas extends CardImpl { return new AugurOfBolas(this); } } - -class AugurOfBolasEffect extends OneShotEffect { - - public AugurOfBolasEffect() { - super(Outcome.DrawCard); - this.staticText = "look at the top three cards of your library. You may reveal an instant or sorcery card from among them and put it into your hand. Put the rest on the bottom of your library in any order"; - } - - public AugurOfBolasEffect(final AugurOfBolasEffect effect) { - super(effect); - } - - @Override - public AugurOfBolasEffect copy() { - return new AugurOfBolasEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller != null && sourceObject != null) { - Cards topCards = new CardsImpl(); - topCards.addAll(controller.getLibrary().getTopCards(game, 3)); - if (!topCards.isEmpty()) { - controller.lookAtCards(sourceObject.getIdName(), topCards, game); - int number = topCards.count(new FilterInstantOrSorceryCard(), source.getSourceId(), source.getControllerId(), game); - if (number > 0) { - if (controller.chooseUse(outcome, "Reveal an instant or sorcery card from the looked at cards and put it into your hand?", source, game)) { - Card card = null; - if (number == 1) { - Set cards = topCards.getCards(new FilterInstantOrSorceryCard(), source.getSourceId(), source.getControllerId(), game); - if (!cards.isEmpty()) { - card = cards.iterator().next(); - } - } else { - TargetCard target = new TargetCard(Zone.LIBRARY, new FilterInstantOrSorceryCard()); - controller.chooseTarget(outcome, topCards, target, source, game); - card = topCards.get(target.getFirstTarget(), game); - } - if (card != null) { - controller.moveCards(card, Zone.HAND, source, game); - controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game); - topCards.remove(card); - } - } - } - controller.putCardsOnBottomOfLibrary(topCards, game, source, true); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/a/AuntiesSnitch.java b/Mage.Sets/src/mage/cards/a/AuntiesSnitch.java index 7432bd05b7c..a57287ace22 100644 --- a/Mage.Sets/src/mage/cards/a/AuntiesSnitch.java +++ b/Mage.Sets/src/mage/cards/a/AuntiesSnitch.java @@ -18,7 +18,6 @@ import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; /** @@ -83,7 +82,7 @@ class AuntiesSnitchTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { DamagedPlayerEvent damageEvent = (DamagedPlayerEvent)event; Permanent p = game.getPermanent(event.getSourceId()); - return damageEvent.isCombatDamage() && filter.match(p, getSourceId(), getControllerId(), game); + return damageEvent.isCombatDamage() && filter.match(p, getControllerId(), this, game); } @Override diff --git a/Mage.Sets/src/mage/cards/a/AuraBarbs.java b/Mage.Sets/src/mage/cards/a/AuraBarbs.java index 9fc5d9157e6..175efc7aad2 100644 --- a/Mage.Sets/src/mage/cards/a/AuraBarbs.java +++ b/Mage.Sets/src/mage/cards/a/AuraBarbs.java @@ -54,7 +54,7 @@ public final class AuraBarbs extends CardImpl { FilterPermanent filterEnchantments = new FilterPermanent(); filterEnchantments.add(CardType.ENCHANTMENT.getPredicate()); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filterEnchantments, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filterEnchantments, source.getControllerId(), source, game)) { Player controller = game.getPlayer(permanent.getControllerId()); if (controller != null) { controller.damage(2, permanent.getId(), source, game); @@ -63,7 +63,7 @@ public final class AuraBarbs extends CardImpl { } filterEnchantments.add(SubType.AURA.getPredicate()); - for (Permanent auraEnchantment : game.getBattlefield().getActivePermanents(filterEnchantments, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent auraEnchantment : game.getBattlefield().getActivePermanents(filterEnchantments, source.getControllerId(), source, game)) { if (auraEnchantment.getAttachedTo() != null) { Permanent attachedToCreature = game.getPermanent(auraEnchantment.getAttachedTo()); if (attachedToCreature != null && attachedToCreature.isCreature(game)) { diff --git a/Mage.Sets/src/mage/cards/a/AuraFinesse.java b/Mage.Sets/src/mage/cards/a/AuraFinesse.java index 6322a94a769..8e5416f8c0c 100644 --- a/Mage.Sets/src/mage/cards/a/AuraFinesse.java +++ b/Mage.Sets/src/mage/cards/a/AuraFinesse.java @@ -35,13 +35,13 @@ public final class AuraFinesse extends CardImpl { public AuraFinesse(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}"); - // Attach target Aura you control to target creature. this.getSpellAbility().addEffect(new AuraFinesseEffect()); this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private AuraFinesse(final AuraFinesse card) { @@ -70,26 +70,28 @@ class AuraFinesseEffect extends OneShotEffect { return new AuraFinesseEffect(this); } + // 15/06/2010 As Aura Finesse resolves, if either target is illegal, + // the spell resolves but the Aura doesn’t move. You still draw a card. + // If both targets are illegal, Aura Finesse doesn’t resolve and you don’t draw a card. @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent aura = game.getPermanent(source.getFirstTarget()); - Permanent creature = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (aura != null && creature != null) { - Permanent oldCreature = game.getPermanent(aura.getAttachedTo()); - if (oldCreature != null && !oldCreature.equals(creature)) { - Target auraTarget = aura.getSpellAbility().getTargets().get(0); - if (!auraTarget.canTarget(creature.getId(), game)) { - game.informPlayers(aura.getLogName() + " was not attched to " +creature.getLogName() + " because it's no legal target for the aura" ); - } else if (oldCreature.removeAttachment(aura.getId(), source, game)) { - game.informPlayers(aura.getLogName() + " was unattached from " + oldCreature.getLogName() + " and attached to " + creature.getLogName()); - creature.addAttachment(aura.getId(), source, game); - } + if (controller == null) { return false; } + + Permanent aura = game.getPermanent(source.getFirstTarget()); + Permanent creature = game.getPermanent(source.getTargets().get(1).getFirstTarget()); + if (aura != null && creature != null) { + Permanent oldCreature = game.getPermanent(aura.getAttachedTo()); + if (oldCreature != null && !oldCreature.equals(creature)) { + Target auraTarget = aura.getSpellAbility().getTargets().get(0); + if (!auraTarget.canTarget(creature.getId(), game)) { + game.informPlayers(aura.getLogName() + " was not attched to " +creature.getLogName() + " because it's no legal target for the aura" ); + } else if (oldCreature.removeAttachment(aura.getId(), source, game)) { + game.informPlayers(aura.getLogName() + " was unattached from " + oldCreature.getLogName() + " and attached to " + creature.getLogName()); + creature.addAttachment(aura.getId(), source, game); } } - return true; } - return false; + return true; } } diff --git a/Mage.Sets/src/mage/cards/a/AuraGraft.java b/Mage.Sets/src/mage/cards/a/AuraGraft.java index 27fad23790d..82397b57a6e 100644 --- a/Mage.Sets/src/mage/cards/a/AuraGraft.java +++ b/Mage.Sets/src/mage/cards/a/AuraGraft.java @@ -123,8 +123,8 @@ class MoveTargetAuraEffect extends OneShotEffect { filter.add(new PermanentCanBeAttachedToPredicate(enchantment)); Target target = new TargetPermanent(filter); target.setNotTarget(true); - if (target.canChoose(oldAttachment.getId(), controller.getId(), game) - && controller.choose(outcome, target, oldAttachment.getId(), game)) { + if (target.canChoose(controller.getId(), source, game) + && controller.choose(outcome, target, source, game)) { Permanent newAttachment = game.getPermanent(target.getFirstTarget()); if (newAttachment != null && oldAttachment.removeAttachment(enchantment.getId(), source, game)) { diff --git a/Mage.Sets/src/mage/cards/a/AuraThief.java b/Mage.Sets/src/mage/cards/a/AuraThief.java index 792ea8b9874..90026e5f609 100644 --- a/Mage.Sets/src/mage/cards/a/AuraThief.java +++ b/Mage.Sets/src/mage/cards/a/AuraThief.java @@ -71,7 +71,7 @@ class AuraThiefDiesTriggeredEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { boolean ret = false; - for(Permanent enchantment : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_ENCHANTMENT, source.getControllerId(), source.getControllerId(), game)) { + for(Permanent enchantment : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_ENCHANTMENT, source.getControllerId(), source, game)) { ContinuousEffect gainControl = new GainControlTargetEffect(Duration.EndOfGame); gainControl.setTargetPointer(new FixedTarget(enchantment.getId(), game)); game.addEffect(gainControl, source); diff --git a/Mage.Sets/src/mage/cards/a/Auramancer.java b/Mage.Sets/src/mage/cards/a/Auramancer.java index 6b1d939754c..9319cadce9d 100644 --- a/Mage.Sets/src/mage/cards/a/Auramancer.java +++ b/Mage.Sets/src/mage/cards/a/Auramancer.java @@ -1,12 +1,9 @@ - - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -14,6 +11,8 @@ import mage.constants.SubType; import mage.filter.FilterCard; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** * @author Loki */ @@ -26,13 +25,13 @@ public final class Auramancer extends CardImpl { } public Auramancer(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.WIZARD); this.power = new MageInt(2); this.toughness = new MageInt(2); - Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), true); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AureliasFury.java b/Mage.Sets/src/mage/cards/a/AureliasFury.java index 5d5e32a7c5d..3ce2d3b5357 100644 --- a/Mage.Sets/src/mage/cards/a/AureliasFury.java +++ b/Mage.Sets/src/mage/cards/a/AureliasFury.java @@ -140,7 +140,7 @@ class AureliasFuryCantCastEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast noncreature spells this turn (you were dealt damage by " + mageObject.getLogName() + ')'; } diff --git a/Mage.Sets/src/mage/cards/a/AuriokEdgewright.java b/Mage.Sets/src/mage/cards/a/AuriokEdgewright.java index 87522791a94..55aa47616c4 100644 --- a/Mage.Sets/src/mage/cards/a/AuriokEdgewright.java +++ b/Mage.Sets/src/mage/cards/a/AuriokEdgewright.java @@ -19,7 +19,7 @@ import java.util.UUID; */ public final class AuriokEdgewright extends CardImpl { - protected static String effectText = "Metalcraft — Auriok Edgewright has double strike as long as you control three or more artifacts."; + private static final String effectText = "{this} has double strike as long as you control three or more artifacts."; public AuriokEdgewright(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}"); diff --git a/Mage.Sets/src/mage/cards/a/AuriokSiegeSled.java b/Mage.Sets/src/mage/cards/a/AuriokSiegeSled.java index 4c859bc0dbd..bb360508011 100644 --- a/Mage.Sets/src/mage/cards/a/AuriokSiegeSled.java +++ b/Mage.Sets/src/mage/cards/a/AuriokSiegeSled.java @@ -1,11 +1,10 @@ - package mage.cards.a; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.combat.CantBeBlockedByTargetSourceEffect; import mage.abilities.effects.common.combat.MustBeBlockedByTargetSourceEffect; import mage.cards.CardImpl; @@ -13,8 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; /** @@ -23,12 +21,6 @@ import mage.target.common.TargetCreaturePermanent; */ public final class AuriokSiegeSled extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("artifact creature"); - - static { - filter.add(CardType.ARTIFACT.getPredicate()); - } - public AuriokSiegeSled(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{6}"); this.subtype.add(SubType.JUGGERNAUT); @@ -37,15 +29,17 @@ public final class AuriokSiegeSled extends CardImpl { // {1}: Target artifact creature blocks Auriok Siege Sled this turn if able. MustBeBlockedByTargetSourceEffect effect = new MustBeBlockedByTargetSourceEffect(Duration.EndOfTurn); - effect.setText("Target artifact creature blocks {this} this turn if able."); - Ability ability1 = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}")); - ability1.addTarget(new TargetCreaturePermanent(filter)); + effect.setText("target artifact creature blocks {this} this turn if able"); + Ability ability1 = new SimpleActivatedAbility(effect, new GenericManaCost(1)); + ability1.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE)); this.addAbility(ability1); // {1}: Target artifact creature can't block Auriok Siege Sled this turn. - Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CantBeBlockedByTargetSourceEffect(Duration.EndOfTurn), - new ManaCostsImpl("{1}")); - ability2.addTarget(new TargetCreaturePermanent(filter)); + Ability ability2 = new SimpleActivatedAbility( + new CantBeBlockedByTargetSourceEffect(Duration.EndOfTurn), + new GenericManaCost(1) + ); + ability2.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE)); this.addAbility(ability2); } diff --git a/Mage.Sets/src/mage/cards/a/AurraSingBaneOfJedi.java b/Mage.Sets/src/mage/cards/a/AurraSingBaneOfJedi.java index 0d33dabdcc4..3aeda316adf 100644 --- a/Mage.Sets/src/mage/cards/a/AurraSingBaneOfJedi.java +++ b/Mage.Sets/src/mage/cards/a/AurraSingBaneOfJedi.java @@ -2,7 +2,6 @@ package mage.cards.a; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageControllerEffect; @@ -38,7 +37,7 @@ public final class AurraSingBaneOfJedi extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.AURRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: You may have {this} deal 2 damage to target creature. If you don't, {this} deals 1 damage to you. Ability ability = new LoyaltyAbility(new AurraSingBaneOfJediEffect(), +1); @@ -112,7 +111,7 @@ class SacrificeAllEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - List permanents = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getId(), game); + List permanents = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game); for (Permanent p : permanents) { p.sacrifice(source, game); } diff --git a/Mage.Sets/src/mage/cards/a/AustereCommand.java b/Mage.Sets/src/mage/cards/a/AustereCommand.java index 5f0a0950bf2..0890190d8a9 100644 --- a/Mage.Sets/src/mage/cards/a/AustereCommand.java +++ b/Mage.Sets/src/mage/cards/a/AustereCommand.java @@ -36,16 +36,13 @@ public final class AustereCommand extends CardImpl { // Destroy all artifacts; this.getSpellAbility().addEffect(new DestroyAllEffect(new FilterArtifactPermanent("artifacts"))); // or destroy all enchantments; - Mode mode = new Mode(); - mode.addEffect(new DestroyAllEffect(new FilterEnchantmentPermanent("enchantments"))); + Mode mode = new Mode(new DestroyAllEffect(new FilterEnchantmentPermanent("enchantments"))); this.getSpellAbility().getModes().addMode(mode); // or destroy all creatures with converted mana cost 3 or less; - mode = new Mode(); - mode.addEffect(new DestroyAllEffect(filter3orLess)); + mode = new Mode(new DestroyAllEffect(filter3orLess)); this.getSpellAbility().getModes().addMode(mode); // or destroy all creatures with converted mana cost 4 or greater. - mode = new Mode(); - mode.addEffect(new DestroyAllEffect(filter4orMore)); + mode = new Mode(new DestroyAllEffect(filter4orMore)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/AuthorityOfTheConsuls.java b/Mage.Sets/src/mage/cards/a/AuthorityOfTheConsuls.java index 5ad578250d3..505feb03a18 100644 --- a/Mage.Sets/src/mage/cards/a/AuthorityOfTheConsuls.java +++ b/Mage.Sets/src/mage/cards/a/AuthorityOfTheConsuls.java @@ -7,8 +7,7 @@ import mage.abilities.effects.common.PermanentsEnterBattlefieldTappedEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterOpponentsCreaturePermanent; +import mage.filter.StaticFilters; import java.util.UUID; @@ -17,19 +16,16 @@ import java.util.UUID; */ public final class AuthorityOfTheConsuls extends CardImpl { - private static final FilterPermanent filter - = new FilterOpponentsCreaturePermanent("creatures your opponents control"); - public AuthorityOfTheConsuls(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); // Creatures your opponents control enter the battlefield tapped. - this.addAbility(new SimpleStaticAbility(new PermanentsEnterBattlefieldTappedEffect(filter))); + this.addAbility(new SimpleStaticAbility(new PermanentsEnterBattlefieldTappedEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES))); // Whenever a creature enters the battlefield under an opponent's control, you gain 1 life. this.addAbility(new EntersBattlefieldAllTriggeredAbility( - new GainLifeEffect(1), filter, "Whenever a creature enters " + - "the battlefield under an opponent's control, you gain 1 life." + new GainLifeEffect(1), StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, + "Whenever a creature enters the battlefield under an opponent's control, you gain 1 life." )); } diff --git a/Mage.Sets/src/mage/cards/a/AutomatedArtificer.java b/Mage.Sets/src/mage/cards/a/AutomatedArtificer.java new file mode 100644 index 00000000000..e39f0d2b9c1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AutomatedArtificer.java @@ -0,0 +1,101 @@ +package mage.cards.a; + +import mage.ConditionalMana; +import mage.MageInt; +import mage.MageObject; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.mana.ConditionalColorlessManaAbility; +import mage.abilities.mana.builder.ConditionalManaBuilder; +import mage.abilities.mana.conditional.ManaCondition; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.command.Commander; +import mage.game.stack.StackObject; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AutomatedArtificer extends CardImpl { + + public AutomatedArtificer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); + + this.subtype.add(SubType.ARTIFICER); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // {T}: Add {C}. Spend this mana only to activate an ability or cast an artifact spell. + this.addAbility(new ConditionalColorlessManaAbility( + new TapSourceCost(), 1, new AutomatedArtificerManaBuilder() + )); + } + + private AutomatedArtificer(final AutomatedArtificer card) { + super(card); + } + + @Override + public AutomatedArtificer copy() { + return new AutomatedArtificer(this); + } +} + +class AutomatedArtificerManaBuilder extends ConditionalManaBuilder { + + @Override + public ConditionalMana build(Object... options) { + return new AutomatedArtificerConditionalMana(this.mana); + } + + @Override + public String getRule() { + return "Spend this mana only to activate an ability or cast an artifact spell"; + } +} + +class AutomatedArtificerConditionalMana extends ConditionalMana { + + AutomatedArtificerConditionalMana(Mana mana) { + super(mana); + staticText = "Spend this mana only to activate an ability or cast an artifact spell"; + addCondition(new AutomatedArtificerManaCondition()); + } +} + +class AutomatedArtificerManaCondition extends ManaCondition { + + @Override + public boolean apply(Game game, Ability source) { + if (source == null) { + return false; + } + switch (source.getAbilityType()) { + case MANA: + case ACTIVATED: + return true; + case SPELL: + MageObject object = source.getSourceObject(game); + if (!(object instanceof StackObject) && !game.inCheckPlayableState()) { + return false; + } + if (object instanceof Commander) { + return ((Commander) object).getSourceObject().isArtifact(game); + } + return object.isArtifact(game); + } + return false; + } + + @Override + public boolean apply(Game game, Ability source, UUID originalId, Cost costsToPay) { + return apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AutumnWillow.java b/Mage.Sets/src/mage/cards/a/AutumnWillow.java index 8ee5b02cfd5..e7bd1c7ba35 100644 --- a/Mage.Sets/src/mage/cards/a/AutumnWillow.java +++ b/Mage.Sets/src/mage/cards/a/AutumnWillow.java @@ -70,14 +70,9 @@ class AutumnWillowEffect extends AsThoughEffectImpl { @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.equals(source.getSourceId())) { - return true; - } - } - } - return false; + if (!affectedControllerId.equals(source.getFirstTarget())) { return false; } + Permanent creature = game.getPermanent(sourceId); + + return creature != null &&sourceId.equals(source.getSourceId()); } } diff --git a/Mage.Sets/src/mage/cards/a/AvacynsJudgment.java b/Mage.Sets/src/mage/cards/a/AvacynsJudgment.java index 3fe86e5fb30..c13154d5ae3 100644 --- a/Mage.Sets/src/mage/cards/a/AvacynsJudgment.java +++ b/Mage.Sets/src/mage/cards/a/AvacynsJudgment.java @@ -25,7 +25,7 @@ public final class AvacynsJudgment extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{R}"); // Madness {X}{R} - Ability ability = new MadnessAbility(this, new ManaCostsImpl("{X}{R}")); + Ability ability = new MadnessAbility(new ManaCostsImpl("{X}{R}")); ability.setRuleAtTheTop(true); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/AvatarOfWoe.java b/Mage.Sets/src/mage/cards/a/AvatarOfWoe.java index 47e4137ed23..31a47150ab3 100644 --- a/Mage.Sets/src/mage/cards/a/AvatarOfWoe.java +++ b/Mage.Sets/src/mage/cards/a/AvatarOfWoe.java @@ -66,9 +66,6 @@ class AvatarOfWoeCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - if (AvatarOfWoe.graveyardCount.calculate(game, source, null) >= 10) { - return true; - } - return false; + return AvatarOfWoe.graveyardCount.calculate(game, source, null) >= 10; } } diff --git a/Mage.Sets/src/mage/cards/a/AvenCourier.java b/Mage.Sets/src/mage/cards/a/AvenCourier.java new file mode 100644 index 00000000000..559b52d0fdb --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AvenCourier.java @@ -0,0 +1,119 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetControlledPermanent; +import mage.util.CardUtil; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class AvenCourier extends CardImpl { + + public AvenCourier(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Aven Courier attacks, choose a counter on a permanent you control. Put a counter of that kind on target permanent you control if it doesn't have a counter of that kind on it. + Ability ability = new AttacksTriggeredAbility(new AvenCourierEffect()); + ability.addTarget(new TargetControlledPermanent()); + this.addAbility(ability); + } + + private AvenCourier(final AvenCourier card) { + super(card); + } + + @Override + public AvenCourier copy() { + return new AvenCourier(this); + } +} + +class AvenCourierEffect extends OneShotEffect { + + AvenCourierEffect() { + super(Outcome.Benefit); + staticText = "choose a counter on a permanent you control. Put a counter of that kind " + + "on target permanent you control if it doesn't have a counter of that kind on it"; + } + + private AvenCourierEffect(final AvenCourierEffect effect) { + super(effect); + } + + @Override + public AvenCourierEffect copy() { + return new AvenCourierEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (player == null || permanent == null) { + return false; + } + Set counterTypes = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_PERMANENT, + source.getControllerId(), source, game + ).stream() + .map(p -> p.getCounters(game)) + .map(HashMap::keySet) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toSet()); + String counterType; + switch (counterTypes.size()) { + case 0: + return false; + case 1: + counterType = counterTypes.iterator().next(); + break; + case 2: + Iterator iterator = counterTypes.iterator(); + String type1 = iterator.next(); + String type2 = iterator.next(); + counterType = player.chooseUse( + outcome, "Choose a counter to put on " + permanent.getName(), null, + CardUtil.getTextWithFirstCharUpperCase(type1), + CardUtil.getTextWithFirstCharUpperCase(type2), source, game + ) ? type1 : type2; + break; + default: + Choice choice = new ChoiceImpl(true); + choice.setChoices(counterTypes); + player.choose(outcome, choice, game); + counterType = choice.getChoice(); + } + return permanent.getCounters(game).getCount(counterType) < 1 + && permanent.addCounters(CounterType.findByName(counterType).createInstance(), source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AvenHeartstabber.java b/Mage.Sets/src/mage/cards/a/AvenHeartstabber.java new file mode 100644 index 00000000000..a276b93fce0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AvenHeartstabber.java @@ -0,0 +1,66 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.DifferentManaValuesInGraveCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.MillCardsControllerEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.DifferentManaValuesInGraveHint; +import mage.abilities.keyword.DeathtouchAbility; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AvenHeartstabber extends CardImpl { + + public AvenHeartstabber(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{B}"); + + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // As long as there are five or more mana values among cards in your graveyard, Aven Heartstabber gets +2/+2 and has deathtouch. + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), + DifferentManaValuesInGraveCondition.FIVE, "as long as there are five " + + "or more mana values among cards in your graveyard, {this} gets +2/+2" + )); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(DeathtouchAbility.getInstance()), + DifferentManaValuesInGraveCondition.FIVE, "and has deathtouch" + )); + this.addAbility(ability.addHint(DifferentManaValuesInGraveHint.instance)); + + // When Aven Heartstabber dies, mill two cards, then draw a card. + ability = new DiesSourceTriggeredAbility(new MillCardsControllerEffect(2)); + ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy(", then")); + this.addAbility(ability); + } + + private AvenHeartstabber(final AvenHeartstabber card) { + super(card); + } + + @Override + public AvenHeartstabber copy() { + return new AvenHeartstabber(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AvenLiberator.java b/Mage.Sets/src/mage/cards/a/AvenLiberator.java index ec0647ce4c0..18deae5c05a 100644 --- a/Mage.Sets/src/mage/cards/a/AvenLiberator.java +++ b/Mage.Sets/src/mage/cards/a/AvenLiberator.java @@ -32,7 +32,7 @@ public final class AvenLiberator extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Morph {3}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{W}"))); // When Aven Liberator is turned face up, target creature you control gains protection from the color of your choice until end of turn. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new GainProtectionFromColorTargetEffect(Duration.EndOfTurn)); ability.addTarget(new TargetControlledCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/a/AvenShrine.java b/Mage.Sets/src/mage/cards/a/AvenShrine.java index 43bd4c8b79a..fa652eef316 100644 --- a/Mage.Sets/src/mage/cards/a/AvenShrine.java +++ b/Mage.Sets/src/mage/cards/a/AvenShrine.java @@ -90,7 +90,7 @@ class AvenShrineEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int count = 0; - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if(mageObject != null) { Spell spell = (Spell) game.getState().getValue("avenShrine" + mageObject); if (spell != null) { diff --git a/Mage.Sets/src/mage/cards/a/AvenSoulgazer.java b/Mage.Sets/src/mage/cards/a/AvenSoulgazer.java index 1fae3a76be9..647c2d9c61c 100644 --- a/Mage.Sets/src/mage/cards/a/AvenSoulgazer.java +++ b/Mage.Sets/src/mage/cards/a/AvenSoulgazer.java @@ -81,7 +81,7 @@ class AvenSoulgazerLookFaceDownEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (player == null || mageObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/a/AvenSunstriker.java b/Mage.Sets/src/mage/cards/a/AvenSunstriker.java index c75cb4a63a9..aa2765914e0 100644 --- a/Mage.Sets/src/mage/cards/a/AvenSunstriker.java +++ b/Mage.Sets/src/mage/cards/a/AvenSunstriker.java @@ -30,7 +30,7 @@ public final class AvenSunstriker extends CardImpl { // Double strike this.addAbility(DoubleStrikeAbility.getInstance()); // Megamorph {4}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{W}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{W}"), true)); } private AvenSunstriker(final AvenSunstriker card) { diff --git a/Mage.Sets/src/mage/cards/a/AvenSurveyor.java b/Mage.Sets/src/mage/cards/a/AvenSurveyor.java index 986226eb057..a0799a1ab36 100644 --- a/Mage.Sets/src/mage/cards/a/AvenSurveyor.java +++ b/Mage.Sets/src/mage/cards/a/AvenSurveyor.java @@ -37,8 +37,7 @@ public final class AvenSurveyor extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())); // * Return target creature to its owner's hand - Mode mode = new Mode(); - mode.addEffect(new ReturnToHandTargetEffect()); + Mode mode = new Mode(new ReturnToHandTargetEffect()); mode.addTarget(new TargetCreaturePermanent()); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/AvenTrailblazer.java b/Mage.Sets/src/mage/cards/a/AvenTrailblazer.java index dffb4444326..9954e2607bc 100644 --- a/Mage.Sets/src/mage/cards/a/AvenTrailblazer.java +++ b/Mage.Sets/src/mage/cards/a/AvenTrailblazer.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.DomainValue; @@ -10,19 +8,17 @@ import mage.abilities.hint.common.DomainHint; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.*; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class AvenTrailblazer extends CardImpl { public AvenTrailblazer(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.BIRD); this.subtype.add(SubType.SOLDIER); @@ -31,10 +27,12 @@ public final class AvenTrailblazer extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // Domain - Aven Trailblazer's toughness is equal to the number of basic land types among lands you control. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetToughnessSourceEffect(new DomainValue(), Duration.EndOfGame)).addHint(DomainHint.instance)); - + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SetToughnessSourceEffect(DomainValue.REGULAR, Duration.EndOfGame) + .setText("{this}'s toughness is equal to the number of basic land types among lands you control") + ).addHint(DomainHint.instance).setAbilityWord(AbilityWord.DOMAIN)); } private AvenTrailblazer(final AvenTrailblazer card) { diff --git a/Mage.Sets/src/mage/cards/a/AzcantaTheSunkenRuin.java b/Mage.Sets/src/mage/cards/a/AzcantaTheSunkenRuin.java index 4352f6c7813..fce92d1a56d 100644 --- a/Mage.Sets/src/mage/cards/a/AzcantaTheSunkenRuin.java +++ b/Mage.Sets/src/mage/cards/a/AzcantaTheSunkenRuin.java @@ -1,4 +1,3 @@ - package mage.cards.a; import java.util.UUID; @@ -6,14 +5,13 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.mana.BlueManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; @@ -23,7 +21,7 @@ import mage.filter.predicate.Predicates; */ public final class AzcantaTheSunkenRuin extends CardImpl { - private static final FilterCard filter = new FilterCard("noncreature, nonland card"); + private static final FilterCard filter = new FilterCard("a noncreature, nonland card"); static { filter.add(Predicates.not(CardType.CREATURE.getPredicate())); @@ -44,11 +42,8 @@ public final class AzcantaTheSunkenRuin extends CardImpl { // {2}{U} , {T} : Look at the top four cards of your library. You may reveal a noncreature, nonland card from among them and put it into your hand. Put the rest on the bottom of your library in any order. Ability ability = new SimpleActivatedAbility( - Zone.BATTLEFIELD, - new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(1), - filter, Zone.LIBRARY, false, true, true - ), new ManaCostsImpl<>("{2}{U}") + new LookLibraryAndPickControllerEffect(4, 1, filter, PutCards.HAND, PutCards.BOTTOM_ANY), + new ManaCostsImpl<>("{2}{U}") ); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/AzorTheLawbringer.java b/Mage.Sets/src/mage/cards/a/AzorTheLawbringer.java index 49c90ae4d72..4a1b428af29 100644 --- a/Mage.Sets/src/mage/cards/a/AzorTheLawbringer.java +++ b/Mage.Sets/src/mage/cards/a/AzorTheLawbringer.java @@ -113,7 +113,7 @@ class AzorTheLawbringerCantCastEffect extends ContinuousRuleModifyingEffectImpl @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast instant or sorcery spells this turn (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/a/AzoriusAethermage.java b/Mage.Sets/src/mage/cards/a/AzoriusAethermage.java index 333f7855d93..10a0b598ab1 100644 --- a/Mage.Sets/src/mage/cards/a/AzoriusAethermage.java +++ b/Mage.Sets/src/mage/cards/a/AzoriusAethermage.java @@ -11,7 +11,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; @@ -24,8 +24,6 @@ import java.util.UUID; */ public final class AzoriusAethermage extends CardImpl { - private static final String rule = "Whenever a permanent is returned to your hand, "; - public AzoriusAethermage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); @@ -35,8 +33,8 @@ public final class AzoriusAethermage extends CardImpl { this.toughness = new MageInt(1); // Whenever a permanent is returned to your hand, you may pay {1}. If you do, draw a card. - Effect effect = new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{1}")); - this.addAbility(new AzoriusAEthermageAbility(Zone.BATTLEFIELD, Zone.BATTLEFIELD, Zone.HAND, effect, new FilterPermanent(), rule, false)); + Effect effect = new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{1}")); + this.addAbility(new AzoriusAEthermageAbility(effect)); } private AzoriusAethermage(final AzoriusAethermage card) { @@ -51,25 +49,14 @@ public final class AzoriusAethermage extends CardImpl { class AzoriusAEthermageAbility extends TriggeredAbilityImpl { - protected FilterPermanent filter; - protected Zone fromZone; - protected Zone toZone; - protected String rule; + private static final String rule = "Whenever a permanent is returned to your hand, "; - public AzoriusAEthermageAbility(Zone zone, Zone fromZone, Zone toZone, Effect effect, FilterPermanent filter, String rule, boolean optional) { - super(zone, effect, optional); - this.fromZone = fromZone; - this.toZone = toZone; - this.rule = rule; - this.filter = filter; + public AzoriusAEthermageAbility(Effect effect) { + super(Zone.BATTLEFIELD, effect, false); } - public AzoriusAEthermageAbility(final AzoriusAEthermageAbility ability) { + private AzoriusAEthermageAbility(final AzoriusAEthermageAbility ability) { super(ability); - this.fromZone = ability.fromZone; - this.toZone = ability.toZone; - this.rule = ability.rule; - this.filter = ability.filter; } @Override @@ -80,35 +67,29 @@ class AzoriusAEthermageAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if ((fromZone == null || zEvent.getFromZone() == fromZone) - && (toZone == null || zEvent.getToZone() == toZone)) { - Permanent permanentThatMoved = null; - if (zEvent.getTarget() != null) { - permanentThatMoved = zEvent.getTarget(); - } - //The controller's hand is where the permanent moved to. - return permanentThatMoved != null - && filter.match(permanentThatMoved, sourceId, controllerId, game) - && zEvent.getPlayerId().equals(controllerId); + if (zEvent.getFromZone() != Zone.BATTLEFIELD || zEvent.getToZone() != Zone.HAND) { + return false; } - return false; + + if (!zEvent.getPlayerId().equals(controllerId)) { + return false; + } + + Permanent permanentThatMoved = zEvent.getTarget(); + if (permanentThatMoved == null) { + return false; + } + + return StaticFilters.FILTER_PERMANENT_CREATURE.match(permanentThatMoved, controllerId, this, game); } @Override public String getTriggerPhrase() { - return rule ; + return rule; } @Override public AzoriusAEthermageAbility copy() { return new AzoriusAEthermageAbility(this); } - - public Zone getFromZone() { - return fromZone; - } - - public Zone getToZone() { - return toZone; - } } diff --git a/Mage.Sets/src/mage/cards/a/AzoriusCharm.java b/Mage.Sets/src/mage/cards/a/AzoriusCharm.java index aa364fe42d3..1f44849bf43 100644 --- a/Mage.Sets/src/mage/cards/a/AzoriusCharm.java +++ b/Mage.Sets/src/mage/cards/a/AzoriusCharm.java @@ -28,14 +28,12 @@ public final class AzoriusCharm extends CardImpl { this.getSpellAbility().addEffect(new GainAbilityControlledEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn, new FilterControlledCreaturePermanent("Creatures"))); // or draw a card; - Mode mode = new Mode(); - mode.addEffect(new DrawCardSourceControllerEffect(1)); + Mode mode = new Mode(new DrawCardSourceControllerEffect(1)); this.getSpellAbility().addMode(mode); // or put target attacking or blocking creature on top of its owner's library. - mode = new Mode(); + mode = new Mode(new PutOnLibraryTargetEffect(true)); mode.addTarget(new TargetAttackingOrBlockingCreature()); - mode.addEffect(new PutOnLibraryTargetEffect(true)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/AzoriusJusticiar.java b/Mage.Sets/src/mage/cards/a/AzoriusJusticiar.java index 97376007acf..fc23e4a143e 100644 --- a/Mage.Sets/src/mage/cards/a/AzoriusJusticiar.java +++ b/Mage.Sets/src/mage/cards/a/AzoriusJusticiar.java @@ -1,4 +1,3 @@ - package mage.cards.a; import java.util.UUID; @@ -10,9 +9,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; /** * @@ -20,12 +17,6 @@ import mage.target.common.TargetCreaturePermanent; */ public final class AzoriusJusticiar extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public AzoriusJusticiar(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}{W}"); this.subtype.add(SubType.HUMAN); @@ -37,7 +28,7 @@ public final class AzoriusJusticiar extends CardImpl { // When Azorius Justiciar enters the battlefield, detain up to two target creatures your opponents control. // (Until your next turn, those creatures can't attack or block and their activated abilities can't be activated.) Ability ability = new EntersBattlefieldTriggeredAbility(new DetainTargetEffect()); - ability.addTarget(new TargetCreaturePermanent(0,2,filter,false)); + ability.addTarget(new TargetOpponentsCreaturePermanent(0, 2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AzorsGateway.java b/Mage.Sets/src/mage/cards/a/AzorsGateway.java index 9e97185af0c..18e42b3e952 100644 --- a/Mage.Sets/src/mage/cards/a/AzorsGateway.java +++ b/Mage.Sets/src/mage/cards/a/AzorsGateway.java @@ -38,7 +38,9 @@ public final class AzorsGateway extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.secondSideCardClazz = mage.cards.s.SanctumOfTheSun.class; - // {1}, {T}: Draw a card, then exile a card from your hand. If cards with five or more different converted mana costs are exiled with Azor's Gateway, you gain 5 life, untap Azor's Gateway, and transform it. + // {1}, {T}: Draw a card, then exile a card from your hand. + // If cards with five or more different converted mana costs are exiled with Azor's Gateway, + // you gain 5 life, untap Azor's Gateway, and transform it. this.addAbility(new TransformAbility()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AzorsGatewayEffect(), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); @@ -59,7 +61,9 @@ class AzorsGatewayEffect extends OneShotEffect { public AzorsGatewayEffect() { super(Outcome.Benefit); - this.staticText = "Draw a card, then exile a card from your hand. If cards with five or more different mana values are exiled with {this}, you gain 5 life, untap Azor's Gateway, and transform it"; + this.staticText = "Draw a card, then exile a card from your hand. " + + "If cards with five or more different mana values are exiled with {this}, " + + "you gain 5 life, untap Azor's Gateway, and transform it"; } public AzorsGatewayEffect(final AzorsGatewayEffect effect) { @@ -74,30 +78,32 @@ class AzorsGatewayEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - UUID exileId = CardUtil.getCardExileZoneId(game, source); + if (controller == null) { return false; } + MageObject sourceObject = source.getSourceObject(game); - if (controller != null && exileId != null && sourceObject != null) { - controller.drawCards(1, source, game); - TargetCardInHand target = new TargetCardInHand(); - controller.choose(outcome, target, source.getSourceId(), game); - Card cardToExile = game.getCard(target.getFirstTarget()); - if (cardToExile != null) { - controller.moveCardsToExile(cardToExile, source, game, true, exileId, sourceObject.getIdName()); - } - Set usedCMC = new HashSet<>(); - ExileZone exileZone = game.getExile().getExileZone(exileId); - if (exileZone != null) { - for (Card card : exileZone.getCards(game)) { - usedCMC.add(card.getManaValue()); - } - if (usedCMC.size() > 4) { - controller.gainLife(4, game, source); - new UntapSourceEffect().apply(game, source); - new TransformSourceEffect().apply(game, source); - } - } - return true; + if (sourceObject == null) { return false; } + + UUID exileId = CardUtil.getCardExileZoneId(game, source); + + controller.drawCards(1, source, game); + TargetCardInHand target = new TargetCardInHand(); + controller.choose(outcome, target, source, game); + Card cardToExile = game.getCard(target.getFirstTarget()); + if (cardToExile != null) { + controller.moveCardsToExile(cardToExile, source, game, true, exileId, sourceObject.getIdName()); } - return false; + Set usedCMC = new HashSet<>(); + ExileZone exileZone = game.getExile().getExileZone(exileId); + if (exileZone != null) { + for (Card card : exileZone.getCards(game)) { + usedCMC.add(card.getManaValue()); + } + if (usedCMC.size() > 4) { + controller.gainLife(4, game, source); + new UntapSourceEffect().apply(game, source); + new TransformSourceEffect().apply(game, source); + } + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/a/AzraBladeseeker.java b/Mage.Sets/src/mage/cards/a/AzraBladeseeker.java index 4a73bdf6af4..46ec46c4431 100644 --- a/Mage.Sets/src/mage/cards/a/AzraBladeseeker.java +++ b/Mage.Sets/src/mage/cards/a/AzraBladeseeker.java @@ -75,7 +75,7 @@ class AzraBladeseekerEffect extends OneShotEffect { continue; } Target target = new TargetDiscard(playerId); - if (target.choose(Outcome.DrawCard, playerId, source.getSourceId(), game)) { + if (target.choose(Outcome.DrawCard, playerId, source.getSourceId(), source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { playerCardList.add(new PlayerCard(player, card)); diff --git a/Mage.Sets/src/mage/cards/a/AzraOddsmaker.java b/Mage.Sets/src/mage/cards/a/AzraOddsmaker.java index c119b222b78..28f4dc7f6b7 100644 --- a/Mage.Sets/src/mage/cards/a/AzraOddsmaker.java +++ b/Mage.Sets/src/mage/cards/a/AzraOddsmaker.java @@ -82,7 +82,7 @@ class AzraOddsmakerEffect extends OneShotEffect { Permanent permanent = null; TargetCreaturePermanent target = new TargetCreaturePermanent(); target.setNotTarget(true); - if (player.choose(Outcome.DrawCard, target, source.getSourceId(), game)) { + if (player.choose(Outcome.DrawCard, target, source, game)) { permanent = game.getPermanent(target.getFirstTarget()); } if (permanent == null) { diff --git a/Mage.Sets/src/mage/cards/b/BINGO.java b/Mage.Sets/src/mage/cards/b/BINGO.java index c02556c1903..979e459faa3 100644 --- a/Mage.Sets/src/mage/cards/b/BINGO.java +++ b/Mage.Sets/src/mage/cards/b/BINGO.java @@ -83,7 +83,7 @@ class BingoEffect extends OneShotEffect { if (spell.getManaValue() > 9) { return true; } - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { Map chipCounters = new HashMap<>(); // Map if (game.getState().getValue(mageObject.getId() + "_chip") != null) { diff --git a/Mage.Sets/src/mage/cards/b/BackFromTheBrink.java b/Mage.Sets/src/mage/cards/b/BackFromTheBrink.java index 54c0b94a254..7f326f2d9b3 100644 --- a/Mage.Sets/src/mage/cards/b/BackFromTheBrink.java +++ b/Mage.Sets/src/mage/cards/b/BackFromTheBrink.java @@ -67,12 +67,12 @@ class BackFromTheBrinkCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - if (targets.choose(Outcome.Exile, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.Exile, controllerId, source.getSourceId(), source, game)) { Player controller = game.getPlayer(controllerId); if (controller != null) { Card card = controller.getGraveyard().get(targets.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/cards/b/Backfire.java b/Mage.Sets/src/mage/cards/b/Backfire.java index e9948284cbc..57e3fdf6cf7 100644 --- a/Mage.Sets/src/mage/cards/b/Backfire.java +++ b/Mage.Sets/src/mage/cards/b/Backfire.java @@ -1,10 +1,8 @@ - package mage.cards.b; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; -import mage.abilities.dynamicvalue.common.NumericSetToEffectValues; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.DamageAttachedControllerEffect; import mage.abilities.keyword.EnchantAbility; @@ -32,11 +30,10 @@ public final class Backfire extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.UnboostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Whenever enchanted creature deals damage to you, Backfire deals that much damage to that creature's controller. - this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility(new DamageAttachedControllerEffect(new NumericSetToEffectValues("that much", "damage")), "enchanted creature", false, true, false, TargetController.YOU)); + this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility(new DamageAttachedControllerEffect(SavedDamageValue.MUCH), "enchanted creature", false, true, false, TargetController.YOU)); } private Backfire(final Backfire card) { diff --git a/Mage.Sets/src/mage/cards/b/BackstreetBruiser.java b/Mage.Sets/src/mage/cards/b/BackstreetBruiser.java new file mode 100644 index 00000000000..80419d64518 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BackstreetBruiser.java @@ -0,0 +1,71 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalAsThoughEffect; +import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderSourceEffect; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.Counter; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author weirddan455 + */ +public final class BackstreetBruiser extends CardImpl { + + public BackstreetBruiser(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.CEPHALID); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // As long as there are two or more counters among creatures you control, Backstreet Bruiser can attack as though it didn't have defender. + this.addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect( + new CanAttackAsThoughItDidntHaveDefenderSourceEffect(Duration.WhileOnBattlefield), + BackstreetBruiserCondition.instance + ).setText("As long as there are two or more counters among creatures you control, {this} can attack as though it didn't have defender"))); + } + + private BackstreetBruiser(final BackstreetBruiser card) { + super(card); + } + + @Override + public BackstreetBruiser copy() { + return new BackstreetBruiser(this); + } +} + +enum BackstreetBruiserCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + int totalCounters = 0; + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_CREATURE, source.getControllerId(), source, game)) { + for (Counter counter : permanent.getCounters(game).values()) { + totalCounters += counter.getCount(); + if (totalCounters >= 2) { + return true; + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BackupAgent.java b/Mage.Sets/src/mage/cards/b/BackupAgent.java new file mode 100644 index 00000000000..3eaa6a21e4b --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BackupAgent.java @@ -0,0 +1,43 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author weirddan455 + */ +public final class BackupAgent extends CardImpl { + + public BackupAgent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When Backup Agent enters the battlefield, put a +1/+1 counter on target creature. + Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private BackupAgent(final BackupAgent card) { + super(card); + } + + @Override + public BackupAgent copy() { + return new BackupAgent(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BagOfDevouring.java b/Mage.Sets/src/mage/cards/b/BagOfDevouring.java index b223aa83345..c0a57fc5eb0 100644 --- a/Mage.Sets/src/mage/cards/b/BagOfDevouring.java +++ b/Mage.Sets/src/mage/cards/b/BagOfDevouring.java @@ -113,7 +113,7 @@ class BagOfDevouringEffect extends OneShotEffect { CardUtil.getExileZoneId(game, source) ); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); player.moveCards(new CardsImpl(target.getTargets()), Zone.HAND, source, game); return true; } diff --git a/Mage.Sets/src/mage/cards/b/BakisCurse.java b/Mage.Sets/src/mage/cards/b/BakisCurse.java index 0afce6934a4..78b4627151d 100644 --- a/Mage.Sets/src/mage/cards/b/BakisCurse.java +++ b/Mage.Sets/src/mage/cards/b/BakisCurse.java @@ -55,7 +55,7 @@ class BakisCurseEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), source, game)) { int count = 0; List attachments = creature.getAttachments(); for (UUID attachmentId : attachments) { diff --git a/Mage.Sets/src/mage/cards/b/BalaGedThief.java b/Mage.Sets/src/mage/cards/b/BalaGedThief.java index f27ca9a8548..574025d2f60 100644 --- a/Mage.Sets/src/mage/cards/b/BalaGedThief.java +++ b/Mage.Sets/src/mage/cards/b/BalaGedThief.java @@ -36,7 +36,7 @@ public final class BalaGedThief extends CardImpl { // You choose one of them. That player discards that card. Ability ability = new AllyEntersBattlefieldTriggeredAbility(new DiscardCardYouChooseTargetEffect(TargetController.ANY, xValue), false); ability.addTarget(new TargetPlayer()); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(null)); } private BalaGedThief(final BalaGedThief card) { diff --git a/Mage.Sets/src/mage/cards/b/BalancingAct.java b/Mage.Sets/src/mage/cards/b/BalancingAct.java index 45403e59038..d0c157143b9 100644 --- a/Mage.Sets/src/mage/cards/b/BalancingAct.java +++ b/Mage.Sets/src/mage/cards/b/BalancingAct.java @@ -64,7 +64,7 @@ class BalancingActEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - int count = game.getBattlefield().getActivePermanents(new FilterControlledPermanent(), player.getId(), source.getSourceId(), game).size(); + int count = game.getBattlefield().getActivePermanents(new FilterControlledPermanent(), player.getId(), source, game).size(); if (count < minPermanent) { minPermanent = count; } @@ -75,8 +75,8 @@ class BalancingActEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null) { TargetControlledPermanent target = new TargetControlledPermanent(minPermanent, minPermanent, new FilterControlledPermanent(), true); - if (target.choose(Outcome.Benefit, player.getId(), source.getSourceId(), game)) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledPermanent(), player.getId(), source.getSourceId(), game)) { + if (target.choose(Outcome.Benefit, player.getId(), source.getSourceId(), source, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledPermanent(), player.getId(), source, game)) { if (permanent != null && !target.getTargets().contains(permanent.getId())) { permanent.sacrifice(source, game); } @@ -101,7 +101,7 @@ class BalancingActEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null) { TargetCardInHand target = new TargetCardInHand(minCard, new FilterCard()); - if (target.choose(Outcome.Benefit, player.getId(), source.getSourceId(), game)) { + if (target.choose(Outcome.Benefit, player.getId(), source.getSourceId(), source, game)) { Cards cards = player.getHand().copy(); cards.removeIf(target.getTargets()::contains); player.discard(cards, false, source, game); diff --git a/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java b/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java index 6bb41553fa1..51276efd26e 100644 --- a/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java +++ b/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java @@ -115,8 +115,8 @@ class BalduvianWarlordUnblockEffect extends OneShotEffect { FilterAttackingCreature filter = new FilterAttackingCreature("creature attacking " + targetsController.getLogName()); filter.add(new PermanentInListPredicate(list)); TargetAttackingCreature target = new TargetAttackingCreature(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - while (!target.isChosen() && target.canChoose(source.getSourceId(), controller.getId(), game) && controller.canRespond()) { + if (target.canChoose(controller.getId(), source, game)) { + while (!target.isChosen() && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target, source, game); } } else { diff --git a/Mage.Sets/src/mage/cards/b/BalefireDragon.java b/Mage.Sets/src/mage/cards/b/BalefireDragon.java index 827778e328a..61468c3d7dd 100644 --- a/Mage.Sets/src/mage/cards/b/BalefireDragon.java +++ b/Mage.Sets/src/mage/cards/b/BalefireDragon.java @@ -1,21 +1,15 @@ - package mage.cards.b; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.DamageAllControlledTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; /** * @@ -31,9 +25,12 @@ public final class BalefireDragon extends CardImpl { this.toughness = new MageInt(6); this.addAbility(FlyingAbility.getInstance()); - // Whenever Balefire Dragon deals combat damage to a player, it deals that much damage to each creature that player controls. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new BalefireDragonEffect(), false, true)); + // Whenever Balefire Dragon deals combat damage to a player, + // it deals that much damage to each creature that player controls. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DamageAllControlledTargetEffect(SavedDamageValue.MUCH, "it"), + false, true)); } private BalefireDragon(final BalefireDragon card) { @@ -45,36 +42,3 @@ public final class BalefireDragon extends CardImpl { return new BalefireDragon(this); } } - -class BalefireDragonEffect extends OneShotEffect { - - public BalefireDragonEffect() { - super(Outcome.Damage); - staticText = "it deals that much damage to each creature that player controls"; - } - - public BalefireDragonEffect(final BalefireDragonEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(targetPointer.getFirst(game, source)); - if (player != null) { - int amount = (Integer) getValue("damage"); - if (amount > 0) { - for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, player.getId(), game)) { - creature.damage(amount, source.getSourceId(), source, game, false, true); - } - } - return true; - } - return false; - } - - @Override - public BalefireDragonEffect copy() { - return new BalefireDragonEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/b/BallroomBrawlers.java b/Mage.Sets/src/mage/cards/b/BallroomBrawlers.java new file mode 100644 index 00000000000..5dbe42a864e --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BallroomBrawlers.java @@ -0,0 +1,95 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.LifelinkAbility; +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.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTargets; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BallroomBrawlers extends CardImpl { + + public BallroomBrawlers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(5); + + // Whenever Ballroom Brawlers attacks, Ballroom Brawlers and up to one other target creature you control each gain your choice of first strike or lifelink until end of turn. + Ability ability = new AttacksTriggeredAbility(new BallroomBrawlersEffect()); + ability.addTarget(new TargetPermanent(0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); + this.addAbility(ability); + } + + private BallroomBrawlers(final BallroomBrawlers card) { + super(card); + } + + @Override + public BallroomBrawlers copy() { + return new BallroomBrawlers(this); + } +} + +class BallroomBrawlersEffect extends OneShotEffect { + + BallroomBrawlersEffect() { + super(Outcome.Benefit); + staticText = "{this} and up to one other target creature you control " + + "both gain your choice of first strike or lifelink until end of turn"; + } + + private BallroomBrawlersEffect(final BallroomBrawlersEffect effect) { + super(effect); + } + + @Override + public BallroomBrawlersEffect copy() { + return new BallroomBrawlersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + List permanents = new ArrayList<>(); + permanents.add(source.getSourcePermanentIfItStillExists(game)); + permanents.add(game.getPermanent(getTargetPointer().getFirst(game, source))); + permanents.removeIf(Objects::isNull); + if (permanents.isEmpty()) { + return false; + } + Ability ability = player.chooseUse( + outcome, "Choose first strike or lifelink", null, + "First Strike", "Lifelink", source, game + ) ? FirstStrikeAbility.getInstance() : LifelinkAbility.getInstance(); + game.addEffect(new GainAbilityTargetEffect(ability, Duration.EndOfTurn) + .setTargetPointer(new FixedTargets(permanents, game)), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BallynockCohort.java b/Mage.Sets/src/mage/cards/b/BallynockCohort.java index a7afdb28be3..539e3f0a082 100644 --- a/Mage.Sets/src/mage/cards/b/BallynockCohort.java +++ b/Mage.Sets/src/mage/cards/b/BallynockCohort.java @@ -35,7 +35,7 @@ public final class BallynockCohort extends CardImpl { filter.add(AnotherPredicate.instance); } - private String rule = "{this} gets +1/+1 as long as you control another white creature"; + private static final String rule = "{this} gets +1/+1 as long as you control another white creature"; public BallynockCohort(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); diff --git a/Mage.Sets/src/mage/cards/b/BalmOfRestoration.java b/Mage.Sets/src/mage/cards/b/BalmOfRestoration.java index f7af97f9800..12e9d88efad 100644 --- a/Mage.Sets/src/mage/cards/b/BalmOfRestoration.java +++ b/Mage.Sets/src/mage/cards/b/BalmOfRestoration.java @@ -32,8 +32,7 @@ public final class BalmOfRestoration extends CardImpl { ability.addCost(new SacrificeSourceCost()); // or prevent the next 2 damage that would be dealt to any target this turn. - Mode mode = new Mode(); - mode.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, 2)); + Mode mode = new Mode(new PreventDamageToTargetEffect(Duration.EndOfTurn, 2)); mode.addTarget(new TargetAnyTarget()); ability.addMode(mode); diff --git a/Mage.Sets/src/mage/cards/b/BalthorTheDefiled.java b/Mage.Sets/src/mage/cards/b/BalthorTheDefiled.java index 2328627e1b5..46bb525f73f 100644 --- a/Mage.Sets/src/mage/cards/b/BalthorTheDefiled.java +++ b/Mage.Sets/src/mage/cards/b/BalthorTheDefiled.java @@ -89,7 +89,7 @@ class BalthorTheDefiledEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - cardsToReturn.addAll(player.getGraveyard().getCards(filter, source.getSourceId(), source.getControllerId(), game)); + cardsToReturn.addAll(player.getGraveyard().getCards(filter, source.getControllerId(), source, game)); } } controller.moveCards(cardsToReturn.getCards(game), Zone.BATTLEFIELD, source, game, false, false, true, null); diff --git a/Mage.Sets/src/mage/cards/b/BaneAlleyBroker.java b/Mage.Sets/src/mage/cards/b/BaneAlleyBroker.java index 26b383bded4..f90e667e36e 100644 --- a/Mage.Sets/src/mage/cards/b/BaneAlleyBroker.java +++ b/Mage.Sets/src/mage/cards/b/BaneAlleyBroker.java @@ -162,7 +162,7 @@ class BaneAlleyBrokerReturnToHandEffect extends OneShotEffect { if (card == null) { return false; } - return card != null && player.moveCards(card, Zone.HAND, source, game); + return player.moveCards(card, Zone.HAND, source, game); } } diff --git a/Mage.Sets/src/mage/cards/b/BaneOfProgress.java b/Mage.Sets/src/mage/cards/b/BaneOfProgress.java index 609daa3db66..b452f1339f6 100644 --- a/Mage.Sets/src/mage/cards/b/BaneOfProgress.java +++ b/Mage.Sets/src/mage/cards/b/BaneOfProgress.java @@ -70,7 +70,7 @@ class BaneOfProgressEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int destroyedPermanents = 0; - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (permanent.destroy(source, game, false)) { destroyedPermanents++; } diff --git a/Mage.Sets/src/mage/cards/b/BaneOfTheLiving.java b/Mage.Sets/src/mage/cards/b/BaneOfTheLiving.java index e0765a87d3b..7d951ad6fc4 100644 --- a/Mage.Sets/src/mage/cards/b/BaneOfTheLiving.java +++ b/Mage.Sets/src/mage/cards/b/BaneOfTheLiving.java @@ -31,7 +31,7 @@ public final class BaneOfTheLiving extends CardImpl { this.toughness = new MageInt(3); // Morph {X}{B}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{X}{B}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{X}{B}{B}"))); // When Bane of the Living is turned face up, all creatures get -X/-X until end of turn. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new BoostAllEffect(morphX, morphX, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_ALL_CREATURES, false, null, true))); diff --git a/Mage.Sets/src/mage/cards/b/BaneclawMarauder.java b/Mage.Sets/src/mage/cards/b/BaneclawMarauder.java index 2a2394c962e..e158a3c738f 100644 --- a/Mage.Sets/src/mage/cards/b/BaneclawMarauder.java +++ b/Mage.Sets/src/mage/cards/b/BaneclawMarauder.java @@ -1,7 +1,6 @@ package mage.cards.b; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.common.BecomesBlockedSourceTriggeredAbility; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.effects.common.LoseLifeTargetControllerEffect; @@ -12,18 +11,10 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.WatcherScope; -import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.ObjectSourcePlayer; -import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.watchers.Watcher; -import java.util.*; +import java.util.UUID; /** * @author TheElk801 @@ -31,11 +22,9 @@ import java.util.*; public final class BaneclawMarauder extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - private static final FilterPermanent filter2 = new FilterCreaturePermanent("a creature blocking {this}"); static { filter.add(BlockingOrBlockedBySourcePredicate.BLOCKING); - filter2.add(BaneclawMarauderPredicate.instance); } public BaneclawMarauder(UUID ownerId, CardSetInfo setInfo) { @@ -56,8 +45,8 @@ public final class BaneclawMarauder extends CardImpl { this.addAbility(new DiesCreatureTriggeredAbility( new LoseLifeTargetControllerEffect(1) .setText("that creature's controller loses 1 life"), - false, filter2, true - ), new BaneclawMarauderWatcher()); + false, filter, true + )); // Nightbound this.addAbility(new NightboundAbility()); @@ -72,55 +61,3 @@ public final class BaneclawMarauder extends CardImpl { return new BaneclawMarauder(this); } } - -enum BaneclawMarauderPredicate implements ObjectSourcePlayerPredicate { - instance; - - @Override - public boolean apply(ObjectSourcePlayer input, Game game) { - return BaneclawMarauderWatcher.check(input.getSourceId(), input.getObject(), game); - } -} - -class BaneclawMarauderWatcher extends Watcher { - - private final Map> blockerMap = new HashMap<>(); - - BaneclawMarauderWatcher() { - super(WatcherScope.GAME); - } - - @Override - public void watch(GameEvent event, Game game) { - switch (event.getType()) { - case BLOCKER_DECLARED: - blockerMap - .computeIfAbsent(new MageObjectReference(event.getTargetId(), game), x -> new HashSet<>()) - .add(new MageObjectReference(event.getSourceId(), game)); - return; - case END_COMBAT_STEP_POST: - blockerMap.clear(); - return; - case REMOVED_FROM_COMBAT: - blockerMap - .values() - .stream() - .forEach(set -> set.removeIf(mor -> mor.refersTo(event.getTargetId(), game))); - } - } - - @Override - public void reset() { - super.reset(); - blockerMap.clear(); - } - - static boolean check(UUID sourceId, Permanent blocker, Game game) { - return game.getState() - .getWatcher(BaneclawMarauderWatcher.class) - .blockerMap - .getOrDefault(new MageObjectReference(sourceId, game), Collections.emptySet()) - .stream() - .anyMatch(mor -> mor.refersTo(blocker, game)); - } -} diff --git a/Mage.Sets/src/mage/cards/b/Banefire.java b/Mage.Sets/src/mage/cards/b/Banefire.java index ccf67d35f2a..8c3657e3606 100644 --- a/Mage.Sets/src/mage/cards/b/Banefire.java +++ b/Mage.Sets/src/mage/cards/b/Banefire.java @@ -34,6 +34,7 @@ public final class Banefire extends CardImpl { // Banefire deals X damage to any target. this.getSpellAbility().addEffect(new BaneFireEffect()); this.getSpellAbility().addTarget(new TargetAnyTarget()); + // If X is 5 or more, Banefire can't be countered and the damage can't be prevented. this.addAbility(new SimpleStaticAbility(Zone.STACK, new BanefireCantCounterEffect())); } @@ -50,8 +51,8 @@ public final class Banefire extends CardImpl { class testCondition implements Condition { - private DynamicValue xValue; - private int limit; + private final DynamicValue xValue; + private final int limit; public testCondition(DynamicValue xValue, int limit) { this.xValue = xValue; @@ -105,7 +106,7 @@ class BaneFireEffect extends OneShotEffect { class BanefireCantCounterEffect extends ContinuousRuleModifyingEffectImpl { - Condition condition = new testCondition(ManacostVariableValue.REGULAR, 5); + private Condition condition = new testCondition(ManacostVariableValue.REGULAR, 5); public BanefireCantCounterEffect() { super(Duration.WhileOnStack, Outcome.Benefit); @@ -129,18 +130,14 @@ class BanefireCantCounterEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.COUNTER) { - Card card = game.getCard(source.getSourceId()); - if (card != null) { - UUID spellId = card.getSpellAbility().getId(); - if (event.getTargetId().equals(spellId)) { - if (condition.apply(game, source)) { - return true; - } - } - } - } - return false; - } + if (event.getType() != GameEvent.EventType.COUNTER) { return false; } + Card card = game.getCard(source.getSourceId()); + if (card == null) { return false; } + + UUID spellId = card.getSpellAbility().getId(); + if (!event.getTargetId().equals(spellId)) { return false; } + + return condition.apply(game, source); + } } diff --git a/Mage.Sets/src/mage/cards/b/BantCharm.java b/Mage.Sets/src/mage/cards/b/BantCharm.java index 98ba3c09e82..bce7fcac5e0 100644 --- a/Mage.Sets/src/mage/cards/b/BantCharm.java +++ b/Mage.Sets/src/mage/cards/b/BantCharm.java @@ -34,13 +34,11 @@ public final class BantCharm extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetArtifactPermanent()); // or put target creature on the bottom of its owner's library; - Mode mode = new Mode(); - mode.addEffect(new PutOnLibraryTargetEffect(false)); + Mode mode = new Mode(new PutOnLibraryTargetEffect(false)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or counter target instant spell. - mode = new Mode(); - mode.addEffect(new CounterTargetEffect()); + mode = new Mode(new CounterTargetEffect()); mode.addTarget(new TargetSpell(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/BantSojourners.java b/Mage.Sets/src/mage/cards/b/BantSojourners.java index c96ea3fe610..f2d7d76d62b 100644 --- a/Mage.Sets/src/mage/cards/b/BantSojourners.java +++ b/Mage.Sets/src/mage/cards/b/BantSojourners.java @@ -1,41 +1,44 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.CycleTriggeredAbility; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.CyclingAbility; +import mage.abilities.meta.OrTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.Zone; import mage.game.permanent.token.SoldierToken; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class BantSojourners extends CardImpl { public BantSojourners(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{W}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}{U}"); this.subtype.add(SubType.HUMAN, SubType.SOLDIER); this.power = new MageInt(2); this.toughness = new MageInt(4); // When you cycle Bant Sojourners or it dies, you may create a 1/1 white Soldier creature token. - Ability ability1 = new CycleTriggeredAbility(new CreateTokenEffect(new SoldierToken()), true); - Ability ability2 = new DiesSourceTriggeredAbility(new CreateTokenEffect(new SoldierToken()), true); - this.addAbility(ability1); - this.addAbility(ability2); - + this.addAbility(new OrTriggeredAbility(Zone.ALL, + new CreateTokenEffect(new SoldierToken()), + true, + "When you cycle {this} or it dies, ", + new CycleTriggeredAbility(null, true), + new DiesSourceTriggeredAbility(null, true) + )); + // Cycling {2}{W} - this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}{W}"))); + this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{2}{W}"))); } private BantSojourners(final BantSojourners card) { diff --git a/Mage.Sets/src/mage/cards/b/BanthaHerd.java b/Mage.Sets/src/mage/cards/b/BanthaHerd.java index a20e4be969a..0e06b46df17 100644 --- a/Mage.Sets/src/mage/cards/b/BanthaHerd.java +++ b/Mage.Sets/src/mage/cards/b/BanthaHerd.java @@ -65,10 +65,10 @@ class BathaHerdEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - int xValue = ((BecomesMonstrousSourceTriggeredAbility) source).getMonstrosityValue(); - return new CreateTokenEffect(new TuskenRaiderToken(), xValue).apply(game, source); - } - return false; + if (controller == null) { return false; } + + int xValue = ((BecomesMonstrousSourceTriggeredAbility) source).getMonstrosityValue(); + + return new CreateTokenEffect(new TuskenRaiderToken(), xValue).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/b/BaralChiefOfCompliance.java b/Mage.Sets/src/mage/cards/b/BaralChiefOfCompliance.java index f22bd18f2fc..6a6bc26cd0f 100644 --- a/Mage.Sets/src/mage/cards/b/BaralChiefOfCompliance.java +++ b/Mage.Sets/src/mage/cards/b/BaralChiefOfCompliance.java @@ -18,7 +18,6 @@ import mage.filter.predicate.Predicates; import java.util.UUID; /** - * * @author fireshoes */ public final class BaralChiefOfCompliance extends CardImpl { @@ -35,7 +34,7 @@ public final class BaralChiefOfCompliance extends CardImpl { public BaralChiefOfCompliance(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); - addSuperType(SuperType.LEGENDARY); + addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN, SubType.WIZARD); this.power = new MageInt(1); this.toughness = new MageInt(3); @@ -44,7 +43,7 @@ public final class BaralChiefOfCompliance extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(filter, 1))); // Whenever a spell or ability you control counters a spell, you may draw a card. If you do, discard a card. - this.addAbility(new SpellCounteredControllerTriggeredAbility(new DrawDiscardControllerEffect(), true)); + this.addAbility(new SpellCounteredControllerTriggeredAbility(new DrawDiscardControllerEffect(true))); } private BaralChiefOfCompliance(final BaralChiefOfCompliance card) { diff --git a/Mage.Sets/src/mage/cards/b/BaralsExpertise.java b/Mage.Sets/src/mage/cards/b/BaralsExpertise.java index 634b7ee170f..483f3a0a59a 100644 --- a/Mage.Sets/src/mage/cards/b/BaralsExpertise.java +++ b/Mage.Sets/src/mage/cards/b/BaralsExpertise.java @@ -1,27 +1,34 @@ package mage.cards.b; -import java.util.UUID; import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect; +import mage.abilities.effects.common.cost.CastFromHandForFreeEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class BaralsExpertise extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("artifacts and/or creatures"); + private static final FilterCard filter2 = new FilterCard("a spell with mana value 4 or less"); static { - filter.add(Predicates.or(CardType.ARTIFACT.getPredicate(), - CardType.CREATURE.getPredicate())); + filter.add(Predicates.or( + CardType.ARTIFACT.getPredicate(), + CardType.CREATURE.getPredicate() + )); + filter2.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 5)); } public BaralsExpertise(UUID ownerId, CardSetInfo setInfo) { @@ -32,7 +39,7 @@ public final class BaralsExpertise extends CardImpl { getSpellAbility().addTarget(new TargetPermanent(0, 3, filter, false)); // You may cast a card with converted mana cost 4 or less from your hand without paying its mana cost. - getSpellAbility().addEffect(new CastWithoutPayingManaCostEffect(4).concatBy("
")); + getSpellAbility().addEffect(new CastFromHandForFreeEffect(filter2).concatBy("
")); } private BaralsExpertise(final BaralsExpertise card) { diff --git a/Mage.Sets/src/mage/cards/b/BarbedBackWurm.java b/Mage.Sets/src/mage/cards/b/BarbedBackWurm.java index a3d937a91d5..5941c3d1831 100644 --- a/Mage.Sets/src/mage/cards/b/BarbedBackWurm.java +++ b/Mage.Sets/src/mage/cards/b/BarbedBackWurm.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -13,30 +11,37 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LoneFox */ public final class BarbedBackWurm extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("green creature blocking {this}"); + + static { + filter.add(new ColorPredicate(ObjectColor.GREEN)); + filter.add(BlockingOrBlockedBySourcePredicate.BLOCKING); + } + public BarbedBackWurm(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.WURM); this.power = new MageInt(4); this.toughness = new MageInt(3); // {B}: Target green creature blocking Barbed-Back Wurm gets -1/-1 until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(-1, -1, Duration.EndOfTurn), new ManaCostsImpl("{B}")); - FilterCreaturePermanent filter = new FilterCreaturePermanent("green creature blocking {this}"); - filter.add(new ColorPredicate(ObjectColor.GREEN)); - filter.add(new BlockingAttackerIdPredicate(this.getId())); - ability.addTarget(new TargetCreaturePermanent(filter)); + Ability ability = new SimpleActivatedAbility(new BoostTargetEffect( + -1, -1, Duration.EndOfTurn + ), new ManaCostsImpl<>("{B}")); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BarbedLightning.java b/Mage.Sets/src/mage/cards/b/BarbedLightning.java index 5f774da7f45..d8252a6fcff 100644 --- a/Mage.Sets/src/mage/cards/b/BarbedLightning.java +++ b/Mage.Sets/src/mage/cards/b/BarbedLightning.java @@ -25,8 +25,7 @@ public final class BarbedLightning extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // or Barbed Lightning deals 3 damage to target player. - Mode mode = new Mode(); - mode.addEffect(new DamageTargetEffect(3)); + Mode mode = new Mode(new DamageTargetEffect(3)); mode.addTarget(new TargetPlayerOrPlaneswalker()); this.getSpellAbility().getModes().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/b/BarbedShocker.java b/Mage.Sets/src/mage/cards/b/BarbedShocker.java index 97406cf6662..c921f095ef5 100644 --- a/Mage.Sets/src/mage/cards/b/BarbedShocker.java +++ b/Mage.Sets/src/mage/cards/b/BarbedShocker.java @@ -31,8 +31,11 @@ public final class BarbedShocker extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Haste this.addAbility(HasteAbility.getInstance()); + // Whenever Barbed Shocker deals damage to a player, that player discards all the cards in their hand, then draws that many cards. - this.addAbility(new DealsDamageToAPlayerTriggeredAbility(new BarbedShockerEffect(), false, true)); + this.addAbility(new DealsDamageToAPlayerTriggeredAbility( + new BarbedShockerEffect(), false, true + )); } private BarbedShocker(final BarbedShocker card) { @@ -49,7 +52,7 @@ class BarbedShockerEffect extends OneShotEffect { BarbedShockerEffect() { super(Outcome.Discard); - this.staticText = " that player discards all the cards in their hand, then draws that many cards"; + this.staticText = "that player discards all the cards in their hand, then draws that many cards"; } private BarbedShockerEffect(final BarbedShockerEffect effect) { @@ -64,11 +67,12 @@ class BarbedShockerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); - if (targetPlayer == null) { + if (targetPlayer == null || targetPlayer.getHand().isEmpty()) { return false; } - int count = targetPlayer.discard(targetPlayer.getHand(), false, source, game).size(); - targetPlayer.drawCards(count, source, game); + targetPlayer.drawCards(targetPlayer.discard( + targetPlayer.getHand(), false, source, game + ).size(), source, game); return true; } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/b/BarbedSliver.java b/Mage.Sets/src/mage/cards/b/BarbedSliver.java index 6eb399d6442..0b8a258bb3e 100644 --- a/Mage.Sets/src/mage/cards/b/BarbedSliver.java +++ b/Mage.Sets/src/mage/cards/b/BarbedSliver.java @@ -29,7 +29,7 @@ public final class BarbedSliver extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn).setText("this creature gets +1/+0 until end of turn"), - new GenericManaCost(2)), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, false))); + new GenericManaCost(2)), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS, false))); } private BarbedSliver(final BarbedSliver card) { diff --git a/Mage.Sets/src/mage/cards/b/BarbedWire.java b/Mage.Sets/src/mage/cards/b/BarbedWire.java index e8f42a84fe0..6fcc49d55f3 100644 --- a/Mage.Sets/src/mage/cards/b/BarbedWire.java +++ b/Mage.Sets/src/mage/cards/b/BarbedWire.java @@ -24,7 +24,7 @@ import mage.players.Player; */ public final class BarbedWire extends CardImpl { - private final String rule = "At the beginning of each player's upkeep, " + private static final String rule = "At the beginning of each player's upkeep, " + "Barbed Wire deals 1 damage to that player."; public BarbedWire(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BarkshellBlessing.java b/Mage.Sets/src/mage/cards/b/BarkshellBlessing.java index 15a587256d3..86c46bfb2bd 100644 --- a/Mage.Sets/src/mage/cards/b/BarkshellBlessing.java +++ b/Mage.Sets/src/mage/cards/b/BarkshellBlessing.java @@ -24,7 +24,7 @@ public final class BarkshellBlessing extends CardImpl { this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn)); // Conspire - this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE)); + this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.ONE)); } private BarkshellBlessing(final BarkshellBlessing card) { diff --git a/Mage.Sets/src/mage/cards/b/BaronVonCount.java b/Mage.Sets/src/mage/cards/b/BaronVonCount.java index cd15e61d273..063be647844 100644 --- a/Mage.Sets/src/mage/cards/b/BaronVonCount.java +++ b/Mage.Sets/src/mage/cards/b/BaronVonCount.java @@ -76,7 +76,7 @@ class BaronVonCountPutCounterEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } if (controller != null && mageObject != null) { Integer doomNumber = 5; @@ -172,7 +172,7 @@ class BaronVonCountMoveDoomCounterEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (controller != null && sourcePermanent != null && mageObject != null) { if (game.getState().getValue(mageObject.getId() + "_doom") == null) { return false; @@ -249,7 +249,7 @@ class BaronVonCountDestroyPlayerEffect extends OneShotEffect { targetPlayer.lost(game); // double checks canLose, but seems more future-proof than lostForced } Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (sourcePermanent != null && mageObject != null) { if (game.getState().getValue(mageObject.getId() + "_doom") == null) { return false; diff --git a/Mage.Sets/src/mage/cards/b/BarrinsSpite.java b/Mage.Sets/src/mage/cards/b/BarrinsSpite.java index a9be4bde62e..f90e68333c5 100644 --- a/Mage.Sets/src/mage/cards/b/BarrinsSpite.java +++ b/Mage.Sets/src/mage/cards/b/BarrinsSpite.java @@ -7,7 +7,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -30,9 +29,7 @@ public final class BarrinsSpite extends CardImpl { // Choose two target creatures controlled by the same player. Their controller chooses and sacrifices one of them. Return the other to its owner's hand. this.getSpellAbility().addEffect(new BarrinsSpiteEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanentSameController( - 2, 2, StaticFilters.FILTER_PERMANENT_CREATURE, false - )); + this.getSpellAbility().addTarget(new TargetCreaturePermanentSameController(2)); } private BarrinsSpite(final BarrinsSpite card) { diff --git a/Mage.Sets/src/mage/cards/b/BaseCamp.java b/Mage.Sets/src/mage/cards/b/BaseCamp.java index d5c97d41156..79de773fff5 100644 --- a/Mage.Sets/src/mage/cards/b/BaseCamp.java +++ b/Mage.Sets/src/mage/cards/b/BaseCamp.java @@ -75,7 +75,7 @@ enum BaseCampCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && ( object.hasSubtype(SubType.CLERIC, game) || object.hasSubtype(SubType.ROGUE, game) diff --git a/Mage.Sets/src/mage/cards/b/BasicConjuration.java b/Mage.Sets/src/mage/cards/b/BasicConjuration.java index b4ad758ab45..4c8e38d7fa1 100644 --- a/Mage.Sets/src/mage/cards/b/BasicConjuration.java +++ b/Mage.Sets/src/mage/cards/b/BasicConjuration.java @@ -2,11 +2,11 @@ package mage.cards.b; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import java.util.UUID; @@ -24,9 +24,7 @@ public final class BasicConjuration extends CardImpl { // Look at the top six cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. You gain 3 life. this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - 6, 1, StaticFilters.FILTER_CARD_CREATURE_A, - true, false, Zone.HAND, true - ).setBackInRandomOrder(true)); + 6, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_RANDOM)); this.getSpellAbility().addEffect(new GainLifeEffect(3)); } diff --git a/Mage.Sets/src/mage/cards/b/BaskingRootwalla.java b/Mage.Sets/src/mage/cards/b/BaskingRootwalla.java index f0573659bee..b8c4bdbbe93 100644 --- a/Mage.Sets/src/mage/cards/b/BaskingRootwalla.java +++ b/Mage.Sets/src/mage/cards/b/BaskingRootwalla.java @@ -32,7 +32,7 @@ public final class BaskingRootwalla extends CardImpl { new BoostSourceEffect(2, 2, Duration.EndOfTurn), new ManaCostsImpl("{1}{G}"))); // Madness {0} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{0}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{0}"))); } private BaskingRootwalla(final BaskingRootwalla card) { diff --git a/Mage.Sets/src/mage/cards/b/BasriDevotedPaladin.java b/Mage.Sets/src/mage/cards/b/BasriDevotedPaladin.java index c484ec5995a..310a1694c41 100644 --- a/Mage.Sets/src/mage/cards/b/BasriDevotedPaladin.java +++ b/Mage.Sets/src/mage/cards/b/BasriDevotedPaladin.java @@ -3,7 +3,6 @@ package mage.cards.b; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; @@ -39,7 +38,7 @@ public final class BasriDevotedPaladin extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.BASRI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Put a +1/+1 counter on up to one target creature. It gains vigilance until end of turn. Ability ability = new LoyaltyAbility(new AddCountersTargetEffect( diff --git a/Mage.Sets/src/mage/cards/b/BasriKet.java b/Mage.Sets/src/mage/cards/b/BasriKet.java index 2c4bd29ff94..d1fbff60631 100644 --- a/Mage.Sets/src/mage/cards/b/BasriKet.java +++ b/Mage.Sets/src/mage/cards/b/BasriKet.java @@ -3,7 +3,6 @@ package mage.cards.b; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -39,7 +38,7 @@ public final class BasriKet extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.BASRI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Put a +1/+1 counter on up to one target creature. It gains indestructible until end of turn. Ability ability = new LoyaltyAbility(new AddCountersTargetEffect( diff --git a/Mage.Sets/src/mage/cards/b/BatheInLight.java b/Mage.Sets/src/mage/cards/b/BatheInLight.java index 1c5ea0c9a7e..932559944e3 100644 --- a/Mage.Sets/src/mage/cards/b/BatheInLight.java +++ b/Mage.Sets/src/mage/cards/b/BatheInLight.java @@ -70,34 +70,32 @@ class BatheInLightEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (target != null) { - ChoiceColor colorChoice = new ChoiceColor(); - if (!controller.choose(Outcome.Benefit, colorChoice, game)) { - return false; - } - game.informPlayers(target.getName() + ": " + controller.getLogName() + " has chosen " + colorChoice.getChoice()); - game.getState().setValue(target.getId() + "_color", colorChoice.getColor()); + if (controller == null) { return false; } - ObjectColor protectColor = (ObjectColor) game.getState().getValue(target.getId() + "_color"); - if (protectColor != null) { - ContinuousEffect effect = new ProtectionChosenColorTargetEffect(); - game.addEffect(effect, source); - ObjectColor color = target.getColor(game); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { - if (!permanent.getId().equals(target.getId()) && permanent.getColor(game).shares(color)) { - game.getState().setValue(permanent.getId() + "_color", colorChoice.getColor()); - effect.setTargetPointer(new FixedTarget(permanent, game)); - game.addEffect(effect, source); - } - } + Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (target == null) { return false; } - } - return true; + ChoiceColor colorChoice = new ChoiceColor(); + if (!controller.choose(Outcome.Benefit, colorChoice, game)) { return false; } + + game.informPlayers(target.getName() + ": " + controller.getLogName() + " has chosen " + colorChoice.getChoice()); + game.getState().setValue(target.getId() + "_color", colorChoice.getColor()); + + ObjectColor protectColor = (ObjectColor) game.getState().getValue(target.getId() + "_color"); + if (protectColor == null) { return true; } + + ContinuousEffect effect = new ProtectionChosenColorTargetEffect(); + game.addEffect(effect, source); + ObjectColor color = target.getColor(game); + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { + if (!permanent.getId().equals(target.getId()) && permanent.getColor(game).shares(color)) { + game.getState().setValue(permanent.getId() + "_color", colorChoice.getColor()); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); } } - return false; + + return true; } } @@ -128,19 +126,20 @@ class ProtectionChosenColorTargetEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent != null) { - ObjectColor color = (ObjectColor) game.getState().getValue(permanent.getId() + "_color"); - if (color != null && (protectionAbility == null || !color.equals(chosenColor))) { - chosenColor = color; - FilterObject protectionFilter = new FilterObject(chosenColor.getDescription()); - protectionFilter.add(new ColorPredicate(chosenColor)); - protectionAbility = new ProtectionAbility(protectionFilter); - } - if (protectionAbility != null) { - permanent.addAbility(protectionAbility, source.getSourceId(), game); - return true; - } + if (permanent == null) { return false; } + + ObjectColor color = (ObjectColor) game.getState().getValue(permanent.getId() + "_color"); + if (color != null && (protectionAbility == null || !color.equals(chosenColor))) { + chosenColor = color; + FilterObject protectionFilter = new FilterObject<>(chosenColor.getDescription()); + protectionFilter.add(new ColorPredicate(chosenColor)); + protectionAbility = new ProtectionAbility(protectionFilter); } + if (protectionAbility != null) { + permanent.addAbility(protectionAbility, source.getSourceId(), game); + return true; + } + return false; } } diff --git a/Mage.Sets/src/mage/cards/b/BatteringCraghorn.java b/Mage.Sets/src/mage/cards/b/BatteringCraghorn.java index b28e0a4712d..ea4ccd5fd6c 100644 --- a/Mage.Sets/src/mage/cards/b/BatteringCraghorn.java +++ b/Mage.Sets/src/mage/cards/b/BatteringCraghorn.java @@ -27,7 +27,7 @@ public final class BatteringCraghorn extends CardImpl { // First strike this.addAbility(FirstStrikeAbility.getInstance()); // Morph {1}{R}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{R}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{R}{R}"))); } private BatteringCraghorn(final BatteringCraghorn card) { diff --git a/Mage.Sets/src/mage/cards/b/BattleForBretagard.java b/Mage.Sets/src/mage/cards/b/BattleForBretagard.java index ed2e3c190a5..ac11200470e 100644 --- a/Mage.Sets/src/mage/cards/b/BattleForBretagard.java +++ b/Mage.Sets/src/mage/cards/b/BattleForBretagard.java @@ -89,7 +89,7 @@ class BattleForBretagardEffect extends OneShotEffect { return false; } TargetPermanent target = new BattleForBretagardTarget(); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); for (UUID targetId : target.getTargets()) { new CreateTokenCopyTargetEffect() .setTargetPointer(new FixedTarget(targetId, game)) @@ -145,8 +145,8 @@ class BattleForBretagardTarget extends TargetPermanent { @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set possibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); Set names = this.getTargets() .stream() .map(game::getPermanent) diff --git a/Mage.Sets/src/mage/cards/b/BattleSliver.java b/Mage.Sets/src/mage/cards/b/BattleSliver.java index 7bf8276baa1..29cde1e0dc7 100644 --- a/Mage.Sets/src/mage/cards/b/BattleSliver.java +++ b/Mage.Sets/src/mage/cards/b/BattleSliver.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.BoostControlledEffect; @@ -10,11 +8,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class BattleSliver extends CardImpl { @@ -27,9 +25,10 @@ public final class BattleSliver extends CardImpl { this.toughness = new MageInt(3); // Sliver creatures you control get +2/+0. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new BoostControlledEffect(2, 0, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS))); - + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 2, 0, Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_SLIVERS + ))); } private BattleSliver(final BattleSliver card) { diff --git a/Mage.Sets/src/mage/cards/b/BattlefieldScrounger.java b/Mage.Sets/src/mage/cards/b/BattlefieldScrounger.java index 04ad2419f8e..ceb6de8a6b7 100644 --- a/Mage.Sets/src/mage/cards/b/BattlefieldScrounger.java +++ b/Mage.Sets/src/mage/cards/b/BattlefieldScrounger.java @@ -68,7 +68,7 @@ class BattlefieldScroungerCost extends CostImpl { public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { - if (targets.choose(Outcome.Removal, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.Removal, controllerId, source.getSourceId(), source, game)) { for (UUID targetId: targets.get(0).getTargets()) { Card card = game.getCard(targetId); if (card == null || game.getState().getZone(targetId) != Zone.GRAVEYARD) { @@ -84,7 +84,7 @@ class BattlefieldScroungerCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/b/BattlefieldThaumaturge.java b/Mage.Sets/src/mage/cards/b/BattlefieldThaumaturge.java index c911bd92af5..20694150ff0 100644 --- a/Mage.Sets/src/mage/cards/b/BattlefieldThaumaturge.java +++ b/Mage.Sets/src/mage/cards/b/BattlefieldThaumaturge.java @@ -66,7 +66,7 @@ class BattlefieldThaumaturgeSpellsCostReductionEffect extends CostModificationEf @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { - int reduceAmount = 0; + int reduceAmount; if (game.inCheckPlayableState()) { // checking state (search max possible targets) reduceAmount = getMaxPossibleTargetCreatures(abilityToModify, game); @@ -99,7 +99,7 @@ class BattlefieldThaumaturgeSpellsCostReductionEffect extends CostModificationEf if (target.isNotTarget()) { continue; } - Set possibleList = target.possibleTargets(ability.getSourceId(), ability.getControllerId(), game); + Set possibleList = target.possibleTargets(ability.getControllerId(), ability, game); possibleList.removeIf(id -> { Permanent permanent = game.getPermanent(id); return permanent == null || !permanent.isCreature(game); @@ -117,7 +117,7 @@ class BattlefieldThaumaturgeSpellsCostReductionEffect extends CostModificationEf && abilityToModify.isControlledBy(source.getControllerId())) { Spell spell = (Spell) game.getStack().getStackObject(abilityToModify.getId()); if (spell != null) { - return spell != null && StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(spell, game); + return StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(spell, game); } else { Card sourceCard = game.getCard(abilityToModify.getSourceId()); return sourceCard != null && StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(sourceCard, game); diff --git a/Mage.Sets/src/mage/cards/b/BattlegateMimic.java b/Mage.Sets/src/mage/cards/b/BattlegateMimic.java index 7466db08d17..86ae874ccea 100644 --- a/Mage.Sets/src/mage/cards/b/BattlegateMimic.java +++ b/Mage.Sets/src/mage/cards/b/BattlegateMimic.java @@ -31,7 +31,7 @@ public final class BattlegateMimic extends CardImpl { filter.add(new ColorPredicate(ObjectColor.WHITE)); } - private String rule = "Whenever you cast a spell that's both red and white, {this} has base power and toughness 4/2 and gains first strike until end of turn."; + private static final String rule = "Whenever you cast a spell that's both red and white, {this} has base power and toughness 4/2 until end of turn and gains first strike until end of turn."; public BattlegateMimic(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R/W}"); diff --git a/Mage.Sets/src/mage/cards/b/BattlegraceAngel.java b/Mage.Sets/src/mage/cards/b/BattlegraceAngel.java index 7d7c48646ee..716eb9d1a32 100644 --- a/Mage.Sets/src/mage/cards/b/BattlegraceAngel.java +++ b/Mage.Sets/src/mage/cards/b/BattlegraceAngel.java @@ -35,7 +35,7 @@ public final class BattlegraceAngel extends CardImpl { // Whenever a creature you control attacks alone, it gains lifelink until end of turn. this.addAbility(new AttacksAloneControlledTriggeredAbility(new GainAbilityTargetEffect( LifelinkAbility.getInstance(), Duration.EndOfTurn - ).setText("it gains lifelink until end of turn"))); + ).setText("it gains lifelink until end of turn"), true, false)); } public BattlegraceAngel(final BattlegraceAngel card) { diff --git a/Mage.Sets/src/mage/cards/b/BayouGroff.java b/Mage.Sets/src/mage/cards/b/BayouGroff.java index b45b35fe2bd..52f441c2c2a 100644 --- a/Mage.Sets/src/mage/cards/b/BayouGroff.java +++ b/Mage.Sets/src/mage/cards/b/BayouGroff.java @@ -28,9 +28,9 @@ public final class BayouGroff extends CardImpl { // As an additional cost to cast this spell, sacrifice a creature or pay {3}. this.getSpellAbility().addCost(new OrCost( - new SacrificeTargetCost(new TargetControlledPermanent( + "sacrifice a creature or pay {3}", new SacrificeTargetCost(new TargetControlledPermanent( StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT - )), new GenericManaCost(3), "sacrifice a creature or pay {3}" + )), new GenericManaCost(3) )); } diff --git a/Mage.Sets/src/mage/cards/b/BeaconOfDestiny.java b/Mage.Sets/src/mage/cards/b/BeaconOfDestiny.java index 80b6b4c4aff..f390f76d8bb 100644 --- a/Mage.Sets/src/mage/cards/b/BeaconOfDestiny.java +++ b/Mage.Sets/src/mage/cards/b/BeaconOfDestiny.java @@ -71,7 +71,7 @@ class BeaconOfDestinyEffect extends RedirectionEffect { @Override public void init(Ability source, Game game) { - this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); super.init(source, game); } diff --git a/Mage.Sets/src/mage/cards/b/BeamsplitterMage.java b/Mage.Sets/src/mage/cards/b/BeamsplitterMage.java index 1163654b047..04b192dc2c6 100644 --- a/Mage.Sets/src/mage/cards/b/BeamsplitterMage.java +++ b/Mage.Sets/src/mage/cards/b/BeamsplitterMage.java @@ -112,7 +112,7 @@ class BeamsplitterMageTriggeredAbility extends TriggeredAbilityImpl { } return game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - getControllerId(), getSourceId(), game + getControllerId(), this, game ).stream() .filter(Objects::nonNull) .filter(permanent -> permanent.isCreature(game)) @@ -165,7 +165,7 @@ class BeamsplitterMageEffect extends OneShotEffect { filter.add(new BeamsplitterMagePredicate(spell)); TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent == null) { return false; diff --git a/Mage.Sets/src/mage/cards/b/BearUmbra.java b/Mage.Sets/src/mage/cards/b/BearUmbra.java index 66a746ee6f2..9041e77289a 100644 --- a/Mage.Sets/src/mage/cards/b/BearUmbra.java +++ b/Mage.Sets/src/mage/cards/b/BearUmbra.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -13,33 +11,37 @@ import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.TotemArmorAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class BearUmbra extends CardImpl { public BearUmbra(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{G}"); this.subtype.add(SubType.AURA); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); - + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // Enchanted creature gets +2/+2 and has "Whenever this creature attacks, untap all lands you control." - Ability attachedAbility = new AttacksTriggeredAbility(new UntapAllLandsControllerEffect(), false); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, 2, Duration.WhileOnBattlefield))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(attachedAbility, AttachmentType.AURA))); - + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(2, 2)); + ability.addEffect(new GainAbilityAttachedEffect(new AttacksTriggeredAbility( + new UntapAllLandsControllerEffect(), false + ), AttachmentType.AURA).setText("and has \"Whenever this creature attacks, untap all lands you control.\"")); + this.addAbility(ability); + // Totem armor this.addAbility(new TotemArmorAbility()); } diff --git a/Mage.Sets/src/mage/cards/b/BeckCall.java b/Mage.Sets/src/mage/cards/b/BeckCall.java index 5a5932f6956..0a63bff7c77 100644 --- a/Mage.Sets/src/mage/cards/b/BeckCall.java +++ b/Mage.Sets/src/mage/cards/b/BeckCall.java @@ -14,7 +14,6 @@ import mage.constants.SpellAbilityType; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.game.permanent.token.BirdToken; @@ -65,7 +64,7 @@ class BeckTriggeredAbility extends DelayedTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { UUID targetId = event.getTargetId(); Permanent permanent = game.getPermanent(targetId); - return filter.match(permanent, getSourceId(), getControllerId(), game); + return filter.match(permanent, getControllerId(), this, game); } @Override diff --git a/Mage.Sets/src/mage/cards/b/BellowingSaddlebrute.java b/Mage.Sets/src/mage/cards/b/BellowingSaddlebrute.java index 83c8dfd3755..08b697864de 100644 --- a/Mage.Sets/src/mage/cards/b/BellowingSaddlebrute.java +++ b/Mage.Sets/src/mage/cards/b/BellowingSaddlebrute.java @@ -32,7 +32,7 @@ public final class BellowingSaddlebrute extends CardImpl { this.addAbility(new ConditionalInterveningIfTriggeredAbility( new EntersBattlefieldTriggeredAbility(new LoseLifeSourceControllerEffect(4)), new InvertCondition(RaidCondition.instance), - "Raid — When {this} enters the battlefield, you lose 4 life unless you attacked this turn.") + "When {this} enters the battlefield, you lose 4 life unless you attacked this turn.") .setAbilityWord(AbilityWord.RAID) .addHint(RaidHint.instance), new PlayerAttackedWatcher()); diff --git a/Mage.Sets/src/mage/cards/b/BelltollDragon.java b/Mage.Sets/src/mage/cards/b/BelltollDragon.java index d8385290b1c..bb6ed0e1bc3 100644 --- a/Mage.Sets/src/mage/cards/b/BelltollDragon.java +++ b/Mage.Sets/src/mage/cards/b/BelltollDragon.java @@ -41,7 +41,7 @@ public final class BelltollDragon extends CardImpl { // Hexproof this.addAbility(HexproofAbility.getInstance()); // Megamorph {5}{U}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{5}{U}{U}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{5}{U}{U}"), true)); // When Belltoll Dragon is turned face up, put a +1/+1 counter on each other Dragon creature you control. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter), false, false)); diff --git a/Mage.Sets/src/mage/cards/b/BendOrBreak.java b/Mage.Sets/src/mage/cards/b/BendOrBreak.java index 18018f38b28..fc347eb89d2 100644 --- a/Mage.Sets/src/mage/cards/b/BendOrBreak.java +++ b/Mage.Sets/src/mage/cards/b/BendOrBreak.java @@ -64,122 +64,123 @@ class BendOrBreakEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { + if (controller == null) { return false; } - // Map of players and their piles - Map>> playerPermanents = new LinkedHashMap<>(); + // Map of players and their piles + Map>> playerPermanents = new LinkedHashMap<>(); - PlayerList playerList = game.getState().getPlayerList().copy(); - while (!playerList.get().equals(source.getControllerId()) && controller.canRespond()) { - playerList.getNext(); - } - Player currentPlayer = game.getPlayer(playerList.get()); - Player nextPlayer; - UUID firstNextPlayer = null; - - while (!getNextPlayerInDirection(true, playerList).equals(firstNextPlayer) && controller.canRespond()) { - nextPlayer = game.getPlayer(playerList.get()); - if (nextPlayer == null) { - return false; - } - if (firstNextPlayer == null) { - firstNextPlayer = nextPlayer.getId(); - } - if (!nextPlayer.canRespond()) { - continue; - } - // Each player separates all nontoken lands they control into two piles - if (currentPlayer != null && game.getState().getPlayersInRange(controller.getId(), game).contains(currentPlayer.getId())) { - List firstPile = new ArrayList<>(); - List secondPile = new ArrayList<>(); - FilterControlledLandPermanent filter = new FilterControlledLandPermanent("lands you control to assign to the first pile (lands not chosen will be assigned to the second pile)"); - TargetPermanent target = new TargetControlledPermanent(0, Integer.MAX_VALUE, filter, true); - if (target.canChoose(source.getSourceId(), currentPlayer.getId(), game)) { - // TODO: add support for AI (50/50), need AI hints mechanic here - currentPlayer.chooseTarget(Outcome.Neutral, target, source, game); - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, currentPlayer.getId(), game)) { - if (target.getTargets().contains(permanent.getId())) { - firstPile.add(permanent); - } else { - secondPile.add(permanent); - } - } - - StringBuilder sb = new StringBuilder("First pile of ").append(currentPlayer.getLogName()).append(": "); - sb.append(firstPile.stream().map(Permanent::getLogName).collect(Collectors.joining(", "))); - - game.informPlayers(sb.toString()); - - sb = new StringBuilder("Second pile of ").append(currentPlayer.getLogName()).append(": "); - sb.append(secondPile.stream().map(Permanent::getLogName).collect(Collectors.joining(", "))); - - game.informPlayers(sb.toString()); - } - List> playerPiles = new ArrayList<>(); - playerPiles.add(firstPile); - playerPiles.add(secondPile); - playerPermanents.put(currentPlayer.getId(), playerPiles); - } - currentPlayer = nextPlayer; - } - - // For each player, one of their piles is chosen by one of their opponents of their choice - for (Map.Entry>> playerPiles : playerPermanents.entrySet()) { - Player player = game.getPlayer(playerPiles.getKey()); - if (player != null) { - FilterPlayer filter = new FilterPlayer("opponent"); - List opponentPredicates = new ArrayList<>(); - for (UUID opponentId : game.getOpponents(player.getId())) { - opponentPredicates.add(new PlayerIdPredicate(opponentId)); - } - filter.add(Predicates.or(opponentPredicates)); - Target target = new TargetPlayer(1, 1, true, filter); - target.setTargetController(player.getId()); - target.setAbilityController(source.getControllerId()); - if (player.chooseTarget(outcome, target, source, game)) { - Player chosenOpponent = game.getPlayer(target.getFirstTarget()); - if (chosenOpponent != null) { - List firstPile = playerPiles.getValue().get(0); - List secondPile = playerPiles.getValue().get(1); - game.informPlayers(player.getLogName() + " chose " + chosenOpponent.getLogName() + " to choose their pile"); - if (chosenOpponent.choosePile(outcome, "Piles of " + player.getName(), firstPile, secondPile, game)) { - List> lists = playerPiles.getValue(); - lists.clear(); - lists.add(firstPile); - lists.add(secondPile); - game.informPlayers(player.getLogName() + " will have their first pile destroyed"); - } else { - List> lists = playerPiles.getValue(); - lists.clear(); - lists.add(secondPile); - lists.add(firstPile); - game.informPlayers(player.getLogName() + " will have their second pile destroyed"); - } - } - } - } - } - // Destroy all lands in the chosen piles. Tap all lands in the other piles - for (Map.Entry>> playerPiles : playerPermanents.entrySet()) { - Player player = game.getPlayer(playerPiles.getKey()); - if (player != null) { - List pileToSac = playerPiles.getValue().get(0); - List pileToTap = playerPiles.getValue().get(1); - for (Permanent permanent : pileToSac) { - if (permanent != null) { - permanent.destroy(source, game, false); - } - } - for (Permanent permanent : pileToTap) { - if (permanent != null) { - permanent.tap(source, game); - } - } - } - } - return true; + PlayerList playerList = game.getState().getPlayerList().copy(); + while (!playerList.get().equals(source.getControllerId()) && controller.canRespond()) { + playerList.getNext(); } - return false; + Player currentPlayer = game.getPlayer(playerList.get()); + Player nextPlayer; + UUID firstNextPlayer = null; + + while (!getNextPlayerInDirection(true, playerList).equals(firstNextPlayer) && controller.canRespond()) { + nextPlayer = game.getPlayer(playerList.get()); + if (nextPlayer == null) { + return false; + } + if (firstNextPlayer == null) { + firstNextPlayer = nextPlayer.getId(); + } + if (!nextPlayer.canRespond()) { + continue; + } + // Each player separates all nontoken lands they control into two piles + if (currentPlayer == null || !game.getState().getPlayersInRange(controller.getId(), game).contains(currentPlayer.getId())) { + continue; + } + List firstPile = new ArrayList<>(); + List secondPile = new ArrayList<>(); + FilterControlledLandPermanent filter = new FilterControlledLandPermanent("lands you control to assign to the first pile (lands not chosen will be assigned to the second pile)"); + TargetPermanent target = new TargetControlledPermanent(0, Integer.MAX_VALUE, filter, true); + if (!target.canChoose(currentPlayer.getId(), source, game)) { continue; } + + // TODO: add support for AI (50/50), need AI hints mechanic here + currentPlayer.chooseTarget(Outcome.Neutral, target, source, game); + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, currentPlayer.getId(), game)) { + if (target.getTargets().contains(permanent.getId())) { + firstPile.add(permanent); + } else { + secondPile.add(permanent); + } + } + + StringBuilder sb = new StringBuilder("First pile of ").append(currentPlayer.getLogName()).append(": "); + sb.append(firstPile.stream().map(Permanent::getLogName).collect(Collectors.joining(", "))); + + game.informPlayers(sb.toString()); + + sb = new StringBuilder("Second pile of ").append(currentPlayer.getLogName()).append(": "); + sb.append(secondPile.stream().map(Permanent::getLogName).collect(Collectors.joining(", "))); + + game.informPlayers(sb.toString()); + + List> playerPiles = new ArrayList<>(); + playerPiles.add(firstPile); + playerPiles.add(secondPile); + playerPermanents.put(currentPlayer.getId(), playerPiles); + + currentPlayer = nextPlayer; + } + + // For each player, one of their piles is chosen by one of their opponents of their choice + for (Map.Entry>> playerPiles : playerPermanents.entrySet()) { + Player player = game.getPlayer(playerPiles.getKey()); + if (player == null) { continue; } + + FilterPlayer filter = new FilterPlayer("opponent"); + List opponentPredicates = new ArrayList<>(); + for (UUID opponentId : game.getOpponents(player.getId())) { + opponentPredicates.add(new PlayerIdPredicate(opponentId)); + } + filter.add(Predicates.or(opponentPredicates)); + Target target = new TargetPlayer(1, 1, true, filter); + target.setTargetController(player.getId()); + target.setAbilityController(source.getControllerId()); + if (!player.chooseTarget(outcome, target, source, game)) { continue; } + + Player chosenOpponent = game.getPlayer(target.getFirstTarget()); + if (chosenOpponent == null) { continue; } + + List firstPile = playerPiles.getValue().get(0); + List secondPile = playerPiles.getValue().get(1); + game.informPlayers(player.getLogName() + " chose " + chosenOpponent.getLogName() + " to choose their pile"); + if (chosenOpponent.choosePile(outcome, "Piles of " + player.getName(), firstPile, secondPile, game)) { + List> lists = playerPiles.getValue(); + lists.clear(); + lists.add(firstPile); + lists.add(secondPile); + game.informPlayers(player.getLogName() + " will have their first pile destroyed"); + } else { + List> lists = playerPiles.getValue(); + lists.clear(); + lists.add(secondPile); + lists.add(firstPile); + game.informPlayers(player.getLogName() + " will have their second pile destroyed"); + } + } + // Destroy all lands in the chosen piles. Tap all lands in the other piles + for (Map.Entry>> playerPiles : playerPermanents.entrySet()) { + Player player = game.getPlayer(playerPiles.getKey()); + if (player == null) { continue; } + + List pileToSac = playerPiles.getValue().get(0); + List pileToTap = playerPiles.getValue().get(1); + for (Permanent permanent : pileToSac) { + if (permanent != null) { + permanent.destroy(source, game, false); + } + } + for (Permanent permanent : pileToTap) { + if (permanent != null) { + permanent.tap(source, game); + } + } + } + return true; } private UUID getNextPlayerInDirection(boolean left, PlayerList playerList) { diff --git a/Mage.Sets/src/mage/cards/b/BenefactionOfRhonas.java b/Mage.Sets/src/mage/cards/b/BenefactionOfRhonas.java index cccf8353357..b391ad05407 100644 --- a/Mage.Sets/src/mage/cards/b/BenefactionOfRhonas.java +++ b/Mage.Sets/src/mage/cards/b/BenefactionOfRhonas.java @@ -61,7 +61,7 @@ class BenefactionOfRhonasEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && controller != null) { Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5)); boolean creatureCardFound = false; diff --git a/Mage.Sets/src/mage/cards/b/BenevolentOffering.java b/Mage.Sets/src/mage/cards/b/BenevolentOffering.java index c6bd066c468..f3365b3f2be 100644 --- a/Mage.Sets/src/mage/cards/b/BenevolentOffering.java +++ b/Mage.Sets/src/mage/cards/b/BenevolentOffering.java @@ -63,19 +63,18 @@ class BenevolentOfferingEffect1 extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Target target = new TargetOpponent(true); - target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), game); - Player opponent = game.getPlayer(target.getFirstTarget()); - if (opponent != null) { - Effect effect = new CreateTokenTargetEffect(new SpiritWhiteToken(), 3); - effect.setTargetPointer(new FixedTarget(opponent.getId())); - effect.apply(game, source); - new CreateTokenEffect(new SpiritWhiteToken(), 3).apply(game, source); - return true; - } - } - return false; + if (controller == null) { return false; } + + Target target = new TargetOpponent(true); + target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), source, game); + Player opponent = game.getPlayer(target.getFirstTarget()); + if (opponent == null) { return false; } + + Effect effect = new CreateTokenTargetEffect(new SpiritWhiteToken(), 3); + effect.setTargetPointer(new FixedTarget(opponent.getId())); + effect.apply(game, source); + new CreateTokenEffect(new SpiritWhiteToken(), 3).apply(game, source); + return true; } } @@ -98,18 +97,18 @@ class BenevolentOfferingEffect2 extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Target target = new TargetOpponent(true); - target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), game); - Player opponent = game.getPlayer(target.getFirstTarget()); - if (opponent != null) { - int count = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), game) * 2; - controller.gainLife(count, game, source); - count = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, opponent.getId(), game) * 2; - opponent.gainLife(count, game, source); - return true; - } - } - return false; + if (controller == null) { return false; } + + Target target = new TargetOpponent(true); + target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), source, game); + Player opponent = game.getPlayer(target.getFirstTarget()); + if (opponent == null) { return false; } + + int count = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), game) * 2; + controller.gainLife(count, game, source); + count = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, opponent.getId(), game) * 2; + opponent.gainLife(count, game, source); + + return true; } } diff --git a/Mage.Sets/src/mage/cards/b/BennieBracksZoologist.java b/Mage.Sets/src/mage/cards/b/BennieBracksZoologist.java new file mode 100644 index 00000000000..26729bc7206 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BennieBracksZoologist.java @@ -0,0 +1,47 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.common.CreatedTokenThisTurnCondition; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.ConvokeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.watchers.common.CreatedTokenWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BennieBracksZoologist extends CardImpl { + + public BennieBracksZoologist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Convoke + this.addAbility(new ConvokeAbility()); + + // At the beginning of each end step, if you created a token this turn, draw a card. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), + TargetController.ANY, CreatedTokenThisTurnCondition.instance, false + ).addHint(CreatedTokenThisTurnCondition.getHint()), new CreatedTokenWatcher()); + } + + private BennieBracksZoologist(final BennieBracksZoologist card) { + super(card); + } + + @Override + public BennieBracksZoologist copy() { + return new BennieBracksZoologist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BenthicExplorers.java b/Mage.Sets/src/mage/cards/b/BenthicExplorers.java index 1b91349da20..661e60a3040 100644 --- a/Mage.Sets/src/mage/cards/b/BenthicExplorers.java +++ b/Mage.Sets/src/mage/cards/b/BenthicExplorers.java @@ -67,7 +67,7 @@ public final class BenthicExplorers extends CardImpl { class BenthicExplorersCost extends CostImpl { - TargetLandPermanent target; + private final TargetLandPermanent target; public BenthicExplorersCost(TargetLandPermanent target) { this.target = target; @@ -81,7 +81,7 @@ class BenthicExplorersCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - if (target.choose(Outcome.Untap, controllerId, source.getSourceId(), game)) { + if (target.choose(Outcome.Untap, controllerId, source.getSourceId(), source, game)) { for (UUID targetId : target.getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent == null) { @@ -98,7 +98,7 @@ class BenthicExplorersCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return target.canChoose(source.getSourceId(), controllerId, game); + return target.canChoose(controllerId, source, game); } @Override @@ -155,59 +155,60 @@ class BenthicExplorersManaEffect extends ManaEffect { @Override public Mana produceMana(Game game, Ability source) { Mana mana = new Mana(); - if (game == null) { - return mana; - } + if (game == null) { return mana; } + Choice choice = ManaType.getChoiceOfManaTypes(getManaTypes(game, source), false); - if (!choice.getChoices().isEmpty()) { - Player player = game.getPlayer(source.getControllerId()); - if (choice.getChoices().size() == 1) { - choice.setChoice(choice.getChoices().iterator().next()); - } else { - if (player == null - || !player.choose(Outcome.Neutral, choice, game)) { - return mana; - } - } - if (choice.getChoice() != null) { - switch (choice.getChoice()) { - case "Black": - mana.setBlack(1); - break; - case "Blue": - mana.setBlue(1); - break; - case "Red": - mana.setRed(1); - break; - case "Green": - mana.setGreen(1); - break; - case "White": - mana.setWhite(1); - break; - case "Colorless": - mana.setColorless(1); - break; - } + if (choice.getChoices().isEmpty()) { return mana; } + + Player player = game.getPlayer(source.getControllerId()); + if (choice.getChoices().size() == 1) { + choice.setChoice(choice.getChoices().iterator().next()); + } else { + if (player == null + || !player.choose(Outcome.Neutral, choice, game)) { + return mana; } } + + if (choice.getChoice() == null) { return mana; } + + switch (choice.getChoice()) { + case "Black": + mana.setBlack(1); + break; + case "Blue": + mana.setBlue(1); + break; + case "Red": + mana.setRed(1); + break; + case "Green": + mana.setGreen(1); + break; + case "White": + mana.setWhite(1); + break; + case "Colorless": + mana.setColorless(1); + break; + } + return mana; } private Set getManaTypes(Game game, Ability source) { Set types = EnumSet.noneOf(ManaType.class); - if (game == null - || game.getPhase() == null) { + if (game == null || game.getPhase() == null) { return types; } + Permanent land = (Permanent) game.getState().getValue("UntapTargetCost" + source.getSourceId().toString()); - if (land != null) { - Abilities mana = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD); - for (ActivatedManaAbilityImpl ability : mana) { - if (ability.definesMana(game)) { - types.addAll(ability.getProducableManaTypes(game)); - } + if (land == null) { return types; } + + Abilities mana = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD); + for (ActivatedManaAbilityImpl ability : mana) { + if (ability.definesMana(game)) { + types.addAll(ability.getProducableManaTypes(game)); } } return types; diff --git a/Mage.Sets/src/mage/cards/b/Benthicore.java b/Mage.Sets/src/mage/cards/b/Benthicore.java index 7f9763a7040..f4151c1554f 100644 --- a/Mage.Sets/src/mage/cards/b/Benthicore.java +++ b/Mage.Sets/src/mage/cards/b/Benthicore.java @@ -45,8 +45,8 @@ public final class Benthicore extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new MerfolkWizardToken(), 2), false)); // Tap two untapped Merfolk you control: Untap Benthicore. It gains shroud until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new UntapSourceEffect(), new TapTargetCost(new TargetControlledPermanent(2, 2, filter, false))); - ability.addEffect(new GainAbilitySourceEffect(ShroudAbility.getInstance(), Duration.EndOfTurn)); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new UntapSourceEffect(), new TapTargetCost(new TargetControlledPermanent(2, filter))); + ability.addEffect(new GainAbilitySourceEffect(ShroudAbility.getInstance(), Duration.EndOfTurn).setText("it gains shroud until end of turn")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/Berserk.java b/Mage.Sets/src/mage/cards/b/Berserk.java index ab4ac242365..da69f465d89 100644 --- a/Mage.Sets/src/mage/cards/b/Berserk.java +++ b/Mage.Sets/src/mage/cards/b/Berserk.java @@ -127,15 +127,15 @@ class BerserkDestroyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - //create delayed triggered ability - Effect effect = new BerserkDelayedDestroyEffect(); - effect.setTargetPointer(new FixedTarget(this.getTargetPointer().getFirst(game, source), game)); - AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); - game.addDelayedTriggeredAbility(delayedAbility, source); - return true; - } - return false; + if (controller == null) { return false; } + + //create delayed triggered ability + Effect effect = new BerserkDelayedDestroyEffect(); + effect.setTargetPointer(new FixedTarget(this.getTargetPointer().getFirst(game, source), game)); + AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); + game.addDelayedTriggeredAbility(delayedAbility, source); + + return true; } } @@ -158,15 +158,15 @@ class BerserkDelayedDestroyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); - if (permanent != null) { - AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); - if (watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(permanent, game))) { - return permanent.destroy(source, game, false); - } - } - } - return false; + if (controller == null) { return false; } + + Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); + if (permanent == null) { return false; } + + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); + if (watcher == null) { return false; } + + return watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(permanent, game)) + && permanent.destroy(source, game, false); } } diff --git a/Mage.Sets/src/mage/cards/b/BerserkersFrenzy.java b/Mage.Sets/src/mage/cards/b/BerserkersFrenzy.java index 2dc7617417e..744b5503e4e 100644 --- a/Mage.Sets/src/mage/cards/b/BerserkersFrenzy.java +++ b/Mage.Sets/src/mage/cards/b/BerserkersFrenzy.java @@ -99,7 +99,7 @@ class BerserkersFrenzyEffect extends OneShotEffect { } TargetPermanent target = new TargetCreaturePermanent(0, Integer.MAX_VALUE); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); game.addEffect(new BlocksIfAbleTargetEffect(Duration.EndOfTurn) .setTargetPointer(new FixedTargets(new CardsImpl(target.getTargets()), game)), source); return true; diff --git a/Mage.Sets/src/mage/cards/b/Besmirch.java b/Mage.Sets/src/mage/cards/b/Besmirch.java index ff160ad483e..f510600418d 100644 --- a/Mage.Sets/src/mage/cards/b/Besmirch.java +++ b/Mage.Sets/src/mage/cards/b/Besmirch.java @@ -1,9 +1,6 @@ package mage.cards.b; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.combat.GoadTargetEffect; @@ -20,8 +17,9 @@ import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.TargetPointer; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class Besmirch extends CardImpl { @@ -66,24 +64,19 @@ class BesmirchEffect extends OneShotEffect { TargetPointer target = new FixedTarget(source.getFirstTarget(), game); // gain control - ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfTurn); - effect.setTargetPointer(target); - game.addEffect(effect, source); + game.addEffect(new GainControlTargetEffect(Duration.EndOfTurn) + .setTargetPointer(target), source); // haste - effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); - effect.setTargetPointer(target); - game.addEffect(effect, source); + game.addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setTargetPointer(target), source); // goad - Effect effect2 = new GoadTargetEffect(); - effect2.setTargetPointer(target); - effect2.apply(game, source); + game.addEffect(new GoadTargetEffect().setTargetPointer(target), source); // untap - effect2 = new UntapTargetEffect(); - effect2.setTargetPointer(target); - effect2.apply(game, source); + new UntapTargetEffect().setTargetPointer(target).apply(game, source); return true; } diff --git a/Mage.Sets/src/mage/cards/b/BetrayalOfFlesh.java b/Mage.Sets/src/mage/cards/b/BetrayalOfFlesh.java index f5a8328bbda..08741a0f536 100644 --- a/Mage.Sets/src/mage/cards/b/BetrayalOfFlesh.java +++ b/Mage.Sets/src/mage/cards/b/BetrayalOfFlesh.java @@ -33,8 +33,7 @@ public final class BetrayalOfFlesh extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // or return target creature card from your graveyard to the battlefield. - Mode mode = new Mode(); - mode.addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); + Mode mode = new Mode(new ReturnFromGraveyardToBattlefieldTargetEffect()); mode.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().getModes().addMode(mode); // Entwine-Sacrifice three lands. diff --git a/Mage.Sets/src/mage/cards/b/Bewilder.java b/Mage.Sets/src/mage/cards/b/Bewilder.java index 10ddaddde57..4d13dcb3072 100644 --- a/Mage.Sets/src/mage/cards/b/Bewilder.java +++ b/Mage.Sets/src/mage/cards/b/Bewilder.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; @@ -10,21 +8,22 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class Bewilder extends CardImpl { public Bewilder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}"); // Target creature gets -3/-0 until end of turn. this.getSpellAbility().addEffect(new BoostTargetEffect(-3, 0, Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private Bewilder(final Bewilder card) { diff --git a/Mage.Sets/src/mage/cards/b/BigGameHunter.java b/Mage.Sets/src/mage/cards/b/BigGameHunter.java index cefa0d6c158..ca3cd824caf 100644 --- a/Mage.Sets/src/mage/cards/b/BigGameHunter.java +++ b/Mage.Sets/src/mage/cards/b/BigGameHunter.java @@ -41,7 +41,7 @@ public final class BigGameHunter extends CardImpl { ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); // Madness {B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{B}"))); } private BigGameHunter(final BigGameHunter card) { diff --git a/Mage.Sets/src/mage/cards/b/BigScore.java b/Mage.Sets/src/mage/cards/b/BigScore.java new file mode 100644 index 00000000000..83f24b0b3ae --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BigScore.java @@ -0,0 +1,37 @@ +package mage.cards.b; + +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; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BigScore extends CardImpl { + + public BigScore(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}"); + + // As an additional cost to cast this spell, draw a card. + this.getSpellAbility().addCost(new DiscardCardCost(false)); + + // Draw two cards and create two Treasure tokens. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); + this.getSpellAbility().addEffect(new CreateTokenEffect(new TreasureToken(), 2).concatBy("and")); + } + + private BigScore(final BigScore card) { + super(card); + } + + @Override + public BigScore copy() { + return new BigScore(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BindingAgony.java b/Mage.Sets/src/mage/cards/b/BindingAgony.java index 8f73dfd4190..f3332c069d1 100644 --- a/Mage.Sets/src/mage/cards/b/BindingAgony.java +++ b/Mage.Sets/src/mage/cards/b/BindingAgony.java @@ -1,13 +1,10 @@ - package mage.cards.b; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.common.DealtDamageAttachedTriggeredAbility; -import mage.abilities.dynamicvalue.common.NumericSetToEffectValues; -import mage.abilities.effects.Effect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DamageAttachedControllerEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -29,12 +26,10 @@ public final class BindingAgony extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // Whenever enchanted creature is dealt damage, Binding Agony deals that much damage to that creature's controller. - Effect effect = new DamageTargetEffect(new NumericSetToEffectValues("that much", "damage")); - effect.setText("{this} deals that much damage to that creature's controller"); - this.addAbility(new DealtDamageAttachedTriggeredAbility(Zone.BATTLEFIELD, effect, false, SetTargetPointer.PLAYER)); + this.addAbility(new DealtDamageAttachedTriggeredAbility(new DamageAttachedControllerEffect(SavedDamageValue.MUCH), false)); } private BindingAgony(final BindingAgony card) { diff --git a/Mage.Sets/src/mage/cards/b/BiomanticMastery.java b/Mage.Sets/src/mage/cards/b/BiomanticMastery.java index 19742a056f7..73de4b5d5d7 100644 --- a/Mage.Sets/src/mage/cards/b/BiomanticMastery.java +++ b/Mage.Sets/src/mage/cards/b/BiomanticMastery.java @@ -26,7 +26,6 @@ public final class BiomanticMastery extends CardImpl { // Draw a card for each creature target player controls, then draw a card for each creature another target player controls. this.getSpellAbility().addEffect(new BiomanticMasteryEffect()); this.getSpellAbility().addTarget(new TargetPlayer(2)); - } private BiomanticMastery(final BiomanticMastery card) { @@ -58,16 +57,15 @@ class BiomanticMasteryEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - for (UUID playerId : getTargetPointer().getTargets(game, source)) { - Player player = game.getPlayer(playerId); - if (player != null) { - int creatures = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game); - controller.drawCards(creatures, source, game); - } - } - return true; + if (controller == null) { return false; } + + for (UUID playerId : getTargetPointer().getTargets(game, source)) { + Player player = game.getPlayer(playerId); + if (player == null) { continue; } + + int creatures = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game); + controller.drawCards(creatures, source, game); } - return false; + return true; } } diff --git a/Mage.Sets/src/mage/cards/b/BirchloreRangers.java b/Mage.Sets/src/mage/cards/b/BirchloreRangers.java index 29f0351e04e..ebcbbf2eef7 100644 --- a/Mage.Sets/src/mage/cards/b/BirchloreRangers.java +++ b/Mage.Sets/src/mage/cards/b/BirchloreRangers.java @@ -45,7 +45,7 @@ public final class BirchloreRangers extends CardImpl { new TapTargetCost(new TargetControlledCreaturePermanent(2, 2, filter, false)))); // Morph {G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{G}"))); } private BirchloreRangers(final BirchloreRangers card) { @@ -80,7 +80,7 @@ class BirchloreRangersManaEffect extends AddManaOfAnyColorEffect { @Override public List getNetMana(Game game, Ability source) { if (game != null && game.inCheckPlayableState()) { - int count = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) / 2; + int count = game.getBattlefield().count(filter, source.getControllerId(), source, game) / 2; List netMana = new ArrayList<>(); if (count > 0) { netMana.add(Mana.AnyMana(count * 2)); diff --git a/Mage.Sets/src/mage/cards/b/BitingPalmNinja.java b/Mage.Sets/src/mage/cards/b/BitingPalmNinja.java index 54545f492f1..8197edfd741 100644 --- a/Mage.Sets/src/mage/cards/b/BitingPalmNinja.java +++ b/Mage.Sets/src/mage/cards/b/BitingPalmNinja.java @@ -44,7 +44,7 @@ public final class BitingPalmNinja extends CardImpl { new DoWhenCostPaid(new ReflexiveTriggeredAbility( new ExileCardYouChooseTargetOpponentEffect(StaticFilters.FILTER_CARD_A_NON_LAND), false, "that player reveals their hand and you choose a nonland card from it. Exile that card" - ), new RemoveCountersSourceCost(CounterType.MENACE.createInstance()), "Remove a menace counter?"), false, true + ), new RemoveCountersSourceCost(CounterType.MENACE.createInstance()).setText("remove a menace counter from it"), "Remove a menace counter?"), false, true )); } diff --git a/Mage.Sets/src/mage/cards/b/BitingRain.java b/Mage.Sets/src/mage/cards/b/BitingRain.java index 005b8b1aab0..c9b8312f934 100644 --- a/Mage.Sets/src/mage/cards/b/BitingRain.java +++ b/Mage.Sets/src/mage/cards/b/BitingRain.java @@ -23,7 +23,7 @@ public final class BitingRain extends CardImpl { this.getSpellAbility().addEffect(new BoostAllEffect(-2, -2, Duration.EndOfTurn)); // Madness {2}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{2}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{2}{B}"))); } private BitingRain(final BitingRain card) { diff --git a/Mage.Sets/src/mage/cards/b/BitterFeud.java b/Mage.Sets/src/mage/cards/b/BitterFeud.java index 8ad9ab2694b..8ced30b6ded 100644 --- a/Mage.Sets/src/mage/cards/b/BitterFeud.java +++ b/Mage.Sets/src/mage/cards/b/BitterFeud.java @@ -63,23 +63,27 @@ class BitterFeudEntersBattlefieldEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + Permanent permanent = game.getPermanentEntering(source.getSourceId()); - if (controller != null && permanent != null) { - TargetPlayer target = new TargetPlayer(2, 2, true); - controller.chooseTarget(outcome, target, source, game); - Player player1 = game.getPlayer(target.getFirstTarget()); - if (target.getTargets().size() > 1) { - Player player2 = game.getPlayer(target.getTargets().get(1)); - if (player1 != null && player2 != null) { - game.getState().setValue(source.getSourceId() + "_player1", player1); - game.getState().setValue(source.getSourceId() + "_player2", player2); - game.informPlayers(permanent.getLogName() + ": " + controller.getLogName() + " has chosen " + player1.getLogName() + " and " + player2.getLogName()); - permanent.addInfo("chosen players", "Chosen players: " + player1.getName() + ", " + player2.getName() + "", game); - return true; - } - } - } - return false; + if (permanent == null) { return false; } + + TargetPlayer target = new TargetPlayer(2, 2, true); + controller.chooseTarget(outcome, target, source, game); + Player player1 = game.getPlayer(target.getFirstTarget()); + if (player1 == null) { return false; } + + if (target.getTargets().size() <= 1) { return false; } + + Player player2 = game.getPlayer(target.getTargets().get(1)); + if (player2 == null) { return false; } + + game.getState().setValue(source.getSourceId() + "_player1", player1); + game.getState().setValue(source.getSourceId() + "_player2", player2); + game.informPlayers(permanent.getLogName() + ": " + controller.getLogName() + " has chosen " + player1.getLogName() + " and " + player2.getLogName()); + permanent.addInfo("chosen players", "Chosen players: " + player1.getName() + ", " + player2.getName() + "", game); + + return true; } @Override @@ -91,8 +95,8 @@ class BitterFeudEntersBattlefieldEffect extends OneShotEffect { class BitterFeudEffect extends ReplacementEffectImpl { - Player player1; - Player player2; + private Player player1; + private Player player2; public BitterFeudEffect() { super(Duration.WhileOnBattlefield, Outcome.Damage); @@ -101,6 +105,8 @@ class BitterFeudEffect extends ReplacementEffectImpl { public BitterFeudEffect(final BitterFeudEffect effect) { super(effect); + this.player1 = effect.player1; + this.player2 = effect.player2; } @Override @@ -110,54 +116,50 @@ class BitterFeudEffect extends ReplacementEffectImpl { @Override public boolean checksEventType(GameEvent event, Game game) { - switch (event.getType()) { - case DAMAGE_PERMANENT: - case DAMAGE_PLAYER: - return true; - default: - return false; - } + return event.getType() == GameEvent.EventType.DAMAGE_PERMANENT && event.getType() == GameEvent.EventType.DAMAGE_PLAYER; } @Override public boolean applies(GameEvent event, Ability source, Game game) { player1 = (Player) game.getState().getValue(source.getSourceId() + "_player1"); - player2 = (Player) game.getState().getValue(source.getSourceId() + "_player2"); - if (player1 != null && player2 != null) { - UUID targetPlayerId = null; - switch (event.getType()) { - case DAMAGE_PLAYER: - targetPlayerId = event.getTargetId(); - break; - case DAMAGE_PERMANENT: - Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null) { - targetPlayerId = permanent.getControllerId(); - } - break; - default: - return false; - } + if (player1 == null) { return false; } - if (player1.getId().equals(targetPlayerId) || player2.getId().equals(targetPlayerId)) { - UUID sourcePlayerId = null; - MageObject damageSource = game.getObject(event.getSourceId()); - if (damageSource instanceof StackObject) { - sourcePlayerId = ((StackObject) damageSource).getControllerId(); - } else if (damageSource instanceof Permanent) { - sourcePlayerId = ((Permanent) damageSource).getControllerId(); - } else if (damageSource instanceof Card) { - sourcePlayerId = ((Card) damageSource).getOwnerId(); - } - if (sourcePlayerId != null - && (player1.getId().equals(sourcePlayerId) || player2.getId().equals(sourcePlayerId)) - && !sourcePlayerId.equals(targetPlayerId)) { - return true; - } - } + player2 = (Player) game.getState().getValue(source.getSourceId() + "_player2"); + if (player2 == null) { return false; } + + UUID targetPlayerId; + switch (event.getType()) { + case DAMAGE_PLAYER: + targetPlayerId = event.getTargetId(); + break; + case DAMAGE_PERMANENT: + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent == null) { return false; } + + targetPlayerId = permanent.getControllerId(); + break; + default: + return false; } - return false; + if (!player1.getId().equals(targetPlayerId) && !player2.getId().equals(targetPlayerId)) { return false; } + + UUID sourcePlayerId; + MageObject damageSource = game.getObject(event.getSourceId()); + + if (damageSource instanceof StackObject) { + sourcePlayerId = ((StackObject) damageSource).getControllerId(); + } else if (damageSource instanceof Permanent) { + sourcePlayerId = ((Permanent) damageSource).getControllerId(); + } else if (damageSource instanceof Card) { + sourcePlayerId = ((Card) damageSource).getOwnerId(); + } else { + return false; + } + + return sourcePlayerId != null + && (player1.getId().equals(sourcePlayerId) || player2.getId().equals(sourcePlayerId)) + && !sourcePlayerId.equals(targetPlayerId); } @Override diff --git a/Mage.Sets/src/mage/cards/b/BitterOrdeal.java b/Mage.Sets/src/mage/cards/b/BitterOrdeal.java index 2e445d8d26d..22dd7745b16 100644 --- a/Mage.Sets/src/mage/cards/b/BitterOrdeal.java +++ b/Mage.Sets/src/mage/cards/b/BitterOrdeal.java @@ -1,37 +1,28 @@ - package mage.cards.b; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.search.SearchLibraryAndExileTargetEffect; import mage.abilities.keyword.GravestormAbility; -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.game.Game; -import mage.players.Player; import mage.target.TargetPlayer; -import mage.target.common.TargetCardInLibrary; -import mage.watchers.common.GravestormWatcher; + +import java.util.UUID; /** - * * @author emerald000 */ public final class BitterOrdeal extends CardImpl { public BitterOrdeal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); // Search target player's library for a card and exile it. Then that player shuffles their library. - this.getSpellAbility().addEffect(new BitterOrdealEffect()); + this.getSpellAbility().addEffect(new SearchLibraryAndExileTargetEffect(1, false)); this.getSpellAbility().addTarget(new TargetPlayer()); - + // Gravestorm - this.addAbility(new GravestormAbility(), new GravestormWatcher()); + this.addAbility(new GravestormAbility()); } private BitterOrdeal(final BitterOrdeal card) { @@ -43,38 +34,3 @@ public final class BitterOrdeal extends CardImpl { return new BitterOrdeal(this); } } - -class BitterOrdealEffect extends OneShotEffect { - - BitterOrdealEffect() { - super(Outcome.Exile); - staticText = "Search target player's library for a card and exile it. Then that player shuffles."; - } - - BitterOrdealEffect(final BitterOrdealEffect effect) { - super(effect); - } - - @Override - public BitterOrdealEffect copy() { - return new BitterOrdealEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player targetPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null && targetPlayer != null) { - TargetCardInLibrary target = new TargetCardInLibrary(); - if (controller.searchLibrary(target, source, game, targetPlayer.getId())) { - Card card = targetPlayer.getLibrary().getCard(target.getFirstTarget(), game); - if (card != null) { - controller.moveCardToExileWithInfo(card, null, null, source, game, Zone.LIBRARY, true); - } - } - targetPlayer.shuffleLibrary(source, game); - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/b/BitterRevelation.java b/Mage.Sets/src/mage/cards/b/BitterRevelation.java index 531e91595f6..0e37f7fbaa2 100644 --- a/Mage.Sets/src/mage/cards/b/BitterRevelation.java +++ b/Mage.Sets/src/mage/cards/b/BitterRevelation.java @@ -1,14 +1,12 @@ - package mage.cards.b; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.StaticFilters; /** * @@ -20,8 +18,7 @@ public final class BitterRevelation extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); // Look at the top four cards of your library. Put two of them into your hand and the rest into your graveyard. You lose 2 life. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(4), false, StaticValue.get(2), - StaticFilters.FILTER_CARD, Zone.GRAVEYARD, false, false, false, Zone.HAND, false)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(4, 2, PutCards.HAND, PutCards.GRAVEYARD)); this.getSpellAbility().addEffect(new LoseLifeSourceControllerEffect(2)); } diff --git a/Mage.Sets/src/mage/cards/l/LucasTheSharpshooter.java b/Mage.Sets/src/mage/cards/b/BjornaNightfallAlchemist.java similarity index 83% rename from Mage.Sets/src/mage/cards/l/LucasTheSharpshooter.java rename to Mage.Sets/src/mage/cards/b/BjornaNightfallAlchemist.java index 1f6fce94307..99b286dd644 100644 --- a/Mage.Sets/src/mage/cards/l/LucasTheSharpshooter.java +++ b/Mage.Sets/src/mage/cards/b/BjornaNightfallAlchemist.java @@ -1,4 +1,4 @@ -package mage.cards.l; +package mage.cards.b; import mage.MageInt; import mage.abilities.Ability; @@ -22,9 +22,9 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class LucasTheSharpshooter extends CardImpl { +public final class BjornaNightfallAlchemist extends CardImpl { - public LucasTheSharpshooter(UUID ownerId, CardSetInfo setInfo) { + public BjornaNightfallAlchemist(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{R}"); this.addSuperType(SuperType.LEGENDARY); @@ -43,12 +43,12 @@ public final class LucasTheSharpshooter extends CardImpl { this.addAbility(FriendsForeverAbility.getInstance()); } - private LucasTheSharpshooter(final LucasTheSharpshooter card) { + private BjornaNightfallAlchemist(final BjornaNightfallAlchemist card) { super(card); } @Override - public LucasTheSharpshooter copy() { - return new LucasTheSharpshooter(this); + public BjornaNightfallAlchemist copy() { + return new BjornaNightfallAlchemist(this); } } diff --git a/Mage.Sets/src/mage/cards/b/BlackMarketTycoon.java b/Mage.Sets/src/mage/cards/b/BlackMarketTycoon.java new file mode 100644 index 00000000000..a73c6a835dc --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BlackMarketTycoon.java @@ -0,0 +1,60 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BlackMarketTycoon extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.TREASURE); + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter, 2); + private static final Hint hint = new ValueHint( + "Treasures you control", new PermanentsOnBattlefieldCount(filter) + ); + + public BlackMarketTycoon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{G}"); + + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // At the beginning of your upkeep, Black Market Tycoon deals 2 damage to you for each Treasure you control. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new DamageControllerEffect(xValue), TargetController.YOU, false + ).addHint(hint)); + + // {T}: Create a Treasure token. + this.addAbility(new SimpleActivatedAbility(new CreateTokenEffect(new TreasureToken()), new TapSourceCost())); + } + + private BlackMarketTycoon(final BlackMarketTycoon card) { + super(card); + } + + @Override + public BlackMarketTycoon copy() { + return new BlackMarketTycoon(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BlackWard.java b/Mage.Sets/src/mage/cards/b/BlackWard.java index 1b124f23192..73bd956aa21 100644 --- a/Mage.Sets/src/mage/cards/b/BlackWard.java +++ b/Mage.Sets/src/mage/cards/b/BlackWard.java @@ -1,36 +1,29 @@ - package mage.cards.b; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.ProtectionAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.ColorPredicate; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LoneFox */ public final class BlackWard extends CardImpl { - private static final FilterCard filter = new FilterCard("black"); - - static { - filter.add(new ColorPredicate(ObjectColor.BLACK)); - } - public BlackWard(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -38,12 +31,11 @@ public final class BlackWard extends CardImpl { this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Protect)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // Enchanted creature has protection from black. This effect doesn't remove Black Ward. - ProtectionAbility gainedAbility = new ProtectionAbility(filter); - gainedAbility.setAuraIdNotToBeRemoved(this.getId()); - Effect effect = new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA); - effect.setText("Enchanted creature has protection from black. This effect doesn't remove {this}."); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( + ProtectionAbility.from(ObjectColor.BLACK), AttachmentType.AURA + ).setDoesntRemoveItself(true))); } private BlackWard(final BlackWard card) { diff --git a/Mage.Sets/src/mage/cards/b/BladeOfTheOni.java b/Mage.Sets/src/mage/cards/b/BladeOfTheOni.java new file mode 100644 index 00000000000..ed6a5b035e9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BladeOfTheOni.java @@ -0,0 +1,114 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.keyword.MenaceAbility; +import mage.abilities.keyword.ReconfigureAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BladeOfTheOni extends CardImpl { + + public BladeOfTheOni(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.EQUIPMENT); + this.subtype.add(SubType.DEMON); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Menace + this.addAbility(new MenaceAbility(false)); + + // Equipped creature has base power and toughness 5/5, has menace, and is a black Demon in addition to its other colors and types. + this.addAbility(new SimpleStaticAbility(new BladeOfTheOniEffect())); + + // Reconfigure {2}{B}{B} + this.addAbility(new ReconfigureAbility("{2}{B}{B}")); + } + + private BladeOfTheOni(final BladeOfTheOni card) { + super(card); + } + + @Override + public BladeOfTheOni copy() { + return new BladeOfTheOni(this); + } +} + +class BladeOfTheOniEffect extends ContinuousEffectImpl { + + BladeOfTheOniEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "equipped creature has base power and toughness 5/5, " + + "has menace, and is a black Demon in addition to its other colors and types"; + } + + private BladeOfTheOniEffect(final BladeOfTheOniEffect effect) { + super(effect); + } + + @Override + public BladeOfTheOniEffect copy() { + return new BladeOfTheOniEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + if (sourcePermanent == null) { + return false; + } + Permanent permanent = game.getPermanent(sourcePermanent.getAttachedTo()); + if (permanent == null) { + return false; + } + switch (layer) { + case AbilityAddingRemovingEffects_6: + permanent.addAbility(new MenaceAbility(false), source.getSourceId(), game); + return true; + case ColorChangingEffects_5: + permanent.getColor(game).setBlack(true); + return true; + case TypeChangingEffects_4: + permanent.addSubType(game, SubType.DEMON); + return true; + case PTChangingEffects_7: + if (sublayer != SubLayer.SetPT_7b) { + return false; + } + permanent.getPower().setValue(5); + permanent.getToughness().setValue(5); + return true; + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + switch (layer) { + case TypeChangingEffects_4: + case ColorChangingEffects_5: + case AbilityAddingRemovingEffects_6: + case PTChangingEffects_7: + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BladeSliver.java b/Mage.Sets/src/mage/cards/b/BladeSliver.java index 7fc07a17b9b..644d8fe77e9 100644 --- a/Mage.Sets/src/mage/cards/b/BladeSliver.java +++ b/Mage.Sets/src/mage/cards/b/BladeSliver.java @@ -28,7 +28,7 @@ public final class BladeSliver extends CardImpl { // All Sliver creatures get +1/+0. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new BoostAllEffect(1, 0, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, false))); + new BoostAllEffect(1, 0, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS, false))); } private BladeSliver(final BladeSliver card) { diff --git a/Mage.Sets/src/mage/cards/b/BladeSplicer.java b/Mage.Sets/src/mage/cards/b/BladeSplicer.java index 3fd48e080cf..a6290b2378e 100644 --- a/Mage.Sets/src/mage/cards/b/BladeSplicer.java +++ b/Mage.Sets/src/mage/cards/b/BladeSplicer.java @@ -21,10 +21,9 @@ import java.util.UUID; * @author Loki */ public final class BladeSplicer extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("Golem creatures"); + private static final FilterPermanent filter = new FilterPermanent("Golems"); static { - filter.add(CardType.CREATURE.getPredicate()); filter.add(SubType.GOLEM.getPredicate()); } diff --git a/Mage.Sets/src/mage/cards/b/BladeTribeBerserkers.java b/Mage.Sets/src/mage/cards/b/BladeTribeBerserkers.java index d1b971152b3..2c9f4e5ad4c 100644 --- a/Mage.Sets/src/mage/cards/b/BladeTribeBerserkers.java +++ b/Mage.Sets/src/mage/cards/b/BladeTribeBerserkers.java @@ -23,7 +23,7 @@ import java.util.UUID; */ public final class BladeTribeBerserkers extends CardImpl { - private static final String effectText = "Metalcraft — When Blade-Tribe Berserkers enters the battlefield, if you control three or more artifacts, Blade-Tribe Berserkers gets +3/+3 and gains haste until end of turn."; + private static final String effectText = "When {this} enters the battlefield, if you control three or more artifacts, {this} gets +3/+3 and gains haste until end of turn."; public BladeTribeBerserkers(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); diff --git a/Mage.Sets/src/mage/cards/b/BladebackSliver.java b/Mage.Sets/src/mage/cards/b/BladebackSliver.java index de3440775f2..109101d3c45 100644 --- a/Mage.Sets/src/mage/cards/b/BladebackSliver.java +++ b/Mage.Sets/src/mage/cards/b/BladebackSliver.java @@ -39,7 +39,7 @@ public final class BladebackSliver extends CardImpl { this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( new GainAbilityControlledEffect( ability, Duration.WhileOnBattlefield, - StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS + StaticFilters.FILTER_PERMANENT_ALL_SLIVERS ), HellbentCondition.instance, "Hellbent — " + "As long as you have no cards in hand, Sliver creatures you control have " + "\"{T}: This creature deals 1 damage to target player or planeswalker.\"" diff --git a/Mage.Sets/src/mage/cards/b/BlademaneBaku.java b/Mage.Sets/src/mage/cards/b/BlademaneBaku.java index 144a4440645..fd9b07f0a49 100644 --- a/Mage.Sets/src/mage/cards/b/BlademaneBaku.java +++ b/Mage.Sets/src/mage/cards/b/BlademaneBaku.java @@ -1,30 +1,34 @@ - - package mage.cards.b; - import java.util.UUID; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.costs.Cost; import mage.abilities.costs.common.RemoveVariableCountersSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.MultipliedValue; +import mage.abilities.dynamicvalue.common.RemovedCountersForCostValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; - import mage.cards.CardSetInfo; - import mage.constants.*; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; -import mage.game.Game; /** * @author LevelX2 */ public final class BlademaneBaku extends CardImpl { + private static final DynamicValue xValue = new MultipliedValue(RemovedCountersForCostValue.instance, 2); + public BlademaneBaku(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}"); this.subtype.add(SubType.SPIRIT); @@ -32,12 +36,14 @@ public final class BlademaneBaku extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - // Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Skullmane Baku. + // Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Blademane Baku. this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true)); // {1}, Remove X ki counters from Blademane Baku: For each counter removed, Blademane Baku gets +2/+0 until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BlademaneBakuBoostEffect(), new GenericManaCost(1)); - ability.addCost(new RemoveVariableCountersSourceCost(CounterType.KI.createInstance(1))); + Effect effect = new BoostSourceEffect(xValue, StaticValue.get(0), Duration.EndOfTurn); + effect.setText("for each counter removed, {this} gets +2/+0 until end of turn"); + Ability ability = new SimpleActivatedAbility(effect, new GenericManaCost(1)); + ability.addCost(new RemoveVariableCountersSourceCost(CounterType.KI.createInstance())); this.addAbility(ability); } @@ -49,37 +55,4 @@ public final class BlademaneBaku extends CardImpl { public BlademaneBaku copy() { return new BlademaneBaku(this); } - - static class BlademaneBakuBoostEffect extends OneShotEffect { - - public BlademaneBakuBoostEffect() { - super(Outcome.UnboostCreature); - staticText = "For each counter removed, {this} gets +2/+0 until end of turn"; - } - - public BlademaneBakuBoostEffect(BlademaneBakuBoostEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - int numberToBoost = 0; - for (Cost cost : source.getCosts()) { - if (cost instanceof RemoveVariableCountersSourceCost) { - numberToBoost = ((RemoveVariableCountersSourceCost)cost).getAmount() * 2; - } - } - if (numberToBoost >= 0) { - game.addEffect(new BoostSourceEffect(numberToBoost, 0, Duration.EndOfTurn), source); - return true; - } - return false; - } - - @Override - public BlademaneBakuBoostEffect copy() { - return new BlademaneBakuBoostEffect(this); - } - - } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/b/BlankaFerociousFriend.java b/Mage.Sets/src/mage/cards/b/BlankaFerociousFriend.java new file mode 100644 index 00000000000..090f31fe734 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BlankaFerociousFriend.java @@ -0,0 +1,76 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BecomesTargetTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.watchers.common.CastSpellLastTurnWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BlankaFerociousFriend extends CardImpl { + + public BlankaFerociousFriend(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.BEAST); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Rolling Attack—Blanka, Ferocious Friend has trample as long as you've cast three or more spells this turn. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(TrampleAbility.getInstance()), BlankaFerociousFriendCondition.instance, + "{this} has trample as long as you've cast three or more spells this turn" + )).withFlavorWord("Rolling Attack")); + + // Electric Thunder—Whenever Blanka becomes the target of a spell, he gets +2/+2 until end of turn and deals 2 damage to each opponent. + Ability ability = new BecomesTargetTriggeredAbility(new BoostSourceEffect( + 2, 2, Duration.EndOfTurn + ).setText("he gets +2/+2 until end of turn"), StaticFilters.FILTER_SPELL_A).setTriggerPhrase("Whenever {this} becomes the target of a spell, "); + ability.addEffect(new DamagePlayersEffect(2, TargetController.OPPONENT) + .setText("and deals 2 damage to each opponent")); + this.addAbility(ability.withFlavorWord("Electric Thunder")); + } + + private BlankaFerociousFriend(final BlankaFerociousFriend card) { + super(card); + } + + @Override + public BlankaFerociousFriend copy() { + return new BlankaFerociousFriend(this); + } +} + +enum BlankaFerociousFriendCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return game + .getState() + .getWatcher(CastSpellLastTurnWatcher.class) + .getAmountOfSpellsPlayerCastOnCurrentTurn(source.getControllerId()) >= 3; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BlasphemousAct.java b/Mage.Sets/src/mage/cards/b/BlasphemousAct.java index c67a14b6763..f17a9d0f425 100644 --- a/Mage.Sets/src/mage/cards/b/BlasphemousAct.java +++ b/Mage.Sets/src/mage/cards/b/BlasphemousAct.java @@ -57,12 +57,12 @@ class BlasphemousCostReductionEffect extends CostModificationEffectImpl { @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - int reductionAmount = game.getBattlefield().count(StaticFilters.FILTER_PERMANENT_CREATURE, source.getSourceId(), source.getControllerId(), game); - CardUtil.reduceCost(abilityToModify, reductionAmount); - return true; - } - return false; + if (player == null) { return false; } + + int reductionAmount = game.getBattlefield().count(StaticFilters.FILTER_PERMANENT_CREATURE, source.getSourceId(), source, game); + CardUtil.reduceCost(abilityToModify, reductionAmount); + + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/b/BlastFromThePast.java b/Mage.Sets/src/mage/cards/b/BlastFromThePast.java index 97bdd6bc46a..9b993cc074f 100644 --- a/Mage.Sets/src/mage/cards/b/BlastFromThePast.java +++ b/Mage.Sets/src/mage/cards/b/BlastFromThePast.java @@ -15,7 +15,6 @@ import mage.abilities.keyword.MadnessAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.TimingRule; import mage.game.permanent.token.GoblinToken; import mage.target.common.TargetAnyTarget; @@ -29,7 +28,7 @@ public final class BlastFromThePast extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}"); // Madness {R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{R}"))); // Cycling {1}{R} this.addAbility(new CyclingAbility(new ManaCostsImpl("{1}{R}"))); // Kicker {2}{R} diff --git a/Mage.Sets/src/mage/cards/b/BlastOfGenius.java b/Mage.Sets/src/mage/cards/b/BlastOfGenius.java index 3bdc32a0641..4aea551192e 100644 --- a/Mage.Sets/src/mage/cards/b/BlastOfGenius.java +++ b/Mage.Sets/src/mage/cards/b/BlastOfGenius.java @@ -60,8 +60,8 @@ class BlastOfGeniusEffect extends OneShotEffect { if (player != null) { player.drawCards(3, source, game); TargetDiscard target = new TargetDiscard(player.getId()); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { - player.choose(Outcome.Discard, target, source.getSourceId(), game); + if (target.canChoose(player.getId(), source, game)) { + player.choose(Outcome.Discard, target, source, game); Card card = player.getHand().get(target.getFirstTarget(), game); if (card != null) { player.discard(card, false, source, game); diff --git a/Mage.Sets/src/mage/cards/b/BlatantThievery.java b/Mage.Sets/src/mage/cards/b/BlatantThievery.java index 9a754b68068..c619988e8f5 100644 --- a/Mage.Sets/src/mage/cards/b/BlatantThievery.java +++ b/Mage.Sets/src/mage/cards/b/BlatantThievery.java @@ -52,7 +52,7 @@ enum BlatantThieveryAdjuster implements TargetAdjuster { Player opponent = game.getPlayer(opponentId); if (opponent == null || game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_PERMANENT, - ability.getSourceId(), opponentId, game + opponentId, ability, game ) < 1) { continue; } diff --git a/Mage.Sets/src/mage/cards/b/BlazingEffigy.java b/Mage.Sets/src/mage/cards/b/BlazingEffigy.java index 68c7af94966..c64d4e9826f 100644 --- a/Mage.Sets/src/mage/cards/b/BlazingEffigy.java +++ b/Mage.Sets/src/mage/cards/b/BlazingEffigy.java @@ -89,15 +89,16 @@ class BlazingEffigyWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.DAMAGED_PERMANENT) { - if (!event.getSourceId().equals(event.getTargetId())) { - MageObjectReference damageSourceRef = new MageObjectReference(event.getSourceId(), game); - MageObjectReference damageTargetRef = new MageObjectReference(event.getTargetId(), game); - if (game.getPermanentOrLKIBattlefield(event.getSourceId()) != null && game.getPermanentOrLKIBattlefield(event.getSourceId()).getName().equals("Blazing Effigy")) { - damagedObjects.putIfAbsent(damageTargetRef, 0); - damagedObjects.compute(damageTargetRef, (k, damage) -> damage + event.getAmount()); - } - } + if (event.getType() != GameEvent.EventType.DAMAGED_PERMANENT) { return; } + + if (event.getSourceId().equals(event.getTargetId())) { return; } + + // TODO: Should damageSourceRef be used for anything? + MageObjectReference damageSourceRef = new MageObjectReference(event.getSourceId(), game); + MageObjectReference damageTargetRef = new MageObjectReference(event.getTargetId(), game); + if (game.getPermanentOrLKIBattlefield(event.getSourceId()) != null && game.getPermanentOrLKIBattlefield(event.getSourceId()).getName().equals("Blazing Effigy")) { + damagedObjects.putIfAbsent(damageTargetRef, 0); + damagedObjects.compute(damageTargetRef, (k, damage) -> damage + event.getAmount()); } } diff --git a/Mage.Sets/src/mage/cards/b/BlazingHope.java b/Mage.Sets/src/mage/cards/b/BlazingHope.java index 319e1ed3437..f85d5a86ef6 100644 --- a/Mage.Sets/src/mage/cards/b/BlazingHope.java +++ b/Mage.Sets/src/mage/cards/b/BlazingHope.java @@ -54,29 +54,29 @@ class BlazingHopeTarget extends TargetCreaturePermanent { if (permanent != null) { if (!isNotTarget()) { if (!permanent.canBeTargetedBy(game.getObject(source.getId()), controllerId, game) - || !permanent.canBeTargetedBy(game.getObject(source.getSourceId()), controllerId, game)) { + || !permanent.canBeTargetedBy(game.getObject(source), controllerId, game)) { return false; } } Player controller = game.getPlayer(source.getControllerId()); if (controller != null && permanent.getPower().getValue() >= controller.getLife()) { - return filter.match(permanent, source.getSourceId(), controllerId, game); + return filter.match(permanent, controllerId, source, game); } } return false; } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { int remainingTargets = this.minNumberOfTargets - targets.size(); if (remainingTargets <= 0) { return true; } int count = 0; Player controller = game.getPlayer(sourceControllerId); - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); if(targetSource != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (!targets.containsKey(permanent.getId())) { if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { if (controller != null && permanent.getPower().getValue() >= controller.getLife()) { diff --git a/Mage.Sets/src/mage/cards/b/BlazingRootwalla.java b/Mage.Sets/src/mage/cards/b/BlazingRootwalla.java index f3e450b8d7a..a8b711d1449 100644 --- a/Mage.Sets/src/mage/cards/b/BlazingRootwalla.java +++ b/Mage.Sets/src/mage/cards/b/BlazingRootwalla.java @@ -32,7 +32,7 @@ public final class BlazingRootwalla extends CardImpl { new BoostSourceEffect(2, 0, Duration.EndOfTurn), new ManaCostsImpl("{R}"))); // Madness{0} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{0}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{0}"))); } private BlazingRootwalla(final BlazingRootwalla card) { diff --git a/Mage.Sets/src/mage/cards/b/BlazingShoal.java b/Mage.Sets/src/mage/cards/b/BlazingShoal.java index c460a3d7228..ad753cc0da2 100644 --- a/Mage.Sets/src/mage/cards/b/BlazingShoal.java +++ b/Mage.Sets/src/mage/cards/b/BlazingShoal.java @@ -12,8 +12,6 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterOwnedCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCreaturePermanent; @@ -25,19 +23,27 @@ import java.util.UUID; */ public final class BlazingShoal extends CardImpl { + private static final FilterOwnedCard filter + = new FilterOwnedCard("a red card with mana value X from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + } + public BlazingShoal(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{R}{R}"); this.subtype.add(SubType.ARCANE); - // You may exile a red card with converted mana cost X from your hand rather than pay Blazing Shoal's mana cost. - FilterOwnedCard filter = new FilterOwnedCard("a red card with mana value X from your hand"); - filter.add(new ColorPredicate(ObjectColor.RED)); - filter.add(Predicates.not(new CardIdPredicate(this.getId()))); // the exile cost can never be paid with the card itself - this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter), true))); + this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost( + new TargetCardInHand(filter), true + ))); // Target creature gets +X/+0 until end of turn. - this.getSpellAbility().addEffect(new BoostTargetEffect(ExileFromHandCostCardConvertedMana.instance, StaticValue.get(0), Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new BoostTargetEffect( + ExileFromHandCostCardConvertedMana.instance, + StaticValue.get(0), Duration.EndOfTurn + )); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/b/BleakCovenVampires.java b/Mage.Sets/src/mage/cards/b/BleakCovenVampires.java index 87ccf22aff4..54b1e7a1ab9 100644 --- a/Mage.Sets/src/mage/cards/b/BleakCovenVampires.java +++ b/Mage.Sets/src/mage/cards/b/BleakCovenVampires.java @@ -23,7 +23,7 @@ import java.util.UUID; */ public final class BleakCovenVampires extends CardImpl { - private static final String effectText = "Metalcraft — When Bleak Coven Vampires enters the battlefield, if you control three or more artifacts, target player loses 4 life and you gain 4 life."; + private static final String effectText = "When {this} enters the battlefield, if you control three or more artifacts, target player loses 4 life and you gain 4 life."; public BleakCovenVampires(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); diff --git a/Mage.Sets/src/mage/cards/b/BlessedAlliance.java b/Mage.Sets/src/mage/cards/b/BlessedAlliance.java index 23af303722e..1edb08eed24 100644 --- a/Mage.Sets/src/mage/cards/b/BlessedAlliance.java +++ b/Mage.Sets/src/mage/cards/b/BlessedAlliance.java @@ -49,16 +49,14 @@ public final class BlessedAlliance extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterGainLife).withChooseHint("player gains 4 life")); // Untap up to two target creatures. - Mode mode = new Mode(); effect = new UntapTargetEffect(); effect.setText("Untap up to two target creatures"); - mode.addEffect(effect); + Mode mode = new Mode(effect); mode.addTarget(new TargetCreaturePermanent(0, 2, filterCreature, false).withChooseHint("untap")); this.getSpellAbility().addMode(mode); // Target opponent sacrifices an attacking creature. - mode = new Mode(); - mode.addEffect(new SacrificeEffect(new FilterAttackingCreature(), 1, "Target opponent")); + mode = new Mode(new SacrificeEffect(new FilterAttackingCreature(), 1, "Target opponent")); mode.addTarget(new TargetPlayer(1, 1, false, filterSacrifice).withChooseHint("sacrifices an attacking creature")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/BlessedDefiance.java b/Mage.Sets/src/mage/cards/b/BlessedDefiance.java index 1c234914355..f151510822b 100644 --- a/Mage.Sets/src/mage/cards/b/BlessedDefiance.java +++ b/Mage.Sets/src/mage/cards/b/BlessedDefiance.java @@ -28,7 +28,7 @@ import java.util.UUID; public class BlessedDefiance extends CardImpl { public BlessedDefiance(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "W"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); // Target creature you control gets +2/+0 and gains lifelink until end of turn. When that creature dies this turn, create a 1/1 white Spirit creature token with flying. this.getSpellAbility().addEffect(new BoostTargetEffect(2, 0) diff --git a/Mage.Sets/src/mage/cards/b/BlessingOfFrost.java b/Mage.Sets/src/mage/cards/b/BlessingOfFrost.java index 1deee6907f5..a90524a964c 100644 --- a/Mage.Sets/src/mage/cards/b/BlessingOfFrost.java +++ b/Mage.Sets/src/mage/cards/b/BlessingOfFrost.java @@ -91,7 +91,7 @@ class BlessingOfFrostEffect extends OneShotEffect { } game.getState().processAction(game); player.drawCards(game.getBattlefield().count( - filter, source.getSourceId(), source.getControllerId(), game + filter, source.getControllerId(), source, game ), source, game); return true; } diff --git a/Mage.Sets/src/mage/cards/b/BlexVexingPest.java b/Mage.Sets/src/mage/cards/b/BlexVexingPest.java index 0c0a87da95c..c67811db949 100644 --- a/Mage.Sets/src/mage/cards/b/BlexVexingPest.java +++ b/Mage.Sets/src/mage/cards/b/BlexVexingPest.java @@ -6,21 +6,18 @@ import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.effects.common.LookLibraryControllerEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.cards.ModalDoubleFacesCard; import mage.constants.*; import mage.cards.CardSetInfo; -import mage.filter.FilterCard; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; /** * @@ -81,15 +78,11 @@ public final class BlexVexingPest extends ModalDoubleFacesCard { } } -class SearchForBlexEffect extends LookLibraryControllerEffect { +class SearchForBlexEffect extends LookLibraryAndPickControllerEffect { - private static final FilterCard filter = new FilterCard("cards to put into your hand"); - - public SearchForBlexEffect() { - super(Outcome.DrawCard, StaticValue.get(5), false, Zone.GRAVEYARD, true); - this.staticText = "Look at the top five cards of your library. " - + "You may put any number of them into your hand and the rest into your graveyard. " - + "You lose 3 life for each card you put into your hand this way"; + SearchForBlexEffect() { + super(5, Integer.MAX_VALUE, PutCards.HAND, PutCards.GRAVEYARD); + this.optional = true; } private SearchForBlexEffect(final SearchForBlexEffect effect) { @@ -102,21 +95,14 @@ class SearchForBlexEffect extends LookLibraryControllerEffect { } @Override - protected void actionWithSelectedCards(Cards cards, Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - TargetCard target = new TargetCard(0, 5, Zone.LIBRARY, filter); - if (player.choose(outcome, cards, target, game)) { - Cards pickedCards = new CardsImpl(target.getTargets()); - cards.removeAll(pickedCards); - player.moveCards(pickedCards, Zone.HAND, source, game); - player.loseLife(pickedCards.size() * 3, game, source, false); - } - } + protected boolean actionWithPickedCards(Game game, Ability source, Player player, Cards pickedCards, Cards otherCards) { + super.actionWithPickedCards(game, source, player, pickedCards, otherCards); + player.loseLife(pickedCards.size() * 3, game, source, false); + return true; } @Override public String getText(Mode mode) { - return staticText; + return super.getText(mode).concat(". You lose 3 life for each card you put into your hand this way"); } } diff --git a/Mage.Sets/src/mage/cards/b/BlightHerder.java b/Mage.Sets/src/mage/cards/b/BlightHerder.java index 82c0a5afaac..a33c25b6563 100644 --- a/Mage.Sets/src/mage/cards/b/BlightHerder.java +++ b/Mage.Sets/src/mage/cards/b/BlightHerder.java @@ -72,7 +72,7 @@ class BlightHerderEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Target target = new TargetCardInExile(2, 2, filter, null); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (target.canChoose(source.getControllerId(), source, game)) { if (controller.chooseTarget(outcome, target, source, game)) { Cards cardsToGraveyard = new CardsImpl(target.getTargets()); controller.moveCards(cardsToGraveyard, Zone.GRAVEYARD, source, game); diff --git a/Mage.Sets/src/mage/cards/b/BlimComedicGenius.java b/Mage.Sets/src/mage/cards/b/BlimComedicGenius.java index 5b1782303c2..0664c90748c 100644 --- a/Mage.Sets/src/mage/cards/b/BlimComedicGenius.java +++ b/Mage.Sets/src/mage/cards/b/BlimComedicGenius.java @@ -93,13 +93,13 @@ class BlimComedicGeniusEffect extends OneShotEffect { if (player == null) { continue; } - int count = game.getBattlefield().count(filter, source.getSourceId(), playerId, game); + int count = game.getBattlefield().count(filter, playerId, source, game); if (count < 1) { continue; } player.loseLife(count, game, source, true); TargetDiscard target = new TargetDiscard(StaticFilters.FILTER_CARD, playerId); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); cardsMap.put(playerId, new CardsImpl(target.getTargets())); } for (Map.Entry entry : cardsMap.entrySet()) { diff --git a/Mage.Sets/src/mage/cards/b/BlindingBeam.java b/Mage.Sets/src/mage/cards/b/BlindingBeam.java index d358aa68c2f..e208efa112e 100644 --- a/Mage.Sets/src/mage/cards/b/BlindingBeam.java +++ b/Mage.Sets/src/mage/cards/b/BlindingBeam.java @@ -41,8 +41,7 @@ public final class BlindingBeam extends CardImpl { this.getSpellAbility().addEffect(new TapTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent(2,2)); // or creatures don't untap during target player's next untap step. - Mode mode = new Mode(); - mode.addEffect(new BlindingBeamEffect()); + Mode mode = new Mode(new BlindingBeamEffect()); mode.addTarget(new TargetPlayer()); this.getSpellAbility().getModes().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/b/BlindingSouleater.java b/Mage.Sets/src/mage/cards/b/BlindingSouleater.java index b2e51005868..e9fd4a7a2e1 100644 --- a/Mage.Sets/src/mage/cards/b/BlindingSouleater.java +++ b/Mage.Sets/src/mage/cards/b/BlindingSouleater.java @@ -1,28 +1,25 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.PhyrexianManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.TapTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ColoredManaSymbol; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class BlindingSouleater extends CardImpl { public BlindingSouleater(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CLERIC); @@ -30,9 +27,7 @@ public final class BlindingSouleater extends CardImpl { this.toughness = new MageInt(3); // {W/P},{T}: Tap target creature. ( can be paid with either or 2 life.) - SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new TapTargetEffect(), - new PhyrexianManaCost(ColoredManaSymbol.W)); + SimpleActivatedAbility ability = new SimpleActivatedAbility(new TapTargetEffect(), new ManaCostsImpl<>("{W/P}")); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/b/BlindingSpray.java b/Mage.Sets/src/mage/cards/b/BlindingSpray.java index 0a51960e0de..29001f55cde 100644 --- a/Mage.Sets/src/mage/cards/b/BlindingSpray.java +++ b/Mage.Sets/src/mage/cards/b/BlindingSpray.java @@ -1,4 +1,3 @@ - package mage.cards.b; import java.util.UUID; @@ -8,8 +7,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; /** * @@ -17,18 +15,11 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class BlindingSpray extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public BlindingSpray(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{4}{U}"); - // Creatures your opponents control get -4/-0 until end of turn. - this.getSpellAbility().addEffect(new BoostAllEffect(-4, 0, Duration.EndOfTurn, filter, false)); + this.getSpellAbility().addEffect(new BoostAllEffect(-4, 0, Duration.EndOfTurn, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, false)); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); diff --git a/Mage.Sets/src/mage/cards/b/BlinkmothInfusion.java b/Mage.Sets/src/mage/cards/b/BlinkmothInfusion.java index a02615bfd77..9bc1c7020ee 100644 --- a/Mage.Sets/src/mage/cards/b/BlinkmothInfusion.java +++ b/Mage.Sets/src/mage/cards/b/BlinkmothInfusion.java @@ -23,9 +23,9 @@ public final class BlinkmothInfusion extends CardImpl { public BlinkmothInfusion(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{12}{U}{U}"); - // Affinity for artifacts this.addAbility(new AffinityForArtifactsAbility()); + // Untap all artifacts. this.getSpellAbility().addEffect(new UntapAllArtifactsEffect()); } @@ -54,13 +54,12 @@ class UntapAllArtifactsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - for (Permanent artifact: game.getBattlefield().getAllActivePermanents(new FilterArtifactPermanent(), game)) { - artifact.untap(game); - } - return true; + if (player == null) { return false; } + + for (Permanent artifact: game.getBattlefield().getAllActivePermanents(new FilterArtifactPermanent(), game)) { + artifact.untap(game); } - return false; + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/b/BlinkmothUrn.java b/Mage.Sets/src/mage/cards/b/BlinkmothUrn.java index 23a6f1b7157..cf3cf34b851 100644 --- a/Mage.Sets/src/mage/cards/b/BlinkmothUrn.java +++ b/Mage.Sets/src/mage/cards/b/BlinkmothUrn.java @@ -66,7 +66,7 @@ class BlinkmothUrnEffect extends OneShotEffect { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (player != null && sourcePermanent != null && !sourcePermanent.isTapped()) { player.getManaPool().addMana(Mana.ColorlessMana( - game.getState().getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game). + game.getState().getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game). size()), game, source, false); return true; } diff --git a/Mage.Sets/src/mage/cards/b/BlisteringFirecat.java b/Mage.Sets/src/mage/cards/b/BlisteringFirecat.java index ec1c357a85b..a13d2111184 100644 --- a/Mage.Sets/src/mage/cards/b/BlisteringFirecat.java +++ b/Mage.Sets/src/mage/cards/b/BlisteringFirecat.java @@ -35,7 +35,7 @@ public final class BlisteringFirecat extends CardImpl { // At the beginning of the end step, sacrifice Blistering Firecat. this.addAbility(new OnEventTriggeredAbility(GameEvent.EventType.END_TURN_STEP_PRE, "beginning of the end step", true, new SacrificeSourceEffect())); // Morph {R}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{R}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{R}{R}"))); } private BlisteringFirecat(final BlisteringFirecat card) { diff --git a/Mage.Sets/src/mage/cards/b/BlisterstickShaman.java b/Mage.Sets/src/mage/cards/b/BlisterstickShaman.java index c21730c32ca..0f03c5173b0 100644 --- a/Mage.Sets/src/mage/cards/b/BlisterstickShaman.java +++ b/Mage.Sets/src/mage/cards/b/BlisterstickShaman.java @@ -25,7 +25,7 @@ public final class BlisterstickShaman extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(1); - Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(1)); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(1, "it")); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BlitzHellion.java b/Mage.Sets/src/mage/cards/b/BlitzHellion.java index d1b0ded175b..89d548493d1 100644 --- a/Mage.Sets/src/mage/cards/b/BlitzHellion.java +++ b/Mage.Sets/src/mage/cards/b/BlitzHellion.java @@ -1,10 +1,7 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.ShuffleIntoLibrarySourceEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.TrampleAbility; @@ -13,16 +10,16 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; -import mage.constants.Zone; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class BlitzHellion extends CardImpl { public BlitzHellion(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{G}"); this.subtype.add(SubType.HELLION); this.power = new MageInt(7); this.toughness = new MageInt(7); @@ -34,9 +31,11 @@ public final class BlitzHellion extends CardImpl { this.addAbility(HasteAbility.getInstance()); // At the beginning of the end step, Blitz Hellion's owner shuffles it into their library. - Effect effect = new ShuffleIntoLibrarySourceEffect(); - effect.setText("{this}'s owner shuffles it into their library."); - this.addAbility(new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD, effect, TargetController.ANY, null, false)); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new ShuffleIntoLibrarySourceEffect() + .setText("{this}'s owner shuffles it into their library."), + TargetController.NEXT, false + )); } private BlitzHellion(final BlitzHellion card) { diff --git a/Mage.Sets/src/mage/cards/b/BlizzardBrawl.java b/Mage.Sets/src/mage/cards/b/BlizzardBrawl.java index 4d82979e5e6..44e37d37f76 100644 --- a/Mage.Sets/src/mage/cards/b/BlizzardBrawl.java +++ b/Mage.Sets/src/mage/cards/b/BlizzardBrawl.java @@ -61,7 +61,7 @@ class BlizzardBrawlEffect extends OneShotEffect { staticText = "Choose target creature you control and target creature you don't control. " + "If you control three or more snow permanents, the creature you control gets +1/+0 " + "and gains indestructible until end of turn. " + - "Then those creatures fight each other." + + "Then those creatures fight each other. " + "(Each deals damage equal to its power to the other.)"; } @@ -81,7 +81,7 @@ class BlizzardBrawlEffect extends OneShotEffect { if (creature1 == null) { return false; } - if (game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) >= 3) { + if (game.getBattlefield().count(filter, source.getControllerId(), source, game) >= 3) { game.addEffect(new BoostTargetEffect( 1, 0, Duration.EndOfTurn ).setTargetPointer(new FixedTarget(creature1.getId(), game)), source); diff --git a/Mage.Sets/src/mage/cards/b/BlizzardSpecter.java b/Mage.Sets/src/mage/cards/b/BlizzardSpecter.java index 71f9d0dc46d..6067663d03b 100644 --- a/Mage.Sets/src/mage/cards/b/BlizzardSpecter.java +++ b/Mage.Sets/src/mage/cards/b/BlizzardSpecter.java @@ -40,8 +40,7 @@ public final class BlizzardSpecter extends CardImpl { Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ReturnToHandEffect(), false, true); // or that player discards a card. - Mode mode = new Mode(); - mode.addEffect(new DiscardTargetEffect(1, false)); + Mode mode = new Mode(new DiscardTargetEffect(1, false)); ability.addMode(mode); this.addAbility(ability); @@ -80,7 +79,7 @@ class ReturnToHandEffect extends OneShotEffect { return false; } Target target = new TargetControlledPermanent(1, 1, new FilterControlledPermanent(), true); - if (target.canChoose(source.getSourceId(), targetPlayer.getId(), game)) { + if (target.canChoose(targetPlayer.getId(), source, game)) { targetPlayer.chooseTarget(Outcome.ReturnToHand, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/b/BlizzardStrix.java b/Mage.Sets/src/mage/cards/b/BlizzardStrix.java index b45eaca2a0c..01a422fdf79 100644 --- a/Mage.Sets/src/mage/cards/b/BlizzardStrix.java +++ b/Mage.Sets/src/mage/cards/b/BlizzardStrix.java @@ -7,7 +7,6 @@ import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbil import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; import mage.abilities.keyword.FlashAbility; @@ -90,18 +89,17 @@ class BlizzardStrixEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); Player controller = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (controller != null && permanent != null && sourcePermanent != null) { - if (controller.moveCardToExileWithInfo(permanent, source.getSourceId(), sourcePermanent.getIdName(), source, game, Zone.BATTLEFIELD, true)) { - //create delayed triggered ability - Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false); - effect.setText("Return that card to the battlefield under its owner's control at the beginning of the next end step"); - effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game)); - game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source); - return true; - } + if (controller == null || permanent == null) { + return false; } - return false; + controller.moveCards(permanent, Zone.EXILED, source, game); + //create delayed triggered ability + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false) + .setText("Return that card to the battlefield under its owner's control at the beginning of the next end step") + .setTargetPointer(new FixedTarget(source.getFirstTarget(), game)) + ), source); + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/b/BloodBaronOfVizkopa.java b/Mage.Sets/src/mage/cards/b/BloodBaronOfVizkopa.java index 68b1873d0e2..0137ca84c6b 100644 --- a/Mage.Sets/src/mage/cards/b/BloodBaronOfVizkopa.java +++ b/Mage.Sets/src/mage/cards/b/BloodBaronOfVizkopa.java @@ -32,7 +32,6 @@ public final class BloodBaronOfVizkopa extends CardImpl { // As long as you have 30 or more life and an opponent has 10 or less life, Blood Baron of Vizkopa gets +6/+6 and has flying. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BloodBaronOfVizkopaEffect())); - } private BloodBaronOfVizkopa(final BloodBaronOfVizkopa card) { @@ -53,7 +52,7 @@ class BloodBaronOfVizkopaEffect extends ContinuousEffectImpl { staticText = "As long as you have 30 or more life and an opponent has 10 or less life, {this} gets +6/+6 and has flying"; } - public BloodBaronOfVizkopaEffect(final BloodBaronOfVizkopaEffect effect) { + private BloodBaronOfVizkopaEffect(final BloodBaronOfVizkopaEffect effect) { super(effect); } @@ -64,41 +63,45 @@ class BloodBaronOfVizkopaEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - if (conditionState(source, game)) { - Permanent creature = game.getPermanent(source.getSourceId()); - if (creature != null) { - switch (layer) { - case PTChangingEffects_7: - if (sublayer == SubLayer.ModifyPT_7c) { - creature.addPower(6); - creature.addToughness(6); - } - break; - case AbilityAddingRemovingEffects_6: - if (sublayer == SubLayer.NA) { - creature.addAbility(FlyingAbility.getInstance(), source.getSourceId(), game); - } - break; - default: + if (!conditionState(source, game)) { return false; } + + Permanent creature = game.getPermanent(source.getSourceId()); + if (creature == null) { return false; } + + switch (layer) { + case PTChangingEffects_7: + if (sublayer == SubLayer.ModifyPT_7c) { + creature.addPower(6); + creature.addToughness(6); } - return true; - } + break; + case AbilityAddingRemovingEffects_6: + if (sublayer == SubLayer.NA) { + creature.addAbility(FlyingAbility.getInstance(), source.getSourceId(), game); + } + break; + default: + return false; } - return false; + + return true; } - protected boolean conditionState(Ability source, Game game) { + private boolean conditionState(Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null && controller.getLife() >= 30) { - for (UUID opponentId : game.getState().getPlayersInRange(controller.getId(), game)) { - if (controller.hasOpponent(opponentId, game)) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null && opponent.getLife() < 11) { - return true; - } - } - } + if (controller == null) { return false; } + + if (controller.getLife() < 30) { return false; } + + for (UUID opponentId : game.getState().getPlayersInRange(controller.getId(), game)) { + if (!controller.hasOpponent(opponentId, game)) { return false; } + + Player opponent = game.getPlayer(opponentId); + if (opponent == null) { return false; } + + return opponent.getLife() < 11; } + return false; } @@ -109,8 +112,6 @@ class BloodBaronOfVizkopaEffect extends ContinuousEffectImpl { @Override public boolean hasLayer(Layer layer) { - return (layer == Layer.AbilityAddingRemovingEffects_6 || layer == layer.PTChangingEffects_7); - + return (layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.PTChangingEffects_7); } - } diff --git a/Mage.Sets/src/mage/cards/b/BloodClock.java b/Mage.Sets/src/mage/cards/b/BloodClock.java index 90739872eff..f17f9752d49 100644 --- a/Mage.Sets/src/mage/cards/b/BloodClock.java +++ b/Mage.Sets/src/mage/cards/b/BloodClock.java @@ -73,7 +73,7 @@ class BloodClockEffect extends OneShotEffect { } Target target = new TargetControlledPermanent(); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), player.getId(), game) + if (!target.canChoose(player.getId(), source, game) || !player.chooseTarget(outcome, target, source, game)) { return false; } diff --git a/Mage.Sets/src/mage/cards/b/BloodCurdle.java b/Mage.Sets/src/mage/cards/b/BloodCurdle.java index 9a75ba77a1e..df33509b6b5 100644 --- a/Mage.Sets/src/mage/cards/b/BloodCurdle.java +++ b/Mage.Sets/src/mage/cards/b/BloodCurdle.java @@ -66,7 +66,7 @@ class BloodCurdleEffect extends OneShotEffect { } Target target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (!player.choose(outcome, target, source.getSourceId(), game)) { + if (!player.choose(outcome, target, source, game)) { return false; } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/b/BloodLust.java b/Mage.Sets/src/mage/cards/b/BloodLust.java index e0ae6a2e613..941c4dc4f72 100644 --- a/Mage.Sets/src/mage/cards/b/BloodLust.java +++ b/Mage.Sets/src/mage/cards/b/BloodLust.java @@ -68,7 +68,7 @@ class TargetMatchesFilterCondition implements Condition { public boolean apply(Game game, Ability source) { Permanent target = game.getBattlefield().getPermanent(source.getFirstTarget()); if (target != null) { - if (filter.match(target, source.getSourceId(), source.getControllerId(), game)) { + if (filter.match(target, source.getControllerId(), source, game)) { return true; } } diff --git a/Mage.Sets/src/mage/cards/b/BloodOath.java b/Mage.Sets/src/mage/cards/b/BloodOath.java index 0893ebbd5dd..1a4756c3cf7 100644 --- a/Mage.Sets/src/mage/cards/b/BloodOath.java +++ b/Mage.Sets/src/mage/cards/b/BloodOath.java @@ -73,7 +73,7 @@ class BloodOathEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Player player = game.getPlayer(source.getControllerId()); Player opponent = game.getPlayer(source.getFirstTarget()); if (player != null && opponent != null && sourceObject != null) { diff --git a/Mage.Sets/src/mage/cards/b/BloodPrice.java b/Mage.Sets/src/mage/cards/b/BloodPrice.java index 68dde6c913b..93305849f4c 100644 --- a/Mage.Sets/src/mage/cards/b/BloodPrice.java +++ b/Mage.Sets/src/mage/cards/b/BloodPrice.java @@ -1,13 +1,11 @@ package mage.cards.b; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import java.util.UUID; @@ -20,13 +18,7 @@ public final class BloodPrice extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); // Look at the top four cards of your library. Put two of them into your hand and the rest on the bottom of your library in any order. You lose 2 life. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(2), - StaticFilters.FILTER_CARD, Zone.LIBRARY, false, - false, false, Zone.HAND, false, - false, true - ).setText("Look at at the top four cards of your library." + - "Put two of them into your hand and the rest on the bottom of your library in any order ")); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(4, 2, PutCards.HAND, PutCards.BOTTOM_ANY)); this.getSpellAbility().addEffect(new LoseLifeSourceControllerEffect(2)); } diff --git a/Mage.Sets/src/mage/cards/b/BloodSun.java b/Mage.Sets/src/mage/cards/b/BloodSun.java index 0a9e2dd853a..55bfd19f9da 100644 --- a/Mage.Sets/src/mage/cards/b/BloodSun.java +++ b/Mage.Sets/src/mage/cards/b/BloodSun.java @@ -69,7 +69,7 @@ class BloodSunEffect extends ContinuousEffectImpl { public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - for (Permanent permanent : game.getState().getBattlefield().getActivePermanents(StaticFilters.FILTER_LANDS, player.getId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getState().getBattlefield().getActivePermanents(StaticFilters.FILTER_LANDS, player.getId(), source, game)) { switch (layer) { case AbilityAddingRemovingEffects_6: List toRemove = new ArrayList<>(); diff --git a/Mage.Sets/src/mage/cards/b/BloodTribute.java b/Mage.Sets/src/mage/cards/b/BloodTribute.java index d0dee861e18..2559e50297a 100644 --- a/Mage.Sets/src/mage/cards/b/BloodTribute.java +++ b/Mage.Sets/src/mage/cards/b/BloodTribute.java @@ -7,18 +7,16 @@ import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.KickerAbility; -import mage.abilities.text.TextPartSubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.mageobject.TextPartSubtypePredicate; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetOpponent; import java.util.UUID; @@ -28,15 +26,18 @@ import java.util.UUID; */ public final class BloodTribute extends CardImpl { + private static final FilterControlledPermanent filter + = new FilterControlledPermanent(SubType.VAMPIRE, "an untapped Vampire you control"); + + static { + filter.add(TappedPredicate.UNTAPPED); + } + public BloodTribute(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}{B}"); // Kicker - Tap an untapped Vampire you control. - TextPartSubType textPartVampire = (TextPartSubType) addTextPart(new TextPartSubType(SubType.VAMPIRE)); - FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an untapped Vampire you control"); - filter.add(new TextPartSubtypePredicate(textPartVampire)); - filter.add(TappedPredicate.UNTAPPED); - this.addAbility(new KickerAbility(new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, true)))); + this.addAbility(new KickerAbility(new TapTargetCost(new TargetControlledPermanent(filter)))); // Target opponent loses half their life, rounded up. this.getSpellAbility().addEffect(new BloodTributeLoseLifeEffect()); diff --git a/Mage.Sets/src/mage/cards/b/BloodhallPriest.java b/Mage.Sets/src/mage/cards/b/BloodhallPriest.java index b25f7385704..2bd018e71a7 100644 --- a/Mage.Sets/src/mage/cards/b/BloodhallPriest.java +++ b/Mage.Sets/src/mage/cards/b/BloodhallPriest.java @@ -38,7 +38,7 @@ public final class BloodhallPriest extends CardImpl { )); // Madness {1}{B}{R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{B}{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{1}{B}{R}"))); } private BloodhallPriest(final BloodhallPriest card) { diff --git a/Mage.Sets/src/mage/cards/b/Bloodletter.java b/Mage.Sets/src/mage/cards/b/Bloodletter.java index 39e5867931d..ace3e39ce06 100644 --- a/Mage.Sets/src/mage/cards/b/Bloodletter.java +++ b/Mage.Sets/src/mage/cards/b/Bloodletter.java @@ -64,7 +64,7 @@ class BloodletterStateTriggeredAbility extends StateTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { Map initialCount = new HashMap<>(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterNonlandPermanent(), getControllerId(), getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterNonlandPermanent(), getControllerId(), this, game)) { Character initial = permanent.getName().charAt(0); initialCount.putIfAbsent(initial, 0); initialCount.put(initial, initialCount.get(initial) + 1); diff --git a/Mage.Sets/src/mage/cards/b/BloodlineShaman.java b/Mage.Sets/src/mage/cards/b/BloodlineShaman.java index 08eb1ff2a06..b561b9795a6 100644 --- a/Mage.Sets/src/mage/cards/b/BloodlineShaman.java +++ b/Mage.Sets/src/mage/cards/b/BloodlineShaman.java @@ -67,31 +67,34 @@ class BloodlineShamanEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + MageObject sourceObject = game.getObject(source.getSourceId()); + if (sourceObject == null) { return false; } + Choice typeChoice = new ChoiceCreatureType(sourceObject); - if (controller != null && sourceObject != null && controller.choose(outcome, typeChoice, game)) { - game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); - FilterCard filterSubtype = new FilterCard(); - filterSubtype.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); + if (!controller.choose(outcome, typeChoice, game)) { return false; } - // Reveal the top card of your library. - if (controller.getLibrary().hasCards()) { - Card card = controller.getLibrary().getFromTop(game); - Cards cards = new CardsImpl(card); - controller.revealCards(sourceObject.getIdName(), cards, game); + game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); + FilterCard filterSubtype = new FilterCard(); + filterSubtype.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); - if (card != null) { - // If that card is a creature card of the chosen type, put it into your hand. - if (filterSubtype.match(card, game)) { - controller.moveCards(card, Zone.HAND, source, game); - // Otherwise, put it into your graveyard. - } else { - controller.moveCards(card, Zone.GRAVEYARD, source, game); - } + // Reveal the top card of your library. + if (controller.getLibrary().hasCards()) { + Card card = controller.getLibrary().getFromTop(game); + Cards cards = new CardsImpl(card); + controller.revealCards(sourceObject.getIdName(), cards, game); + + if (card != null) { + // If that card is a creature card of the chosen type, put it into your hand. + if (filterSubtype.match(card, game)) { + controller.moveCards(card, Zone.HAND, source, game); + // Otherwise, put it into your graveyard. + } else { + controller.moveCards(card, Zone.GRAVEYARD, source, game); } } - return true; } - return false; + return true; } } diff --git a/Mage.Sets/src/mage/cards/b/BloodmadVampire.java b/Mage.Sets/src/mage/cards/b/BloodmadVampire.java index 1666d8b7b1c..39e228db340 100644 --- a/Mage.Sets/src/mage/cards/b/BloodmadVampire.java +++ b/Mage.Sets/src/mage/cards/b/BloodmadVampire.java @@ -29,7 +29,7 @@ public final class BloodmadVampire extends CardImpl { this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), false)); // Madness {1}{R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{1}{R}"))); } private BloodmadVampire(final BloodmadVampire card) { diff --git a/Mage.Sets/src/mage/cards/b/BloodriteInvoker.java b/Mage.Sets/src/mage/cards/b/BloodriteInvoker.java index d7eaa877878..78e904835cb 100644 --- a/Mage.Sets/src/mage/cards/b/BloodriteInvoker.java +++ b/Mage.Sets/src/mage/cards/b/BloodriteInvoker.java @@ -29,7 +29,7 @@ public final class BloodriteInvoker extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(1); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseLifeTargetEffect(3), new GenericManaCost(8)); - ability.addEffect(new GainLifeEffect(3)); + ability.addEffect(new GainLifeEffect(3).concatBy("and")); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BloodstokeHowler.java b/Mage.Sets/src/mage/cards/b/BloodstokeHowler.java index c699f30b94c..1ba54e6320c 100644 --- a/Mage.Sets/src/mage/cards/b/BloodstokeHowler.java +++ b/Mage.Sets/src/mage/cards/b/BloodstokeHowler.java @@ -34,7 +34,7 @@ public final class BloodstokeHowler extends CardImpl { this.toughness = new MageInt(4); // Morph {6}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{6}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{6}{R}"))); // When Bloodstoke Howler is turned face up, Beast creatures you control get +3/+0 until end of turn. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new BoostControlledEffect(3, 0, Duration.EndOfTurn, filter))); diff --git a/Mage.Sets/src/mage/cards/b/BloodthirstyBlade.java b/Mage.Sets/src/mage/cards/b/BloodthirstyBlade.java index 164776fc09f..98961f8e187 100644 --- a/Mage.Sets/src/mage/cards/b/BloodthirstyBlade.java +++ b/Mage.Sets/src/mage/cards/b/BloodthirstyBlade.java @@ -2,9 +2,10 @@ package mage.cards.b; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; -import mage.abilities.common.GoadAttachedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.combat.GoadAttachedEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -27,10 +28,12 @@ public final class BloodthirstyBlade extends CardImpl { this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +2/+0 and is goaded. - this.addAbility(new GoadAttachedAbility(new BoostEquippedEffect(2, 0))); + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 0)); + ability.addEffect(new GoadAttachedEffect()); + this.addAbility(ability); // {1}: Attach Bloodthirsty Blade to target creature an opponent controls. Active this ability only any time you could cast a sorcery. - Ability ability = new ActivateAsSorceryActivatedAbility( + ability = new ActivateAsSorceryActivatedAbility( Zone.BATTLEFIELD, new AttachEffect( Outcome.Detriment, "Attach {this} to target creature an opponent controls" diff --git a/Mage.Sets/src/mage/cards/b/BlossomPrancer.java b/Mage.Sets/src/mage/cards/b/BlossomPrancer.java new file mode 100644 index 00000000000..4cd309b21df --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BlossomPrancer.java @@ -0,0 +1,89 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.keyword.ReachAbility; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BlossomPrancer extends CardImpl { + + public BlossomPrancer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // When Blossom Prancer enters the battlefield, look at the top five cards of your library. + // You may reveal a creature or enchantment card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. + // If you didn't put a card into your hand this way, you gain 4 life. + this.addAbility(new EntersBattlefieldTriggeredAbility(new BlossomPrancerEffect())); + } + + private BlossomPrancer(final BlossomPrancer card) { + super(card); + } + + @Override + public BlossomPrancer copy() { + return new BlossomPrancer(this); + } +} + +class BlossomPrancerEffect extends LookLibraryAndPickControllerEffect { + + private static final FilterCard filter = new FilterCard("creature or enchantment card"); + + static { + filter.add(Predicates.or( + CardType.CREATURE.getPredicate(), + CardType.ENCHANTMENT.getPredicate() + )); + } + + BlossomPrancerEffect() { + super(5, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM); + } + + private BlossomPrancerEffect(final BlossomPrancerEffect effect) { + super(effect); + } + + @Override + public BlossomPrancerEffect copy() { + return new BlossomPrancerEffect(this); + } + + @Override + public boolean actionWithPickedCards(Game game, Ability source, Player player, Cards pickedCards, Cards otherCards) { + super.actionWithPickedCards(game, source, player, pickedCards, otherCards); + if (pickedCards.isEmpty()) { + player.gainLife(4, game, source); + } + return true; + } + + @Override + public String getText(Mode mode) { + return super.getText(mode).concat(". If you didn't put a card into your hand this way, you gain 4 life"); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BlueElementalBlast.java b/Mage.Sets/src/mage/cards/b/BlueElementalBlast.java index b8b48cadacb..55d1601c202 100644 --- a/Mage.Sets/src/mage/cards/b/BlueElementalBlast.java +++ b/Mage.Sets/src/mage/cards/b/BlueElementalBlast.java @@ -37,8 +37,7 @@ public final class BlueElementalBlast extends CardImpl { this.getSpellAbility().addEffect(new CounterTargetEffect()); this.getSpellAbility().addTarget(new TargetSpell(filterSpell)); - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetPermanent(filterPermanent)); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/b/BlueWard.java b/Mage.Sets/src/mage/cards/b/BlueWard.java index 3366356ce0d..8c2e631858c 100644 --- a/Mage.Sets/src/mage/cards/b/BlueWard.java +++ b/Mage.Sets/src/mage/cards/b/BlueWard.java @@ -1,36 +1,29 @@ - package mage.cards.b; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.ProtectionAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.ColorPredicate; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LoneFox */ public final class BlueWard extends CardImpl { - private static final FilterCard filter = new FilterCard("blue"); - - static { - filter.add(new ColorPredicate(ObjectColor.BLUE)); - } - public BlueWard(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -38,12 +31,11 @@ public final class BlueWard extends CardImpl { this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Protect)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // Enchanted creature has protection from blue. This effect doesn't remove Blue Ward. - ProtectionAbility gainedAbility = new ProtectionAbility(filter); - gainedAbility.setAuraIdNotToBeRemoved(this.getId()); - Effect effect = new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA); - effect.setText("Enchanted creature has protection from blue. This effect doesn't remove {this}."); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( + ProtectionAbility.from(ObjectColor.BLUE), AttachmentType.AURA + ).setDoesntRemoveItself(true))); } private BlueWard(final BlueWard card) { diff --git a/Mage.Sets/src/mage/cards/b/Blustersquall.java b/Mage.Sets/src/mage/cards/b/Blustersquall.java index 1611be826cf..7d316f63a5a 100644 --- a/Mage.Sets/src/mage/cards/b/Blustersquall.java +++ b/Mage.Sets/src/mage/cards/b/Blustersquall.java @@ -30,8 +30,7 @@ public final class Blustersquall extends CardImpl { this.getSpellAbility().addEffect(new TapTargetEffect()); // Overload {3}{U} (You may cast this spell for its overload cost. If you do, change its text by replacing all instances of "target" with "each.") - this.addAbility(new OverloadAbility(this, new BlustersqallTapAllEffect(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL), new ManaCostsImpl("{3}{U}"))); - + this.addAbility(new OverloadAbility(this, new BlustersqallTapAllEffect(), new ManaCostsImpl("{3}{U}"))); } private Blustersquall(final Blustersquall card) { @@ -46,22 +45,18 @@ public final class Blustersquall extends CardImpl { class BlustersqallTapAllEffect extends OneShotEffect { - protected FilterCreaturePermanent filter; - - BlustersqallTapAllEffect(FilterCreaturePermanent filter) { + BlustersqallTapAllEffect() { super(Outcome.Tap); - this.filter = filter; staticText = "Tap each creature you don't control"; } private BlustersqallTapAllEffect(final BlustersqallTapAllEffect effect) { super(effect); - this.filter = effect.filter; } @Override public boolean apply(Game game, Ability source) { - for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL, source.getControllerId(), source, game)) { creature.tap(source, game); } return true; diff --git a/Mage.Sets/src/mage/cards/b/BoardTheWeatherlight.java b/Mage.Sets/src/mage/cards/b/BoardTheWeatherlight.java index ebaa10ff365..f8539a32c22 100644 --- a/Mage.Sets/src/mage/cards/b/BoardTheWeatherlight.java +++ b/Mage.Sets/src/mage/cards/b/BoardTheWeatherlight.java @@ -1,12 +1,11 @@ package mage.cards.b; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.HistoricPredicate; @@ -27,10 +26,7 @@ public final class BoardTheWeatherlight extends CardImpl { // Look at the top five cards of your library. You may reveal a historic card from among them and put it into your hand. Put the rest on the bottom of your library in random order. this.getSpellAbility().addEffect( - new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), filter, - Zone.LIBRARY, false, true, false, Zone.HAND, true, false, false) - .setBackInRandomOrder(true) + new LookLibraryAndPickControllerEffect(5, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM) .setText("Look at the top five cards of your library. You may reveal a historic card from among them" + " and put it into your hand. Put the rest on the bottom of your library in a random order. " + "(Artifacts, legendaries, and Sagas are historic.)") diff --git a/Mage.Sets/src/mage/cards/b/BoardedWindow.java b/Mage.Sets/src/mage/cards/b/BoardedWindow.java index a762fc91c62..141d2dc8920 100644 --- a/Mage.Sets/src/mage/cards/b/BoardedWindow.java +++ b/Mage.Sets/src/mage/cards/b/BoardedWindow.java @@ -66,8 +66,8 @@ class BoardedWindowFilter extends FilterAttackingCreature { } @Override - public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { - if (!super.match(permanent, sourceId, playerId, game)) { + public boolean match(Permanent permanent, UUID playerId, Ability source, Game game) { + if (!super.match(permanent, playerId, source, game)) { return false; } diff --git a/Mage.Sets/src/mage/cards/b/BodyCount.java b/Mage.Sets/src/mage/cards/b/BodyCount.java new file mode 100644 index 00000000000..c095dce2569 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BodyCount.java @@ -0,0 +1,73 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.SpectacleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.Game; +import mage.watchers.common.CreaturesDiedWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BodyCount extends CardImpl { + + private static final Hint hint = new ValueHint( + "Creatures that died under your control this turn", BodyCountValue.instance + ); + + public BodyCount(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); + + // Spectacle {B} + this.addAbility(new SpectacleAbility(this, new ManaCostsImpl<>("{B}"))); + + // Draw a card for each creature that died under your control this turn. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(BodyCountValue.instance)); + this.getSpellAbility().addHint(hint); + } + + private BodyCount(final BodyCount card) { + super(card); + } + + @Override + public BodyCount copy() { + return new BodyCount(this); + } +} + +enum BodyCountValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return game.getState() + .getWatcher(CreaturesDiedWatcher.class) + .getAmountOfCreaturesDiedThisTurnByController(sourceAbility.getControllerId()); + } + + @Override + public BodyCountValue copy() { + return this; + } + + @Override + public String getMessage() { + return "creature that died under your control this turn"; + } + + @Override + public String toString() { + return "1"; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BodyDouble.java b/Mage.Sets/src/mage/cards/b/BodyDouble.java index 77684c2a4f5..0aeb944e0fe 100644 --- a/Mage.Sets/src/mage/cards/b/BodyDouble.java +++ b/Mage.Sets/src/mage/cards/b/BodyDouble.java @@ -65,8 +65,8 @@ class BodyDoubleCopyEffect extends OneShotEffect { if (player != null) { Target target = new TargetCardInGraveyard(new FilterCreatureCard("creature card in a graveyard")); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { - player.choose(outcome, target, source.getSourceId(), game); + if (target.canChoose(source.getControllerId(), source, game)) { + player.choose(outcome, target, source, game); Card copyFromCard = game.getCard(target.getFirstTarget()); if (copyFromCard != null) { CopyEffect copyEffect = new CopyEffect(Duration.Custom, copyFromCard, source.getSourceId()); diff --git a/Mage.Sets/src/mage/cards/b/BodyDropper.java b/Mage.Sets/src/mage/cards/b/BodyDropper.java new file mode 100644 index 00000000000..88ad2cf6a60 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BodyDropper.java @@ -0,0 +1,58 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SacrificePermanentTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +/** + * + * @author weirddan455 + */ +public final class BodyDropper extends CardImpl { + + public BodyDropper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{R}"); + + this.subtype.add(SubType.DEVIL); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever you sacrifice another creature, put a +1/+1 counter on Body Dropper. + this.addAbility(new SacrificePermanentTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE + )); + + // {B}{R}, Sacrifice another creature: Body Dropper gains menace until end of turn. + Ability ability = new SimpleActivatedAbility( + new GainAbilitySourceEffect(new MenaceAbility(), Duration.EndOfTurn), + new ManaCostsImpl<>("{B}{R}") + ); + ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); + this.addAbility(ability); + } + + private BodyDropper(final BodyDropper card) { + super(card); + } + + @Override + public BodyDropper copy() { + return new BodyDropper(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BodyLaunderer.java b/Mage.Sets/src/mage/cards/b/BodyLaunderer.java new file mode 100644 index 00000000000..7fe27f8bc1c --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BodyLaunderer.java @@ -0,0 +1,94 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.effects.Effects; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +/** + * @author weirddan455 + */ +public final class BodyLaunderer extends CardImpl { + + private static final FilterControlledCreaturePermanent filter + = new FilterControlledCreaturePermanent("another nontoken creature you control"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(TokenPredicate.FALSE); + } + + public BodyLaunderer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // Whenever another nontoken creature you control dies, Body Launderer connives. + this.addAbility(new DiesCreatureTriggeredAbility(new ConniveSourceEffect("{this}"), false, filter)); + + // When Body Launderer dies, return another target non-Rogue creature card with power less than or equal to Body Launderer from your graveyard to the battlefield. + Ability ability = new DiesSourceTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect() + .setText("return another target non-Rogue creature card with equal or lesser power from your graveyard to the battlefield") + ); + ability.setTargetAdjuster(BodyLaundererAdjuster.instance); + this.addAbility(ability); + } + + private BodyLaunderer(final BodyLaunderer card) { + super(card); + } + + @Override + public BodyLaunderer copy() { + return new BodyLaunderer(this); + } +} + +enum BodyLaundererAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int power = 0; + Effects effects = ability.getEffects(); + if (!effects.isEmpty()) { + Object died = effects.get(0).getValue("permanentLeftBattlefield"); + if (died instanceof Permanent) { + power = ((Permanent) died).getPower().getValue(); + } + } + FilterCreatureCard filter = new FilterCreatureCard("another target non-Rogue creature card with power less than or equal to Body Launderer from your graveyard"); + filter.add(AnotherPredicate.instance); + filter.add(Predicates.not(SubType.ROGUE.getPredicate())); + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, power + 1)); + ability.getTargets().clear(); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BodyOfKnowledge.java b/Mage.Sets/src/mage/cards/b/BodyOfKnowledge.java index b28e836ac1d..1f82d8433ad 100644 --- a/Mage.Sets/src/mage/cards/b/BodyOfKnowledge.java +++ b/Mage.Sets/src/mage/cards/b/BodyOfKnowledge.java @@ -1,18 +1,19 @@ package mage.cards.b; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealtDamageToSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.players.Player; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; import java.util.UUID; @@ -44,8 +45,7 @@ public final class BodyOfKnowledge extends CardImpl { // Whenever Body of Knowledge is dealt damage, draw that many cards. this.addAbility(new DealtDamageToSourceTriggeredAbility( - new BodyOfKnowledgeEffect(), false, false - )); + new DrawCardSourceControllerEffect(SavedDamageValue.MANY), false)); } private BodyOfKnowledge(final BodyOfKnowledge card) { @@ -57,29 +57,3 @@ public final class BodyOfKnowledge extends CardImpl { return new BodyOfKnowledge(this); } } - -class BodyOfKnowledgeEffect extends OneShotEffect { - - BodyOfKnowledgeEffect() { - super(Outcome.Benefit); - staticText = "draw that many cards"; - } - - private BodyOfKnowledgeEffect(final BodyOfKnowledgeEffect effect) { - super(effect); - } - - @Override - public BodyOfKnowledgeEffect copy() { - return new BodyOfKnowledgeEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int amount = (Integer) getValue("damage"); - Player player = game.getPlayer(source.getControllerId()); - return player != null - && amount > 0 - && player.drawCards(amount, source, game) > 0; - } -} diff --git a/Mage.Sets/src/mage/cards/b/BoggartBirthRite.java b/Mage.Sets/src/mage/cards/b/BoggartBirthRite.java index efd73cd9480..a4dfc023ee1 100644 --- a/Mage.Sets/src/mage/cards/b/BoggartBirthRite.java +++ b/Mage.Sets/src/mage/cards/b/BoggartBirthRite.java @@ -1,8 +1,6 @@ - package mage.cards.b; -import java.util.UUID; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -10,8 +8,9 @@ import mage.constants.SubType; import mage.filter.FilterCard; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Loki */ public final class BoggartBirthRite extends CardImpl { @@ -23,10 +22,10 @@ public final class BoggartBirthRite extends CardImpl { } public BoggartBirthRite(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.TRIBAL,CardType.SORCERY},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.TRIBAL, CardType.SORCERY}, "{B}"); this.subtype.add(SubType.GOBLIN); - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); } diff --git a/Mage.Sets/src/mage/cards/b/BoggartMob.java b/Mage.Sets/src/mage/cards/b/BoggartMob.java index 711f4c89f75..d7425701433 100644 --- a/Mage.Sets/src/mage/cards/b/BoggartMob.java +++ b/Mage.Sets/src/mage/cards/b/BoggartMob.java @@ -33,7 +33,7 @@ public final class BoggartMob extends CardImpl { this.toughness = new MageInt(5); // Champion a Goblin - this.addAbility(new ChampionAbility(this, SubType.GOBLIN, false)); + this.addAbility(new ChampionAbility(this, SubType.GOBLIN)); // Whenever a Goblin you control deals combat damage to a player, you may create a 1/1 black Goblin Rogue creature token. this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/b/BoggartShenanigans.java b/Mage.Sets/src/mage/cards/b/BoggartShenanigans.java index 32ac7a90116..83bf41637b6 100644 --- a/Mage.Sets/src/mage/cards/b/BoggartShenanigans.java +++ b/Mage.Sets/src/mage/cards/b/BoggartShenanigans.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; @@ -9,21 +7,22 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.common.TargetPlayerOrPlaneswalker; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class BoggartShenanigans extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another Goblin you control"); + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.GOBLIN); static { - filter.add(TargetController.YOU.getControllerPredicate()); - filter.add(SubType.GOBLIN.getPredicate()); + filter.add(AnotherPredicate.instance); } public BoggartShenanigans(UUID ownerId, CardSetInfo setInfo) { @@ -31,7 +30,9 @@ public final class BoggartShenanigans extends CardImpl { this.subtype.add(SubType.GOBLIN); // Whenever another Goblin you control dies, you may have Boggart Shenanigans deal 1 damage to target player. - Ability ability = new DiesCreatureTriggeredAbility(new DamageTargetEffect(1), true, filter, false); + Ability ability = new DiesCreatureTriggeredAbility( + new DamageTargetEffect(1), true, filter, false + ).setTriggerPhrase("Whenever another Goblin you control is put into a graveyard from the battlefield, "); ability.addTarget(new TargetPlayerOrPlaneswalker()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BojukaBrigand.java b/Mage.Sets/src/mage/cards/b/BojukaBrigand.java index 894ae198362..1769d3ea9cc 100644 --- a/Mage.Sets/src/mage/cards/b/BojukaBrigand.java +++ b/Mage.Sets/src/mage/cards/b/BojukaBrigand.java @@ -26,7 +26,7 @@ public final class BojukaBrigand extends CardImpl { this.toughness = new MageInt(1); this.addAbility(new CantBlockAbility()); - this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true)); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true).setAbilityWord(null)); } private BojukaBrigand(final BojukaBrigand card) { diff --git a/Mage.Sets/src/mage/cards/b/BondOfDiscipline.java b/Mage.Sets/src/mage/cards/b/BondOfDiscipline.java index ebc07aa9de8..a0274d07211 100644 --- a/Mage.Sets/src/mage/cards/b/BondOfDiscipline.java +++ b/Mage.Sets/src/mage/cards/b/BondOfDiscipline.java @@ -7,9 +7,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.FilterPermanent; import mage.filter.StaticFilters; -import mage.filter.common.FilterOpponentsCreaturePermanent; import java.util.UUID; @@ -18,14 +16,11 @@ import java.util.UUID; */ public final class BondOfDiscipline extends CardImpl { - private static final FilterPermanent filter - = new FilterOpponentsCreaturePermanent("creatures your opponents control"); - public BondOfDiscipline(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}"); // Tap all creatures your opponents control. Creatures you control gain lifelink until end of turn. - this.getSpellAbility().addEffect(new TapAllEffect(filter)); + this.getSpellAbility().addEffect(new TapAllEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES)); this.getSpellAbility().addEffect(new GainAbilityControlledEffect( LifelinkAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES diff --git a/Mage.Sets/src/mage/cards/b/BondOfFlourishing.java b/Mage.Sets/src/mage/cards/b/BondOfFlourishing.java index 840a0fe5767..de08f840a85 100644 --- a/Mage.Sets/src/mage/cards/b/BondOfFlourishing.java +++ b/Mage.Sets/src/mage/cards/b/BondOfFlourishing.java @@ -1,8 +1,8 @@ package mage.cards.b; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -16,17 +16,14 @@ import java.util.UUID; */ public final class BondOfFlourishing extends CardImpl { - private static final FilterCard filter = new FilterPermanentCard(); + private static final FilterCard filter = new FilterPermanentCard("a permanent card"); public BondOfFlourishing(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); // Look at the top three card of your library. You may reveal a permanent card from among them and put it into your hand. Put the rest on the bottom of your library in any order. You gain 3 life. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(3), false, - StaticValue.get(1), filter, false - )); - this.getSpellAbility().addEffect(new GainLifeEffect(3).setText("You gain 3 life.")); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(3, 1, filter, PutCards.HAND, PutCards.BOTTOM_ANY)); + this.getSpellAbility().addEffect(new GainLifeEffect(3)); } private BondOfFlourishing(final BondOfFlourishing card) { diff --git a/Mage.Sets/src/mage/cards/b/BondOfInsight.java b/Mage.Sets/src/mage/cards/b/BondOfInsight.java index 960fe72b091..e36f25f79c2 100644 --- a/Mage.Sets/src/mage/cards/b/BondOfInsight.java +++ b/Mage.Sets/src/mage/cards/b/BondOfInsight.java @@ -73,7 +73,7 @@ class BondOfInsightEffect extends OneShotEffect { TargetCard target = new TargetCardInYourGraveyard( 0, 2, StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, true ); - if (!player.choose(outcome, target, source.getSourceId(), game)) { + if (!player.choose(outcome, target, source, game)) { return false; } Cards cards = new CardsImpl(target.getTargets()); diff --git a/Mage.Sets/src/mage/cards/b/BondsOfFaith.java b/Mage.Sets/src/mage/cards/b/BondsOfFaith.java index 8a55f11cdfc..ff6b461f474 100644 --- a/Mage.Sets/src/mage/cards/b/BondsOfFaith.java +++ b/Mage.Sets/src/mage/cards/b/BondsOfFaith.java @@ -1,48 +1,55 @@ - package mage.cards.b; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.EquippedHasSubtypeCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalRestrictionEffect; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.combat.CantAttackBlockAttachedEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * @author nantuko */ public final class BondsOfFaith extends CardImpl { - private static final String rule = "Enchanted creature gets +2/+2 as long as it's a Human"; + private static final Condition condition1 = new EquippedHasSubtypeCondition(SubType.HUMAN); + private static final Condition condition2 = new InvertCondition(condition1); public BondsOfFaith(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); this.subtype.add(SubType.AURA); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Neutral)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Enchanted creature gets +2/+2 as long as it's a Human. Otherwise, it can't attack or block. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostEquippedEffect(2, 2), new EquippedHasSubtypeCondition(SubType.HUMAN), rule))); - Effect effect = new ConditionalRestrictionEffect(new CantAttackBlockAttachedEffect(AttachmentType.AURA), new InvertCondition(new EquippedHasSubtypeCondition(SubType.HUMAN))); - effect.setText("Otherwise, it can't attack or block"); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostEquippedEffect(2, 2), condition1, + "Enchanted creature gets +2/+2 as long as it's a Human" + )); + ability.addEffect(new ConditionalRestrictionEffect( + new CantAttackBlockAttachedEffect(AttachmentType.AURA), + condition2, "Otherwise, it can't attack or block" + )); + this.addAbility(ability); } private BondsOfFaith(final BondsOfFaith card) { diff --git a/Mage.Sets/src/mage/cards/b/BondsOfMortality.java b/Mage.Sets/src/mage/cards/b/BondsOfMortality.java index cb6c2b19578..c2b32b3ec0c 100644 --- a/Mage.Sets/src/mage/cards/b/BondsOfMortality.java +++ b/Mage.Sets/src/mage/cards/b/BondsOfMortality.java @@ -5,7 +5,7 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.ColoredManaCost; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.LoseAbilityAllEffect; @@ -14,10 +14,9 @@ import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; /** * @@ -25,12 +24,6 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class BondsOfMortality extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public BondsOfMortality(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{G}"); @@ -38,10 +31,12 @@ public final class BondsOfMortality extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), false)); // {G}: Creatures your opponents control lose hexproof and indestructible until end of turn. - Effect effect = new LoseAbilityAllEffect(HexproofAbility.getInstance(), Duration.EndOfTurn, filter); + Effect effect = new LoseAbilityAllEffect( + HexproofAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES); effect.setText("Creatures your opponents control lose hexproof"); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{G}")); - effect = new LoseAbilityAllEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn, filter); + Ability ability = new SimpleActivatedAbility(effect, new ColoredManaCost(ColoredManaSymbol.G)); + effect = new LoseAbilityAllEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES); effect.setText("and indestructible until end of turn"); ability.addEffect(effect); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/b/BoneDragon.java b/Mage.Sets/src/mage/cards/b/BoneDragon.java index b5a67d9c643..f356a27c55e 100644 --- a/Mage.Sets/src/mage/cards/b/BoneDragon.java +++ b/Mage.Sets/src/mage/cards/b/BoneDragon.java @@ -1,24 +1,24 @@ package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.ExileFromGraveCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; -import mage.constants.SubType; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class BoneDragon extends CardImpl { @@ -26,7 +26,7 @@ public final class BoneDragon extends CardImpl { private static final FilterCard filter = new FilterCard("other cards"); static { - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); } public BoneDragon(UUID ownerId, CardSetInfo setInfo) { @@ -44,7 +44,7 @@ public final class BoneDragon extends CardImpl { Ability ability = new SimpleActivatedAbility( Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(true), - new ManaCostsImpl("{3}{B}{B}") + new ManaCostsImpl<>("{3}{B}{B}") ); ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(7, filter))); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/b/BoneShards.java b/Mage.Sets/src/mage/cards/b/BoneShards.java index 94b45c7385e..8b79ba03d06 100644 --- a/Mage.Sets/src/mage/cards/b/BoneShards.java +++ b/Mage.Sets/src/mage/cards/b/BoneShards.java @@ -22,8 +22,8 @@ public final class BoneShards extends CardImpl { // As an additional cost to cast this spell, sacrifice a creature or discard a card. this.getSpellAbility().addCost(new OrCost( - new SacrificeTargetCost(new TargetControlledCreaturePermanent()), - new DiscardCardCost(), "sacrifice a creature or discard a card" + "sacrifice a creature or discard a card", new SacrificeTargetCost(new TargetControlledCreaturePermanent()), + new DiscardCardCost() )); // Destroy target creature or planeswalker. diff --git a/Mage.Sets/src/mage/cards/b/Boneknitter.java b/Mage.Sets/src/mage/cards/b/Boneknitter.java index edea575b885..ec9b2274ad9 100644 --- a/Mage.Sets/src/mage/cards/b/Boneknitter.java +++ b/Mage.Sets/src/mage/cards/b/Boneknitter.java @@ -40,7 +40,7 @@ public final class Boneknitter extends CardImpl { ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Morph {2}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{B}"))); } private Boneknitter(final Boneknitter card) { diff --git a/Mage.Sets/src/mage/cards/b/BonescytheSliver.java b/Mage.Sets/src/mage/cards/b/BonescytheSliver.java index d386ccdd282..fc222e32f03 100644 --- a/Mage.Sets/src/mage/cards/b/BonescytheSliver.java +++ b/Mage.Sets/src/mage/cards/b/BonescytheSliver.java @@ -30,7 +30,7 @@ public final class BonescytheSliver extends CardImpl { // Sliver creatures you control have double strike. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(DoubleStrikeAbility.getInstance(), - Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS))); + Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_SLIVERS))); } private BonescytheSliver(final BonescytheSliver card) { diff --git a/Mage.Sets/src/mage/cards/b/BonesplitterSliver.java b/Mage.Sets/src/mage/cards/b/BonesplitterSliver.java index a3b89d1af4a..70c8ec855c0 100644 --- a/Mage.Sets/src/mage/cards/b/BonesplitterSliver.java +++ b/Mage.Sets/src/mage/cards/b/BonesplitterSliver.java @@ -27,7 +27,7 @@ public final class BonesplitterSliver extends CardImpl { // All Sliver creatures get +2/+0. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new BoostAllEffect(2, 0, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, false))); + new BoostAllEffect(2, 0, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS, false))); } private BonesplitterSliver(final BonesplitterSliver card) { diff --git a/Mage.Sets/src/mage/cards/b/BoneyardParley.java b/Mage.Sets/src/mage/cards/b/BoneyardParley.java index b72c702aa0b..24ae9d6aec0 100644 --- a/Mage.Sets/src/mage/cards/b/BoneyardParley.java +++ b/Mage.Sets/src/mage/cards/b/BoneyardParley.java @@ -79,7 +79,7 @@ class BoneyardParleyEffect extends OneShotEffect { } if (!cards.isEmpty() && player.moveCards(cards, Zone.EXILED, source, game)) { TargetOpponent targetOpponent = new TargetOpponent(true); - if (player.choose(Outcome.Neutral, targetOpponent, source.getSourceId(), game)) { + if (player.choose(Outcome.Neutral, targetOpponent, source, game)) { Player opponent = game.getPlayer(targetOpponent.getFirstTarget()); if (opponent != null) { TargetCard targetCards = new TargetCard(0, cards.size(), Zone.EXILED, new FilterCard("cards to put in the first pile")); diff --git a/Mage.Sets/src/mage/cards/b/BoneyardScourge.java b/Mage.Sets/src/mage/cards/b/BoneyardScourge.java index 12aeba51068..453c598235d 100644 --- a/Mage.Sets/src/mage/cards/b/BoneyardScourge.java +++ b/Mage.Sets/src/mage/cards/b/BoneyardScourge.java @@ -64,7 +64,7 @@ public final class BoneyardScourge extends CardImpl { class DiesWhileInGraveyardTriggeredAbility extends TriggeredAbilityImpl { - protected FilterCreaturePermanent filter; + private final FilterCreaturePermanent filter; public DiesWhileInGraveyardTriggeredAbility(Effect effect, FilterCreaturePermanent filter) { super(Zone.GRAVEYARD, effect, false); @@ -89,22 +89,19 @@ class DiesWhileInGraveyardTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (!zEvent.isDiesEvent()) { return false; } + for (Zone z : Zone.values()) { if (game.getShortLivingLKI(sourceId, z) && z != Zone.GRAVEYARD) { return false; } } - if (zEvent.isDiesEvent()) { - if (filter.match(zEvent.getTarget(), sourceId, controllerId, game)) { - return true; - } - } - return false; + + return filter.match(zEvent.getTarget(), controllerId,this, game); } @Override public String getTriggerPhrase() { return "Whenever " + filter.getMessage() + " dies while {this} is in your graveyard, " ; } - } diff --git a/Mage.Sets/src/mage/cards/b/BoonOfBoseiju.java b/Mage.Sets/src/mage/cards/b/BoonOfBoseiju.java index 868f4ecc395..a7a896e7549 100644 --- a/Mage.Sets/src/mage/cards/b/BoonOfBoseiju.java +++ b/Mage.Sets/src/mage/cards/b/BoonOfBoseiju.java @@ -53,7 +53,7 @@ enum BoonOfBoseijuValue implements DynamicValue { public int calculate(Game game, Ability sourceAbility, Effect effect) { return game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_PERMANENT, - sourceAbility.getControllerId(), sourceAbility.getSourceId(), game + sourceAbility.getControllerId(), sourceAbility, game ).stream().mapToInt(MageObject::getManaValue).sum(); } diff --git a/Mage.Sets/src/mage/cards/b/BoonOfSafety.java b/Mage.Sets/src/mage/cards/b/BoonOfSafety.java new file mode 100644 index 00000000000..7ecff9bf54b --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BoonOfSafety.java @@ -0,0 +1,37 @@ +package mage.cards.b; + +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BoonOfSafety extends CardImpl { + + public BoonOfSafety(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); + + // Put a shield counter on target creature. + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.SHIELD.createInstance())); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Scry 1. + this.getSpellAbility().addEffect(new ScryEffect(1, false).concatBy("
")); + } + + private BoonOfSafety(final BoonOfSafety card) { + super(card); + } + + @Override + public BoonOfSafety copy() { + return new BoonOfSafety(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BoonweaverGiant.java b/Mage.Sets/src/mage/cards/b/BoonweaverGiant.java index 24766e3ecad..058afd270ab 100644 --- a/Mage.Sets/src/mage/cards/b/BoonweaverGiant.java +++ b/Mage.Sets/src/mage/cards/b/BoonweaverGiant.java @@ -54,7 +54,8 @@ class BoonweaverGiantEffect extends OneShotEffect { public BoonweaverGiantEffect() { super(Outcome.UnboostCreature); - this.staticText = "you may search your graveyard, hand, and/or library for an Aura card and put it onto the battlefield attached to {this}. If you search your library this way, shuffle."; + this.staticText = "you may search your graveyard, hand, and/or library for an Aura card and put it onto the battlefield attached to {this}." + + "If you search your library this way, shuffle."; } public BoonweaverGiantEffect(final BoonweaverGiantEffect effect) { @@ -69,45 +70,40 @@ class BoonweaverGiantEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } + if (controller == null) { return false; } FilterCard filter = new FilterCard("Aura card"); filter.add(CardType.ENCHANTMENT.getPredicate()); filter.add(SubType.AURA.getPredicate()); Card card = null; - Zone zone = null; + + // Choose card from graveyard if (controller.chooseUse(Outcome.Neutral, "Search your graveyard for an Aura card?", source, game)) { TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(filter); if (controller.choose(Outcome.PutCardInPlay, controller.getGraveyard(), target, game)) { card = game.getCard(target.getFirstTarget()); - if (card != null) { - zone = Zone.GRAVEYARD; - } } } + + // Choose card from your hand if (card == null && controller.chooseUse(Outcome.Neutral, "Search your Hand for an Aura card?", source, game)) { TargetCardInHand target = new TargetCardInHand(filter); if (controller.choose(Outcome.PutCardInPlay, controller.getHand(), target, game)) { card = game.getCard(target.getFirstTarget()); - if (card != null) { - zone = Zone.HAND; - } } } + + // Choose a card from your library if (card == null) { TargetCardInLibrary target = new TargetCardInLibrary(filter); if (controller.searchLibrary(target, source, game)) { card = game.getCard(target.getFirstTarget()); - if (card != null) { - zone = Zone.LIBRARY; - } } controller.shuffleLibrary(source, game); } - // aura card found - attach it + + // Aura card found - attach it if (card != null) { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/b/BootleggersStash.java b/Mage.Sets/src/mage/cards/b/BootleggersStash.java new file mode 100644 index 00000000000..5998ae4d555 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BootleggersStash.java @@ -0,0 +1,41 @@ +package mage.cards.b; + +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.StaticFilters; +import mage.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BootleggersStash extends CardImpl { + + public BootleggersStash(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}{G}"); + + // Lands you control have "{T}: Create a Treasure token." + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new SimpleActivatedAbility( + new CreateTokenEffect(new TreasureToken()), new TapSourceCost() + ), Duration.WhileOnBattlefield, StaticFilters.FILTER_LANDS + ))); + } + + private BootleggersStash(final BootleggersStash card) { + super(card); + } + + @Override + public BootleggersStash copy() { + return new BootleggersStash(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BoreasCharger.java b/Mage.Sets/src/mage/cards/b/BoreasCharger.java index 7169a5d1240..b84fa7fddae 100644 --- a/Mage.Sets/src/mage/cards/b/BoreasCharger.java +++ b/Mage.Sets/src/mage/cards/b/BoreasCharger.java @@ -92,7 +92,7 @@ class BoreasChargerEffect extends OneShotEffect { return false; } TargetPlayer target = new TargetPlayer(1, 1, true, filter); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); Player opponent = game.getPlayer(target.getFirstTarget()); if (opponent == null) { controller.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/b/BorosCharm.java b/Mage.Sets/src/mage/cards/b/BorosCharm.java index bc624d16edf..4a714829ab5 100644 --- a/Mage.Sets/src/mage/cards/b/BorosCharm.java +++ b/Mage.Sets/src/mage/cards/b/BorosCharm.java @@ -32,8 +32,7 @@ public final class BorosCharm extends CardImpl { IndestructibleAbility.getInstance(), Duration.EndOfTurn ))); //or target creature gains double strike until end of turn. - Mode mode2 = new Mode(); - mode2.addEffect(new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn)); + Mode mode2 = new Mode(new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn)); mode2.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode2); } diff --git a/Mage.Sets/src/mage/cards/b/BorosReckoner.java b/Mage.Sets/src/mage/cards/b/BorosReckoner.java index bc3a19a925c..1d20671065b 100644 --- a/Mage.Sets/src/mage/cards/b/BorosReckoner.java +++ b/Mage.Sets/src/mage/cards/b/BorosReckoner.java @@ -31,8 +31,8 @@ public final class BorosReckoner extends CardImpl { this.toughness = new MageInt(3); // Whenever Boros Reckoner is dealt damage, it deals that much damage to any target. - Ability ability = new DealtDamageToSourceTriggeredAbility(new DamageTargetEffect(SavedDamageValue.instance) - .setText("it deals that much damage to any target"), false, false); + Ability ability = new DealtDamageToSourceTriggeredAbility( + new DamageTargetEffect(SavedDamageValue.MUCH, "it"), false); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/b/BorrowedGrace.java b/Mage.Sets/src/mage/cards/b/BorrowedGrace.java index c31ecdaf35b..0aa8bc4cffb 100644 --- a/Mage.Sets/src/mage/cards/b/BorrowedGrace.java +++ b/Mage.Sets/src/mage/cards/b/BorrowedGrace.java @@ -31,8 +31,7 @@ public final class BorrowedGrace extends CardImpl { this.getSpellAbility().addEffect(new BoostControlledEffect(2, 0, Duration.EndOfTurn)); // Creatures you control get +0/+2 until end of turn. - Mode mode = new Mode(); - mode.addEffect(new BoostControlledEffect(0, 2, Duration.EndOfTurn)); + Mode mode = new Mode(new BoostControlledEffect(0, 2, Duration.EndOfTurn)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/BorrowedHostility.java b/Mage.Sets/src/mage/cards/b/BorrowedHostility.java index 18948ab3096..780b8319a26 100644 --- a/Mage.Sets/src/mage/cards/b/BorrowedHostility.java +++ b/Mage.Sets/src/mage/cards/b/BorrowedHostility.java @@ -41,10 +41,9 @@ public final class BorrowedHostility extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterBoost).withChooseHint("gets +3/+0 until end of turn")); // Target creature gains first strike until end of turn. - Mode mode = new Mode(); effect = new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn); effect.setText("Target creature gains first strike until end of turn"); - mode.addEffect(effect); + Mode mode = new Mode(effect); mode.addTarget(new TargetCreaturePermanent(filterFirstStrike).withChooseHint("gains first strike until end of turn")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/BorrowedMalevolence.java b/Mage.Sets/src/mage/cards/b/BorrowedMalevolence.java index 06af14582c2..f427b1c6db0 100644 --- a/Mage.Sets/src/mage/cards/b/BorrowedMalevolence.java +++ b/Mage.Sets/src/mage/cards/b/BorrowedMalevolence.java @@ -39,10 +39,9 @@ public final class BorrowedMalevolence extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterCreaturePlus).withChooseHint("gets +1/+1 until end of turn")); // Target creature gets -1/-1 until end of turn. - Mode mode = new Mode(); effect = new BoostTargetEffect(-1, -1, Duration.EndOfTurn); effect.setText("Target creature gets -1/-1 until end of turn"); - mode.addEffect(effect); + Mode mode = new Mode(effect); mode.addTarget(new TargetCreaturePermanent(filterCreatureMinus).withChooseHint("gets -1/-1 until end of turn")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/Borrowing100000Arrows.java b/Mage.Sets/src/mage/cards/b/Borrowing100000Arrows.java index 815623ebc9d..d2f033af6d8 100644 --- a/Mage.Sets/src/mage/cards/b/Borrowing100000Arrows.java +++ b/Mage.Sets/src/mage/cards/b/Borrowing100000Arrows.java @@ -64,7 +64,7 @@ class Borrowing100000ArrowsEffect extends OneShotEffect { FilterCreaturePermanent filter = new FilterCreaturePermanent(); filter.add(TappedPredicate.TAPPED); filter.add(new ControllerIdPredicate(opponent.getId())); - return new DrawCardSourceControllerEffect(game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game)).apply(game, source); + return new DrawCardSourceControllerEffect(game.getBattlefield().count(filter, source.getControllerId(), source, game)).apply(game, source); } return false; } diff --git a/Mage.Sets/src/mage/cards/b/BoseijuReachesSkyward.java b/Mage.Sets/src/mage/cards/b/BoseijuReachesSkyward.java index ca783adf1e1..61aa70ab4e1 100644 --- a/Mage.Sets/src/mage/cards/b/BoseijuReachesSkyward.java +++ b/Mage.Sets/src/mage/cards/b/BoseijuReachesSkyward.java @@ -12,7 +12,7 @@ import mage.constants.SagaChapter; import mage.constants.SubType; import mage.constants.SuperType; import mage.filter.FilterCard; -import mage.filter.StaticFilters; +import mage.filter.common.FilterLandCard; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInYourGraveyard; @@ -24,6 +24,7 @@ import java.util.UUID; public final class BoseijuReachesSkyward extends CardImpl { private static final FilterCard filter = new FilterCard("basic Forest cards"); + private static final FilterCard filter2 = new FilterLandCard("land card from your graveyard"); static { filter.add(SuperType.BASIC.getPredicate()); @@ -51,7 +52,7 @@ public final class BoseijuReachesSkyward extends CardImpl { sagaAbility.addChapterEffect( this, SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, new PutOnLibraryTargetEffect(true), - new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_LAND) + new TargetCardInYourGraveyard(0, 1, filter2) ); // III — Exile this Saga, then return it to the battlefield transformed under your control. diff --git a/Mage.Sets/src/mage/cards/b/BoseijuWhoEndures.java b/Mage.Sets/src/mage/cards/b/BoseijuWhoEndures.java new file mode 100644 index 00000000000..ae970ea5782 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BoseijuWhoEndures.java @@ -0,0 +1,121 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.costs.costadjusters.LegendaryCreatureCostAdjuster; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.ChannelAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterLandCard; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BoseijuWhoEndures extends CardImpl { + + private static final FilterPermanent filter + = new FilterPermanent("artifact, enchantment, or nonbasic land an opponent controls"); + + static { + filter.add(TargetController.OPPONENT.getControllerPredicate()); + filter.add(Predicates.or( + CardType.ARTIFACT.getPredicate(), + CardType.ENCHANTMENT.getPredicate(), + Predicates.and( + Predicates.not(SuperType.BASIC.getPredicate()), + CardType.LAND.getPredicate() + ) + )); + } + + public BoseijuWhoEndures(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + this.addSuperType(SuperType.LEGENDARY); + + // {T}: Add {G}. + this.addAbility(new GreenManaAbility()); + + // Channel — {1}{G}, Discard Boseiju, Who Endures: Destroy target artifact, enchantment, or nonbasic land an opponent controls. That player may search their library for a land card with a basic land type, put it onto the battlefield, then shuffle. This ability costs {1} less to activate for each legendary creature you control. + Ability ability = new ChannelAbility("{1}{G}", new BoseijuWhoEnduresEffect()); + ability.addTarget(new TargetPermanent(filter)); + ability.setCostAdjuster(LegendaryCreatureCostAdjuster.instance); + this.addAbility(ability.addHint(LegendaryCreatureCostAdjuster.getHint())); + } + + private BoseijuWhoEndures(final BoseijuWhoEndures card) { + super(card); + } + + @Override + public BoseijuWhoEndures copy() { + return new BoseijuWhoEndures(this); + } +} + +class BoseijuWhoEnduresEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterLandCard("land card with a basic land type"); + + static { + filter.add(Predicates.or( + SubType.PLAINS.getPredicate(), + SubType.ISLAND.getPredicate(), + SubType.SWAMP.getPredicate(), + SubType.MOUNTAIN.getPredicate(), + SubType.FOREST.getPredicate() + )); + } + + BoseijuWhoEnduresEffect() { + super(Outcome.Benefit); + staticText = "destroy target artifact, enchantment, or nonbasic land an opponent controls. " + + "That player may search their library for a land card with a basic land type, " + + "put it onto the battlefield, then shuffle. " + + "This ability costs {1} less to activate for each legendary creature you control"; + } + + private BoseijuWhoEnduresEffect(final BoseijuWhoEnduresEffect effect) { + super(effect); + } + + @Override + public BoseijuWhoEnduresEffect copy() { + return new BoseijuWhoEnduresEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (controller == null || permanent == null) { + return false; + } + Player player = game.getPlayer(permanent.getControllerId()); + permanent.destroy(source, game); + if (!player.chooseUse(Outcome.PutCardInPlay, "Search your library for a land card?", source, game)) { + return true; + } + TargetCardInLibrary target = new TargetCardInLibrary(filter); + player.searchLibrary(target, source, game); + Card card = player.getLibrary().getCard(target.getFirstTarget(), game); + if (card != null) { + player.moveCards(card, Zone.BATTLEFIELD, source, game); + } + player.shuffleLibrary(source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BoseijuWhoSheltersAll.java b/Mage.Sets/src/mage/cards/b/BoseijuWhoSheltersAll.java index 54d3d5ab997..d3e5160a38c 100644 --- a/Mage.Sets/src/mage/cards/b/BoseijuWhoSheltersAll.java +++ b/Mage.Sets/src/mage/cards/b/BoseijuWhoSheltersAll.java @@ -112,7 +112,7 @@ class BoseijuWhoSheltersAllCantCounterEffect extends ContinuousRuleModifyingEffe @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null) { return "This spell can't be countered because mana from " + sourceObject.getName() + " was spent to cast it."; } diff --git a/Mage.Sets/src/mage/cards/b/BosiumStrip.java b/Mage.Sets/src/mage/cards/b/BosiumStrip.java index bc0a5e4dc70..179cfaf8577 100644 --- a/Mage.Sets/src/mage/cards/b/BosiumStrip.java +++ b/Mage.Sets/src/mage/cards/b/BosiumStrip.java @@ -109,13 +109,13 @@ class BosiumStripReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Card card = (Card) game.getState().getValue("BosiumStrip"); - if (card != null) { - ((ZoneChangeEvent) event).setToZone(Zone.EXILED); - } - } - return false; + if (controller == null) { return false; } + + Card card = (Card) game.getState().getValue("BosiumStrip"); + if (card == null) { return false; } + + ((ZoneChangeEvent) event).setToZone(Zone.EXILED); + return true; } @Override @@ -126,16 +126,16 @@ class BosiumStripReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getToZone() == Zone.GRAVEYARD) { - Card card = game.getCard(event.getSourceId()); - if (card != null - && StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(card, game)) { - CastFromGraveyardWatcher watcher = game.getState().getWatcher(CastFromGraveyardWatcher.class); - return watcher != null - && watcher.spellWasCastFromGraveyard(event.getTargetId(), - game.getState().getZoneChangeCounter(event.getTargetId())); - } - } - return false; + if (zEvent.getToZone() != Zone.GRAVEYARD) { return false; } + + Card card = game.getCard(event.getSourceId()); + if (card == null) { return false; } + + if (!StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(card, game)) { return false; } + + CastFromGraveyardWatcher watcher = game.getState().getWatcher(CastFromGraveyardWatcher.class); + return watcher != null + && watcher.spellWasCastFromGraveyard(event.getTargetId(), + game.getState().getZoneChangeCounter(event.getTargetId())); } } diff --git a/Mage.Sets/src/mage/cards/b/Bossk.java b/Mage.Sets/src/mage/cards/b/Bossk.java index f4f07f8928b..cb63516b910 100644 --- a/Mage.Sets/src/mage/cards/b/Bossk.java +++ b/Mage.Sets/src/mage/cards/b/Bossk.java @@ -70,7 +70,7 @@ class BosskTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkInterveningIfClause(Game game) { - return game.getBattlefield().count(new FilterControlledLandPermanent(), getSourceId(), getControllerId(), game) > 4; + return game.getBattlefield().count(new FilterControlledLandPermanent(), getControllerId(), this, game) > 4; } @Override diff --git a/Mage.Sets/src/mage/cards/b/BosssChauffeur.java b/Mage.Sets/src/mage/cards/b/BosssChauffeur.java new file mode 100644 index 00000000000..c00536a31fb --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BosssChauffeur.java @@ -0,0 +1,72 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.AllianceAbility; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.dynamicvalue.AdditiveDynamicValue; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.CitizenGreenWhiteToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BosssChauffeur extends CardImpl { + + private static final DynamicValue xValue = new AdditiveDynamicValue( + StaticValue.get(1), + new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE) + ); + private static final Hint hint = new ValueHint( + "Other creatures you control", + new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE) + ); + private static final DynamicValue counterCount = new CountersSourceCount(CounterType.P1P1); + + public BosssChauffeur(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Boss's Chauffeur enters the battlefield with a number of +1/+1 counters on it equal to one plus the number of other creatures you control. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect( + CounterType.P1P1.createInstance(), xValue, false + ), "with a number of +1/+1 counters on it equal to " + + "one plus the number of other creatures you control").addHint(hint)); + + // Alliance — Whenever another creature enters the battlefield under your control, put a +1/+1 counter on Boss's Chauffeur. + this.addAbility(new AllianceAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()))); + + // When Boss's Chauffeur dies, create a 1/1 green and white Citizen creature token for each +1/+1 counter on it. + this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect( + new CitizenGreenWhiteToken(), counterCount + ).setText("create a 1/1 green and white Citizen creature token for each +1/+1 counter on it"))); + } + + private BosssChauffeur(final BosssChauffeur card) { + super(card); + } + + @Override + public BosssChauffeur copy() { + return new BosssChauffeur(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BotanicalPlaza.java b/Mage.Sets/src/mage/cards/b/BotanicalPlaza.java new file mode 100644 index 00000000000..3afbf283892 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BotanicalPlaza.java @@ -0,0 +1,50 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; +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.DrawCardSourceControllerEffect; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BotanicalPlaza extends CardImpl { + + public BotanicalPlaza(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Botanical Plaza enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {G} or {W}. + this.addAbility(new GreenManaAbility()); + this.addAbility(new WhiteManaAbility()); + + // {2}{G}{W}, {T}, Sacrifice Botanical Plaza: Draw a card. + Ability ability = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{2}{G}{W}") + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private BotanicalPlaza(final BotanicalPlaza card) { + super(card); + } + + @Override + public BotanicalPlaza copy() { + return new BotanicalPlaza(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BouncersBeatdown.java b/Mage.Sets/src/mage/cards/b/BouncersBeatdown.java new file mode 100644 index 00000000000..e0033956622 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BouncersBeatdown.java @@ -0,0 +1,58 @@ +package mage.cards.b; + +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceTargetsPermanentCondition; +import mage.abilities.dynamicvalue.common.GreatestPowerAmongControlledCreaturesValue; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.ExileTargetIfDiesEffect; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BouncersBeatdown extends CardImpl { + + private static final FilterPermanent filter + = new FilterPermanent("a black permanent"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + } + + private static final Condition condition = new SourceTargetsPermanentCondition(filter); + + public BouncersBeatdown(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); + + // This spell costs {2} less to cast if it targets a black permanent. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SpellCostReductionSourceEffect(2, condition).setCanWorksOnStackOnly(true) + ).setRuleAtTheTop(true)); + + // Bouncer's Beatdown deals X damage to target creature or planeswalker, where X is the greatest power among creatures you control. If that creature or planeswalker would die this turn, exile it instead. + this.getSpellAbility().addEffect(new DamageTargetEffect(GreatestPowerAmongControlledCreaturesValue.instance)); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + this.getSpellAbility().addEffect(new ExileTargetIfDiesEffect("creature or planeswalker")); + this.getSpellAbility().addHint(GreatestPowerAmongControlledCreaturesValue.getHint()); + } + + private BouncersBeatdown(final BouncersBeatdown card) { + super(card); + } + + @Override + public BouncersBeatdown copy() { + return new BouncersBeatdown(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BoundDetermined.java b/Mage.Sets/src/mage/cards/b/BoundDetermined.java index 09c349f5d76..f218090357f 100644 --- a/Mage.Sets/src/mage/cards/b/BoundDetermined.java +++ b/Mage.Sets/src/mage/cards/b/BoundDetermined.java @@ -81,7 +81,7 @@ class BoundEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { TargetControlledPermanent target = new TargetControlledPermanent(1, 1, new FilterControlledCreaturePermanent("a creature (to sacrifice)"), true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { + if (target.canChoose(controller.getId(), source, game)) { if (controller.chooseTarget(outcome, target, source, game)) { Permanent toSacrifice = game.getPermanent(target.getFirstTarget()); if (toSacrifice != null) { @@ -126,7 +126,7 @@ class DeterminedEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null) { return "This spell can't be countered (" + sourceObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/b/BountifulHarvest.java b/Mage.Sets/src/mage/cards/b/BountifulHarvest.java index 9b9a4af9a00..69370f5a64b 100644 --- a/Mage.Sets/src/mage/cards/b/BountifulHarvest.java +++ b/Mage.Sets/src/mage/cards/b/BountifulHarvest.java @@ -1,29 +1,26 @@ - - package mage.cards.b; -import java.util.UUID; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.LandsYouControlCount; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.hint.common.LandsYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterControlledLandPermanent; -import mage.filter.common.FilterControlledPermanent; + +import java.util.UUID; /** * @author Loki */ public final class BountifulHarvest extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledLandPermanent(); - public BountifulHarvest(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{G}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}"); // You gain 1 life for each land you control. - this.getSpellAbility().addEffect(new GainLifeEffect(new PermanentsOnBattlefieldCount(filter))); + this.getSpellAbility().addEffect(new GainLifeEffect(LandsYouControlCount.instance) + .setText("you gain 1 life for each land you control")); + this.getSpellAbility().addHint(LandsYouControlHint.instance); } private BountifulHarvest(final BountifulHarvest card) { @@ -34,5 +31,4 @@ public final class BountifulHarvest extends CardImpl { public BountifulHarvest copy() { return new BountifulHarvest(this); } - } diff --git a/Mage.Sets/src/mage/cards/b/BountyOfTheHunt.java b/Mage.Sets/src/mage/cards/b/BountyOfTheHunt.java index 16aeceb2d3b..6def70de482 100644 --- a/Mage.Sets/src/mage/cards/b/BountyOfTheHunt.java +++ b/Mage.Sets/src/mage/cards/b/BountyOfTheHunt.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.costs.AlternativeCostSourceAbility; import mage.abilities.costs.common.ExileFromHandCost; @@ -11,29 +9,35 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.counters.CounterType; import mage.filter.common.FilterOwnedCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCreaturePermanentAmount; +import java.util.UUID; + /** - * * @author LoneFox */ public final class BountyOfTheHunt extends CardImpl { + private static final FilterOwnedCard filter + = new FilterOwnedCard("a green card from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.GREEN)); + } + public BountyOfTheHunt(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{G}{G}"); // You may exile a green card from your hand rather than pay Bounty of the Hunt's mana cost. - FilterOwnedCard filter = new FilterOwnedCard("green card from your hand"); - filter.add(new ColorPredicate(ObjectColor.GREEN)); - filter.add(Predicates.not(new CardIdPredicate(this.getId()))); // the exile cost can never be paid with the card itself this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter)))); // Distribute three +1/+1 counters among one, two, or three target creatures. For each +1/+1 counter you put on a creature this way, remove a +1/+1 counter from that creature at the beginning of the next cleanup step. - this.getSpellAbility().addEffect(new DistributeCountersEffect(CounterType.P1P1, 3, true, "one, two, or three target creatures")); + this.getSpellAbility().addEffect(new DistributeCountersEffect( + CounterType.P1P1, 3, true, + "one, two, or three target creatures" + )); this.getSpellAbility().addTarget(new TargetCreaturePermanentAmount(3)); } diff --git a/Mage.Sets/src/mage/cards/b/BountyOfTheLuxa.java b/Mage.Sets/src/mage/cards/b/BountyOfTheLuxa.java index 29297c7beb5..6725f4af51d 100644 --- a/Mage.Sets/src/mage/cards/b/BountyOfTheLuxa.java +++ b/Mage.Sets/src/mage/cards/b/BountyOfTheLuxa.java @@ -26,9 +26,10 @@ public final class BountyOfTheLuxa extends CardImpl { public BountyOfTheLuxa(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{U}"); - //At the beginning of your precombat main phase, remove all flood counters from Bounty of the Luxa. If no counters were removed this way, put a flood counter on Bounty of the Luxa and draw a card. Otherwise, add {C}{G}{U}. + // At the beginning of your precombat main phase, remove all flood counters from Bounty of the Luxa. + // If no counters were removed this way, put a flood counter on Bounty of the Luxa and draw a card. + // Otherwise, add {C}{G}{U}. this.addAbility(new BeginningOfPreCombatMainTriggeredAbility(new BountyOfTheLuxaEffect(), TargetController.YOU, false)); - } private BountyOfTheLuxa(final BountyOfTheLuxa card) { @@ -46,7 +47,9 @@ class BountyOfTheLuxaEffect extends OneShotEffect { public BountyOfTheLuxaEffect() { super(Outcome.Benefit); - staticText = "remove all flood counters from {this}. If no counters were removed this way, put a flood counter on {this} and draw a card. Otherwise, add {C}{G}{U}"; + staticText = "remove all flood counters from {this}. " + + "If no counters were removed this way, put a flood counter on {this} and draw a card. " + + "Otherwise, add {C}{G}{U}"; } public BountyOfTheLuxaEffect(final BountyOfTheLuxaEffect effect) { @@ -65,26 +68,25 @@ class BountyOfTheLuxaEffect extends OneShotEffect { if (bountyOfLuxa != null && bountyOfLuxa.getZoneChangeCounter(game) != source.getSourceObjectZoneChangeCounter()) { bountyOfLuxa = null; } - if (controller != null) { - if (bountyOfLuxa != null - && bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD) > 0) { - bountyOfLuxa.removeCounters(CounterType.FLOOD.createInstance(bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD)), source, game); - if (bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD) == 0) { - Mana manaToAdd = new Mana(); - manaToAdd.increaseColorless(); - manaToAdd.increaseGreen(); - manaToAdd.increaseBlue(); - controller.getManaPool().addMana(manaToAdd, game, source); - } - } else { - if (bountyOfLuxa != null) { - new AddCountersSourceEffect(CounterType.FLOOD.createInstance()).apply(game, source); - } - controller.drawCards(1, source, game); + if (controller == null) { return false; } + + if (bountyOfLuxa != null + && bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD) > 0) { + bountyOfLuxa.removeCounters(CounterType.FLOOD.createInstance(bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD)), source, game); + if (bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD) == 0) { + Mana manaToAdd = new Mana(); + manaToAdd.increaseColorless(); + manaToAdd.increaseGreen(); + manaToAdd.increaseBlue(); + controller.getManaPool().addMana(manaToAdd, game, source); } - return true; + } else { + if (bountyOfLuxa != null) { + new AddCountersSourceEffect(CounterType.FLOOD.createInstance()).apply(game, source); + } + controller.drawCards(1, source, game); } - return false; + return true; } } diff --git a/Mage.Sets/src/mage/cards/b/BowOfNylea.java b/Mage.Sets/src/mage/cards/b/BowOfNylea.java index c5ad23462ea..486ad38298d 100644 --- a/Mage.Sets/src/mage/cards/b/BowOfNylea.java +++ b/Mage.Sets/src/mage/cards/b/BowOfNylea.java @@ -48,17 +48,14 @@ public final class BowOfNylea extends CardImpl { ability.addTarget(new TargetCreaturePermanent()); ability.addCost(new TapSourceCost()); // or Bow of Nylea deals 2 damage to target creature with flying; - Mode mode = new Mode(); - mode.addEffect(new DamageTargetEffect(2)); + Mode mode = new Mode(new DamageTargetEffect(2)); mode.addTarget(new TargetCreaturePermanent(filterFlying)); ability.addMode(mode); // or you gain 3 life; - mode = new Mode(); - mode.addEffect(new GainLifeEffect(3)); + mode = new Mode(new GainLifeEffect(3)); ability.addMode(mode); // or put up to four target cards from your graveyard on the bottom of your library in any order. - mode = new Mode(); - mode.addEffect(new PutOnLibraryTargetEffect(false, "put up to four target cards from your graveyard on the bottom of your library in any order")); + mode = new Mode(new PutOnLibraryTargetEffect(false, "put up to four target cards from your graveyard on the bottom of your library in any order")); mode.addTarget(new TargetCardInYourGraveyard(0, 4, StaticFilters.FILTER_CARDS_FROM_YOUR_GRAVEYARD)); ability.addMode(mode); diff --git a/Mage.Sets/src/mage/cards/b/BoxingRing.java b/Mage.Sets/src/mage/cards/b/BoxingRing.java new file mode 100644 index 00000000000..60fe7e037fc --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BoxingRing.java @@ -0,0 +1,165 @@ +package mage.cards.b; + +import mage.MageObject; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.effects.OneShotEffect; +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.WatcherScope; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.TreasureToken; +import mage.target.TargetPermanent; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BoxingRing extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature you don't control with the same mana value"); + + static { + filter.add(BoxingRingPredicate.instance); + } + + public BoxingRing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{G}"); + + // Whenever a creature enters the battlefield under your control, it fights up to one target creature you don't control with the same mana value. + Ability ability = new EntersBattlefieldControlledTriggeredAbility( + new BoxingRingFightEffect(), StaticFilters.FILTER_PERMANENT_A_CREATURE + ); + ability.addTarget(new TargetPermanent(0, 1, filter)); + this.addAbility(ability); + + // {T}: Create a Treasure token. Activate only if you control a creature that fought this turn. + this.addAbility(new ConditionalActivatedAbility( + Zone.BATTLEFIELD, new CreateTokenEffect(new TreasureToken()), + new TapSourceCost(), BoxingRingCondition.instance + ), new BoxingRingWatcher()); + } + + private BoxingRing(final BoxingRing card) { + super(card); + } + + @Override + public BoxingRing copy() { + return new BoxingRing(this); + } +} + +enum BoxingRingPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return input + .getObject() + .getManaValue() + == input + .getSource() + .getEffects() + .stream() + .map(effect -> effect.getValue("permanentEnteringBattlefield")) + .map(Permanent.class::cast) + .filter(Objects::nonNull) + .map(MageObject::getManaValue) + .findFirst() + .orElse(-1); + } +} + +class BoxingRingFightEffect extends OneShotEffect { + + BoxingRingFightEffect() { + super(Outcome.Benefit); + staticText = "it fights up to one target creature you don't control with the same mana value"; + } + + private BoxingRingFightEffect(final BoxingRingFightEffect effect) { + super(effect); + } + + @Override + public BoxingRingFightEffect copy() { + return new BoxingRingFightEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = (Permanent) getValue("permanentEnteringBattlefield"); + Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); + return permanent != null && creature != null && permanent.fight(creature, source, game); + } +} + +enum BoxingRingCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return BoxingRingWatcher.checkPlayer(source.getControllerId(), game); + } + + @Override + public String toString() { + return "you control a creature that fought this turn"; + } +} + +class BoxingRingWatcher extends Watcher { + + private final Set morSet = new HashSet<>(); + + BoxingRingWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.FIGHTED_PERMANENT) { + morSet.add(new MageObjectReference(game.getPermanent(event.getTargetId()), game)); + } + } + + @Override + public void reset() { + super.reset(); + morSet.clear(); + } + + static boolean checkPlayer(UUID playerId, Game game) { + return game + .getState() + .getWatcher(BoxingRingWatcher.class) + .morSet + .stream() + .filter(mor -> mor.zoneCounterIsCurrent(game)) + .map(MageObjectReference::getSourceId) + .map(game::getControllerId) + .anyMatch(playerId::equals); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BraceForImpact.java b/Mage.Sets/src/mage/cards/b/BraceForImpact.java index 63e33ff0552..cf43d37fb21 100644 --- a/Mage.Sets/src/mage/cards/b/BraceForImpact.java +++ b/Mage.Sets/src/mage/cards/b/BraceForImpact.java @@ -72,24 +72,23 @@ class BraceForImpactPreventDamageTargetEffect extends PreventionEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { GameEvent preventEvent = new PreventDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), event.getAmount(), ((DamageEvent) event).isCombatDamage()); - if (!game.replaceEvent(preventEvent)) { - int prevented = 0; - int damage = event.getAmount(); - event.setAmount(0); - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage)); - prevented = damage; + if (game.replaceEvent(preventEvent)) { return false; } + int prevented; + int damage = event.getAmount(); + event.setAmount(0); + game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage)); + prevented = damage; - // add counters now - if (prevented > 0) { - Permanent targetPermanent = game.getPermanent(source.getTargets().getFirstTarget()); - if (targetPermanent != null) { - targetPermanent.addCounters(CounterType.P1P1.createInstance(prevented), source.getControllerId(), source, game); - game.informPlayers("Brace for Impact: Prevented " + prevented + " damage "); - game.informPlayers("Brace for Impact: Adding " + prevented + " +1/+1 counters to " + targetPermanent.getName()); - } + // add counters now + if (prevented > 0) { + Permanent targetPermanent = game.getPermanent(source.getTargets().getFirstTarget()); + if (targetPermanent != null) { + targetPermanent.addCounters(CounterType.P1P1.createInstance(prevented), source.getControllerId(), source, game); + game.informPlayers("Brace for Impact: Prevented " + prevented + " damage "); + game.informPlayers("Brace for Impact: Adding " + prevented + " +1/+1 counters to " + targetPermanent.getName()); } } - return false; + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/b/BrackwaterElemental.java b/Mage.Sets/src/mage/cards/b/BrackwaterElemental.java index 99c585ef54f..4b1b1dc4b98 100644 --- a/Mage.Sets/src/mage/cards/b/BrackwaterElemental.java +++ b/Mage.Sets/src/mage/cards/b/BrackwaterElemental.java @@ -1,41 +1,38 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.AttacksOrBlocksTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.keyword.UnearthAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class BrackwaterElemental extends CardImpl { public BrackwaterElemental(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.ELEMENTAL); this.power = new MageInt(4); this.toughness = new MageInt(4); // When Brackwater Elemental attacks or blocks, sacrifice it at the beginning of the next end step. - this.addAbility(new AttacksOrBlocksTriggeredAbility(new BrackwaterElementalSacrificeEffect(), false)); + this.addAbility(new AttacksOrBlocksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new SacrificeSourceEffect()) + ).setText("sacrifice it at the beginning of the next end step"), false).setTriggerPhrase("When {this} attacks or blocks, ")); + // Unearth {2}{U} - this.addAbility(new UnearthAbility(new ManaCostsImpl("{2}{U}"))); + this.addAbility(new UnearthAbility(new ManaCostsImpl<>("{2}{U}"))); } private BrackwaterElemental(final BrackwaterElemental card) { @@ -47,31 +44,3 @@ public final class BrackwaterElemental extends CardImpl { return new BrackwaterElemental(this); } } - -class BrackwaterElementalSacrificeEffect extends OneShotEffect { - - public BrackwaterElementalSacrificeEffect() { - super(Outcome.Sacrifice); - this.staticText = "sacrifice it at the beginning of the next end step"; - } - - public BrackwaterElementalSacrificeEffect(final BrackwaterElementalSacrificeEffect effect) { - super(effect); - } - - @Override - public BrackwaterElementalSacrificeEffect copy() { - return new BrackwaterElementalSacrificeEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (sourcePermanent != null) { - SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice {this}"); - sacrificeEffect.setTargetPointer(new FixedTarget(sourcePermanent.getId(), game)); - game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect), source); - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/b/BrainGorgers.java b/Mage.Sets/src/mage/cards/b/BrainGorgers.java index 35ba29de4ff..0f9842996af 100644 --- a/Mage.Sets/src/mage/cards/b/BrainGorgers.java +++ b/Mage.Sets/src/mage/cards/b/BrainGorgers.java @@ -37,7 +37,7 @@ public final class BrainGorgers extends CardImpl { this.addAbility(new CastSourceTriggeredAbility(new BrainGorgersCounterSourceEffect())); // Madness {1}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{1}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{1}{B}"))); } private BrainGorgers(final BrainGorgers card) { diff --git a/Mage.Sets/src/mage/cards/b/BrainInAJar.java b/Mage.Sets/src/mage/cards/b/BrainInAJar.java index f2362fcefd7..c383abea1fa 100644 --- a/Mage.Sets/src/mage/cards/b/BrainInAJar.java +++ b/Mage.Sets/src/mage/cards/b/BrainInAJar.java @@ -1,7 +1,5 @@ package mage.cards.b; -import java.util.UUID; -import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.RemoveVariableCountersSourceCost; @@ -10,13 +8,11 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.dynamicvalue.common.RemovedCountersForCostValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.Outcome; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.common.FilterInstantOrSorceryCard; @@ -24,10 +20,11 @@ import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCardInHand; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class BrainInAJar extends CardImpl { @@ -39,20 +36,17 @@ public final class BrainInAJar extends CardImpl { // cast an instant or sorcery card with converted mana costs equal // to the number of charge counters on Brain in a Jar from your // hand without paying its mana cost. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), - new GenericManaCost(1)); + Ability ability = new SimpleActivatedAbility( + new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), new GenericManaCost(1) + ); ability.addEffect(new BrainInAJarCastEffect()); ability.addCost(new TapSourceCost()); this.addAbility(ability); // {3}, {T}, Remove X charge counters from Brain in a Jar: Scry X. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new BrainInAJarScryEffect(), - new GenericManaCost(3)); + ability = new SimpleActivatedAbility(new BrainInAJarScryEffect(), new GenericManaCost(3)); ability.addCost(new TapSourceCost()); - ability.addCost(new RemoveVariableCountersSourceCost( - CounterType.CHARGE.createInstance())); + ability.addCost(new RemoveVariableCountersSourceCost(CounterType.CHARGE.createInstance())); this.addAbility(ability); } @@ -87,32 +81,14 @@ class BrainInAJarCastEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (controller != null - && sourceObject != null) { - int counters = sourceObject.getCounters(game).getCount(CounterType.CHARGE); - FilterCard filter = new FilterInstantOrSorceryCard(); - filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, counters)); - int cardsToCast = controller.getHand().count(filter, source.getControllerId(), - source.getSourceId(), game); - if (cardsToCast > 0 - && controller.chooseUse(Outcome.PlayForFree, - "Cast an instant or sorcery card with mana values of " - + counters + " from your hand without paying its mana cost?", - source, game)) { - TargetCardInHand target = new TargetCardInHand(filter); - controller.chooseTarget(outcome, target, source, game); - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - } - } - return true; + Permanent sourceObject = source.getSourcePermanentOrLKI(game); + if (controller == null || sourceObject == null) { + return false; } - return false; + int counters = sourceObject.getCounters(game).getCount(CounterType.CHARGE); + FilterCard filter = new FilterInstantOrSorceryCard(); + filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, counters)); + return CardUtil.castSpellWithAttributesForFree(controller, source, game, controller.getHand(), filter); } } diff --git a/Mage.Sets/src/mage/cards/b/BrainPry.java b/Mage.Sets/src/mage/cards/b/BrainPry.java index cc8eb1e4bdd..1d1e4475fa8 100644 --- a/Mage.Sets/src/mage/cards/b/BrainPry.java +++ b/Mage.Sets/src/mage/cards/b/BrainPry.java @@ -55,7 +55,7 @@ class BrainPryEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); if (targetPlayer != null && controller != null && sourceObject != null && cardName != null) { boolean hasDiscarded = false; diff --git a/Mage.Sets/src/mage/cards/b/BrambleCreeper.java b/Mage.Sets/src/mage/cards/b/BrambleCreeper.java index 1a83109712b..d73292b1387 100644 --- a/Mage.Sets/src/mage/cards/b/BrambleCreeper.java +++ b/Mage.Sets/src/mage/cards/b/BrambleCreeper.java @@ -24,7 +24,7 @@ public final class BrambleCreeper extends CardImpl { this.power = new MageInt(0); this.toughness = new MageInt(3); // Whenever Bramble Creeper attacks, it gets +5/+0 until end of turn. - this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(5, 0, Duration.EndOfTurn), false)); + this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(5, 0, Duration.EndOfTurn).setText("it gets +5/+0 until end of turn"), false)); } private BrambleCreeper(final BrambleCreeper card) { diff --git a/Mage.Sets/src/mage/cards/b/Bramblesnap.java b/Mage.Sets/src/mage/cards/b/Bramblesnap.java index 94ce24eab1d..a9a4a40b2b4 100644 --- a/Mage.Sets/src/mage/cards/b/Bramblesnap.java +++ b/Mage.Sets/src/mage/cards/b/Bramblesnap.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapTargetCost; @@ -13,16 +11,27 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; /** - * * @author North */ public final class Bramblesnap extends CardImpl { + private static final FilterControlledPermanent filter + = new FilterControlledCreaturePermanent("untapped creature you control"); + + static { + filter.add(TappedPredicate.UNTAPPED); + } + public Bramblesnap(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(1); @@ -31,7 +40,7 @@ public final class Bramblesnap extends CardImpl { this.addAbility(TrampleAbility.getInstance()); this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 1, Duration.EndOfTurn), - new TapTargetCost(new TargetControlledCreaturePermanent()))); + new TapTargetCost(new TargetControlledPermanent(filter)))); } private Bramblesnap(final Bramblesnap card) { diff --git a/Mage.Sets/src/mage/cards/b/BranchingBolt.java b/Mage.Sets/src/mage/cards/b/BranchingBolt.java index f1a9e0dac28..3c6497eae72 100644 --- a/Mage.Sets/src/mage/cards/b/BranchingBolt.java +++ b/Mage.Sets/src/mage/cards/b/BranchingBolt.java @@ -41,8 +41,7 @@ public final class BranchingBolt extends CardImpl { this.getSpellAbility().addEffect(new DamageTargetEffect(3)); this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterFlying).withChooseHint("deals 3 damage, without flying")); // or Branching Bolt deals 3 damage to target creature without flying. - Mode mode = new Mode(); - mode.addEffect(new DamageTargetEffect(3)); + Mode mode = new Mode(new DamageTargetEffect(3)); mode.addTarget(new TargetCreaturePermanent(filterNotFlying).withChooseHint("deals 3 damage, without flying")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/BranchsnapLorian.java b/Mage.Sets/src/mage/cards/b/BranchsnapLorian.java index 08a23e8dc2f..35a0ffef142 100644 --- a/Mage.Sets/src/mage/cards/b/BranchsnapLorian.java +++ b/Mage.Sets/src/mage/cards/b/BranchsnapLorian.java @@ -26,7 +26,7 @@ public final class BranchsnapLorian extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); // Morph {G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{G}"))); } private BranchsnapLorian(final BranchsnapLorian card) { diff --git a/Mage.Sets/src/mage/cards/b/BrandOfIllOmen.java b/Mage.Sets/src/mage/cards/b/BrandOfIllOmen.java index 7cfb2e6c03e..a676d10bcce 100644 --- a/Mage.Sets/src/mage/cards/b/BrandOfIllOmen.java +++ b/Mage.Sets/src/mage/cards/b/BrandOfIllOmen.java @@ -78,7 +78,7 @@ class BrandOfIllOmenEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast creature spells (" + mageObject.getLogName() + " on the battlefield)."; } diff --git a/Mage.Sets/src/mage/cards/b/BrashTaunter.java b/Mage.Sets/src/mage/cards/b/BrashTaunter.java index ca83be0f181..56703a2d804 100644 --- a/Mage.Sets/src/mage/cards/b/BrashTaunter.java +++ b/Mage.Sets/src/mage/cards/b/BrashTaunter.java @@ -6,20 +6,17 @@ import mage.abilities.common.DealtDamageToSourceTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.FightTargetSourceEffect; import mage.abilities.keyword.IndestructibleAbility; 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.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.game.Game; -import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetOpponent; @@ -48,15 +45,15 @@ public final class BrashTaunter extends CardImpl { this.addAbility(IndestructibleAbility.getInstance()); // Whenever Brash Taunter is dealt damage, it deals that much damage to target opponent. - Ability ability = new DealtDamageToSourceTriggeredAbility(new BrashTaunterEffect(), false, false); + Ability ability = new DealtDamageToSourceTriggeredAbility(new DamageTargetEffect(SavedDamageValue.MUCH, "it"), false); ability.addTarget(new TargetOpponent()); this.addAbility(ability); // {2}{R}, {T}: Brash Taunter fights another target creature. - Ability ability1 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new FightTargetSourceEffect(), new ManaCostsImpl("{2}{R}")); - ability1.addCost(new TapSourceCost()); - ability1.addTarget(new TargetPermanent(filter)); - this.addAbility(ability1); + ability = new SimpleActivatedAbility(new FightTargetSourceEffect(), new ManaCostsImpl("{2}{R}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); } private BrashTaunter(final BrashTaunter card) { @@ -68,33 +65,3 @@ public final class BrashTaunter extends CardImpl { return new BrashTaunter(this); } } - -class BrashTaunterEffect extends OneShotEffect { - - public BrashTaunterEffect() { - super(Outcome.Damage); - this.staticText = "it deals that much damage to target opponent"; - } - - public BrashTaunterEffect(final BrashTaunterEffect effect) { - super(effect); - } - - @Override - public BrashTaunterEffect copy() { - return new BrashTaunterEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int amount = (Integer) getValue("damage"); - if (amount > 0) { - Player player = game.getPlayer(targetPointer.getFirst(game, source)); - if (player != null) { - player.damage(amount, source.getSourceId(), source, game); - return true; - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/b/BrassKnuckles.java b/Mage.Sets/src/mage/cards/b/BrassKnuckles.java new file mode 100644 index 00000000000..9e6dbc2839e --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BrassKnuckles.java @@ -0,0 +1,81 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.CastSourceTriggeredAbility; +import mage.abilities.effects.common.CopySourceSpellEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.Collection; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; +import java.util.stream.Stream; + +/** + * @author TheElk801 + */ +public final class BrassKnuckles extends CardImpl { + + public BrassKnuckles(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + + this.subtype.add(SubType.EQUIPMENT); + + // When you cast this spell, copy it. + this.addAbility(new CastSourceTriggeredAbility(new CopySourceSpellEffect().setText("copy it"))); + + // Equipped creature has double strike as long as two or more Equipment are attached to it. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilityAttachedEffect( + DoubleStrikeAbility.getInstance(), AttachmentType.EQUIPMENT + ), BrassKnucklesCondition.instance, "equipped creature has double strike " + + "as long as two or more Equipment are attached to it" + ))); + + // Equip {1} + this.addAbility(new EquipAbility(1)); + } + + private BrassKnuckles(final BrassKnuckles card) { + super(card); + } + + @Override + public BrassKnuckles copy() { + return new BrassKnuckles(this); + } +} + +enum BrassKnucklesCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return Optional + .of(source.getSourcePermanentIfItStillExists(game)) + .filter(Objects::nonNull) + .map(Permanent::getAttachedTo) + .map(game::getPermanent) + .filter(Objects::nonNull) + .map(Permanent::getAttachments) + .map(Collection::stream) + .map(stream -> stream.map(game::getPermanent)) + .map(stream -> stream.filter(Objects::nonNull)) + .map(stream -> stream.filter(p -> p.hasSubtype(SubType.EQUIPMENT, game))) + .map(Stream::count) + .map(x -> x >= 2) + .orElse(false); + } +} diff --git a/Mage.Sets/src/mage/cards/b/Bravado.java b/Mage.Sets/src/mage/cards/b/Bravado.java index 60493c8cce2..0f96ef39fe5 100644 --- a/Mage.Sets/src/mage/cards/b/Bravado.java +++ b/Mage.Sets/src/mage/cards/b/Bravado.java @@ -68,7 +68,7 @@ class BravadoBoostEnchantedEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - int count = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) - 1; + int count = game.getBattlefield().count(filter, source.getControllerId(), source, game) - 1; if (count > 0) { Permanent enchantment = game.getPermanent(source.getSourceId()); if (enchantment != null && enchantment.getAttachedTo() != null) { diff --git a/Mage.Sets/src/mage/cards/b/BrawlersPlate.java b/Mage.Sets/src/mage/cards/b/BrawlersPlate.java index a951d96bea2..1e65814a8ff 100644 --- a/Mage.Sets/src/mage/cards/b/BrawlersPlate.java +++ b/Mage.Sets/src/mage/cards/b/BrawlersPlate.java @@ -4,7 +4,7 @@ package mage.cards.b; import java.util.UUID; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.Effect; +import mage.abilities.Ability; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EquipAbility; @@ -23,14 +23,10 @@ public final class BrawlersPlate extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); this.subtype.add(SubType.EQUIPMENT); - // Equipped creature gets +2/+2 - Effect effect = new BoostEquippedEffect(2, 2); - effect.setText("Equipped creature gets +2/+2"); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); - // and has trample. - effect = new GainAbilityAttachedEffect(TrampleAbility.getInstance(), AttachmentType.EQUIPMENT); - effect.setText("and has trample"); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + // Equipped creature gets +2/+2 and has trample + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 2)); + ability.addEffect(new GainAbilityAttachedEffect(TrampleAbility.getInstance(), AttachmentType.EQUIPMENT).setText("and has trample")); + this.addAbility(ability); // Equip {4} this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(4))); diff --git a/Mage.Sets/src/mage/cards/b/BrazenUpstart.java b/Mage.Sets/src/mage/cards/b/BrazenUpstart.java new file mode 100644 index 00000000000..2d6b63d5b15 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BrazenUpstart.java @@ -0,0 +1,45 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BrazenUpstart extends CardImpl { + + public BrazenUpstart(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{G}{W}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // When Brazen Upstart dies, look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. + this.addAbility(new DiesSourceTriggeredAbility(new LookLibraryAndPickControllerEffect( + 5, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_RANDOM))); + } + + private BrazenUpstart(final BrazenUpstart card) { + super(card); + } + + @Override + public BrazenUpstart copy() { + return new BrazenUpstart(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BreachingLeviathan.java b/Mage.Sets/src/mage/cards/b/BreachingLeviathan.java index 771bcb9febc..9a42d85e5de 100644 --- a/Mage.Sets/src/mage/cards/b/BreachingLeviathan.java +++ b/Mage.Sets/src/mage/cards/b/BreachingLeviathan.java @@ -82,7 +82,7 @@ class BreachingLeviathanEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { List doNotUntapNextUntapStep = new ArrayList<>(); - for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { creature.tap(source, game); doNotUntapNextUntapStep.add(creature); } diff --git a/Mage.Sets/src/mage/cards/b/BreakingEntering.java b/Mage.Sets/src/mage/cards/b/BreakingEntering.java index 6911b38c1d1..2cca2af2e2f 100644 --- a/Mage.Sets/src/mage/cards/b/BreakingEntering.java +++ b/Mage.Sets/src/mage/cards/b/BreakingEntering.java @@ -71,7 +71,7 @@ class EnteringReturnFromGraveyardToBattlefieldEffect extends OneShotEffect { if (controller != null) { Target target = new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + if (target.canChoose(source.getControllerId(), source, game) && controller.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/b/BreakingPoint.java b/Mage.Sets/src/mage/cards/b/BreakingPoint.java index 717cd509807..29efe1f3e33 100644 --- a/Mage.Sets/src/mage/cards/b/BreakingPoint.java +++ b/Mage.Sets/src/mage/cards/b/BreakingPoint.java @@ -78,7 +78,7 @@ class BreakingPointDestroyEffect extends OneShotEffect { } } if (destroyCreatures) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(FILTER_PERMANENT_CREATURES, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(FILTER_PERMANENT_CREATURES, source.getControllerId(), source, game)) { permanent.destroy(source, game, true); } } diff --git a/Mage.Sets/src/mage/cards/b/BreakingWave.java b/Mage.Sets/src/mage/cards/b/BreakingWave.java index f66663ea5b1..bb1e3aaae88 100644 --- a/Mage.Sets/src/mage/cards/b/BreakingWave.java +++ b/Mage.Sets/src/mage/cards/b/BreakingWave.java @@ -64,7 +64,7 @@ class BreakingWaveEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { List creatures = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, - source.getControllerId(), source.getSourceId(), game); + source.getControllerId(), source, game); for (Permanent creature : creatures) { if (creature.isTapped()) { creature.untap(game); diff --git a/Mage.Sets/src/mage/cards/b/Breakthrough.java b/Mage.Sets/src/mage/cards/b/Breakthrough.java index 09806be9f12..62bc8b18ae6 100644 --- a/Mage.Sets/src/mage/cards/b/Breakthrough.java +++ b/Mage.Sets/src/mage/cards/b/Breakthrough.java @@ -68,7 +68,7 @@ class BreakthroughEffect extends OneShotEffect { } else if (amountToKeep < player.getHand().size()) { TargetCardInHand target = new TargetCardInHand(amountToKeep, new FilterCard()); target.setTargetName("cards to keep"); - target.choose(Outcome.Benefit, player.getId(), source.getSourceId(), game); + target.choose(Outcome.Benefit, player.getId(), source.getSourceId(), source, game); Cards cards = player.getHand().copy(); cards.removeIf(target.getTargets()::contains); player.discard(cards, false, source, game); diff --git a/Mage.Sets/src/mage/cards/b/BreathOfFury.java b/Mage.Sets/src/mage/cards/b/BreathOfFury.java index cf437b32809..061eb9e8382 100644 --- a/Mage.Sets/src/mage/cards/b/BreathOfFury.java +++ b/Mage.Sets/src/mage/cards/b/BreathOfFury.java @@ -16,7 +16,6 @@ import mage.filter.predicate.permanent.CanBeEnchantedByPredicate; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.game.turn.TurnMod; import mage.players.Player; @@ -130,8 +129,8 @@ class BreathOfFuryEffect extends OneShotEffect { // Commanders going to the command zone and Rest in Peace style replacement effects don't make Permanent.sacrifice return false. if (enchantedCreature != null && controller != null && enchantedCreature.sacrifice(source, game) - && target.canChoose(source.getSourceId(), controller.getId(), game)) { - controller.choose(outcome, target, source.getSourceId(), game); + && target.canChoose(controller.getId(), source, game)) { + controller.choose(outcome, target, source, game); Permanent newCreature = game.getPermanent(target.getFirstTarget()); boolean success = false; if (newCreature != null) { diff --git a/Mage.Sets/src/mage/cards/b/BreenaTheDemagogue.java b/Mage.Sets/src/mage/cards/b/BreenaTheDemagogue.java index 6f3192bfd0c..5849e71eafd 100644 --- a/Mage.Sets/src/mage/cards/b/BreenaTheDemagogue.java +++ b/Mage.Sets/src/mage/cards/b/BreenaTheDemagogue.java @@ -125,13 +125,13 @@ class BreenaTheDemagogueEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player == null || game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getSourceId(), source.getControllerId(), game + source.getControllerId(), source, game ) < 1) { return false; } TargetPermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); return permanent != null && permanent.addCounters( CounterType.P1P1.createInstance(2), diff --git a/Mage.Sets/src/mage/cards/b/BreyaEtheriumShaper.java b/Mage.Sets/src/mage/cards/b/BreyaEtheriumShaper.java index ea67f1cd8d5..664cdd4b20d 100644 --- a/Mage.Sets/src/mage/cards/b/BreyaEtheriumShaper.java +++ b/Mage.Sets/src/mage/cards/b/BreyaEtheriumShaper.java @@ -49,14 +49,12 @@ public final class BreyaEtheriumShaper extends CardImpl { ability.addTarget(new TargetPlayerOrPlaneswalker()); // Target creature gets -4/-4 until end of turn. - Mode mode = new Mode(); - mode.addEffect(new BoostTargetEffect(-4, -4, Duration.EndOfTurn)); + Mode mode = new Mode(new BoostTargetEffect(-4, -4, Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); ability.addMode(mode); // or You gain 5 life. - mode = new Mode(); - mode.addEffect(new GainLifeEffect(5)); + mode = new Mode(new GainLifeEffect(5)); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BreyasApprentice.java b/Mage.Sets/src/mage/cards/b/BreyasApprentice.java index 9110c2b6648..bc062ac069f 100644 --- a/Mage.Sets/src/mage/cards/b/BreyasApprentice.java +++ b/Mage.Sets/src/mage/cards/b/BreyasApprentice.java @@ -85,7 +85,7 @@ class BreyasApprenticeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/b/BriarberryCohort.java b/Mage.Sets/src/mage/cards/b/BriarberryCohort.java index 135b78470e5..edbe30cab86 100644 --- a/Mage.Sets/src/mage/cards/b/BriarberryCohort.java +++ b/Mage.Sets/src/mage/cards/b/BriarberryCohort.java @@ -35,7 +35,7 @@ public final class BriarberryCohort extends CardImpl { filter.add(AnotherPredicate.instance); } - private String rule = "{this} gets +1/+1 as long as you control another blue creature"; + private static final String rule = "{this} gets +1/+1 as long as you control another blue creature"; public BriarberryCohort(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); diff --git a/Mage.Sets/src/mage/cards/b/BribeTaker.java b/Mage.Sets/src/mage/cards/b/BribeTaker.java new file mode 100644 index 00000000000..7538ac2afa5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BribeTaker.java @@ -0,0 +1,116 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class BribeTaker extends CardImpl { + + public BribeTaker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}"); + + this.subtype.add(SubType.RHINO); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When Bribe Taker enters the battlefield, for each kind of counter on permanents you control, you may put your choice of a +1/+1 counter or a counter of that kind on Bribe Taker. + this.addAbility(new EntersBattlefieldTriggeredAbility(new BribeTakerEffect())); + } + + private BribeTaker(final BribeTaker card) { + super(card); + } + + @Override + public BribeTaker copy() { + return new BribeTaker(this); + } +} + +class BribeTakerEffect extends OneShotEffect { + + private static final String plusName = CounterType.P1P1.getName(); + + BribeTakerEffect() { + super(Outcome.Benefit); + staticText = "for each kind of counter on permanents you control, " + + "you may put your choice of a +1/+1 counter or a counter of that kind on {this}"; + } + + private BribeTakerEffect(final BribeTakerEffect effect) { + super(effect); + } + + @Override + public BribeTakerEffect copy() { + return new BribeTakerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (player == null || permanent == null) { + return false; + } + Set counterTypes = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, + source.getControllerId(), source, game + ).stream() + .map(p -> p.getCounters(game)) + .map(HashMap::keySet) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + if (counterTypes.contains(plusName)) { + if (player.chooseUse(outcome, "Put a " + plusName + + " counter on " + permanent.getName() + '?', source, game)) { + permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + } + counterTypes.remove(plusName); + } + if (counterTypes.isEmpty()) { + return true; + } + for (String cType : counterTypes) { + if (!player.chooseUse( + outcome, "Put a " + cType + " counter or " + plusName + + " counter on " + permanent.getName() + '?', source, game + )) { + continue; + } + CounterType counterType = player.chooseUse( + outcome, "Choose " + cType + " counter or " + plusName + + " counter", null, cType, plusName, source, game + ) ? CounterType.findByName(cType) : CounterType.P1P1; + permanent.addCounters(counterType.createInstance(), source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BridgeFromBelow.java b/Mage.Sets/src/mage/cards/b/BridgeFromBelow.java index 7ec702193ba..aa737a43cc6 100644 --- a/Mage.Sets/src/mage/cards/b/BridgeFromBelow.java +++ b/Mage.Sets/src/mage/cards/b/BridgeFromBelow.java @@ -57,7 +57,7 @@ public final class BridgeFromBelow extends CardImpl { class BridgeFromBelowAbility extends TriggeredAbilityImpl { - protected FilterCreaturePermanent filter; + private final FilterCreaturePermanent filter; public BridgeFromBelowAbility(Effect effect, FilterCreaturePermanent filter) { super(Zone.GRAVEYARD, effect, false); @@ -82,14 +82,12 @@ class BridgeFromBelowAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.isDiesEvent()) { - Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); - if (permanent != null - && filter.match(permanent, sourceId, controllerId, game)) { - return true; - } - } - return false; + if (!zEvent.isDiesEvent()) { return false; } + + Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); + if (permanent == null) { return false; } + + return filter.match(permanent, controllerId, this, game); } @Override diff --git a/Mage.Sets/src/mage/cards/b/Brightflame.java b/Mage.Sets/src/mage/cards/b/Brightflame.java index cdb83cbc2f2..1b6a3054074 100644 --- a/Mage.Sets/src/mage/cards/b/Brightflame.java +++ b/Mage.Sets/src/mage/cards/b/Brightflame.java @@ -64,24 +64,24 @@ class BrightflameEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent target = game.getPermanent(targetPointer.getFirst(game, source)); int damageDealt = 0; - if (target != null) { - ObjectColor color = target.getColor(game); - damageDealt += target.damage(amount.calculate(game, source, this), source.getSourceId(), source, game); - for (Permanent p : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { - if (!target.getId().equals(p.getId()) && p.getColor(game).shares(color)) { - damageDealt += p.damage(amount.calculate(game, source, this), source.getSourceId(), source, game, false, true); - } - } - Player you = game.getPlayer(source.getControllerId()); - if (you != null && damageDealt > 0) { - you.gainLife(damageDealt, game, source); + Permanent target = game.getPermanent(targetPointer.getFirst(game, source)); + if (target == null) { return false; } + + ObjectColor color = target.getColor(game); + damageDealt += target.damage(amount.calculate(game, source, this), source.getSourceId(), source, game); + for (Permanent p : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { + if (!target.getId().equals(p.getId()) && p.getColor(game).shares(color)) { + damageDealt += p.damage(amount.calculate(game, source, this), source.getSourceId(), source, game, false, true); } - return true; } - return false; + + Player you = game.getPlayer(source.getControllerId()); + if (you != null && damageDealt > 0) { + you.gainLife(damageDealt, game, source); + } + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/b/BrightwoodTracker.java b/Mage.Sets/src/mage/cards/b/BrightwoodTracker.java index 8f84a876eca..489ccb31177 100644 --- a/Mage.Sets/src/mage/cards/b/BrightwoodTracker.java +++ b/Mage.Sets/src/mage/cards/b/BrightwoodTracker.java @@ -6,11 +6,11 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import java.util.UUID; @@ -28,11 +28,11 @@ public final class BrightwoodTracker extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(4); - // {5}{G}, {T}: Look at the top four cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. - Ability ability = new SimpleActivatedAbility(new LookLibraryAndPickControllerEffect( - 4, 1, StaticFilters.FILTER_CARD_CREATURE_A, - true, false, Zone.HAND, true - ).setBackInRandomOrder(true), new ManaCostsImpl("{5}{G}")); + // {5}{G}, {T}: Look at the top four cards of your library. You may reveal a creature card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. + Ability ability = new SimpleActivatedAbility( + new LookLibraryAndPickControllerEffect(4, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_RANDOM), + new ManaCostsImpl("{5}{G}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BrigidHeroOfKinsbaile.java b/Mage.Sets/src/mage/cards/b/BrigidHeroOfKinsbaile.java index 4c08237e243..7191cc4db7b 100644 --- a/Mage.Sets/src/mage/cards/b/BrigidHeroOfKinsbaile.java +++ b/Mage.Sets/src/mage/cards/b/BrigidHeroOfKinsbaile.java @@ -1,4 +1,3 @@ - package mage.cards.b; import java.util.UUID; @@ -6,15 +5,12 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageAllControlledTargetEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterAttackingOrBlockingCreature; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; +import mage.filter.StaticFilters; import mage.target.TargetPlayer; /** @@ -35,10 +31,11 @@ public final class BrigidHeroOfKinsbaile extends CardImpl { this.addAbility(FirstStrikeAbility.getInstance()); // {T}: Brigid, Hero of Kinsbaile deals 2 damage to each attacking or blocking creature target player controls. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BrigidHeroOfKinsbaileEffect(), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility( + new DamageAllControlledTargetEffect(2, StaticFilters.FILTER_ATTACKING_OR_BLOCKING_CREATURE), + new TapSourceCost()); ability.addTarget(new TargetPlayer()); this.addAbility(ability); - } private BrigidHeroOfKinsbaile(final BrigidHeroOfKinsbaile card) { @@ -50,32 +47,3 @@ public final class BrigidHeroOfKinsbaile extends CardImpl { return new BrigidHeroOfKinsbaile(this); } } - -class BrigidHeroOfKinsbaileEffect extends OneShotEffect { - - public BrigidHeroOfKinsbaileEffect() { - super(Outcome.Damage); - staticText = "{this} deals 2 damage to each attacking or blocking creature target player controls"; - } - - public BrigidHeroOfKinsbaileEffect(final BrigidHeroOfKinsbaileEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (targetPlayer != null) { - for (Permanent creature : game.getBattlefield().getAllActivePermanents(new FilterAttackingOrBlockingCreature(), targetPlayer.getId(), game)) { - creature.damage(2, source.getSourceId(), source, game, false, true); - } - return true; - } - return false; - } - - @Override - public BrigidHeroOfKinsbaileEffect copy() { - return new BrigidHeroOfKinsbaileEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BrilliantUltimatum.java b/Mage.Sets/src/mage/cards/b/BrilliantUltimatum.java index 158bfc6d391..21308bfd4c0 100644 --- a/Mage.Sets/src/mage/cards/b/BrilliantUltimatum.java +++ b/Mage.Sets/src/mage/cards/b/BrilliantUltimatum.java @@ -59,7 +59,7 @@ class BrilliantUltimatumEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } @@ -69,7 +69,7 @@ class BrilliantUltimatumEffect extends OneShotEffect { controller.moveCardsToExile(pile2.getCards(game), source, game, true, source.getSourceId(), sourceObject.getIdName()); TargetOpponent targetOpponent = new TargetOpponent(true); - targetOpponent.choose(outcome, source.getControllerId(), source.getSourceId(), game); + targetOpponent.choose(outcome, source.getControllerId(), source.getSourceId(), source, game); Player opponent = game.getPlayer(targetOpponent.getFirstTarget()); if (opponent != null) { TargetCard target = new TargetCard(0, pile2.size(), Zone.EXILED, new FilterCard("cards to put in the first pile")); diff --git a/Mage.Sets/src/mage/cards/b/BrimazKingOfOreskos.java b/Mage.Sets/src/mage/cards/b/BrimazKingOfOreskos.java index f0b431005cb..e0521d4bcc5 100644 --- a/Mage.Sets/src/mage/cards/b/BrimazKingOfOreskos.java +++ b/Mage.Sets/src/mage/cards/b/BrimazKingOfOreskos.java @@ -5,7 +5,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.BlocksSourceTriggeredAbility; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.VigilanceAbility; @@ -43,7 +43,7 @@ public final class BrimazKingOfOreskos extends CardImpl { this.addAbility(new AttacksTriggeredAbility(new CreateTokenEffect(new CatSoldierCreatureToken(), 1, false, true), false)); // Whenever Brimaz blocks a creature, create a 1/1 white Cat Soldier creature token with vigilance blocking that creature. - this.addAbility(new BlocksSourceTriggeredAbility(new BrimazKingOfOreskosEffect(), false, true)); + this.addAbility(new BlocksCreatureTriggeredAbility(new BrimazKingOfOreskosEffect())); } private BrimazKingOfOreskos(final BrimazKingOfOreskos card) { @@ -75,31 +75,30 @@ class BrimazKingOfOreskosEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } - if (controller != null) { - Token token = new CatSoldierCreatureToken(); - token.putOntoBattlefield(1, game, source, source.getControllerId()); - Permanent attackingCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (attackingCreature != null && game.getState().getCombat() != null) { - // Possible ruling (see Aetherplasm) - // The token you created is blocking the attacking creature, - // even if the block couldn't legally be declared (for example, if that creature - // enters the battlefield tapped, or it can't block, or the attacking creature - // has protection from it) - CombatGroup combatGroup = game.getState().getCombat().findGroup(attackingCreature.getId()); - if (combatGroup != null) { - for (UUID tokenId : token.getLastAddedTokenIds()) { - Permanent catToken = game.getPermanent(tokenId); - if (catToken != null) { - combatGroup.addBlocker(tokenId, source.getControllerId(), game); - game.getCombat().addBlockingGroup(tokenId, attackingCreature.getId(), controller.getId(), game); - } - } - combatGroup.pickBlockerOrder(attackingCreature.getControllerId(), game); - } - } - return true; + Token token = new CatSoldierCreatureToken(); + token.putOntoBattlefield(1, game, source, source.getControllerId()); + Permanent attackingCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (attackingCreature == null || game.getState().getCombat() == null) { return true; } + + // Possible ruling (see Aetherplasm) + // The token you created is blocking the attacking creature, + // even if the block couldn't legally be declared (for example, if that creature + // enters the battlefield tapped, or it can't block, or the attacking creature + // has protection from it) + CombatGroup combatGroup = game.getState().getCombat().findGroup(attackingCreature.getId()); + if (combatGroup == null) { return true; } + + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent catToken = game.getPermanent(tokenId); + if (catToken == null) { continue; } + + combatGroup.addBlocker(tokenId, source.getControllerId(), game); + game.getCombat().addBlockingGroup(tokenId, attackingCreature.getId(), controller.getId(), game); } - return false; + combatGroup.pickBlockerOrder(attackingCreature.getControllerId(), game); + + return true; } } diff --git a/Mage.Sets/src/mage/cards/b/BrineElemental.java b/Mage.Sets/src/mage/cards/b/BrineElemental.java index 04bc60512b0..9089063a22c 100644 --- a/Mage.Sets/src/mage/cards/b/BrineElemental.java +++ b/Mage.Sets/src/mage/cards/b/BrineElemental.java @@ -32,7 +32,7 @@ public final class BrineElemental extends CardImpl { this.toughness = new MageInt(4); // Morph {5}{U}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{5}{U}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{5}{U}{U}"))); // When Brine Elemental is turned face up, each opponent skips their next untap step. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new BrineElementalEffect())); diff --git a/Mage.Sets/src/mage/cards/b/BrineHag.java b/Mage.Sets/src/mage/cards/b/BrineHag.java index fde66fdf7a9..af7b561d760 100644 --- a/Mage.Sets/src/mage/cards/b/BrineHag.java +++ b/Mage.Sets/src/mage/cards/b/BrineHag.java @@ -68,26 +68,27 @@ class BrineHagEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (sourcePermanent != null) { - List list = new ArrayList<>(); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game)) { - if (sourcePermanent.getDealtDamageByThisTurn().contains(new MageObjectReference(creature.getId(), game))) { - list.add(creature); - } - } + if (sourcePermanent == null) { return false; } + + List list = new ArrayList<>(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player == null) { continue; } + + for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game)) { + if (sourcePermanent.getDealtDamageByThisTurn().contains(new MageObjectReference(creature.getId(), game))) { + list.add(creature); } } - if (!list.isEmpty()) { - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(new PermanentInListPredicate(list)); - game.addEffect(new SetPowerToughnessAllEffect(0, 2, Duration.Custom, filter, true), source); - } - return true; } - return false; + if (!list.isEmpty()) { + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + filter.add(new PermanentInListPredicate(list)); + game.addEffect(new SetPowerToughnessAllEffect(0, 2, Duration.Custom, filter, true), source); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/b/BringToLight.java b/Mage.Sets/src/mage/cards/b/BringToLight.java index 5e229d42f1c..795f1e95e7f 100644 --- a/Mage.Sets/src/mage/cards/b/BringToLight.java +++ b/Mage.Sets/src/mage/cards/b/BringToLight.java @@ -1,23 +1,21 @@ package mage.cards.b; -import java.util.UUID; -import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.dynamicvalue.common.ColorsOfManaSpentToCastCount; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; + +import java.util.UUID; /** * @author LevelX2 @@ -31,6 +29,7 @@ public final class BringToLight extends CardImpl { // cost less than or equal to the number of colors of mana spent to cast Bring to Light, exile that card, // then shuffle your library. You may cast that card without paying its mana cost. this.getSpellAbility().addEffect(new BringToLightEffect()); + this.getSpellAbility().setAbilityWord(AbilityWord.CONVERGE); } private BringToLight(final BringToLight card) { @@ -47,8 +46,8 @@ class BringToLightEffect extends OneShotEffect { public BringToLightEffect() { super(Outcome.PlayForFree); - this.staticText = "Converge — Search your library for a creature, instant, or sorcery card with mana " - + "value less than or equal to the number of colors of mana spent to cast this spell, exile that card, " + this.staticText = "search your library for a creature, instant, or sorcery card with mana value " + + "less than or equal to the number of colors of mana spent to cast this spell, exile that card, " + "then shuffle. You may cast that card without paying its mana cost"; } @@ -64,31 +63,23 @@ class BringToLightEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - int numberColors = ColorsOfManaSpentToCastCount.getInstance().calculate(game, source, this); - FilterCard filter = new FilterCard("a creature, instant, or sorcery card with mana value " - + "less than or equal to " + numberColors); - filter.add(Predicates.or(CardType.CREATURE.getPredicate(), - CardType.INSTANT.getPredicate(), CardType.SORCERY.getPredicate())); - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, numberColors + 1)); - TargetCardInLibrary target = new TargetCardInLibrary(filter); - controller.searchLibrary(target, source, game); - Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); - if (card != null) { - controller.moveCards(card, Zone.EXILED, source, game); - } - controller.shuffleLibrary(source, game); - if (card != null) { - if (controller.chooseUse(Outcome.PlayForFree, "Cast " + card.getName() - + " without paying its mana cost?", source, game)) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - } - } - return true; + if (controller == null) { + return false; } - return false; + int numberColors = ColorsOfManaSpentToCastCount.getInstance().calculate(game, source, this); + FilterCard filter = new FilterCard("a creature, instant, or sorcery card with mana value " + + "less than or equal to " + numberColors); + filter.add(Predicates.or(CardType.CREATURE.getPredicate(), + CardType.INSTANT.getPredicate(), CardType.SORCERY.getPredicate())); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, numberColors + 1)); + TargetCardInLibrary target = new TargetCardInLibrary(filter); + controller.searchLibrary(target, source, game); + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); + if (card != null) { + controller.moveCards(card, Zone.EXILED, source, game); + } + controller.shuffleLibrary(source, game); + CardUtil.castSpellWithAttributesForFree(controller, source, game, card); + return true; } } diff --git a/Mage.Sets/src/mage/cards/b/BringerOfTheWhiteDawn.java b/Mage.Sets/src/mage/cards/b/BringerOfTheWhiteDawn.java index 4077285857b..ebcdc4ec167 100644 --- a/Mage.Sets/src/mage/cards/b/BringerOfTheWhiteDawn.java +++ b/Mage.Sets/src/mage/cards/b/BringerOfTheWhiteDawn.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -15,17 +13,18 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; import mage.constants.Zone; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Plopman */ public final class BringerOfTheWhiteDawn extends CardImpl { public BringerOfTheWhiteDawn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{7}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{7}{W}{W}"); this.subtype.add(SubType.BRINGER); this.power = new MageInt(5); @@ -37,7 +36,7 @@ public final class BringerOfTheWhiteDawn extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // At the beginning of your upkeep, you may return target artifact card from your graveyard to the battlefield. Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), TargetController.YOU, true); - ability.addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BrinkOfDisaster.java b/Mage.Sets/src/mage/cards/b/BrinkOfDisaster.java index 34ac4baf7a3..342113fa044 100644 --- a/Mage.Sets/src/mage/cards/b/BrinkOfDisaster.java +++ b/Mage.Sets/src/mage/cards/b/BrinkOfDisaster.java @@ -43,7 +43,7 @@ public final class BrinkOfDisaster extends CardImpl { this.addAbility(ability); // When enchanted permanent becomes tapped, destroy it. - this.addAbility(new BecomesTappedAttachedTriggeredAbility(new DestroyAttachedToEffect("it"), "enchanted permanent")); + this.addAbility(new BecomesTappedAttachedTriggeredAbility(new DestroyAttachedToEffect("it"), "").setTriggerPhrase("When enchanted permanent becomes tapped, ")); } private BrinkOfDisaster(final BrinkOfDisaster card) { diff --git a/Mage.Sets/src/mage/cards/b/BrionStoutarm.java b/Mage.Sets/src/mage/cards/b/BrionStoutarm.java index a0a6865c344..f4ad0f30562 100644 --- a/Mage.Sets/src/mage/cards/b/BrionStoutarm.java +++ b/Mage.Sets/src/mage/cards/b/BrionStoutarm.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -14,25 +12,22 @@ import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.keyword.LifelinkAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; import mage.game.Game; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetPlayerOrPlaneswalker; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class BrionStoutarm extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature other than Brion Stoutarm"); - - static { - filter.add(AnotherPredicate.instance); - } - public BrionStoutarm(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{W}"); addSuperType(SuperType.LEGENDARY); @@ -43,10 +38,11 @@ public final class BrionStoutarm extends CardImpl { // Lifelink this.addAbility(LifelinkAbility.getInstance()); + // {R}, {tap}, Sacrifice a creature other than Brion Stoutarm: Brion Stoutarm deals damage equal to the sacrificed creature's power to target player. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BrionStoutarmEffect(), new ManaCostsImpl("{R}")); + Ability ability = new SimpleActivatedAbility(new BrionStoutarmEffect(), new ManaCostsImpl<>("{R}")); ability.addCost(new TapSourceCost()); - ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, true))); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE))); ability.addTarget(new TargetPlayerOrPlaneswalker()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BriselaVoiceOfNightmares.java b/Mage.Sets/src/mage/cards/b/BriselaVoiceOfNightmares.java index 981bbaffdd1..e6cce7f8790 100644 --- a/Mage.Sets/src/mage/cards/b/BriselaVoiceOfNightmares.java +++ b/Mage.Sets/src/mage/cards/b/BriselaVoiceOfNightmares.java @@ -82,7 +82,7 @@ class BriselaVoiceOfNightmaresCantCastEffect extends ContinuousRuleModifyingEffe @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast spells with mana value 3 or less (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/b/BrokenConcentration.java b/Mage.Sets/src/mage/cards/b/BrokenConcentration.java index d1e134e9791..a72805845a2 100644 --- a/Mage.Sets/src/mage/cards/b/BrokenConcentration.java +++ b/Mage.Sets/src/mage/cards/b/BrokenConcentration.java @@ -23,7 +23,7 @@ public final class BrokenConcentration extends CardImpl { this.getSpellAbility().addEffect(new CounterTargetEffect()); this.getSpellAbility().addTarget(new TargetSpell()); // Madness {3}{U} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{3}{U}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{3}{U}"))); } private BrokenConcentration(final BrokenConcentration card) { diff --git a/Mage.Sets/src/mage/cards/b/BrokersAscendancy.java b/Mage.Sets/src/mage/cards/b/BrokersAscendancy.java new file mode 100644 index 00000000000..6a6605170aa --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BrokersAscendancy.java @@ -0,0 +1,43 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BrokersAscendancy extends CardImpl { + + public BrokersAscendancy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}{W}{U}"); + + // At the beginning of your end step, put a +1/+1 counter on each creature you control and a loyalty counter on each planeswalker you control. + Ability ability = new BeginningOfEndStepTriggeredAbility(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), + StaticFilters.FILTER_CONTROLLED_CREATURE + ), TargetController.YOU, false); + ability.addEffect(new AddCountersAllEffect( + CounterType.LOYALTY.createInstance(), + StaticFilters.FILTER_CONTROLLED_PERMANENT_PLANESWALKER + ).setText("and a loyalty counter on each planeswalker you control")); + this.addAbility(ability); + } + + private BrokersAscendancy(final BrokersAscendancy card) { + super(card); + } + + @Override + public BrokersAscendancy copy() { + return new BrokersAscendancy(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BrokersCharm.java b/Mage.Sets/src/mage/cards/b/BrokersCharm.java new file mode 100644 index 00000000000..dbca73f54df --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BrokersCharm.java @@ -0,0 +1,57 @@ +package mage.cards.b; + +import mage.abilities.Mode; +import mage.abilities.effects.common.DamageWithPowerFromOneToAnotherTargetEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetEnchantmentPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BrokersCharm extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker an opponent controls"); + + static { + filter.add(TargetController.OPPONENT.getControllerPredicate()); + } + + public BrokersCharm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}{W}{U}"); + + // Choose one — + // • Target creature you control gets +1/+0 until end of turn. It deals damage equal to its power to target creature or planeswalker an opponent controls. + this.getSpellAbility().addEffect(new BoostTargetEffect(1, 0)); + this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect("it")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + + // • Destroy target enchantment. + this.getSpellAbility().addMode(new Mode(new DestroyTargetEffect()).addTarget(new TargetEnchantmentPermanent())); + + // • Draw two cards. + this.getSpellAbility().addMode(new Mode(new DrawCardSourceControllerEffect(2))); + } + + private BrokersCharm(final BrokersCharm card) { + super(card); + } + + @Override + public BrokersCharm copy() { + return new BrokersCharm(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BrokersConfluence.java b/Mage.Sets/src/mage/cards/b/BrokersConfluence.java new file mode 100644 index 00000000000..7b8a5d603a3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BrokersConfluence.java @@ -0,0 +1,46 @@ +package mage.cards.b; + +import mage.abilities.Mode; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.effects.common.PhaseOutTargetEffect; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetActivatedOrTriggeredAbility; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BrokersConfluence extends CardImpl { + + public BrokersConfluence(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}{W}{U}"); + + // 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); + + // • Proliferate. + this.getSpellAbility().addEffect(new ProliferateEffect()); + + // • Target creature phases out. + this.getSpellAbility().addMode(new Mode(new PhaseOutTargetEffect()).addTarget(new TargetCreaturePermanent())); + + // • Counter target activated or triggered ability. + this.getSpellAbility().addMode(new Mode(new CounterTargetEffect()).addTarget(new TargetActivatedOrTriggeredAbility())); + } + + private BrokersConfluence(final BrokersConfluence card) { + super(card); + } + + @Override + public BrokersConfluence copy() { + return new BrokersConfluence(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BrokersHideout.java b/Mage.Sets/src/mage/cards/b/BrokersHideout.java new file mode 100644 index 00000000000..021c7b7f5d3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BrokersHideout.java @@ -0,0 +1,58 @@ +package mage.cards.b; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.effects.common.DoWhenCostPaid; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BrokersHideout extends CardImpl { + + private static final FilterCard filter = new FilterCard("a basic Forest, Plains, or Island card"); + + static { + filter.add(SuperType.BASIC.getPredicate()); + filter.add(Predicates.or( + SubType.FOREST.getPredicate(), + SubType.PLAINS.getPredicate(), + SubType.ISLAND.getPredicate() + )); + } + + public BrokersHideout(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + + // When Brokers Hideout enters the battlefield, sacrifice it. When you do, search your library for a basic Forest, Plains, or Island card, put it onto the battlefield tapped, then shuffle and you gain 1 life. + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new SearchLibraryPutInPlayEffect( + new TargetCardInLibrary(filter), true, true + ), false); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DoWhenCostPaid( + ability, new SacrificeSourceCost().setText("sacrifice it"), null, false + ))); + } + + private BrokersHideout(final BrokersHideout card) { + super(card); + } + + @Override + public BrokersHideout copy() { + return new BrokersHideout(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BrokersInitiate.java b/Mage.Sets/src/mage/cards/b/BrokersInitiate.java new file mode 100644 index 00000000000..a3f31144014 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BrokersInitiate.java @@ -0,0 +1,43 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubLayer; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BrokersInitiate extends CardImpl { + + public BrokersInitiate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // {4}{G/U}: Brokers Initiate has base power and toughness 5/5 until end of turn. + this.addAbility(new SimpleActivatedAbility(new SetPowerToughnessSourceEffect( + 5, 5, Duration.EndOfTurn, SubLayer.SetPT_7b + ), new ManaCostsImpl<>("{4}{G/U}"))); + } + + private BrokersInitiate(final BrokersInitiate card) { + super(card); + } + + @Override + public BrokersInitiate copy() { + return new BrokersInitiate(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BrokersVeteran.java b/Mage.Sets/src/mage/cards/b/BrokersVeteran.java new file mode 100644 index 00000000000..ad1a2307561 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BrokersVeteran.java @@ -0,0 +1,45 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BrokersVeteran extends CardImpl { + + public BrokersVeteran(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // When Brokers Veteran dies, put a shield counter on target creature you control. + Ability ability = new DiesSourceTriggeredAbility( + new AddCountersTargetEffect(CounterType.SHIELD.createInstance()) + ); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private BrokersVeteran(final BrokersVeteran card) { + super(card); + } + + @Override + public BrokersVeteran copy() { + return new BrokersVeteran(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BronzeCudgels.java b/Mage.Sets/src/mage/cards/b/BronzeCudgels.java index c095a827a9d..608b9a6d8d6 100644 --- a/Mage.Sets/src/mage/cards/b/BronzeCudgels.java +++ b/Mage.Sets/src/mage/cards/b/BronzeCudgels.java @@ -76,7 +76,7 @@ class BronzeCudgelsEffect extends OneShotEffect { return false; } game.addEffect(new BoostTargetEffect(resolvedCount, 0) - .setTargetPointer(new FixedTarget(permanent.getOwnerId(), game)), source); + .setTargetPointer(new FixedTarget(permanent.getAttachedTo(), game)), source); return true; } } diff --git a/Mage.Sets/src/mage/cards/b/BronzehideLion.java b/Mage.Sets/src/mage/cards/b/BronzehideLion.java index da5b0187de9..fbd92ad8a99 100644 --- a/Mage.Sets/src/mage/cards/b/BronzehideLion.java +++ b/Mage.Sets/src/mage/cards/b/BronzehideLion.java @@ -88,7 +88,7 @@ class BronzehideLionReturnEffect extends OneShotEffect { } TargetPermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (controller.choose(outcome, target, source.getSourceId(), game) + if (controller.choose(outcome, target, source, game) && game.getPermanent(target.getFirstTarget()) != null) { game.getState().setValue("attachTo:" + source.getSourceId(), target.getFirstTarget()); } diff --git a/Mage.Sets/src/mage/cards/b/BronzeplateBoar.java b/Mage.Sets/src/mage/cards/b/BronzeplateBoar.java index 68e64d1fbed..8895f8b47f7 100644 --- a/Mage.Sets/src/mage/cards/b/BronzeplateBoar.java +++ b/Mage.Sets/src/mage/cards/b/BronzeplateBoar.java @@ -36,6 +36,7 @@ public final class BronzeplateBoar extends CardImpl { ability.addEffect(new GainAbilityAttachedEffect( TrampleAbility.getInstance(), AttachmentType.EQUIPMENT ).setText("and has trample")); + this.addAbility(ability); // Reconfigure {5} this.addAbility(new ReconfigureAbility("{5}")); diff --git a/Mage.Sets/src/mage/cards/b/BroodhatchNantuko.java b/Mage.Sets/src/mage/cards/b/BroodhatchNantuko.java index 81ce22ee1c6..44c86ea0107 100644 --- a/Mage.Sets/src/mage/cards/b/BroodhatchNantuko.java +++ b/Mage.Sets/src/mage/cards/b/BroodhatchNantuko.java @@ -1,22 +1,17 @@ - package mage.cards.b; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealtDamageToSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.MorphAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.game.Game; import mage.game.permanent.token.InsectToken; -import mage.players.Player; /** * @@ -31,9 +26,11 @@ public final class BroodhatchNantuko extends CardImpl { this.toughness = new MageInt(1); // Whenever Broodhatch Nantuko is dealt damage, you may create that many 1/1 green Insect creature tokens. - this.addAbility(new DealtDamageToSourceTriggeredAbility(new BroodhatchNantukoDealDamageEffect(), true, false)); + this.addAbility(new DealtDamageToSourceTriggeredAbility( + new CreateTokenEffect(new InsectToken(), SavedDamageValue.MANY), true)); + // Morph {2}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl<>("{2}{G}"))); } private BroodhatchNantuko(final BroodhatchNantuko card) { @@ -45,32 +42,3 @@ public final class BroodhatchNantuko extends CardImpl { return new BroodhatchNantuko(this); } } - -class BroodhatchNantukoDealDamageEffect extends OneShotEffect { - - public BroodhatchNantukoDealDamageEffect() { - super(Outcome.Damage); - this.staticText = "create that many 1/1 green Insect creature tokens"; - } - - public BroodhatchNantukoDealDamageEffect(final BroodhatchNantukoDealDamageEffect effect) { - super(effect); - } - - @Override - public BroodhatchNantukoDealDamageEffect copy() { - return new BroodhatchNantukoDealDamageEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - int amount = (Integer) getValue("damage"); - if (amount > 0) { - return new CreateTokenEffect(new InsectToken(), amount).apply(game, source); - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/b/BroodmateDragon.java b/Mage.Sets/src/mage/cards/b/BroodmateDragon.java index cd337e76900..cee58d55f3f 100644 --- a/Mage.Sets/src/mage/cards/b/BroodmateDragon.java +++ b/Mage.Sets/src/mage/cards/b/BroodmateDragon.java @@ -19,7 +19,7 @@ import mage.game.permanent.token.DragonToken; */ public final class BroodmateDragon extends CardImpl { - private static DragonToken dragonToken = new DragonToken(); + private static final DragonToken dragonToken = new DragonToken(); public BroodmateDragon(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{R}{G}"); diff --git a/Mage.Sets/src/mage/cards/b/BrothersYamazaki.java b/Mage.Sets/src/mage/cards/b/BrothersYamazaki.java index eb339a13ba0..ee936a0012f 100644 --- a/Mage.Sets/src/mage/cards/b/BrothersYamazaki.java +++ b/Mage.Sets/src/mage/cards/b/BrothersYamazaki.java @@ -99,7 +99,7 @@ class BrothersYamazakiIgnoreLegendRuleEffectEffect extends ContinuousRuleModifyi public boolean applies(GameEvent event, Ability source, Game game) { Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent != null && permanent.getName().equals("Brothers Yamazaki")) { - return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) == 2; + return game.getBattlefield().count(filter, source.getControllerId(), source, game) == 2; } return false; } diff --git a/Mage.Sets/src/mage/cards/b/BrudicladTelchorEngineer.java b/Mage.Sets/src/mage/cards/b/BrudicladTelchorEngineer.java index 32540571ce7..863c43269ab 100644 --- a/Mage.Sets/src/mage/cards/b/BrudicladTelchorEngineer.java +++ b/Mage.Sets/src/mage/cards/b/BrudicladTelchorEngineer.java @@ -94,7 +94,7 @@ class BrudicladTelchorEngineerEffect extends OneShotEffect { TargetControlledPermanent target = new TargetControlledPermanent(0, 1, filter, true); target.setNotTarget(true); if (controller.chooseUse(outcome, "Select a token to copy?", source, game) - && controller.choose(Outcome.Neutral, target, source.getSourceId(), game)) { + && controller.choose(Outcome.Neutral, target, source, game)) { Permanent toCopyFromPermanent = game.getPermanent(target.getFirstTarget()); if (toCopyFromPermanent != null) { diff --git a/Mage.Sets/src/mage/cards/b/BruenorBattlehammer.java b/Mage.Sets/src/mage/cards/b/BruenorBattlehammer.java index c70f83bd04b..17d6ecbaa5e 100644 --- a/Mage.Sets/src/mage/cards/b/BruenorBattlehammer.java +++ b/Mage.Sets/src/mage/cards/b/BruenorBattlehammer.java @@ -72,7 +72,7 @@ class BruenorBattlehammerBoostEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { for (Permanent permanent : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game )) { int equipped = permanent .getAttachments() diff --git a/Mage.Sets/src/mage/cards/b/BrunaLightOfAlabaster.java b/Mage.Sets/src/mage/cards/b/BrunaLightOfAlabaster.java index 9329557a7b0..9a6da1ee603 100644 --- a/Mage.Sets/src/mage/cards/b/BrunaLightOfAlabaster.java +++ b/Mage.Sets/src/mage/cards/b/BrunaLightOfAlabaster.java @@ -75,8 +75,10 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - UUID bruna = source.getSourceId(); Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + + UUID bruna = source.getSourceId(); FilterPermanent filterAura = new FilterPermanent("Aura"); FilterCard filterAuraCard = new FilterCard("Aura card"); @@ -88,13 +90,9 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect { filterAuraCard.add(SubType.AURA.getPredicate()); filterAuraCard.add(new AuraCardCanAttachToPermanentId(bruna)); - if (controller == null) { - return false; - } Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (sourcePermanent == null) { - return false; - } + if (sourcePermanent == null) { return false; } + List fromBattlefield = new ArrayList<>(); List fromHandGraveyard = new ArrayList<>(); @@ -104,16 +102,17 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect { && controller.chooseUse(Outcome.Benefit, "Attach an Aura from the battlefield?", source, game)) { Target targetAura = new TargetPermanent(filterAura); targetAura.setNotTarget(true); - if (controller.choose(Outcome.Benefit, targetAura, source.getSourceId(), game)) { - Permanent aura = game.getPermanent(targetAura.getFirstTarget()); - if (aura != null) { - Target target = aura.getSpellAbility().getTargets().get(0); - if (target != null) { - fromBattlefield.add(aura); - filterAura.add(Predicates.not(new CardIdPredicate(aura.getId()))); - } - } - } + if (!controller.choose(Outcome.Benefit, targetAura, source, game)) { continue; } + + Permanent aura = game.getPermanent(targetAura.getFirstTarget()); + if (aura == null) { continue; } + + Target target = aura.getSpellAbility().getTargets().get(0); + if (target == null) { continue; } + + fromBattlefield.add(aura); + filterAura.add(Predicates.not(new CardIdPredicate(aura.getId()))); + countBattlefield = game.getBattlefield().getAllActivePermanents(filterAura, game).size() - sourcePermanent.getAttachments().size(); } @@ -122,16 +121,16 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect { && countHand > 0 && controller.chooseUse(Outcome.Benefit, "Attach an Aura from your hand?", source, game)) { TargetCard targetAura = new TargetCard(Zone.HAND, filterAuraCard); - if (controller.choose(Outcome.Benefit, controller.getHand(), targetAura, game)) { - Card aura = game.getCard(targetAura.getFirstTarget()); - if (aura != null) { - Target target = aura.getSpellAbility().getTargets().get(0); - if (target != null) { - fromHandGraveyard.add(aura); - filterAuraCard.add(Predicates.not(new CardIdPredicate(aura.getId()))); - } - } - } + if (!controller.choose(Outcome.Benefit, controller.getHand(), targetAura, game)) { continue; } + + Card aura = game.getCard(targetAura.getFirstTarget()); + if (aura == null) { continue; } + + Target target = aura.getSpellAbility().getTargets().get(0); + if (target == null) { continue; } + fromHandGraveyard.add(aura); + filterAuraCard.add(Predicates.not(new CardIdPredicate(aura.getId()))); + countHand = controller.getHand().count(filterAuraCard, game); } @@ -140,18 +139,20 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect { && countGraveyard > 0 && controller.chooseUse(Outcome.Benefit, "Attach an Aura from your graveyard?", source, game)) { TargetCard targetAura = new TargetCard(Zone.GRAVEYARD, filterAuraCard); - if (controller.choose(Outcome.Benefit, controller.getGraveyard(), targetAura, game)) { - Card aura = game.getCard(targetAura.getFirstTarget()); - if (aura != null) { - Target target = aura.getSpellAbility().getTargets().get(0); - if (target != null) { - fromHandGraveyard.add(aura); - filterAuraCard.add(Predicates.not(new CardIdPredicate(aura.getId()))); - } - } - } + if (!controller.choose(Outcome.Benefit, controller.getGraveyard(), targetAura, game)) { continue; } + + Card aura = game.getCard(targetAura.getFirstTarget()); + if (aura == null) { continue; } + + Target target = aura.getSpellAbility().getTargets().get(0); + if (target == null) { continue; } + + fromHandGraveyard.add(aura); + filterAuraCard.add(Predicates.not(new CardIdPredicate(aura.getId()))); + countGraveyard = controller.getGraveyard().count(filterAuraCard, game); } + // Move permanents for (Permanent aura : fromBattlefield) { Permanent attachedTo = game.getPermanent(aura.getAttachedTo()); @@ -160,13 +161,14 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect { } sourcePermanent.addAttachment(aura.getId(), source, game); } + // Move cards for (Card aura : fromHandGraveyard) { - if (aura != null) { - game.getState().setValue("attachTo:" + aura.getId(), sourcePermanent); - controller.moveCards(aura, Zone.BATTLEFIELD, source, game); - sourcePermanent.addAttachment(aura.getId(), source, game); - } + if (aura == null) { continue; } + + game.getState().setValue("attachTo:" + aura.getId(), sourcePermanent); + controller.moveCards(aura, Zone.BATTLEFIELD, source, game); + sourcePermanent.addAttachment(aura.getId(), source, game); } return true; } diff --git a/Mage.Sets/src/mage/cards/b/BrutalExpulsion.java b/Mage.Sets/src/mage/cards/b/BrutalExpulsion.java index 51421920af7..8eec6a17a4a 100644 --- a/Mage.Sets/src/mage/cards/b/BrutalExpulsion.java +++ b/Mage.Sets/src/mage/cards/b/BrutalExpulsion.java @@ -42,8 +42,7 @@ public final class BrutalExpulsion extends CardImpl { this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetSpellOrPermanent(1, 1, filter, false).withChooseHint("return to its owner's hand")); // or Brutal Expulsion deals 2 damage to target creature or planeswalker. If that permanent would be put into a graveyard this turn, exile it instead. - Mode mode = new Mode(); - mode.addEffect(new DamageTargetEffect(2)); + Mode mode = new Mode(new DamageTargetEffect(2)); Effect effect = new DealtDamageToCreatureBySourceDies(this, Duration.EndOfTurn); effect.setText("If that creature or planeswalker would die this turn, exile it instead"); mode.addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/b/BrutalHordechief.java b/Mage.Sets/src/mage/cards/b/BrutalHordechief.java index 8b0eb470a61..7f9ae4c09e6 100644 --- a/Mage.Sets/src/mage/cards/b/BrutalHordechief.java +++ b/Mage.Sets/src/mage/cards/b/BrutalHordechief.java @@ -12,7 +12,7 @@ import mage.abilities.effects.common.combat.ChooseBlockersEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -26,12 +26,6 @@ import java.util.UUID; */ public final class BrutalHordechief extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public BrutalHordechief(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.ORC, SubType.WARRIOR); @@ -43,7 +37,8 @@ public final class BrutalHordechief extends CardImpl { // {3}{R/W}{R/W}: Creatures your opponents control block this turn if able, and you choose how those creatures block. Ability ability = new SimpleActivatedAbility( - new BlocksIfAbleAllEffect(filter, Duration.EndOfTurn), new ManaCostsImpl<>("{3}{R/W}{R/W}") + new BlocksIfAbleAllEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, Duration.EndOfTurn), + new ManaCostsImpl<>("{3}{R/W}{R/W}") ); ability.addEffect(new ChooseBlockersEffect(Duration.EndOfTurn).setText("and you choose how those creatures block")); ability.addWatcher(new ControlCombatRedundancyWatcher()); diff --git a/Mage.Sets/src/mage/cards/b/BrutalizerExarch.java b/Mage.Sets/src/mage/cards/b/BrutalizerExarch.java index c5e1ef23a76..83068067577 100644 --- a/Mage.Sets/src/mage/cards/b/BrutalizerExarch.java +++ b/Mage.Sets/src/mage/cards/b/BrutalizerExarch.java @@ -47,8 +47,7 @@ public final class BrutalizerExarch extends CardImpl { TargetCardInLibrary target = new TargetCardInLibrary(new FilterCreatureCard("a creature card")); Ability ability = new EntersBattlefieldTriggeredAbility(new SearchLibraryPutOnLibraryEffect(target, true, true), false); // or put target noncreature permanent on the bottom of its owner's library. - Mode mode = new Mode(); - mode.addEffect(new BrutalizerExarchEffect2()); + Mode mode = new Mode(new BrutalizerExarchEffect2()); mode.addTarget(new TargetPermanent(filter)); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/b/BuccaneersBravado.java b/Mage.Sets/src/mage/cards/b/BuccaneersBravado.java index 160dbbe01a6..5c8ea2a66f5 100644 --- a/Mage.Sets/src/mage/cards/b/BuccaneersBravado.java +++ b/Mage.Sets/src/mage/cards/b/BuccaneersBravado.java @@ -37,10 +37,9 @@ public final class BuccaneersBravado extends CardImpl { this.getSpellAbility().addEffect(new BoostTargetEffect(1, 1, Duration.EndOfTurn).setText("Target creature gets +1/+1")); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn).setText("and gains first strike until end of turn")); // Target Pirate gets +1/+1 and gains double strike until end of turn. - Mode mode = new Mode(); - mode.addTarget(new TargetPermanent(filter)); - mode.addEffect(new BoostTargetEffect(1, 1, Duration.EndOfTurn).setText("Target Pirate gets +1/+1")); + Mode mode = new Mode(new BoostTargetEffect(1, 1, Duration.EndOfTurn).setText("Target Pirate gets +1/+1")); mode.addEffect(new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn).setText("and gains double strike until end of turn")); + mode.addTarget(new TargetPermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/BudokaGardener.java b/Mage.Sets/src/mage/cards/b/BudokaGardener.java index 58d601a750b..68fc7a99d10 100644 --- a/Mage.Sets/src/mage/cards/b/BudokaGardener.java +++ b/Mage.Sets/src/mage/cards/b/BudokaGardener.java @@ -70,13 +70,12 @@ class BudokaGardenerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - if (game.getBattlefield().count(filterLands, source.getSourceId(), source.getControllerId(), game) >= 10) { - new FlipSourceEffect(new DokaiWeaverofLife()).apply(game, source); - } - return true; + if (controller == null) { return false; } + if (game.getBattlefield().count(filterLands, source.getControllerId(), source, game) < 10) { + return false; } - return false; + + return new FlipSourceEffect(new DokaiWeaverofLife()).apply(game, source); } @Override diff --git a/Mage.Sets/src/mage/cards/b/BuiltToLast.java b/Mage.Sets/src/mage/cards/b/BuiltToLast.java index 470831846d1..40ed0f96d73 100644 --- a/Mage.Sets/src/mage/cards/b/BuiltToLast.java +++ b/Mage.Sets/src/mage/cards/b/BuiltToLast.java @@ -28,7 +28,7 @@ public final class BuiltToLast extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new ConditionalContinuousEffect( new GainAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), new LockedInCondition(new TargetHasCardTypeCondition(CardType.ARTIFACT)), - "If its an artifact creature, it gains indestructible until end of turn")); + "If it's an artifact creature, it gains indestructible until end of turn")); } diff --git a/Mage.Sets/src/mage/cards/b/BuiltToSmash.java b/Mage.Sets/src/mage/cards/b/BuiltToSmash.java index 90664118ba8..2ed5b937989 100644 --- a/Mage.Sets/src/mage/cards/b/BuiltToSmash.java +++ b/Mage.Sets/src/mage/cards/b/BuiltToSmash.java @@ -28,7 +28,7 @@ public final class BuiltToSmash extends CardImpl { this.getSpellAbility().addTarget(new TargetAttackingCreature()); this.getSpellAbility().addEffect(new ConditionalContinuousEffect( new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn), new LockedInCondition(new TargetHasCardTypeCondition(CardType.ARTIFACT)), - "If its an artifact creature, it gains trample until end of turn")); + "If it's an artifact creature, it gains trample until end of turn")); } private BuiltToSmash(final BuiltToSmash card) { diff --git a/Mage.Sets/src/mage/cards/b/BullElephant.java b/Mage.Sets/src/mage/cards/b/BullElephant.java index 2328b9e52f8..75c8a137bab 100644 --- a/Mage.Sets/src/mage/cards/b/BullElephant.java +++ b/Mage.Sets/src/mage/cards/b/BullElephant.java @@ -15,7 +15,7 @@ import java.util.UUID; public final class BullElephant extends CardImpl { - private static FilterControlledLandPermanent controlledForest = new FilterControlledLandPermanent("Forests"); + private static final FilterControlledLandPermanent controlledForest = new FilterControlledLandPermanent("Forests"); static { controlledForest.add(SubType.FOREST.getPredicate()); @@ -25,10 +25,14 @@ public final class BullElephant extends CardImpl { public BullElephant(UUID cardId, CardSetInfo cardSetInfo) { super(cardId, cardSetInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.ELEPHANT); + power = new MageInt(4); toughness = new MageInt(4); -//When Bull Elephant enters the battlefield, sacrifice it unless you return two Forests you control to their owner's hand. - addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(2, 2, controlledForest, false))))); + + // When Bull Elephant enters the battlefield, sacrifice it unless you return two Forests you control to their owner's hand. + addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ReturnToHandChosenControlledPermanentCost( + new TargetControlledPermanent(2, 2, controlledForest, false) + )))); } public BullElephant(BullElephant other) { diff --git a/Mage.Sets/src/mage/cards/b/BurdenOfGreed.java b/Mage.Sets/src/mage/cards/b/BurdenOfGreed.java index f824f61baf9..6b49922a8a8 100644 --- a/Mage.Sets/src/mage/cards/b/BurdenOfGreed.java +++ b/Mage.Sets/src/mage/cards/b/BurdenOfGreed.java @@ -50,7 +50,7 @@ class BurdenOfGreedCount implements DynamicValue { FilterArtifactPermanent filter = new FilterArtifactPermanent(); filter.add(TappedPredicate.TAPPED); filter.add(new ControllerIdPredicate(sourceAbility.getFirstTarget())); - return game.getBattlefield().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + return game.getBattlefield().count(filter, sourceAbility.getControllerId(), sourceAbility, game); } @Override diff --git a/Mage.Sets/src/mage/cards/b/BuriedRuin.java b/Mage.Sets/src/mage/cards/b/BuriedRuin.java index 77e4c5a873b..e323ef27004 100644 --- a/Mage.Sets/src/mage/cards/b/BuriedRuin.java +++ b/Mage.Sets/src/mage/cards/b/BuriedRuin.java @@ -1,36 +1,33 @@ - - package mage.cards.b; -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.GenericManaCost; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** * @author Loki */ public final class BuriedRuin extends CardImpl { public BuriedRuin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.addAbility(new ColorlessManaAbility()); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new GenericManaCost(2)); + Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new GenericManaCost(2)); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); - } private BuriedRuin(final BuriedRuin card) { @@ -41,5 +38,4 @@ public final class BuriedRuin extends CardImpl { public BuriedRuin copy() { return new BuriedRuin(this); } - } diff --git a/Mage.Sets/src/mage/cards/b/BurnFromWithin.java b/Mage.Sets/src/mage/cards/b/BurnFromWithin.java index 1a940c15833..7c11ae7dd31 100644 --- a/Mage.Sets/src/mage/cards/b/BurnFromWithin.java +++ b/Mage.Sets/src/mage/cards/b/BurnFromWithin.java @@ -32,7 +32,6 @@ public final class BurnFromWithin extends CardImpl { // If that creature would die this turn, exile it instead. this.getSpellAbility().addEffect(new BurnFromWithinEffect()); this.getSpellAbility().addTarget(new TargetAnyTarget()); - } private BurnFromWithin(final BurnFromWithin card) { @@ -49,7 +48,9 @@ class BurnFromWithinEffect extends OneShotEffect { public BurnFromWithinEffect() { super(Outcome.Benefit); - this.staticText = "{this} deals X damage to any target. If a creature is dealt damage this way, it loses indestructible until end of turn. If that creature would die this turn, exile it instead"; + this.staticText = "{this} deals X damage to any target. " + + "If a creature is dealt damage this way, it loses indestructible until end of turn. " + + "If that creature would die this turn, exile it instead"; } public BurnFromWithinEffect(final BurnFromWithinEffect effect) { @@ -64,25 +65,31 @@ class BurnFromWithinEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); - int amount = source.getManaCostsToPay().getX(); - if (creature != null) { - game.addEffect(new DiesReplacementEffect(new MageObjectReference(creature, game), Duration.EndOfTurn), source); - int damageDealt = creature.damage(amount, source.getSourceId(), source, game, false, true); - if (damageDealt > 0) { - ContinuousEffect effect = new LoseAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn); - effect.setTargetPointer(new FixedTarget(creature.getId(), game)); - game.addEffect(effect, source); - } - return true; - } - Player targetPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); - if (targetPlayer != null) { - targetPlayer.damage(amount, source.getSourceId(), source, game); - return true; + if (controller == null) { return false; } + + int amount = source.getManaCostsToPay().getX(); + + // Target is a creature + Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (creature != null) { + game.addEffect(new DiesReplacementEffect(new MageObjectReference(creature, game), Duration.EndOfTurn), source); + int damageDealt = creature.damage(amount, source.getSourceId(), source, game, false, true); + if (damageDealt > 0) { + ContinuousEffect effect = new LoseAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(creature.getId(), game)); + game.addEffect(effect, source); } + return true; } + + // Target is a player + Player targetPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); + if (targetPlayer != null) { + targetPlayer.damage(amount, source.getSourceId(), source, game); + return true; + } + + // No valid target return false; } } diff --git a/Mage.Sets/src/mage/cards/b/BurnTrail.java b/Mage.Sets/src/mage/cards/b/BurnTrail.java index f2620442ca4..9c070b730ae 100644 --- a/Mage.Sets/src/mage/cards/b/BurnTrail.java +++ b/Mage.Sets/src/mage/cards/b/BurnTrail.java @@ -23,7 +23,7 @@ public final class BurnTrail extends CardImpl { this.getSpellAbility().addTarget(new TargetAnyTarget()); // Conspire - this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE)); + this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.ONE)); } private BurnTrail(final BurnTrail card) { diff --git a/Mage.Sets/src/mage/cards/b/BurningCinderFuryOfCrimsonChaosFire.java b/Mage.Sets/src/mage/cards/b/BurningCinderFuryOfCrimsonChaosFire.java index c25450038a9..183e267127c 100644 --- a/Mage.Sets/src/mage/cards/b/BurningCinderFuryOfCrimsonChaosFire.java +++ b/Mage.Sets/src/mage/cards/b/BurningCinderFuryOfCrimsonChaosFire.java @@ -145,7 +145,7 @@ class BurningCinderFuryOfCrimsonChaosFireEffect extends OneShotEffect { class BurningCinderFuryOfCrimsonChaosFireCreatureGainControlEffect extends ContinuousEffectImpl { - private UUID controller; + private final UUID controller; public BurningCinderFuryOfCrimsonChaosFireCreatureGainControlEffect(Duration duration, UUID controller) { super(duration, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); diff --git a/Mage.Sets/src/mage/cards/b/BurningOfXinye.java b/Mage.Sets/src/mage/cards/b/BurningOfXinye.java index 5e997123114..cc81dfbf8d5 100644 --- a/Mage.Sets/src/mage/cards/b/BurningOfXinye.java +++ b/Mage.Sets/src/mage/cards/b/BurningOfXinye.java @@ -61,37 +61,36 @@ class BurningOfXinyeEffect extends OneShotEffect{ @Override public boolean apply(Game game, Ability source) { boolean abilityApplied = false; - - Player controller = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { abilityApplied |= playerDestroys(game, source, controller); } - - Player opponent = game.getPlayer(source.getFirstTarget()); - if (controller != null) { + Player opponent = game.getPlayer(source.getFirstTarget()); + if (opponent != null) { abilityApplied |= playerDestroys(game, source, opponent); } + return abilityApplied; } - public boolean playerDestroys(Game game, Ability source,Player player){ + private boolean playerDestroys(Game game, Ability source, Player player){ boolean abilityApplied = false; int realCount = game.getBattlefield().countAll(filter, player.getId(), game); int amount = Math.min(4, realCount); Target target = new TargetControlledPermanent(amount, amount, filter, true); - if (amount > 0 && target.canChoose(source.getSourceId(), player.getId(), game)) { - while (!target.isChosen() && target.canChoose(source.getSourceId(), player.getId(), game) && player.canRespond()) { - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + if (amount > 0 && target.canChoose(player.getId(), source, game)) { + while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) { + player.choose(Outcome.Sacrifice, target, source, game); } - for ( int idx = 0; idx < target.getTargets().size(); idx++) { - Permanent permanent = game.getPermanent(target.getTargets().get(idx)); + for (UUID targetId : target.getTargets()) { + Permanent permanent = game.getPermanent(targetId); - if ( permanent != null ) { + if (permanent != null) { abilityApplied |= permanent.destroy(source, game, false); } } @@ -103,5 +102,4 @@ class BurningOfXinyeEffect extends OneShotEffect{ public BurningOfXinyeEffect copy() { return new BurningOfXinyeEffect(this); } - } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/b/BurningRuneDemon.java b/Mage.Sets/src/mage/cards/b/BurningRuneDemon.java index 53e90462739..7092c4613ab 100644 --- a/Mage.Sets/src/mage/cards/b/BurningRuneDemon.java +++ b/Mage.Sets/src/mage/cards/b/BurningRuneDemon.java @@ -1,17 +1,14 @@ package mage.cards.b; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlyingAbility; import mage.cards.*; +import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.abilities.keyword.FlyingAbility; -import mage.constants.CardType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.StaticFilters; @@ -21,11 +18,13 @@ import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCardWithDifferentNameInLibrary; import mage.target.common.TargetOpponent; -import mage.util.CardUtil; + +import java.util.Set; +import java.util.UUID; /** - * * @author weirddan455 */ public final class BurningRuneDemon extends CardImpl { @@ -60,6 +59,13 @@ public final class BurningRuneDemon extends CardImpl { class BurningRuneDemonEffect extends OneShotEffect { + private static final FilterCard filter + = new FilterCard("cards not named Burning-Rune Demon that have different names"); + + static { + filter.add(Predicates.not(new NamePredicate("Burning-Rune Demon"))); + } + public BurningRuneDemonEffect() { super(Outcome.Benefit); staticText = "search your library for exactly two cards " @@ -81,7 +87,7 @@ class BurningRuneDemonEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - TargetCardInLibrary targetCardInLibrary = new BurningRuneDemonTarget(); + TargetCardInLibrary targetCardInLibrary = new TargetCardWithDifferentNameInLibrary(2, 2, filter); if (controller.searchLibrary(targetCardInLibrary, source, game)) { Cards cards = new CardsImpl(targetCardInLibrary.getTargets()); if (!cards.isEmpty()) { @@ -115,41 +121,3 @@ class BurningRuneDemonEffect extends OneShotEffect { return false; } } - -class BurningRuneDemonTarget extends TargetCardInLibrary { - - private static final FilterCard filter - = new FilterCard("cards not named Burning-Rune Demon that have different names"); - - static { - filter.add(Predicates.not(new NamePredicate("Burning-Rune Demon"))); - } - - public BurningRuneDemonTarget() { - super(2, filter); - } - - private BurningRuneDemonTarget(final BurningRuneDemonTarget target) { - super(target); - } - - @Override - public BurningRuneDemonTarget copy() { - return new BurningRuneDemonTarget(this); - } - - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { - if (!super.canTarget(playerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - return card != null - && this.getTargets() - .stream() - .map(game::getCard) - .filter(Objects::nonNull) - .map(Card::getName) - .noneMatch(n -> CardUtil.haveSameNames(card, n, game)); - } -} diff --git a/Mage.Sets/src/mage/cards/b/BurstLightning.java b/Mage.Sets/src/mage/cards/b/BurstLightning.java index 52c03e02f3f..72f91afae59 100644 --- a/Mage.Sets/src/mage/cards/b/BurstLightning.java +++ b/Mage.Sets/src/mage/cards/b/BurstLightning.java @@ -26,7 +26,7 @@ public final class BurstLightning extends CardImpl { // Burst Lightning deals 2 damage to any target. If Burst Lightning was kicked, it deals 4 damage to that creature or player instead. this.getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new DamageTargetEffect(4), - new DamageTargetEffect(2), KickedCondition.instance, "{this} deals 2 damage to any target. If this spell was kicked, it deals 4 damage to that permanent or player instead")); + new DamageTargetEffect(2), KickedCondition.instance, "{this} deals 2 damage to any target. If this spell was kicked, it deals 4 damage instead")); } private BurstLightning(final BurstLightning card) { diff --git a/Mage.Sets/src/mage/cards/b/BurstOfSpeed.java b/Mage.Sets/src/mage/cards/b/BurstOfSpeed.java index 1a2a7e001f1..02209baadaa 100644 --- a/Mage.Sets/src/mage/cards/b/BurstOfSpeed.java +++ b/Mage.Sets/src/mage/cards/b/BurstOfSpeed.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; @@ -10,8 +8,9 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author Loki */ public final class BurstOfSpeed extends CardImpl { @@ -19,7 +18,10 @@ public final class BurstOfSpeed extends CardImpl { public BurstOfSpeed(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R}"); - this.getSpellAbility().addEffect(new GainAbilityControlledEffect(HasteAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, false)); + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + HasteAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURES, false + )); } private BurstOfSpeed(final BurstOfSpeed card) { diff --git a/Mage.Sets/src/mage/cards/b/BushmeatPoacher.java b/Mage.Sets/src/mage/cards/b/BushmeatPoacher.java index 7be8a1fb834..5219f808060 100644 --- a/Mage.Sets/src/mage/cards/b/BushmeatPoacher.java +++ b/Mage.Sets/src/mage/cards/b/BushmeatPoacher.java @@ -12,9 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -27,12 +25,6 @@ import java.util.UUID; */ public final class BushmeatPoacher extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("another creature"); - - static { - filter.add(AnotherPredicate.instance); - } - public BushmeatPoacher(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); @@ -44,7 +36,7 @@ public final class BushmeatPoacher extends CardImpl { // {1}, {T}, Sacrifice another creature: You gain life equal to that creature's toughness. Draw a card. Ability ability = new SimpleActivatedAbility(new BushmeatPoacherEffect(), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); - ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE))); this.addAbility(ability); } @@ -62,7 +54,7 @@ class BushmeatPoacherEffect extends OneShotEffect { BushmeatPoacherEffect() { super(Outcome.Benefit); - staticText = "you gain life equal to that creature's toughness. Draw a card"; + staticText = "you gain life equal to the sacrificed creature's toughness. Draw a card"; } private BushmeatPoacherEffect(final BushmeatPoacherEffect effect) { diff --git a/Mage.Sets/src/mage/cards/b/ButcherOfTheHorde.java b/Mage.Sets/src/mage/cards/b/ButcherOfTheHorde.java index e45a74da89a..79b81c565e8 100644 --- a/Mage.Sets/src/mage/cards/b/ButcherOfTheHorde.java +++ b/Mage.Sets/src/mage/cards/b/ButcherOfTheHorde.java @@ -71,7 +71,7 @@ class ButcherOfTheHordeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && controller != null) { Choice abilityChoice = new ChoiceImpl(); abilityChoice.setMessage("Choose an ability to add"); diff --git a/Mage.Sets/src/mage/cards/b/BuyYourSilence.java b/Mage.Sets/src/mage/cards/b/BuyYourSilence.java new file mode 100644 index 00000000000..8b56d346ba1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BuyYourSilence.java @@ -0,0 +1,65 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.TreasureToken; +import mage.target.common.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BuyYourSilence extends CardImpl { + + public BuyYourSilence(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}"); + + // Exile target nonland permanent. Its controller creates a Treasure token. + this.getSpellAbility().addEffect(new ExileTargetEffect()); + this.getSpellAbility().addEffect(new BuyYourSilenceEffect()); + this.getSpellAbility().addTarget(new TargetNonlandPermanent()); + } + + private BuyYourSilence(final BuyYourSilence card) { + super(card); + } + + @Override + public BuyYourSilence copy() { + return new BuyYourSilence(this); + } +} + +class BuyYourSilenceEffect extends OneShotEffect { + + BuyYourSilenceEffect() { + super(Outcome.Benefit); + staticText = "Its controller creates a Treasure token"; + } + + private BuyYourSilenceEffect(final BuyYourSilenceEffect effect) { + super(effect); + } + + @Override + public BuyYourSilenceEffect copy() { + return new BuyYourSilenceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); + if (permanent == null) { + return false; + } + return new TreasureToken().putOntoBattlefield(1, game, source, permanent.getControllerId()); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CabalExecutioner.java b/Mage.Sets/src/mage/cards/c/CabalExecutioner.java index 16ba71fdf8f..901009bd167 100644 --- a/Mage.Sets/src/mage/cards/c/CabalExecutioner.java +++ b/Mage.Sets/src/mage/cards/c/CabalExecutioner.java @@ -17,7 +17,6 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.target.targetpointer.FixedTarget; /** @@ -37,7 +36,7 @@ public final class CabalExecutioner extends CardImpl { this.addAbility(new CabalExecutionerAbility()); // Morph {3}{B}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{B}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{B}{B}"))); } private CabalExecutioner(final CabalExecutioner card) { diff --git a/Mage.Sets/src/mage/cards/c/CabalShrine.java b/Mage.Sets/src/mage/cards/c/CabalShrine.java index 319eb43c873..6ba7d6f0adc 100644 --- a/Mage.Sets/src/mage/cards/c/CabalShrine.java +++ b/Mage.Sets/src/mage/cards/c/CabalShrine.java @@ -90,7 +90,7 @@ class CabalShrineEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int count = 0; - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if(mageObject != null) { Spell spell = (Spell) game.getState().getValue("cabalShrine" + mageObject); if (spell != null) { diff --git a/Mage.Sets/src/mage/cards/c/CabalSurgeon.java b/Mage.Sets/src/mage/cards/c/CabalSurgeon.java index ddad3a2ae89..c8db1c1a2af 100644 --- a/Mage.Sets/src/mage/cards/c/CabalSurgeon.java +++ b/Mage.Sets/src/mage/cards/c/CabalSurgeon.java @@ -1,24 +1,22 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.ExileFromGraveCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author markedagain */ public final class CabalSurgeon extends CardImpl { @@ -31,7 +29,7 @@ public final class CabalSurgeon extends CardImpl { 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 ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), 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, StaticFilters.FILTER_CARDS_FROM_YOUR_GRAVEYARD))); diff --git a/Mage.Sets/src/mage/cards/c/CabalTherapist.java b/Mage.Sets/src/mage/cards/c/CabalTherapist.java index 53997fd42a9..6f4395e7281 100644 --- a/Mage.Sets/src/mage/cards/c/CabalTherapist.java +++ b/Mage.Sets/src/mage/cards/c/CabalTherapist.java @@ -81,7 +81,7 @@ class CabalTherapistDiscardEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); if (targetPlayer == null || controller == null || sourceObject == null || cardName == null) { return false; diff --git a/Mage.Sets/src/mage/cards/c/CabalTherapy.java b/Mage.Sets/src/mage/cards/c/CabalTherapy.java index 59cd97eef5f..73ec5c75673 100644 --- a/Mage.Sets/src/mage/cards/c/CabalTherapy.java +++ b/Mage.Sets/src/mage/cards/c/CabalTherapy.java @@ -65,7 +65,7 @@ class CabalTherapyEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); if (targetPlayer == null || controller == null || sourceObject == null || cardName == null) { return false; diff --git a/Mage.Sets/src/mage/cards/c/CabarettiAscendancy.java b/Mage.Sets/src/mage/cards/c/CabarettiAscendancy.java new file mode 100644 index 00000000000..4201c564e64 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CabarettiAscendancy.java @@ -0,0 +1,81 @@ +package mage.cards.c; + +import java.util.UUID; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author weirddan455 + */ +public final class CabarettiAscendancy extends CardImpl { + + public CabarettiAscendancy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}{G}{W}"); + + // At the beginning of your upkeep, look at the top card of your library. If it's a creature or planeswalker card, you may reveal it and put it in your hand. If you don't, you may put it on the bottom of your library. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CabarettiAscendencyEffect(), TargetController.YOU, false)); + } + + private CabarettiAscendancy(final CabarettiAscendancy card) { + super(card); + } + + @Override + public CabarettiAscendancy copy() { + return new CabarettiAscendancy(this); + } +} + +class CabarettiAscendencyEffect extends OneShotEffect { + + public CabarettiAscendencyEffect() { + super(Outcome.DrawCard); + this.staticText = "look at the top card of your library. If it's a creature or planeswalker card, you may reveal it and put it into your hand. If you don't put the card into your hand, you may put it on the bottom of your library"; + } + + private CabarettiAscendencyEffect(final CabarettiAscendencyEffect effect) { + super(effect); + } + + @Override + public CabarettiAscendencyEffect copy() { + return new CabarettiAscendencyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Card card = controller.getLibrary().getFromTop(game); + if (card == null) { + return false; + } + MageObject sourceObject = source.getSourceObject(game); + String objectName = sourceObject == null ? "Cabaretti Ascendency" : sourceObject.getIdName(); + controller.lookAtCards(objectName, card, game); + if ((card.isCreature(game) || card.isPlaneswalker(game)) && controller.chooseUse( + Outcome.DrawCard, "Reveal " + card.getIdName() + " and put it in your hand?", source, game)) { + controller.revealCards(source, new CardsImpl(card), game); + controller.moveCards(card, Zone.HAND, source, game); + } else if (controller.chooseUse(Outcome.Neutral, "Put " + card.getIdName() + " on the bottom of your library?", source, game)) { + controller.putCardsOnBottomOfLibrary(card, game, source, false); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CabarettiCharm.java b/Mage.Sets/src/mage/cards/c/CabarettiCharm.java new file mode 100644 index 00000000000..3c30af0dc40 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CabarettiCharm.java @@ -0,0 +1,59 @@ +package mage.cards.c; + +import mage.abilities.Mode; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.StaticFilters; +import mage.game.permanent.token.CitizenGreenWhiteToken; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CabarettiCharm extends CardImpl { + + public CabarettiCharm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}{G}{W}"); + + // Choose one — + // • Cabaretti Charm deals damage equal to the number of creatures you control to target creature or planeswalker. + this.getSpellAbility().addEffect(new DamageTargetEffect(CreaturesYouControlCount.instance) + .setText("{this} deals damage equal to the number of creatures you control to target creature or planeswalker")); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + this.getSpellAbility().addHint(CreaturesYouControlHint.instance); + + // • Creatures you control get +1/+1 and gain trample until end of turn. + this.getSpellAbility().addMode(new Mode( + new BoostControlledEffect( + 1, 1, Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURES + ).setText("creatures you control get +1/+1") + ).addEffect(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("and gain trample until end of turn"))); + + // • Create two 1/1 green and white Citizen creature tokens. + this.getSpellAbility().addMode(new Mode(new CreateTokenEffect(new CitizenGreenWhiteToken(), 2))); + } + + private CabarettiCharm(final CabarettiCharm card) { + super(card); + } + + @Override + public CabarettiCharm copy() { + return new CabarettiCharm(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CabarettiConfluence.java b/Mage.Sets/src/mage/cards/c/CabarettiConfluence.java new file mode 100644 index 00000000000..fa890c72189 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CabarettiConfluence.java @@ -0,0 +1,96 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.HasteAbility; +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.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CabarettiConfluence extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(TargetController.SOURCE_TARGETS.getControllerPredicate()); + } + + public CabarettiConfluence(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}{G}{W}"); + + // 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); + + // • Create a token that's a copy of target creature you control. It gains haste. Sacrifice it at the beginning of the next end step. + this.getSpellAbility().addEffect(new CabarettiConfluenceEffect()); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + + // • Exile target artifact or enchantment. + this.getSpellAbility().addMode(new Mode(new ExileTargetEffect()) + .addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT))); + + // • Creatures target player controls gets +1/+1 and gain first strike until end of turn. + this.getSpellAbility().addMode(new Mode(new BoostAllEffect( + 1, 1, Duration.EndOfTurn, filter, false + ).setText("creatures target player controls gets +1/+1")).addEffect(new GainAbilityAllEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn, filter + ).setText("and gain first strike until end of turn"))); + } + + private CabarettiConfluence(final CabarettiConfluence card) { + super(card); + } + + @Override + public CabarettiConfluence copy() { + return new CabarettiConfluence(this); + } +} + +class CabarettiConfluenceEffect extends OneShotEffect { + + CabarettiConfluenceEffect() { + super(Outcome.Benefit); + staticText = "create a token that's a copy of target creature you control. " + + "It gains haste. Sacrifice it at the beginning of the next end step"; + } + + private CabarettiConfluenceEffect(final CabarettiConfluenceEffect effect) { + super(effect); + } + + @Override + public CabarettiConfluenceEffect copy() { + return new CabarettiConfluenceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(); + effect.addAdditionalAbilities(HasteAbility.getInstance()); + effect.apply(game, source); + effect.sacrificeTokensCreatedAtNextEndStep(game, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CabarettiCourtyard.java b/Mage.Sets/src/mage/cards/c/CabarettiCourtyard.java new file mode 100644 index 00000000000..bad2a9c30b3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CabarettiCourtyard.java @@ -0,0 +1,57 @@ +package mage.cards.c; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.effects.common.DoWhenCostPaid; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CabarettiCourtyard extends CardImpl { + + private static final FilterCard filter = new FilterCard("a basic Mountain, Forest, or Plains card"); + + static { + filter.add(SuperType.BASIC.getPredicate()); + filter.add(Predicates.or( + SubType.MOUNTAIN.getPredicate(), + SubType.FOREST.getPredicate(), + SubType.PLAINS.getPredicate() + )); + } + + public CabarettiCourtyard(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // When Cabaretti Courtyard enters the battlefield, sacrifice it. When you do, search your library for a basic Mountain, Forest, or Plains card, put it onto the battlefield tapped, then shuffle and you gain 1 life. + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new SearchLibraryPutInPlayEffect( + new TargetCardInLibrary(filter), true, true + ), false); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DoWhenCostPaid( + ability, new SacrificeSourceCost().setText("sacrifice it"), null, false + ))); + } + + private CabarettiCourtyard(final CabarettiCourtyard card) { + super(card); + } + + @Override + public CabarettiCourtyard copy() { + return new CabarettiCourtyard(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CabarettiInitiate.java b/Mage.Sets/src/mage/cards/c/CabarettiInitiate.java new file mode 100644 index 00000000000..7453afb9b42 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CabarettiInitiate.java @@ -0,0 +1,43 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CabarettiInitiate extends CardImpl { + + public CabarettiInitiate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); + + this.subtype.add(SubType.RACCOON); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // {2}{R/W}: Cabaretti Initiate gains double strike until end of turn. + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + DoubleStrikeAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl<>("{2}{R/W}"))); + } + + private CabarettiInitiate(final CabarettiInitiate card) { + super(card); + } + + @Override + public CabarettiInitiate copy() { + return new CabarettiInitiate(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CadaverImp.java b/Mage.Sets/src/mage/cards/c/CadaverImp.java index afd2a85f3c7..2d833bb8e4b 100644 --- a/Mage.Sets/src/mage/cards/c/CadaverImp.java +++ b/Mage.Sets/src/mage/cards/c/CadaverImp.java @@ -1,11 +1,9 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -14,8 +12,9 @@ import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author North */ public final class CadaverImp extends CardImpl { @@ -31,10 +30,9 @@ public final class CadaverImp extends CardImpl { 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 ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), true); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); - } private CadaverImp(final CadaverImp card) { diff --git a/Mage.Sets/src/mage/cards/c/CagedSun.java b/Mage.Sets/src/mage/cards/c/CagedSun.java index ae35a28088f..302ebe401ba 100644 --- a/Mage.Sets/src/mage/cards/c/CagedSun.java +++ b/Mage.Sets/src/mage/cards/c/CagedSun.java @@ -87,7 +87,7 @@ class CagedSunEffect2 extends ContinuousEffectImpl { class CagedSunTriggeredAbility extends TriggeredManaAbility { - private static final String staticText = "Whenever a land's ability adds one or more mana of the chosen color, add one additional mana of that color."; + private static final String staticText = "Whenever a land's ability causes you to add one or more mana of the chosen color, add one additional mana of that color."; public CagedSunTriggeredAbility() { super(Zone.BATTLEFIELD, new CagedSunEffect()); diff --git a/Mage.Sets/src/mage/cards/c/CaldaiaGuardian.java b/Mage.Sets/src/mage/cards/c/CaldaiaGuardian.java new file mode 100644 index 00000000000..497a0b66c23 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CaldaiaGuardian.java @@ -0,0 +1,56 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.DiesThisOrAnotherCreatureTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.BlitzAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.permanent.token.CitizenGreenWhiteToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CaldaiaGuardian extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature you control with mana value 4 or greater"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 3)); + } + + public CaldaiaGuardian(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Whenever Caldaia Guardian or another creature you control with mana value 4 or greater dies, create two 1/1 green and white Citizen creature tokens. + this.addAbility(new DiesThisOrAnotherCreatureTriggeredAbility( + new CreateTokenEffect(new CitizenGreenWhiteToken(), 2), false, filter + )); + + // Blitz {2}{G} + this.addAbility(new BlitzAbility(this, "{2}{G}")); + } + + private CaldaiaGuardian(final CaldaiaGuardian card) { + super(card); + } + + @Override + public CaldaiaGuardian copy() { + return new CaldaiaGuardian(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CaldaiaStrongarm.java b/Mage.Sets/src/mage/cards/c/CaldaiaStrongarm.java new file mode 100644 index 00000000000..37c27101c57 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CaldaiaStrongarm.java @@ -0,0 +1,49 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.BlitzAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CaldaiaStrongarm extends CardImpl { + + public CaldaiaStrongarm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // When Caldaia Strongarm enters the battlefield, put two +1/+1 counters on target creature. + Ability ability = new EntersBattlefieldTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)) + ); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + // Blitz {3}{G} + this.addAbility(new BlitzAbility(this, "{3}{G}")); + } + + private CaldaiaStrongarm(final CaldaiaStrongarm card) { + super(card); + } + + @Override + public CaldaiaStrongarm copy() { + return new CaldaiaStrongarm(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CalixDestinysHand.java b/Mage.Sets/src/mage/cards/c/CalixDestinysHand.java index 13460df08d4..15c7c64dc28 100644 --- a/Mage.Sets/src/mage/cards/c/CalixDestinysHand.java +++ b/Mage.Sets/src/mage/cards/c/CalixDestinysHand.java @@ -4,10 +4,10 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -55,14 +55,13 @@ public final class CalixDestinysHand extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CALIX); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); - // +1: Look at the top four cards of your library. You may reveal an enchantment card from among them and put that card into your hand. Put the rest on the bottom of your library in a random order. + // +1: Look at the top four cards of your library. You may reveal an enchantment card from among them and put that card into your hand. + // Put the rest on the bottom of your library in a random order. this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(1), filter, - Zone.LIBRARY, false, true, false, - Zone.HAND, true, false, false - ).setBackInRandomOrder(true).setText("Look at the top four cards of your library. " + 4, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM + ).setText("Look at the top four cards of your library. " + "You may reveal an enchantment card from among them and put that card into your hand. " + "Put the rest on the bottom of your library in a random order."), 1 )); diff --git a/Mage.Sets/src/mage/cards/c/CallForBlood.java b/Mage.Sets/src/mage/cards/c/CallForBlood.java index bf8bf7d9c30..3f2eafcd776 100644 --- a/Mage.Sets/src/mage/cards/c/CallForBlood.java +++ b/Mage.Sets/src/mage/cards/c/CallForBlood.java @@ -1,23 +1,17 @@ - package mage.cards.c; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.costs.Cost; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.effects.Effect; +import mage.abilities.dynamicvalue.common.SacrificeCostCreaturesPower; +import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; -import mage.game.Game; -import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; @@ -27,14 +21,15 @@ import mage.target.common.TargetCreaturePermanent; */ public final class CallForBlood extends CardImpl { + private static final DynamicValue xValue = new SignInversionDynamicValue(SacrificeCostCreaturesPower.instance, false); + public CallForBlood(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{B}"); this.subtype.add(SubType.ARCANE); - // As an additional cost to cast Call for Blood, sacrifice a creature. + // As an additional cost to cast this spell, sacrifice a creature. this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); // Target creature gets -X/-X until end of turn, where X is the sacrificed creature's power. - DynamicValue xValue = new CallForBloodDynamicValue(); this.getSpellAbility().addEffect(new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn, true)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); @@ -49,37 +44,3 @@ public final class CallForBlood extends CardImpl { return new CallForBlood(this); } } - -class CallForBloodDynamicValue implements DynamicValue { - - @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - Card sourceCard = game.getCard(sourceAbility.getSourceId()); - if (sourceCard != null) { - for (Cost cost : sourceAbility.getCosts()) { - if (cost instanceof SacrificeTargetCost) { - Permanent p = (Permanent) game.getLastKnownInformation(((SacrificeTargetCost) cost).getPermanents().get(0).getId(), Zone.BATTLEFIELD); - if (p != null) { - return -1 * p.getPower().getValue(); - } - } - } - } - return 0; - } - - @Override - public CallForBloodDynamicValue copy() { - return this; - } - - @Override - public String getMessage() { - return ", where X is the sacrificed creature's power"; - } - - @Override - public String toString() { - return "-X"; - } -} diff --git a/Mage.Sets/src/mage/cards/c/CallInAProfessional.java b/Mage.Sets/src/mage/cards/c/CallInAProfessional.java new file mode 100644 index 00000000000..ab5af6a9c77 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CallInAProfessional.java @@ -0,0 +1,39 @@ +package mage.cards.c; + +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.CantGainLifeAllEffect; +import mage.abilities.effects.common.continuous.DamageCantBePreventedEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CallInAProfessional extends CardImpl { + + public CallInAProfessional(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); + + // Players can't gain life this turn. Damage can't be prevented this turn. Call In a Professional deals 3 damage to any target. + this.getSpellAbility().addEffect(new CantGainLifeAllEffect(Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new DamageCantBePreventedEffect( + Duration.EndOfTurn, "Damage can't be prevented this turn", true, false + )); + this.getSpellAbility().addEffect(new DamageTargetEffect(3)); + this.getSpellAbility().addTarget(new TargetAnyTarget()); + } + + private CallInAProfessional(final CallInAProfessional card) { + super(card); + } + + @Override + public CallInAProfessional copy() { + return new CallInAProfessional(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CallOfTheDeathDweller.java b/Mage.Sets/src/mage/cards/c/CallOfTheDeathDweller.java index 583d2ad7fa5..37d72138912 100644 --- a/Mage.Sets/src/mage/cards/c/CallOfTheDeathDweller.java +++ b/Mage.Sets/src/mage/cards/c/CallOfTheDeathDweller.java @@ -96,7 +96,7 @@ class CallOfTheDeathDwellerEffect extends OneShotEffect { FilterPermanent filter = new FilterPermanent("creature to put a deathtouch counter on"); filter.add(Predicates.or(predicates)); Target target = new TargetPermanent(0, 1, filter, true); - if (player.choose(outcome, target, source.getSourceId(), game)) { + if (player.choose(outcome, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.addCounters(CounterType.DEATHTOUCH.createInstance(), source.getControllerId(), source, game); @@ -104,7 +104,7 @@ class CallOfTheDeathDwellerEffect extends OneShotEffect { } filter.setMessage("creature to put a menace counter on"); target = new TargetPermanent(0, 1, filter, true); - if (player.choose(outcome, target, source.getSourceId(), game)) { + if (player.choose(outcome, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.addCounters(CounterType.MENACE.createInstance(), source.getControllerId(), source, game); diff --git a/Mage.Sets/src/mage/cards/c/CallTheCoppercoats.java b/Mage.Sets/src/mage/cards/c/CallTheCoppercoats.java index 76273b96462..456ab584b5c 100644 --- a/Mage.Sets/src/mage/cards/c/CallTheCoppercoats.java +++ b/Mage.Sets/src/mage/cards/c/CallTheCoppercoats.java @@ -53,7 +53,7 @@ class CallTheCoppercoatsEffect extends OneShotEffect { CallTheCoppercoatsEffect() { super(Outcome.Benefit); - staticText = "Choose any number of target opponents. Create X 1/1 white Human soldier creature tokens, " + + staticText = "Choose any number of target opponents. Create X 1/1 white Human Soldier creature tokens, " + "where X is the number of creatures those opponents control."; } diff --git a/Mage.Sets/src/mage/cards/c/CallToMind.java b/Mage.Sets/src/mage/cards/c/CallToMind.java index 70f254a9447..5e3dd5fa281 100644 --- a/Mage.Sets/src/mage/cards/c/CallToMind.java +++ b/Mage.Sets/src/mage/cards/c/CallToMind.java @@ -1,6 +1,6 @@ package mage.cards.c; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -18,7 +18,7 @@ public final class CallToMind extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}"); // Return target instant or sorcery card from your graveyard to your hand. - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); } diff --git a/Mage.Sets/src/mage/cards/c/CallToTheNetherworld.java b/Mage.Sets/src/mage/cards/c/CallToTheNetherworld.java index 75e4751e4a8..c958f67ac5e 100644 --- a/Mage.Sets/src/mage/cards/c/CallToTheNetherworld.java +++ b/Mage.Sets/src/mage/cards/c/CallToTheNetherworld.java @@ -1,10 +1,8 @@ - package mage.cards.c; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.MadnessAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -13,26 +11,27 @@ import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author nigelzor */ public final class CallToTheNetherworld extends CardImpl { - private static FilterCreatureCard filter = new FilterCreatureCard("black creature card from your graveyard"); + private static final FilterCreatureCard filter = new FilterCreatureCard("black creature card from your graveyard"); static { filter.add(new ColorPredicate(ObjectColor.BLACK)); } public CallToTheNetherworld(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); // Return target black creature card from your graveyard to your hand. this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); // Madness {0} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{0}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{0}"))); } private CallToTheNetherworld(final CallToTheNetherworld card) { diff --git a/Mage.Sets/src/mage/cards/c/CallerOfTheHunt.java b/Mage.Sets/src/mage/cards/c/CallerOfTheHunt.java index 6a10b85f2b3..4787e7c7c98 100644 --- a/Mage.Sets/src/mage/cards/c/CallerOfTheHunt.java +++ b/Mage.Sets/src/mage/cards/c/CallerOfTheHunt.java @@ -138,7 +138,7 @@ class ChooseCreatureTypeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); Choice typeChoice = new ChoiceCreatureType(mageObject); if (controller != null && mageObject != null diff --git a/Mage.Sets/src/mage/cards/c/CallousOppressor.java b/Mage.Sets/src/mage/cards/c/CallousOppressor.java index 35cdfca8e54..49d13865bd9 100644 --- a/Mage.Sets/src/mage/cards/c/CallousOppressor.java +++ b/Mage.Sets/src/mage/cards/c/CallousOppressor.java @@ -84,9 +84,9 @@ class CallousOppressorFilter extends FilterCreaturePermanent { } @Override - public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { - if (super.match(permanent, sourceId, playerId, game)) { - SubType subtype = (SubType) game.getState().getValue(sourceId + "_type"); + public boolean match(Permanent permanent, UUID playerId, Ability source, Game game) { + if (super.match(permanent, playerId, source, game)) { + SubType subtype = (SubType) game.getState().getValue(source.getSourceId() + "_type"); if (subtype != null && permanent.hasSubtype(subtype, game)) { return false; } @@ -113,12 +113,12 @@ class CallousOppressorChooseCreatureTypeEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } if (controller != null) { TargetOpponent target = new TargetOpponent(true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - while (!target.isChosen() && target.canChoose(source.getSourceId(), controller.getId(), game) && controller.canRespond()) { + if (target.canChoose(controller.getId(), source, game)) { + while (!target.isChosen() && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target, source, game); } } else { diff --git a/Mage.Sets/src/mage/cards/c/CalmingVerse.java b/Mage.Sets/src/mage/cards/c/CalmingVerse.java index 04653e31979..e00451c3fb4 100644 --- a/Mage.Sets/src/mage/cards/c/CalmingVerse.java +++ b/Mage.Sets/src/mage/cards/c/CalmingVerse.java @@ -75,7 +75,7 @@ class CalmingVerseEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { // Destroy all other enchantments - for (Permanent permanent : game.getBattlefield().getActivePermanents(opponentEnchantmentsFilter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(opponentEnchantmentsFilter, source.getControllerId(), source, game)) { permanent.destroy(source, game, false); } @@ -84,7 +84,7 @@ class CalmingVerseEffect extends OneShotEffect { if (controller != null) { if (game.getState().getBattlefield().countAll(untappedLandFilter, controller.getId(), game) > 0) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(controlledEnchantmentsFilter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(controlledEnchantmentsFilter, source.getControllerId(), source, game)) { permanent.destroy(source, game, false); } } diff --git a/Mage.Sets/src/mage/cards/c/Camaraderie.java b/Mage.Sets/src/mage/cards/c/Camaraderie.java index f5a43597849..8eea5f8f722 100644 --- a/Mage.Sets/src/mage/cards/c/Camaraderie.java +++ b/Mage.Sets/src/mage/cards/c/Camaraderie.java @@ -64,7 +64,7 @@ class CamaraderieEffect extends OneShotEffect { } int xValue = game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getSourceId(), source.getControllerId(), game + source.getControllerId(), source, game ); player.gainLife(xValue, game, source); player.drawCards(xValue, source, game); diff --git a/Mage.Sets/src/mage/cards/c/Camouflage.java b/Mage.Sets/src/mage/cards/c/Camouflage.java index 0d21c27c13b..d9728714b12 100644 --- a/Mage.Sets/src/mage/cards/c/Camouflage.java +++ b/Mage.Sets/src/mage/cards/c/Camouflage.java @@ -117,7 +117,7 @@ class CamouflageEffect extends ContinuousRuleModifyingEffectImpl { } if (defender.chooseUse(Outcome.Neutral, "Make a new blocker pile? If not, all remaining piles stay empty. (remaining piles: " + (attackerCount - masterList.size()) + ')', source, game)) { Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true); - if (target.canChoose(source.getSourceId(), defenderId, game)) { + if (target.canChoose(defenderId, source, game)) { if (defender.chooseTarget(Outcome.Neutral, target, source, game)) { for (UUID creatureId : target.getTargets()) { Permanent creature = game.getPermanent(creatureId); diff --git a/Mage.Sets/src/mage/cards/c/CandlesOfLeng.java b/Mage.Sets/src/mage/cards/c/CandlesOfLeng.java index 45739de5709..449abacaec9 100644 --- a/Mage.Sets/src/mage/cards/c/CandlesOfLeng.java +++ b/Mage.Sets/src/mage/cards/c/CandlesOfLeng.java @@ -62,7 +62,7 @@ class CandlesOfLengEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if(controller == null || sourceObject == null){ return false; } diff --git a/Mage.Sets/src/mage/cards/c/CankerAbomination.java b/Mage.Sets/src/mage/cards/c/CankerAbomination.java index 5129e0b0273..7b2fdce35e8 100644 --- a/Mage.Sets/src/mage/cards/c/CankerAbomination.java +++ b/Mage.Sets/src/mage/cards/c/CankerAbomination.java @@ -72,7 +72,7 @@ class CankerAbominationEffect extends OneShotEffect { if (controller != null && cankerAbomination != null) { Target target = new TargetOpponent(); target.setNotTarget(true); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); Player opponent = game.getPlayer(target.getFirstTarget()); if (opponent != null) { game.informPlayers(cankerAbomination.getName() + ": " + controller.getLogName() + " has chosen " + opponent.getLogName()); diff --git a/Mage.Sets/src/mage/cards/c/CankerousThirst.java b/Mage.Sets/src/mage/cards/c/CankerousThirst.java index ea3a3e04aa1..0bbf88c19bc 100644 --- a/Mage.Sets/src/mage/cards/c/CankerousThirst.java +++ b/Mage.Sets/src/mage/cards/c/CankerousThirst.java @@ -52,7 +52,7 @@ class CankerousThirstEffect extends OneShotEffect { public CankerousThirstEffect() { super(Outcome.Benefit); - this.staticText = "If {B} was spent to cast {this}, you may have target creature get -3/-3 until end of turn. If {G} was spent to cast this spell, you may have target creature get +3/+3 until end of turn"; + this.staticText = "If {B} was spent to cast this spell, you may have target creature get -3/-3 until end of turn. If {G} was spent to cast this spell, you may have target creature get +3/+3 until end of turn"; } public CankerousThirstEffect(final CankerousThirstEffect effect) { diff --git a/Mage.Sets/src/mage/cards/c/Cannibalize.java b/Mage.Sets/src/mage/cards/c/Cannibalize.java index 60c47cc4638..4d6fc737bae 100644 --- a/Mage.Sets/src/mage/cards/c/Cannibalize.java +++ b/Mage.Sets/src/mage/cards/c/Cannibalize.java @@ -1,8 +1,5 @@ - package mage.cards.c; -import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -11,14 +8,17 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.counters.CounterType; -import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanentSameController; +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; + /** - * * @author LevelX2 */ public final class Cannibalize extends CardImpl { @@ -28,7 +28,7 @@ public final class Cannibalize extends CardImpl { // Choose two target creatures controlled by the same player. Exile one of the creatures and put two +1/+1 counters on the other. this.getSpellAbility().addEffect(new CannibalizeEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanentSameController(2, 2, StaticFilters.FILTER_PERMANENT_CREATURE, false)); + this.getSpellAbility().addTarget(new TargetCreaturePermanentSameController(2)); } private Cannibalize(final Cannibalize card) { @@ -45,7 +45,8 @@ class CannibalizeEffect extends OneShotEffect { public CannibalizeEffect() { super(Outcome.Benefit); - this.staticText = "Choose two target creatures controlled by the same player. Exile one of the creatures and put two +1/+1 counters on the other"; + this.staticText = "Choose two target creatures controlled by the same player. " + + "Exile one of the creatures and put two +1/+1 counters on the other"; } public CannibalizeEffect(final CannibalizeEffect effect) { @@ -59,27 +60,48 @@ class CannibalizeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { - boolean exileDone = false; - int count = 0; - for (UUID targetId : getTargetPointer().getTargets(game, source)) { - Permanent creature = game.getPermanent(targetId); - if (creature != null) { - if ((count == 0 && controller.chooseUse(Outcome.Exile, "Exile " + creature.getLogName() + '?', source, game)) - || (count == 1 && !exileDone)) { - controller.moveCardToExileWithInfo(creature, null, "", source, game, Zone.BATTLEFIELD, true); - exileDone = true; - } else { - creature.addCounters(CounterType.P1P1.createInstance(2), source.getControllerId(), source, game); - game.informPlayers("Added two +1/+1 counters on " + creature.getLogName()); - } - count++; - } - } - return true; + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; } - return false; + List permanents = this + .getTargetPointer() + .getTargets(game, source) + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + switch (permanents.size()) { + case 0: + return false; + case 1: + Permanent permanent = permanents.get(0); + if (player.chooseUse( + outcome, "Exile " + permanent.getIdName() + + " or put two +1/+1 counters on it?", null, + "Exile", "Add counters", source, game + )) { + player.moveCards(permanent, Zone.EXILED, source, game); + } else { + permanent.addCounters(CounterType.P1P1.createInstance(2), source, game); + } + return true; + } + Permanent permanent1 = permanents.get(0); + Permanent permanent2 = permanents.get(1); + if (player.chooseUse( + outcome, "Exile " + permanent1.getIdName() + + " or " + permanent2.getIdName() + '?', + "The other creature will get two +1/+1 counters", + "Exile " + permanent1.getIdName(), + "Exile " + permanent2.getIdName(), source, game + )) { + player.moveCards(permanent1, Zone.EXILED, source, game); + permanent2.addCounters(CounterType.P1P1.createInstance(2), source, game); + } else { + player.moveCards(permanent2, Zone.EXILED, source, game); + permanent1.addCounters(CounterType.P1P1.createInstance(2), source, game); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/c/CanyonLurkers.java b/Mage.Sets/src/mage/cards/c/CanyonLurkers.java index 167befb3d3e..7bfeb186bac 100644 --- a/Mage.Sets/src/mage/cards/c/CanyonLurkers.java +++ b/Mage.Sets/src/mage/cards/c/CanyonLurkers.java @@ -25,7 +25,7 @@ public final class CanyonLurkers extends CardImpl { this.toughness = new MageInt(2); // Morph 3R - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{R}"))); } private CanyonLurkers(final CanyonLurkers card) { diff --git a/Mage.Sets/src/mage/cards/c/CapennaExpress.java b/Mage.Sets/src/mage/cards/c/CapennaExpress.java new file mode 100644 index 00000000000..10bad4bdfa1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CapennaExpress.java @@ -0,0 +1,48 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect; +import mage.abilities.keyword.CrewAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CapennaExpress extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.TREASURE, "Treasure"); + + public CapennaExpress(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}{G}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Sacrifice a Treasure: Capenna Express becomes an artifact creature until end of turn. + this.addAbility(new SimpleActivatedAbility(new AddCardTypeSourceEffect( + Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE + ), new SacrificeTargetCost(filter))); + + // Crew 3 + this.addAbility(new CrewAbility(3)); + } + + private CapennaExpress(final CapennaExpress card) { + super(card); + } + + @Override + public CapennaExpress copy() { + return new CapennaExpress(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/Capricopian.java b/Mage.Sets/src/mage/cards/c/Capricopian.java index 521a3696a6f..92c0fb04b2b 100644 --- a/Mage.Sets/src/mage/cards/c/Capricopian.java +++ b/Mage.Sets/src/mage/cards/c/Capricopian.java @@ -117,7 +117,7 @@ class CapricopianEffect extends OneShotEffect { filterPlayer.add(Predicates.not(new PlayerIdPredicate(permanent.getControllerId()))); filterPlayer.add(Predicates.not(new PlayerIdPredicate(game.getCombat().getDefenderId(permanent.getId())))); TargetPlayer targetPlayer = new TargetPlayer(0, 1, true, filterPlayer); - player.choose(outcome, targetPlayer, source.getSourceId(), game); + player.choose(outcome, targetPlayer, source, game); Player newPlayer = game.getPlayer(targetPlayer.getFirstTarget()); if (newPlayer == null) { return false; diff --git a/Mage.Sets/src/mage/cards/c/CaptainOfTheWatch.java b/Mage.Sets/src/mage/cards/c/CaptainOfTheWatch.java index 1e6c89a9462..cb15f652a20 100644 --- a/Mage.Sets/src/mage/cards/c/CaptainOfTheWatch.java +++ b/Mage.Sets/src/mage/cards/c/CaptainOfTheWatch.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -15,33 +13,43 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.game.permanent.token.SoldierToken; +import java.util.UUID; + /** * @author Loki */ public final class CaptainOfTheWatch extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Soldier creatures"); - - static { - filter.add(SubType.SOLDIER.getPredicate()); - } + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent(SubType.SOLDIER, "Soldier creatures"); public CaptainOfTheWatch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); this.power = new MageInt(3); this.toughness = new MageInt(3); + + // Vigilance this.addAbility(VigilanceAbility.getInstance()); - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filter, true)); - ability.addEffect(new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, filter, true)); + + // Other Soldier creatures you control get +1/+1 and have vigilance. + Ability ability = new SimpleStaticAbility(new BoostControlledEffect( + 1, 1, Duration.WhileOnBattlefield, filter, true + )); + ability.addEffect(new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, filter, true + ).setText("and have vigilance")); this.addAbility(ability); - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new SoldierToken(), 3), false)); + + // When Captain of the Watch enters the battlefield, create three 1/1 white Soldier creature tokens. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new CreateTokenEffect(new SoldierToken(), 3), false + )); } private CaptainOfTheWatch(final CaptainOfTheWatch card) { diff --git a/Mage.Sets/src/mage/cards/c/CarpetOfFlowers.java b/Mage.Sets/src/mage/cards/c/CarpetOfFlowers.java index bb5dcc74be4..c66f8e7cd87 100644 --- a/Mage.Sets/src/mage/cards/c/CarpetOfFlowers.java +++ b/Mage.Sets/src/mage/cards/c/CarpetOfFlowers.java @@ -14,7 +14,6 @@ import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.players.Player; import mage.target.common.TargetOpponent; @@ -120,7 +119,7 @@ class CarpetOfFlowersEffect extends ManaEffect { CarpetOfFlowersEffect() { super(); - staticText = "add X mana of any one color, where X is the number of Islands target opponent controls"; + staticText = "you may add X mana of any one color, where X is the number of Islands target opponent controls"; } CarpetOfFlowersEffect(final CarpetOfFlowersEffect effect) { @@ -131,7 +130,7 @@ class CarpetOfFlowersEffect extends ManaEffect { public List getNetMana(Game game, Ability source) { List netMana = new ArrayList<>(); if (game != null) { - int count = game.getBattlefield().count(filter, source.getSourceId(), source.getTargets().getFirstTarget(), game); + int count = game.getBattlefield().count(filter, source.getTargets().getFirstTarget(), source, game); if (count > 0) { netMana.add(Mana.AnyMana(count)); } @@ -148,7 +147,7 @@ class CarpetOfFlowersEffect extends ManaEffect { Player controller = game.getPlayer(source.getControllerId()); ChoiceColor choice = new ChoiceColor(); if (controller != null && controller.choose(Outcome.Benefit, choice, game)) { - int count = game.getBattlefield().count(filter, source.getSourceId(), source.getTargets().getFirstTarget(), game); + int count = game.getBattlefield().count(filter, source.getTargets().getFirstTarget(), source, game); if (count > 0) { switch (choice.getChoice()) { case "Black": diff --git a/Mage.Sets/src/mage/cards/c/CarrionThrash.java b/Mage.Sets/src/mage/cards/c/CarrionThrash.java index 2b48d62e814..b030aabaced 100644 --- a/Mage.Sets/src/mage/cards/c/CarrionThrash.java +++ b/Mage.Sets/src/mage/cards/c/CarrionThrash.java @@ -1,30 +1,30 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author North */ public final class CarrionThrash extends CardImpl { - private static final FilterCreatureCard filter = new FilterCreatureCard("another creature card from your graveyard"); + private static final FilterCreatureCard filter = new FilterCreatureCard("another target creature card from your graveyard"); static { - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); } public CarrionThrash(UUID ownerId, CardSetInfo setInfo) { @@ -36,7 +36,7 @@ public final class CarrionThrash extends CardImpl { this.toughness = new MageInt(4); // When Carrion Thrash dies, you may pay {2}. If you do, return another target creature card from your graveyard to your hand. - DiesSourceTriggeredAbility ability = new DiesSourceTriggeredAbility(new DoIfCostPaid(new ReturnToHandTargetEffect(), new GenericManaCost(2)), false); + DiesSourceTriggeredAbility ability = new DiesSourceTriggeredAbility(new DoIfCostPaid(new ReturnFromGraveyardToHandTargetEffect(), new GenericManaCost(2)), false); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CarthTheLion.java b/Mage.Sets/src/mage/cards/c/CarthTheLion.java index aafed85ddf8..0cf232a649d 100644 --- a/Mage.Sets/src/mage/cards/c/CarthTheLion.java +++ b/Mage.Sets/src/mage/cards/c/CarthTheLion.java @@ -7,6 +7,7 @@ import mage.abilities.LoyaltyAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.constants.*; import mage.cards.CardImpl; @@ -56,9 +57,7 @@ class CarthTheLionTriggeredAbility extends TriggeredAbilityImpl { public CarthTheLionTriggeredAbility() { super(Zone.BATTLEFIELD, new LookLibraryAndPickControllerEffect( - 7, 1, filter, true, false, Zone.HAND, true) - .setBackInRandomOrder(true) - ); + 7, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM)); } private CarthTheLionTriggeredAbility(final CarthTheLionTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/c/CartographersSurvey.java b/Mage.Sets/src/mage/cards/c/CartographersSurvey.java index 3e4989f9623..47b0cfb460d 100644 --- a/Mage.Sets/src/mage/cards/c/CartographersSurvey.java +++ b/Mage.Sets/src/mage/cards/c/CartographersSurvey.java @@ -2,20 +2,12 @@ package mage.cards.c; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.common.LookLibraryControllerEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; /** * @@ -27,7 +19,8 @@ public final class CartographersSurvey extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}"); // Look at the top seven cards of your library. Put up to two land cards from among them onto the battlefield tapped. Put the rest on the bottom of your library in a random order. - this.getSpellAbility().addEffect(new CartographersSurveyEffect()); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + 7, 2, StaticFilters.FILTER_CARD_LANDS, PutCards.BATTLEFIELD_TAPPED, PutCards.BOTTOM_RANDOM, false)); } private CartographersSurvey(final CartographersSurvey card) { @@ -39,35 +32,3 @@ public final class CartographersSurvey extends CardImpl { return new CartographersSurvey(this); } } - -class CartographersSurveyEffect extends LookLibraryControllerEffect { - - public CartographersSurveyEffect() { - super(Outcome.PutLandInPlay, StaticValue.get(7), false, Zone.LIBRARY, false); - this.setBackInRandomOrder(true); - staticText = "Look at the top seven cards of your library. Put up to two land cards from among them onto the battlefield tapped. Put the rest on the bottom of your library in a random order"; - } - - private CartographersSurveyEffect(final CartographersSurveyEffect effect) { - super(effect); - } - - @Override - public CartographersSurveyEffect copy() { - return new CartographersSurveyEffect(this); - } - - @Override - protected void actionWithSelectedCards(Cards cards, Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - TargetCard target = new TargetCard(0, 2, Zone.LIBRARY, StaticFilters.FILTER_CARD_LANDS); - controller.choose(outcome, cards, target, game); - Cards pickedCards = new CardsImpl(target.getTargets()); - if (!pickedCards.isEmpty()) { - cards.removeAll(pickedCards); - controller.moveCards(pickedCards.getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null); - } - } - } -} diff --git a/Mage.Sets/src/mage/cards/c/CaseTheJoint.java b/Mage.Sets/src/mage/cards/c/CaseTheJoint.java new file mode 100644 index 00000000000..c8d8ad8d518 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CaseTheJoint.java @@ -0,0 +1,75 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CaseTheJoint extends CardImpl { + + public CaseTheJoint(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}"); + + // Draw two cards, then look at the top card of each player's library. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); + this.getSpellAbility().addEffect(new CaseTheJointEffect()); + } + + private CaseTheJoint(final CaseTheJoint card) { + super(card); + } + + @Override + public CaseTheJoint copy() { + return new CaseTheJoint(this); + } +} + +class CaseTheJointEffect extends OneShotEffect { + + CaseTheJointEffect() { + super(Outcome.Benefit); + staticText = ", then look at the top card of each player's library"; + } + + private CaseTheJointEffect(final CaseTheJointEffect effect) { + super(effect); + } + + @Override + public CaseTheJointEffect copy() { + return new CaseTheJointEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + continue; + } + Card card = player.getLibrary().getFromTop(game); + if (card == null) { + continue; + } + controller.lookAtCards(source, "Top card of " + player.getName() + "'s library", new CardsImpl(card), game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CastleGarenbrig.java b/Mage.Sets/src/mage/cards/c/CastleGarenbrig.java index b97b7bd31fa..e2ebf923851 100644 --- a/Mage.Sets/src/mage/cards/c/CastleGarenbrig.java +++ b/Mage.Sets/src/mage/cards/c/CastleGarenbrig.java @@ -90,7 +90,7 @@ enum CastleGarenbrigManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object != null && object.isCreature(game)) { return true; } diff --git a/Mage.Sets/src/mage/cards/c/Cataclysm.java b/Mage.Sets/src/mage/cards/c/Cataclysm.java index df46dd71517..e307076e49d 100644 --- a/Mage.Sets/src/mage/cards/c/Cataclysm.java +++ b/Mage.Sets/src/mage/cards/c/Cataclysm.java @@ -67,8 +67,8 @@ class CataclysmEffect extends OneShotEffect { Target target3 = new TargetControlledPermanent(1, 1, new FilterControlledEnchantmentPermanent(), true); Target target4 = new TargetControlledPermanent(1, 1, new FilterControlledLandPermanent(), true); - if (target1.canChoose(source.getSourceId(), player.getId(), game)) { - while (player.canRespond() && !target1.isChosen() && target1.canChoose(source.getSourceId(), player.getId(), game)) { + if (target1.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target1.isChosen() && target1.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target1, source, game); } Permanent artifact = game.getPermanent(target1.getFirstTarget()); @@ -78,8 +78,8 @@ class CataclysmEffect extends OneShotEffect { target1.clearChosen(); } - if (target2.canChoose(source.getSourceId(), player.getId(), game)) { - while (player.canRespond() && !target2.isChosen() && target2.canChoose(source.getSourceId(), player.getId(), game)) { + if (target2.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target2.isChosen() && target2.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target2, source, game); } Permanent creature = game.getPermanent(target2.getFirstTarget()); @@ -89,8 +89,8 @@ class CataclysmEffect extends OneShotEffect { target2.clearChosen(); } - if (target3.canChoose(source.getSourceId(), player.getId(), game)) { - while (player.canRespond() && !target3.isChosen() && target3.canChoose(source.getSourceId(), player.getId(), game)) { + if (target3.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target3.isChosen() && target3.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target3, source, game); } Permanent enchantment = game.getPermanent(target3.getFirstTarget()); @@ -100,8 +100,8 @@ class CataclysmEffect extends OneShotEffect { target3.clearChosen(); } - if (target4.canChoose(source.getSourceId(), player.getId(), game)) { - while (player.canRespond() && !target4.isChosen() && target4.canChoose(source.getSourceId(), player.getId(), game)) { + if (target4.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target4.isChosen() && target4.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target4, source, game); } Permanent land = game.getPermanent(target4.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/c/CataclysmicGearhulk.java b/Mage.Sets/src/mage/cards/c/CataclysmicGearhulk.java index f86a5525c8c..57e82bd582b 100644 --- a/Mage.Sets/src/mage/cards/c/CataclysmicGearhulk.java +++ b/Mage.Sets/src/mage/cards/c/CataclysmicGearhulk.java @@ -100,8 +100,8 @@ class CataclysmicGearhulkEffect extends OneShotEffect { Target target3 = new TargetControlledPermanent(1, 1, filterEnchantment, true); Target target4 = new TargetControlledPermanent(1, 1, filterPlaneswalker, true); - if (target1.canChoose(source.getSourceId(), player.getId(), game)) { - while (player.canRespond() && !target1.isChosen() && target1.canChoose(source.getSourceId(), player.getId(), game)) { + if (target1.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target1.isChosen() && target1.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target1, source, game); } Permanent artifact = game.getPermanent(target1.getFirstTarget()); @@ -111,8 +111,8 @@ class CataclysmicGearhulkEffect extends OneShotEffect { target1.clearChosen(); } - if (target2.canChoose(source.getSourceId(), player.getId(), game)) { - while (player.canRespond() && !target2.isChosen() && target2.canChoose(source.getSourceId(), player.getId(), game)) { + if (target2.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target2.isChosen() && target2.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target2, source, game); } Permanent creature = game.getPermanent(target2.getFirstTarget()); @@ -122,8 +122,8 @@ class CataclysmicGearhulkEffect extends OneShotEffect { target2.clearChosen(); } - if (target3.canChoose(source.getSourceId(), player.getId(), game)) { - while (player.canRespond() && !target3.isChosen() && target3.canChoose(source.getSourceId(), player.getId(), game)) { + if (target3.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target3.isChosen() && target3.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target3, source, game); } Permanent enchantment = game.getPermanent(target3.getFirstTarget()); @@ -133,8 +133,8 @@ class CataclysmicGearhulkEffect extends OneShotEffect { target3.clearChosen(); } - if (target4.canChoose(source.getSourceId(), player.getId(), game)) { - while (player.canRespond() && !target4.isChosen() && target4.canChoose(source.getSourceId(), player.getId(), game)) { + if (target4.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target4.isChosen() && target4.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target4, source, game); } Permanent planeswalker = game.getPermanent(target4.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/c/Catastrophe.java b/Mage.Sets/src/mage/cards/c/Catastrophe.java index fb8ae17279d..74ef2af9065 100644 --- a/Mage.Sets/src/mage/cards/c/Catastrophe.java +++ b/Mage.Sets/src/mage/cards/c/Catastrophe.java @@ -58,11 +58,11 @@ class CatastropheEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { if (controller.chooseUse(outcome, "Destroy all lands? (otherwise all creatures are destroyed)", source, game)) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterLandPermanent(), controller.getId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterLandPermanent(), controller.getId(), source, game)) { permanent.destroy(source, game, permanent.isCreature(game)); } } else { - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), source, game)) { permanent.destroy(source, game, true); } } diff --git a/Mage.Sets/src/mage/cards/c/CatchRelease.java b/Mage.Sets/src/mage/cards/c/CatchRelease.java index 93024ebc137..a281c668697 100644 --- a/Mage.Sets/src/mage/cards/c/CatchRelease.java +++ b/Mage.Sets/src/mage/cards/c/CatchRelease.java @@ -86,8 +86,8 @@ class ReleaseSacrificeEffect extends OneShotEffect { Target target4 = new TargetControlledPermanent(1, 1, new FilterControlledLandPermanent(), true); Target target5 = new TargetControlledPermanent(1, 1, new FilterControlledPlaneswalkerPermanent(), true); - if (target1.canChoose(source.getSourceId(), player.getId(), game)) { - while (player.canRespond() && !target1.isChosen() && target1.canChoose(source.getSourceId(), player.getId(), game)) { + if (target1.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target1.isChosen() && target1.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target1, source, game); } Permanent artifact = game.getPermanent(target1.getFirstTarget()); @@ -97,8 +97,8 @@ class ReleaseSacrificeEffect extends OneShotEffect { target1.clearChosen(); } - if (target2.canChoose(source.getSourceId(), player.getId(), game)) { - while (player.canRespond() && !target2.isChosen() && target2.canChoose(source.getSourceId(), player.getId(), game)) { + if (target2.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target2.isChosen() && target2.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target2, source, game); } Permanent creature = game.getPermanent(target2.getFirstTarget()); @@ -108,8 +108,8 @@ class ReleaseSacrificeEffect extends OneShotEffect { target2.clearChosen(); } - if (target3.canChoose(source.getSourceId(), player.getId(), game)) { - while (player.canRespond() && !target3.isChosen() && target3.canChoose(source.getSourceId(), player.getId(), game)) { + if (target3.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target3.isChosen() && target3.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target3, source, game); } Permanent enchantment = game.getPermanent(target3.getFirstTarget()); @@ -119,8 +119,8 @@ class ReleaseSacrificeEffect extends OneShotEffect { target3.clearChosen(); } - if (target4.canChoose(source.getSourceId(), player.getId(), game)) { - while (player.canRespond() && !target4.isChosen() && target4.canChoose(source.getSourceId(), player.getId(), game)) { + if (target4.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target4.isChosen() && target4.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target4, source, game); } Permanent land = game.getPermanent(target4.getFirstTarget()); @@ -130,8 +130,8 @@ class ReleaseSacrificeEffect extends OneShotEffect { target4.clearChosen(); } - if (target5.canChoose(source.getSourceId(), player.getId(), game)) { - while (player.canRespond() && !target5.isChosen() && target5.canChoose(source.getSourceId(), player.getId(), game)) { + if (target5.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target5.isChosen() && target5.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target5, source, game); } Permanent planeswalker = game.getPermanent(target5.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/c/CaterwaulingBoggart.java b/Mage.Sets/src/mage/cards/c/CaterwaulingBoggart.java index 7e976c7b309..0fbf734337d 100644 --- a/Mage.Sets/src/mage/cards/c/CaterwaulingBoggart.java +++ b/Mage.Sets/src/mage/cards/c/CaterwaulingBoggart.java @@ -1,53 +1,45 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.MenaceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class CaterwaulingBoggart extends CardImpl { - private static final FilterPermanent filterGoblin = new FilterControlledCreaturePermanent("Goblin"); - private static final FilterPermanent filterElemental = new FilterControlledCreaturePermanent("Elemental"); + private static final FilterPermanent filter = new FilterPermanent("Goblins you control and Elementals"); static { - filterGoblin.add(SubType.GOBLIN.getPredicate()); - filterElemental.add(SubType.ELEMENTAL.getPredicate()); + filter.add(Predicates.or( + SubType.GOBLIN.getPredicate(), + SubType.ELEMENTAL.getPredicate() + )); } public CaterwaulingBoggart(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.SHAMAN); this.power = new MageInt(2); this.toughness = new MageInt(2); - // Each Goblin you control has menace. (They can't be blocked except by two or more creatures.) - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect( - new MenaceAbility(), - Duration.WhileOnBattlefield, filterGoblin, - "Each Goblin you control has menace. (They can't be blocked except by two or more creatures.)"))); - - // Each Elemental you control has menace. (They can't be blocked except by two or more creatures.) - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect( - new MenaceAbility(), - Duration.WhileOnBattlefield, filterElemental, - "Each Elemental you control has menace. (They can't be blocked except by two or more creatures.)"))); + // Goblins you control and Elementals you control have menace. + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new MenaceAbility(true), Duration.WhileOnBattlefield, filter + ))); } private CaterwaulingBoggart(final CaterwaulingBoggart card) { diff --git a/Mage.Sets/src/mage/cards/c/CaughtInTheBrights.java b/Mage.Sets/src/mage/cards/c/CaughtInTheBrights.java index 8a5e6d559d9..cb593ab1d96 100644 --- a/Mage.Sets/src/mage/cards/c/CaughtInTheBrights.java +++ b/Mage.Sets/src/mage/cards/c/CaughtInTheBrights.java @@ -44,7 +44,7 @@ public final class CaughtInTheBrights extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackBlockAttachedEffect(AttachmentType.AURA))); // When a Vehicle you control attacks, exile enchanted creature. - this.addAbility(new AttacksAllTriggeredAbility(new ExileAttachedEffect(), false, filter, SetTargetPointer.NONE, false)); + this.addAbility(new AttacksAllTriggeredAbility(new ExileAttachedEffect(), false, filter, SetTargetPointer.NONE, false).setTriggerPhrase("When a Vehicle you control attacks, ")); } private CaughtInTheBrights(final CaughtInTheBrights card) { diff --git a/Mage.Sets/src/mage/cards/c/CauldronDance.java b/Mage.Sets/src/mage/cards/c/CauldronDance.java index 035584db826..88c38e6fda9 100644 --- a/Mage.Sets/src/mage/cards/c/CauldronDance.java +++ b/Mage.Sets/src/mage/cards/c/CauldronDance.java @@ -119,7 +119,7 @@ class CauldronDancePutCreatureFromHandOntoBattlefieldEffect extends OneShotEffec if (controller != null) { if (controller.chooseUse(Outcome.PutCreatureInPlay, CHOICE_TEXT, source, game)) { TargetCardInHand target = new TargetCardInHand(StaticFilters.FILTER_CARD_CREATURE); - if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCreatureInPlay, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { diff --git a/Mage.Sets/src/mage/cards/c/CavalierOfThorns.java b/Mage.Sets/src/mage/cards/c/CavalierOfThorns.java index f6c56822f94..7277d9269f7 100644 --- a/Mage.Sets/src/mage/cards/c/CavalierOfThorns.java +++ b/Mage.Sets/src/mage/cards/c/CavalierOfThorns.java @@ -5,27 +5,24 @@ import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.costs.common.ExileSourceFromGraveCost; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.common.RevealLibraryPickControllerEffect; import mage.abilities.keyword.ReachAbility; -import mage.cards.*; +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.common.FilterLandCard; +import mage.filter.StaticFilters; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; /** - * @author TheElk801 + * @author awjackson */ public final class CavalierOfThorns extends CardImpl { @@ -46,8 +43,10 @@ public final class CavalierOfThorns extends CardImpl { // Reach this.addAbility(ReachAbility.getInstance()); - // When Cavalier of Thorns enters the battlefield, reveal the top five cards of your library. You may put a land card from among them onto the battlefield. Put the rest into your graveyard. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CavalierOfThornsEffect())); + // When Cavalier of Thorns enters the battlefield, reveal the top five cards of your library. + // Put a land card from among them onto the battlefield and the rest into your graveyard. + this.addAbility(new EntersBattlefieldTriggeredAbility(new RevealLibraryPickControllerEffect( + 5, 1, StaticFilters.FILTER_CARD_LAND_A, PutCards.BATTLEFIELD, PutCards.GRAVEYARD, false))); // When Cavalier of Thorns dies, you may exile it. If you do, put another target card from your graveyard on top of your library. Ability ability = new DiesSourceTriggeredAbility(new DoIfCostPaid( @@ -66,47 +65,3 @@ public final class CavalierOfThorns extends CardImpl { return new CavalierOfThorns(this); } } - -class CavalierOfThornsEffect extends OneShotEffect { - - private static final FilterCard filter = new FilterLandCard("land card to put on the battlefield"); - - CavalierOfThornsEffect() { - super(Outcome.PutCreatureInPlay); - this.staticText = "reveal the top five cards of your library. " + - "Put a land card from among them onto the battlefield and the rest into your graveyard."; - } - - private CavalierOfThornsEffect(final CavalierOfThornsEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5)); - if (cards.isEmpty()) { - return true; - } - controller.revealCards(source, cards, game); - TargetCard target = new TargetCard(1, 1, Zone.LIBRARY, filter); - if (cards.getCards(game).stream().anyMatch(card1 -> card1.isLand(game)) - && controller.choose(Outcome.PutCardInPlay, cards, target, game)) { - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - controller.moveCards(card, Zone.BATTLEFIELD, source, game); - } - } - controller.moveCards(cards, Zone.GRAVEYARD, source, game); - return true; - } - - @Override - public CavalierOfThornsEffect copy() { - return new CavalierOfThornsEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CaveIn.java b/Mage.Sets/src/mage/cards/c/CaveIn.java index 51d6cc315e9..ccccf8741c5 100644 --- a/Mage.Sets/src/mage/cards/c/CaveIn.java +++ b/Mage.Sets/src/mage/cards/c/CaveIn.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.costs.AlternativeCostSourceAbility; import mage.abilities.costs.common.ExileFromHandCost; @@ -10,27 +8,29 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterOwnedCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetCardInHand; +import java.util.UUID; + /** - * * @author emerald000 */ public final class CaveIn extends CardImpl { - public CaveIn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{R}{R}"); + private static final FilterOwnedCard filter + = new FilterOwnedCard("a red card from your hand"); + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + } + + public CaveIn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}{R}"); // You may exile a red card from your hand rather than pay Cave-In's mana cost. - FilterOwnedCard filter = new FilterOwnedCard("a red card from your hand"); - filter.add(new ColorPredicate(ObjectColor.RED)); - filter.add(Predicates.not(new CardIdPredicate(this.getId()))); this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter)))); - + // Cave-In deals 2 damage to each creature and each player. this.getSpellAbility().addEffect(new DamageEverythingEffect(2)); } diff --git a/Mage.Sets/src/mage/cards/c/CavernOfSouls.java b/Mage.Sets/src/mage/cards/c/CavernOfSouls.java index ea0ac58c26a..3acd3b26d27 100644 --- a/Mage.Sets/src/mage/cards/c/CavernOfSouls.java +++ b/Mage.Sets/src/mage/cards/c/CavernOfSouls.java @@ -67,7 +67,7 @@ class CavernOfSoulsManaBuilder extends ConditionalManaBuilder { creatureType = subType; } Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null && mana.getAny() == 0) { game.informPlayers(controller.getLogName() + " produces " + mana.toString() + " with " + sourceObject.getLogName() + " (can only be spend to cast for creatures of type " + creatureType + " and that spell can't be countered)"); @@ -108,7 +108,7 @@ class CavernOfSoulsManaCondition extends CreatureCastManaCondition { // check: ... to cast a creature spell if (super.apply(game, source)) { // check: ... of the chosen type - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (creatureType != null && object != null && object.hasSubtype(creatureType, game)) { return true; } @@ -170,7 +170,7 @@ class CavernOfSoulsCantCounterEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null) { return "This spell can't be countered because a colored mana from " + sourceObject.getName() + " was spent to cast it."; } diff --git a/Mage.Sets/src/mage/cards/c/CeaseFire.java b/Mage.Sets/src/mage/cards/c/CeaseFire.java index dc559d1afe9..3683fe6f949 100644 --- a/Mage.Sets/src/mage/cards/c/CeaseFire.java +++ b/Mage.Sets/src/mage/cards/c/CeaseFire.java @@ -64,7 +64,7 @@ class CeaseFireEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast creature spells this turn (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/c/CecilyHauntedMage.java b/Mage.Sets/src/mage/cards/c/CecilyHauntedMage.java new file mode 100644 index 00000000000..d37f882a645 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CecilyHauntedMage.java @@ -0,0 +1,87 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; +import mage.abilities.keyword.FriendsForeverAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CecilyHauntedMage extends CardImpl { + + public CecilyHauntedMage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(3); + this.toughness = new MageInt(5); + + // Your maximum hand size is eleven. + this.addAbility(new SimpleStaticAbility(new MaximumHandSizeControllerEffect( + 11, Duration.WhileOnBattlefield, MaximumHandSizeControllerEffect.HandSizeModification.SET + ))); + + // Whenever Eleven, the Mage attacks, you draw a card and you lose 1 life. Then if you have eleven or more cards in your hand, you may cast an instant or sorcery spell from your hand without paying its mana cost. + this.addAbility(new AttacksTriggeredAbility(new CecilyHauntedMageEffect())); + + // Friends forever + this.addAbility(FriendsForeverAbility.getInstance()); + } + + private CecilyHauntedMage(final CecilyHauntedMage card) { + super(card); + } + + @Override + public CecilyHauntedMage copy() { + return new CecilyHauntedMage(this); + } +} + +class CecilyHauntedMageEffect extends OneShotEffect { + + CecilyHauntedMageEffect() { + super(Outcome.Benefit); + staticText = "you draw a card and you lose 1 life. Then if you have eleven or more cards in your hand, " + + "you may cast an instant or sorcery spell from your hand without paying its mana cost"; + } + + private CecilyHauntedMageEffect(final CecilyHauntedMageEffect effect) { + super(effect); + } + + @Override + public CecilyHauntedMageEffect copy() { + return new CecilyHauntedMageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + player.drawCards(1, source, game); + player.loseLife(1, game, source, false); + return player.getHand().size() < 11 + || CardUtil.castSpellWithAttributesForFree( + player, source, game, player.getHand().copy(), + StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY + ); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CelebrateTheHarvest.java b/Mage.Sets/src/mage/cards/c/CelebrateTheHarvest.java index 47fcbcb28f7..4bf241f98c4 100644 --- a/Mage.Sets/src/mage/cards/c/CelebrateTheHarvest.java +++ b/Mage.Sets/src/mage/cards/c/CelebrateTheHarvest.java @@ -70,7 +70,7 @@ class CelebrateTheHarvestEffect extends OneShotEffect { .getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game ) .stream() .filter(Objects::nonNull) diff --git a/Mage.Sets/src/mage/cards/c/CelebrityFencer.java b/Mage.Sets/src/mage/cards/c/CelebrityFencer.java new file mode 100644 index 00000000000..330e949ee84 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CelebrityFencer.java @@ -0,0 +1,39 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.AllianceAbility; +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.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CelebrityFencer extends CardImpl { + + public CelebrityFencer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Alliance — Whenever another creature enters the battlefield under your control, put a +1/+1 counter on Celebrity Fencer. + this.addAbility(new AllianceAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()))); + } + + private CelebrityFencer(final CelebrityFencer card) { + super(card); + } + + @Override + public CelebrityFencer copy() { + return new CelebrityFencer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CelestialJudgment.java b/Mage.Sets/src/mage/cards/c/CelestialJudgment.java index 5ac6057ad24..b62c88ea32d 100644 --- a/Mage.Sets/src/mage/cards/c/CelestialJudgment.java +++ b/Mage.Sets/src/mage/cards/c/CelestialJudgment.java @@ -68,7 +68,7 @@ class CelestialJudgmentEffect extends OneShotEffect { .getBattlefield() .getActivePermanents( StaticFilters.FILTER_PERMANENT_CREATURE, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game ); Map> powerMap = permanents .stream() @@ -89,7 +89,7 @@ class CelestialJudgmentEffect extends OneShotEffect { filter.add(new PowerPredicate(ComparisonType.EQUAL_TO, entry.getKey())); TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); toKeep.add(target.getFirstTarget()); } for (Permanent permanent : permanents) { diff --git a/Mage.Sets/src/mage/cards/c/CelestialRegulator.java b/Mage.Sets/src/mage/cards/c/CelestialRegulator.java new file mode 100644 index 00000000000..f499ded4111 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CelestialRegulator.java @@ -0,0 +1,91 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.CounterAnyPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author weirddan455 + */ +public final class CelestialRegulator extends CardImpl { + + public CelestialRegulator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); + + this.subtype.add(SubType.ANGEL); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Celestial Regulator enters the battlefield, choose target creature you don't control and tap it. + // If you control a creature with a counter on it, the chosen creature doesn't untap during its controller's next untap step. + Ability ability = new EntersBattlefieldTriggeredAbility(new CelestialRegulatorEffect()); + ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.addAbility(ability); + } + + private CelestialRegulator(final CelestialRegulator card) { + super(card); + } + + @Override + public CelestialRegulator copy() { + return new CelestialRegulator(this); + } +} + +class CelestialRegulatorEffect extends OneShotEffect { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(CounterAnyPredicate.instance); + } + + public CelestialRegulatorEffect() { + super(Outcome.Tap); + this.staticText = "choose target creature you don't control and tap it. " + + "If you control a creature with a counter on it, the chosen creature doesn't untap during its controller's next untap step"; + } + + private CelestialRegulatorEffect(final CelestialRegulatorEffect effect) { + super(effect); + } + + @Override + public CelestialRegulatorEffect copy() { + return new CelestialRegulatorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent targetCreature = game.getPermanent(source.getFirstTarget()); + if (targetCreature == null) { + return false; + } + targetCreature.tap(source, game); + if (game.getBattlefield().count(filter, source.getControllerId(), source, game) > 0) { + game.addEffect(new DontUntapInControllersNextUntapStepTargetEffect(), source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CelestusSanctifier.java b/Mage.Sets/src/mage/cards/c/CelestusSanctifier.java index 2f14919631a..141461a4b0b 100644 --- a/Mage.Sets/src/mage/cards/c/CelestusSanctifier.java +++ b/Mage.Sets/src/mage/cards/c/CelestusSanctifier.java @@ -3,14 +3,12 @@ package mage.cards.c; import mage.MageInt; import mage.abilities.common.BecomeDayAsEntersAbility; import mage.abilities.common.BecomesDayOrNightTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import java.util.UUID; @@ -31,10 +29,8 @@ public final class CelestusSanctifier extends CardImpl { this.addAbility(new BecomeDayAsEntersAbility()); // Whenever day becomes night or night becomes day, look at the top two cards of your library. Put one of them into your graveyard. - this.addAbility(new BecomesDayOrNightTriggeredAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(2), false, StaticValue.get(1), StaticFilters.FILTER_CARD, - Zone.LIBRARY, true, false, false, Zone.GRAVEYARD, false - ).setText("look at the top two cards of your library. Put one of them into your graveyard"))); + this.addAbility(new BecomesDayOrNightTriggeredAbility( + new LookLibraryAndPickControllerEffect(2, 1, PutCards.GRAVEYARD, PutCards.TOP_ANY))); } private CelestusSanctifier(final CelestusSanctifier card) { diff --git a/Mage.Sets/src/mage/cards/c/CementShoes.java b/Mage.Sets/src/mage/cards/c/CementShoes.java new file mode 100644 index 00000000000..eae1973b498 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CementShoes.java @@ -0,0 +1,53 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfYourEndStepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect; +import mage.abilities.effects.common.TapSourceEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author weirddan455 + */ +public final class CementShoes extends CardImpl { + + public CementShoes(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature gets +3/+3 and has "At the beginning of your end step, tap this creature." + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(3, 3)); + ability.addEffect(new GainAbilityAttachedEffect( + new BeginningOfYourEndStepTriggeredAbility(new TapSourceEffect(), false), + AttachmentType.EQUIPMENT + ).setText("and has \"At the beginning of your end step, tap this creature.\"")); + this.addAbility(ability); + + // Equipped creature doesn't untap during its controller's untap step. + this.addAbility(new SimpleStaticAbility(new DontUntapInControllersUntapStepEnchantedEffect() + .setText("Equipped creature doesn't untap during its controller's untap step"))); + + // Equip {2} + this.addAbility(new EquipAbility(2)); + } + + private CementShoes(final CementShoes card) { + super(card); + } + + @Override + public CementShoes copy() { + return new CementShoes(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CemeteryDesecrator.java b/Mage.Sets/src/mage/cards/c/CemeteryDesecrator.java index 60b72184552..439ea276999 100644 --- a/Mage.Sets/src/mage/cards/c/CemeteryDesecrator.java +++ b/Mage.Sets/src/mage/cards/c/CemeteryDesecrator.java @@ -88,7 +88,7 @@ class CemeteryDesecratorEffect extends OneShotEffect { if (controller != null) { TargetCardInGraveyard target = new TargetCardInGraveyard(filter); target.setNotTarget(true); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card != null) { int manaValue = card.getManaValue(); diff --git a/Mage.Sets/src/mage/cards/c/CemeteryGatekeeper.java b/Mage.Sets/src/mage/cards/c/CemeteryGatekeeper.java index 4bdcc579128..26b3af039da 100644 --- a/Mage.Sets/src/mage/cards/c/CemeteryGatekeeper.java +++ b/Mage.Sets/src/mage/cards/c/CemeteryGatekeeper.java @@ -83,7 +83,7 @@ class CemeteryGatekeeperEffect extends OneShotEffect { if (controller != null) { TargetCardInGraveyard target = new TargetCardInGraveyard(); target.setNotTarget(true); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card != null) { UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); diff --git a/Mage.Sets/src/mage/cards/c/CemeteryIlluminator.java b/Mage.Sets/src/mage/cards/c/CemeteryIlluminator.java index 20d51cabb6a..160d30bba59 100644 --- a/Mage.Sets/src/mage/cards/c/CemeteryIlluminator.java +++ b/Mage.Sets/src/mage/cards/c/CemeteryIlluminator.java @@ -88,7 +88,7 @@ class CemeteryIlluminatorExileEffect extends OneShotEffect { if (controller != null) { TargetCardInGraveyard target = new TargetCardInGraveyard(); target.setNotTarget(true); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card != null) { UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); diff --git a/Mage.Sets/src/mage/cards/c/CemeteryProtector.java b/Mage.Sets/src/mage/cards/c/CemeteryProtector.java index 79cfa40752a..f3eed733466 100644 --- a/Mage.Sets/src/mage/cards/c/CemeteryProtector.java +++ b/Mage.Sets/src/mage/cards/c/CemeteryProtector.java @@ -84,7 +84,7 @@ class CemeteryProtectorEffect extends OneShotEffect { if (controller != null) { TargetCardInGraveyard target = new TargetCardInGraveyard(); target.setNotTarget(true); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card != null) { UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); diff --git a/Mage.Sets/src/mage/cards/c/CemeteryProwler.java b/Mage.Sets/src/mage/cards/c/CemeteryProwler.java index d70f7aafbe4..2c841a7d97d 100644 --- a/Mage.Sets/src/mage/cards/c/CemeteryProwler.java +++ b/Mage.Sets/src/mage/cards/c/CemeteryProwler.java @@ -76,7 +76,7 @@ class CemeteryProwlerExileEffect extends OneShotEffect { if (controller != null) { TargetCardInGraveyard target = new TargetCardInGraveyard(); target.setNotTarget(true); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card != null) { UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); diff --git a/Mage.Sets/src/mage/cards/c/CemeteryPuca.java b/Mage.Sets/src/mage/cards/c/CemeteryPuca.java index 2950b2e4c8f..cc4a08d17b5 100644 --- a/Mage.Sets/src/mage/cards/c/CemeteryPuca.java +++ b/Mage.Sets/src/mage/cards/c/CemeteryPuca.java @@ -57,7 +57,7 @@ class CemeteryPucaEffect extends OneShotEffect { public CemeteryPucaEffect() { super(Outcome.Copy); - staticText = " {this} becomes a copy of that creature, except it has this ability"; + staticText = "{this} becomes a copy of that creature, except it has this ability"; } public CemeteryPucaEffect(final CemeteryPucaEffect effect) { diff --git a/Mage.Sets/src/mage/cards/c/CemeteryTampering.java b/Mage.Sets/src/mage/cards/c/CemeteryTampering.java new file mode 100644 index 00000000000..a34d2d3d826 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CemeteryTampering.java @@ -0,0 +1,76 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.HideawayPlayEffect; +import mage.abilities.keyword.HideawayAbility; +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.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CemeteryTampering extends CardImpl { + + public CemeteryTampering(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); + + // Hideaway 5 + this.addAbility(new HideawayAbility(5)); + + // At the beginning of your upkeep, you may mill three cards. Then if there are twenty or more cards in your graveyard, you may play the exiled card without paying its mana cost. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new CemeteryTamperingEffect(), TargetController.YOU, false + )); + } + + private CemeteryTampering(final CemeteryTampering card) { + super(card); + } + + @Override + public CemeteryTampering copy() { + return new CemeteryTampering(this); + } +} + +class CemeteryTamperingEffect extends OneShotEffect { + + CemeteryTamperingEffect() { + super(Outcome.Benefit); + staticText = "you may mill three cards. Then if there are twenty or more cards in your graveyard, " + + "you may play the exiled card without paying its mana cost"; + } + + private CemeteryTamperingEffect(final CemeteryTamperingEffect effect) { + super(effect); + } + + @Override + public CemeteryTamperingEffect copy() { + return new CemeteryTamperingEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + if (player.chooseUse(outcome, "Mill three cards?", source, game)) { + player.millCards(3, source, game); + } + if (player.getGraveyard().size() >= 20) { + new HideawayPlayEffect().apply(game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CephalidFacetaker.java b/Mage.Sets/src/mage/cards/c/CephalidFacetaker.java new file mode 100644 index 00000000000..5929e246f0f --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CephalidFacetaker.java @@ -0,0 +1,95 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; +import mage.abilities.keyword.CantBeBlockedSourceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.util.functions.CopyApplier; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CephalidFacetaker extends CardImpl { + + public CephalidFacetaker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.CEPHALID); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // Cephalid Facetaker can't be blocked. + this.addAbility(new CantBeBlockedSourceAbility()); + + // At the beginning of combat on your turn, you may have Cephalid Facetaker become a copy of another target creature until end of turn, except its a 1/4 and has "This creature can't be blocked." + Ability ability = new BeginningOfCombatTriggeredAbility( + new CephalidFacetakerEffect(), TargetController.YOU, true + ); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); + this.addAbility(ability); + } + + private CephalidFacetaker(final CephalidFacetaker card) { + super(card); + } + + @Override + public CephalidFacetaker copy() { + return new CephalidFacetaker(this); + } +} + +class CephalidFacetakerEffect extends OneShotEffect { + + private static final CopyApplier copyApplier = new CopyApplier() { + @Override + public boolean apply(Game game, MageObject blueprint, Ability source, UUID targetObjectId) { + blueprint.getPower().modifyBaseValue(1); + blueprint.getToughness().modifyBaseValue(4); + blueprint.getAbilities().add(new SimpleStaticAbility( + new CantBeBlockedSourceEffect().setText("this creature can't be blocked") + )); + return true; + } + }; + + CephalidFacetakerEffect() { + super(Outcome.Benefit); + staticText = "you may have {this} become a copy of another target creature until end of turn, " + + "except it's 1/4 and has \"This creature can't be blocked.\""; + } + + private CephalidFacetakerEffect(final CephalidFacetakerEffect effect) { + super(effect); + } + + @Override + public CephalidFacetakerEffect copy() { + return new CephalidFacetakerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (sourcePermanent == null || creature == null) { + return false; + } + game.copyPermanent(Duration.EndOfTurn, creature, sourcePermanent.getId(), source, copyApplier); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CephalidShrine.java b/Mage.Sets/src/mage/cards/c/CephalidShrine.java index 32d77b5d345..66e6072566f 100644 --- a/Mage.Sets/src/mage/cards/c/CephalidShrine.java +++ b/Mage.Sets/src/mage/cards/c/CephalidShrine.java @@ -95,7 +95,7 @@ class CephalidShrineEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int count = 0; - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { Spell spell = (Spell) game.getState().getValue("cephalidShrine" + mageObject); if (spell != null) { diff --git a/Mage.Sets/src/mage/cards/c/CerebralEruption.java b/Mage.Sets/src/mage/cards/c/CerebralEruption.java index d72297536a3..1200f337456 100644 --- a/Mage.Sets/src/mage/cards/c/CerebralEruption.java +++ b/Mage.Sets/src/mage/cards/c/CerebralEruption.java @@ -53,7 +53,7 @@ class CerebralEruptionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getFirstTarget()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (player != null && sourceObject != null && player.getLibrary().hasCards()) { Card card = player.getLibrary().getFromTop(game); Cards cards = new CardsImpl(card); diff --git a/Mage.Sets/src/mage/cards/c/CeremonialGroundbreaker.java b/Mage.Sets/src/mage/cards/c/CeremonialGroundbreaker.java new file mode 100644 index 00000000000..f5b5db988cd --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CeremonialGroundbreaker.java @@ -0,0 +1,56 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CeremonialGroundbreaker extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.CITIZEN, "Citizen"); + + public CeremonialGroundbreaker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{G}{W}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature gets +2/+1 and has trample. + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 1)); + ability.addEffect(new GainAbilityAttachedEffect( + TrampleAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and has trample")); + this.addAbility(ability); + + // Equip Citizen {1} + this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(1), new TargetPermanent(filter))); + + // Equip {3} + this.addAbility(new EquipAbility(3)); + } + + private CeremonialGroundbreaker(final CeremonialGroundbreaker card) { + super(card); + } + + @Override + public CeremonialGroundbreaker copy() { + return new CeremonialGroundbreaker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CeruleanWisps.java b/Mage.Sets/src/mage/cards/c/CeruleanWisps.java index 3cc5469f800..bfb26fbc714 100644 --- a/Mage.Sets/src/mage/cards/c/CeruleanWisps.java +++ b/Mage.Sets/src/mage/cards/c/CeruleanWisps.java @@ -28,7 +28,7 @@ public final class CeruleanWisps extends CardImpl { this.getSpellAbility().addEffect(new UntapTargetEffect().setText("Untap that creature")); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } public CeruleanWisps (final CeruleanWisps card) { diff --git a/Mage.Sets/src/mage/cards/c/Chainbreaker.java b/Mage.Sets/src/mage/cards/c/Chainbreaker.java index b45f94e5122..ac21c9ced0b 100644 --- a/Mage.Sets/src/mage/cards/c/Chainbreaker.java +++ b/Mage.Sets/src/mage/cards/c/Chainbreaker.java @@ -1,51 +1,51 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.counters.CounterType; -import mage.filter.common.FilterCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class Chainbreaker extends CardImpl { - + public Chainbreaker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); this.subtype.add(SubType.SCARECROW); this.power = new MageInt(3); this.toughness = new MageInt(3); // Chainbreaker enters the battlefield with two -1/-1 counters on it. - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance(2), false), "with two -1/-1 counters on it")); + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect( + CounterType.M1M1.createInstance(2), false + ), "with two -1/-1 counters on it")); // {3}, {tap}: Remove a -1/-1 counter from target creature. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RemoveCounterTargetEffect(CounterType.M1M1.createInstance()), new ManaCostsImpl("{3}")); + Ability ability = new SimpleActivatedAbility( + new RemoveCounterTargetEffect(CounterType.M1M1.createInstance()), new GenericManaCost(3) + ); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("target creature"))); + ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); - } - + private Chainbreaker(final Chainbreaker card) { super(card); } - + @Override public Chainbreaker copy() { return new Chainbreaker(this); diff --git a/Mage.Sets/src/mage/cards/c/ChandraAblaze.java b/Mage.Sets/src/mage/cards/c/ChandraAblaze.java index 2e665564dff..9806fd544c3 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraAblaze.java +++ b/Mage.Sets/src/mage/cards/c/ChandraAblaze.java @@ -3,7 +3,6 @@ package mage.cards.c; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardAllEffect; @@ -11,23 +10,23 @@ import mage.abilities.effects.common.discard.DiscardHandAllEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.SuperType; import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; +import mage.filter.common.FilterInstantOrSorceryCard; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetAnyTarget; -import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetDiscard; +import mage.util.CardUtil; -import java.util.Set; import java.util.UUID; -import mage.ApprovingObject; /** * @author North @@ -39,7 +38,7 @@ public final class ChandraAblaze extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Discard a card. If a red card is discarded this way, Chandra Ablaze deals 4 damage to any target. LoyaltyAbility ability = new LoyaltyAbility(new ChandraAblazeEffect1(), 1); @@ -88,7 +87,7 @@ class ChandraAblazeEffect1 extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null) { TargetDiscard target = new TargetDiscard(player.getId()); - player.choose(Outcome.Discard, target, source.getSourceId(), game); + player.choose(Outcome.Discard, target, source, game); Card card = player.getHand().get(target.getFirstTarget(), game); if (card != null) { player.discard(card, false, source, game); @@ -139,6 +138,12 @@ class ChandraAblazeEffect2 extends OneShotEffect { class ChandraAblazeEffect5 extends OneShotEffect { + private static final FilterCard filter = new FilterInstantOrSorceryCard(); + + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + } + public ChandraAblazeEffect5() { super(Outcome.PlayForFree); this.staticText = "Cast any number of red instant and/or sorcery cards from your graveyard without paying their mana costs"; @@ -155,33 +160,17 @@ class ChandraAblazeEffect5 extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { + // Under this card's current oracle wording, it only casts red instant or sorcery cards + // This may have been a mistake which could change in the future Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - FilterCard filter = new FilterCard("red instant or sorcery card from your graveyard to play"); - filter.add(new ColorPredicate(ObjectColor.RED)); - filter.add(Predicates.or( - CardType.INSTANT.getPredicate(), - CardType.SORCERY.getPredicate())); - - String message = "Play red instant or sorcery card from your graveyard without paying its mana cost?"; - Set cards = player.getGraveyard().getCards(filter, game); - TargetCardInGraveyard target = new TargetCardInGraveyard(filter); - while (!cards.isEmpty() && player.chooseUse(outcome, message, source, game)) { - target.clearChosen(); - if (player.choose(outcome, target, source.getSourceId(), game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - player.cast(player.chooseAbilityForCast(card, game, true), game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - - cards.remove(card); - } - } - } - - return true; + if (player == null) { + return false; } - return false; + CardUtil.castMultipleWithAttributeForFree( + player, source, game, + new CardsImpl(player.getGraveyard().getCards(filter, game)), + StaticFilters.FILTER_CARD + ); + return true; } } diff --git a/Mage.Sets/src/mage/cards/c/ChandraAcolyteOfFlame.java b/Mage.Sets/src/mage/cards/c/ChandraAcolyteOfFlame.java index acce249973c..2ceeb02b127 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraAcolyteOfFlame.java +++ b/Mage.Sets/src/mage/cards/c/ChandraAcolyteOfFlame.java @@ -3,7 +3,6 @@ package mage.cards.c; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.*; import mage.abilities.effects.common.InfoEffect; @@ -55,7 +54,7 @@ public final class ChandraAcolyteOfFlame extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // 0: Put a loyalty counter on each red planeswalker you control. this.addAbility(new LoyaltyAbility(new AddCountersAllEffect(CounterType.LOYALTY.createInstance(), filter), 0)); diff --git a/Mage.Sets/src/mage/cards/c/ChandraAwakenedInferno.java b/Mage.Sets/src/mage/cards/c/ChandraAwakenedInferno.java index a9781b1009a..d188189f6f1 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraAwakenedInferno.java +++ b/Mage.Sets/src/mage/cards/c/ChandraAwakenedInferno.java @@ -3,7 +3,6 @@ package mage.cards.c; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CantBeCounteredSourceAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.GetXLoyaltyValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageAllEffect; @@ -40,7 +39,7 @@ public final class ChandraAwakenedInferno extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(6)); + this.setStartingLoyalty(6); // This spell can't be countered. this.addAbility(new CantBeCounteredSourceAbility()); diff --git a/Mage.Sets/src/mage/cards/c/ChandraBoldPyromancer.java b/Mage.Sets/src/mage/cards/c/ChandraBoldPyromancer.java index 3687ef58e82..c48a05742d8 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraBoldPyromancer.java +++ b/Mage.Sets/src/mage/cards/c/ChandraBoldPyromancer.java @@ -5,7 +5,6 @@ import java.util.UUID; import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effects; import mage.abilities.effects.mana.BasicManaEffect; import mage.abilities.effects.common.DamageAllControlledTargetEffect; @@ -30,7 +29,7 @@ public final class ChandraBoldPyromancer extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Add {R}{R}. Chandra, Bold Pyromancer deals 2 damage to target player. Ability ability = new LoyaltyAbility(new BasicManaEffect(Mana.RedMana(2)), +1); diff --git a/Mage.Sets/src/mage/cards/c/ChandraDressedToKill.java b/Mage.Sets/src/mage/cards/c/ChandraDressedToKill.java index ead71a7256e..be5a74be307 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraDressedToKill.java +++ b/Mage.Sets/src/mage/cards/c/ChandraDressedToKill.java @@ -7,7 +7,6 @@ import mage.MageObject; import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -39,7 +38,7 @@ public final class ChandraDressedToKill extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Add {R}. Chandra, Dressed to Kill deals 1 damage to up to one target player or planeswalker. Ability ability = new LoyaltyAbility(new AddManaToManaPoolSourceControllerEffect(new Mana(ManaType.RED, 1)), 1); diff --git a/Mage.Sets/src/mage/cards/c/ChandraFireArtisan.java b/Mage.Sets/src/mage/cards/c/ChandraFireArtisan.java index bd3011a153a..85cb7459a98 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraFireArtisan.java +++ b/Mage.Sets/src/mage/cards/c/ChandraFireArtisan.java @@ -4,7 +4,6 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; @@ -29,7 +28,7 @@ public final class ChandraFireArtisan extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // Whenever one or more loyalty counters are removed from Chandra, Fire Artisan, she deals that much damage to target opponent or planeswalker. this.addAbility(new ChandraFireArtisanTriggeredAbility()); diff --git a/Mage.Sets/src/mage/cards/c/ChandraFlamecaller.java b/Mage.Sets/src/mage/cards/c/ChandraFlamecaller.java index 7a27babd504..97e7fa43803 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraFlamecaller.java +++ b/Mage.Sets/src/mage/cards/c/ChandraFlamecaller.java @@ -2,7 +2,6 @@ package mage.cards.c; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.GetXLoyaltyValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; @@ -30,7 +29,7 @@ public final class ChandraFlamecaller extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Create two 3/1 red Elemental creature tokens with haste. Exile them at the beginning of the next end step. this.addAbility(new LoyaltyAbility(new ChandraElementalEffect(), 1)); diff --git a/Mage.Sets/src/mage/cards/c/ChandraFlamesCatalyst.java b/Mage.Sets/src/mage/cards/c/ChandraFlamesCatalyst.java index 9c78e245a3e..91763674b5d 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraFlamesCatalyst.java +++ b/Mage.Sets/src/mage/cards/c/ChandraFlamesCatalyst.java @@ -3,7 +3,6 @@ package mage.cards.c; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.CastCardFromGraveyardThenExileItEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamagePlayersEffect; @@ -39,7 +38,7 @@ public final class ChandraFlamesCatalyst extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Chandra, Flame's Catalyst deals 3 damage to each opponent. this.addAbility(new LoyaltyAbility(new DamagePlayersEffect(3, TargetController.OPPONENT), 1)); diff --git a/Mage.Sets/src/mage/cards/c/ChandraFlamesFury.java b/Mage.Sets/src/mage/cards/c/ChandraFlamesFury.java index 454b0153f82..8ed4fa1f39e 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraFlamesFury.java +++ b/Mage.Sets/src/mage/cards/c/ChandraFlamesFury.java @@ -2,7 +2,6 @@ package mage.cards.c; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageAllControlledTargetEffect; import mage.abilities.effects.common.DamageTargetEffect; @@ -32,7 +31,7 @@ public final class ChandraFlamesFury extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Chandra, Flame's Fury deals 2 damage to any target. Ability ability = new LoyaltyAbility(new DamageTargetEffect(2), 1); diff --git a/Mage.Sets/src/mage/cards/c/ChandraGremlinWrangler.java b/Mage.Sets/src/mage/cards/c/ChandraGremlinWrangler.java index 643baa27a87..d4cf5ff5619 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraGremlinWrangler.java +++ b/Mage.Sets/src/mage/cards/c/ChandraGremlinWrangler.java @@ -2,7 +2,6 @@ package mage.cards.c; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; @@ -37,7 +36,7 @@ public final class ChandraGremlinWrangler extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Create a 2/2 red Gremlin creature token. this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new GremlinToken()), 1)); diff --git a/Mage.Sets/src/mage/cards/c/ChandraHeartOfFire.java b/Mage.Sets/src/mage/cards/c/ChandraHeartOfFire.java index 4453a0e4263..fbf1ddfd3bb 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraHeartOfFire.java +++ b/Mage.Sets/src/mage/cards/c/ChandraHeartOfFire.java @@ -4,7 +4,6 @@ import mage.Mana; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; @@ -43,7 +42,7 @@ public final class ChandraHeartOfFire extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Discard your hand, then exile the top three cards of your library. Until end of turn, you may play cards exiled this way. Ability ability = new LoyaltyAbility(new DiscardHandControllerEffect(), 1); @@ -102,16 +101,16 @@ class ChandraHeartOfFireUltimateEffect extends OneShotEffect { // from graveyard Target target = new TargetCardInYourGraveyard(0, Integer.MAX_VALUE, filter, true).withChooseHint("from graveyard"); - if (target.canChoose(source.getSourceId(), controller.getId(), game) - && target.choose(Outcome.AIDontUseIt, controller.getId(), source.getSourceId(), game)) { + if (target.canChoose(controller.getId(), source, game) + && target.choose(Outcome.AIDontUseIt, controller.getId(), source.getSourceId(), source, game)) { Set cards = new CardsImpl(target.getTargets()).getCards(game); exiledCards.addAll(cards); } // from library target = new TargetCardInLibrary(0, Integer.MAX_VALUE, filter).withChooseHint("from library"); - if (target.canChoose(source.getSourceId(), controller.getId(), game) - && target.choose(Outcome.AIDontUseIt, controller.getId(), source.getSourceId(), game)) { + if (target.canChoose(controller.getId(), source, game) + && target.choose(Outcome.AIDontUseIt, controller.getId(), source.getSourceId(), source, game)) { Set cards = new CardsImpl(target.getTargets()).getCards(game); exiledCards.addAll(cards); } diff --git a/Mage.Sets/src/mage/cards/c/ChandraNalaar.java b/Mage.Sets/src/mage/cards/c/ChandraNalaar.java index 09c6b329535..f4ef053a684 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraNalaar.java +++ b/Mage.Sets/src/mage/cards/c/ChandraNalaar.java @@ -2,7 +2,6 @@ package mage.cards.c; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.GetXLoyaltyValue; import mage.abilities.effects.Effects; import mage.abilities.effects.common.DamageAllControlledTargetEffect; @@ -28,7 +27,7 @@ public final class ChandraNalaar extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(6)); + this.setStartingLoyalty(6); // +1: Chandra Nalaar deals 1 damage to target player or planeswalker. LoyaltyAbility ability1 = new LoyaltyAbility(new DamageTargetEffect(1), 1); diff --git a/Mage.Sets/src/mage/cards/c/ChandraNovicePyromancer.java b/Mage.Sets/src/mage/cards/c/ChandraNovicePyromancer.java index e262ee17f94..cfa960e489b 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraNovicePyromancer.java +++ b/Mage.Sets/src/mage/cards/c/ChandraNovicePyromancer.java @@ -3,7 +3,6 @@ package mage.cards.c; import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.mana.BasicManaEffect; @@ -31,7 +30,7 @@ public final class ChandraNovicePyromancer extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Elementals you control get +2/+0 until end of turn. this.addAbility(new LoyaltyAbility( diff --git a/Mage.Sets/src/mage/cards/c/ChandraPyrogenius.java b/Mage.Sets/src/mage/cards/c/ChandraPyrogenius.java index 3c4249d7b1b..37977180130 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraPyrogenius.java +++ b/Mage.Sets/src/mage/cards/c/ChandraPyrogenius.java @@ -3,7 +3,6 @@ package mage.cards.c; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effects; import mage.abilities.effects.common.DamageAllControlledTargetEffect; @@ -31,7 +30,7 @@ public final class ChandraPyrogenius extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +2: Chandra, Pyrogenius deals 2 damage to each opponent. this.addAbility(new LoyaltyAbility(new DamagePlayersEffect(Outcome.Damage, StaticValue.get(2), TargetController.OPPONENT), 2)); diff --git a/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java b/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java index 7ab9781e7c0..e267aa4e980 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java +++ b/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java @@ -7,7 +7,6 @@ import mage.ApprovingObject; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; @@ -36,7 +35,7 @@ public final class ChandraPyromaster extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Chandra, Pyromaster deals 1 damage to target player and 1 damage to // up to one target creature that player controls. That creature can't block this turn. @@ -127,16 +126,16 @@ class ChandraPyromasterTarget extends TargetPermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set availablePossibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set availablePossibleTargets = super.possibleTargets(sourceControllerId, source, game); Set possibleTargets = new HashSet<>(); - MageObject object = game.getObject(sourceId); + MageObject object = game.getObject(source); for (StackObject item : game.getState().getStack()) { - if (item.getId().equals(sourceId)) { + if (item.getId().equals(source.getSourceId())) { object = item; } - if (item.getSourceId().equals(sourceId)) { + if (item.getSourceId().equals(source.getSourceId())) { object = item; } } diff --git a/Mage.Sets/src/mage/cards/c/ChandraRoaringFlame.java b/Mage.Sets/src/mage/cards/c/ChandraRoaringFlame.java index 0308ad1de7d..ce08c704fe1 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraRoaringFlame.java +++ b/Mage.Sets/src/mage/cards/c/ChandraRoaringFlame.java @@ -2,7 +2,6 @@ package mage.cards.c; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; @@ -34,7 +33,7 @@ public final class ChandraRoaringFlame extends CardImpl { this.nightCard = true; - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Chandra, Roaring Flame deals 2 damage to target player. LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new DamageTargetEffect(2), 1); diff --git a/Mage.Sets/src/mage/cards/c/ChandraTheFirebrand.java b/Mage.Sets/src/mage/cards/c/ChandraTheFirebrand.java index 2f18156678f..aa85c501d14 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraTheFirebrand.java +++ b/Mage.Sets/src/mage/cards/c/ChandraTheFirebrand.java @@ -4,7 +4,6 @@ package mage.cards.c; import java.util.UUID; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CopyTargetSpellEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; @@ -32,7 +31,7 @@ public final class ChandraTheFirebrand extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Chandra, the Firebrand deals 1 damage to any target. LoyaltyAbility ability1 = new LoyaltyAbility(new DamageTargetEffect(1), 1); diff --git a/Mage.Sets/src/mage/cards/c/ChandraTorchOfDefiance.java b/Mage.Sets/src/mage/cards/c/ChandraTorchOfDefiance.java index 0f921f1fd25..651e30a7e38 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraTorchOfDefiance.java +++ b/Mage.Sets/src/mage/cards/c/ChandraTorchOfDefiance.java @@ -6,7 +6,6 @@ import mage.MageObject; import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamagePlayersEffect; @@ -38,7 +37,7 @@ public final class ChandraTorchOfDefiance extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.CHANDRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Exile the top card of your library. You may cast that card. If you don't, Chandra, Torch of Defiance deals 2 damage to each opponent. LoyaltyAbility ability = new LoyaltyAbility(new ChandraTorchOfDefianceEffect(), 1); diff --git a/Mage.Sets/src/mage/cards/c/ChandrasEmbercat.java b/Mage.Sets/src/mage/cards/c/ChandrasEmbercat.java index e5f9e25542d..cfad9feed45 100644 --- a/Mage.Sets/src/mage/cards/c/ChandrasEmbercat.java +++ b/Mage.Sets/src/mage/cards/c/ChandrasEmbercat.java @@ -69,7 +69,7 @@ class ChandrasEmbercatElementalManaCondition extends CreatureCastManaCondition { if (!super.apply(game, source)) { return false; } - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object == null) { return false; } @@ -84,7 +84,7 @@ class ChandrasEmbercatPlaneswalkerManaCondition extends PlaneswalkerCastManaCond if (!super.apply(game, source)) { return false; } - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/c/ChandrasIgnition.java b/Mage.Sets/src/mage/cards/c/ChandrasIgnition.java index 28393821c59..9398409ceb1 100644 --- a/Mage.Sets/src/mage/cards/c/ChandrasIgnition.java +++ b/Mage.Sets/src/mage/cards/c/ChandrasIgnition.java @@ -57,7 +57,7 @@ class ChandrasIgnitionEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); if (targetCreature != null && targetCreature.getPower().getValue() > 0) { - for (Permanent creature : game.getState().getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getState().getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { if (!creature.getId().equals(targetCreature.getId())) { creature.damage(targetCreature.getPower().getValue(), targetCreature.getId(), source, game, false, true); } diff --git a/Mage.Sets/src/mage/cards/c/ChandrasTriumph.java b/Mage.Sets/src/mage/cards/c/ChandrasTriumph.java index 356df7abe44..6fe22ed35fd 100644 --- a/Mage.Sets/src/mage/cards/c/ChandrasTriumph.java +++ b/Mage.Sets/src/mage/cards/c/ChandrasTriumph.java @@ -75,7 +75,7 @@ class ChandrasTriumphEffect extends OneShotEffect { return false; } int damage = 3; - if (!game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game).isEmpty()) { + if (!game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game).isEmpty()) { damage = 5; } return permanent.damage(damage, source.getSourceId(), source, game) > 0; diff --git a/Mage.Sets/src/mage/cards/c/ChangeOfPlans.java b/Mage.Sets/src/mage/cards/c/ChangeOfPlans.java new file mode 100644 index 00000000000..4ec4a4f7507 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChangeOfPlans.java @@ -0,0 +1,112 @@ +package mage.cards.c; + +import mage.MageItem; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class ChangeOfPlans extends CardImpl { + + public ChangeOfPlans(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{1}{U}"); + + // Each of X target creatures you control connive. You may have any number of them phase out. + this.getSpellAbility().addEffect(new ChangeOfPlansEffect()); + this.getSpellAbility().setTargetAdjuster(ChangeOfPlansAdjuster.instance); + } + + private ChangeOfPlans(final ChangeOfPlans card) { + super(card); + } + + @Override + public ChangeOfPlans copy() { + return new ChangeOfPlans(this); + } +} + +enum ChangeOfPlansAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetControlledCreaturePermanent(ability.getManaCostsToPay().getX())); + } +} + +class ChangeOfPlansEffect extends OneShotEffect { + + ChangeOfPlansEffect() { + super(Outcome.Benefit); + staticText = "each of X target creatures you control connive. You may have any number of them phase out"; + } + + private ChangeOfPlansEffect(final ChangeOfPlansEffect effect) { + super(effect); + } + + @Override + public ChangeOfPlansEffect copy() { + return new ChangeOfPlansEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Set permanents = this + .getTargetPointer() + .getTargets(game, source) + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + if (permanents.isEmpty()) { + return false; + } + for (Permanent permanent : permanents) { + ConniveSourceEffect.connive(permanent, 1, source, game); + } + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return true; + } + FilterPermanent filter = new FilterPermanent("creatures"); + filter.add(Predicates.or( + permanents + .stream() + .map(MageItem::getId) + .map(PermanentIdPredicate::new) + .collect(Collectors.toSet()) + )); + TargetPermanent target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); + player.choose(outcome, target.withChooseHint("to phase out"), source, game); + for (UUID targetId : target.getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + permanent.phaseOut(game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/ChangelingBerserker.java b/Mage.Sets/src/mage/cards/c/ChangelingBerserker.java index 80845e7b462..9559c1ce355 100644 --- a/Mage.Sets/src/mage/cards/c/ChangelingBerserker.java +++ b/Mage.Sets/src/mage/cards/c/ChangelingBerserker.java @@ -30,7 +30,7 @@ public final class ChangelingBerserker extends CardImpl { this.addAbility(HasteAbility.getInstance()); // Champion a creature - this.addAbility(new ChampionAbility(this, true)); + this.addAbility(new ChampionAbility(this)); } private ChangelingBerserker(final ChangelingBerserker card) { diff --git a/Mage.Sets/src/mage/cards/c/ChangelingHero.java b/Mage.Sets/src/mage/cards/c/ChangelingHero.java index a8f1c038fee..51d00ce67af 100644 --- a/Mage.Sets/src/mage/cards/c/ChangelingHero.java +++ b/Mage.Sets/src/mage/cards/c/ChangelingHero.java @@ -27,7 +27,7 @@ public final class ChangelingHero extends CardImpl { this.addAbility(new ChangelingAbility()); // Champion a creature - this.addAbility(new ChampionAbility(this, true)); + this.addAbility(new ChampionAbility(this)); // Lifelink this.addAbility(LifelinkAbility.getInstance()); diff --git a/Mage.Sets/src/mage/cards/c/ChangelingTitan.java b/Mage.Sets/src/mage/cards/c/ChangelingTitan.java index 85905b743aa..40e80e26d90 100644 --- a/Mage.Sets/src/mage/cards/c/ChangelingTitan.java +++ b/Mage.Sets/src/mage/cards/c/ChangelingTitan.java @@ -26,7 +26,7 @@ public final class ChangelingTitan extends CardImpl { this.addAbility(new ChangelingAbility()); // Champion a creature - this.addAbility(new ChampionAbility(this, true)); + this.addAbility(new ChampionAbility(this)); } private ChangelingTitan(final ChangelingTitan card) { diff --git a/Mage.Sets/src/mage/cards/c/ChanneledForce.java b/Mage.Sets/src/mage/cards/c/ChanneledForce.java index 7e933d29193..698172bc82b 100644 --- a/Mage.Sets/src/mage/cards/c/ChanneledForce.java +++ b/Mage.Sets/src/mage/cards/c/ChanneledForce.java @@ -25,7 +25,7 @@ public final class ChanneledForce extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}{R}"); // As an additional cost to cast this spell, discard X cards. - this.getSpellAbility().addCost(new DiscardXTargetCost(StaticFilters.FILTER_CARD_CARDS, true)); + this.getSpellAbility().addCost(new DiscardXTargetCost(StaticFilters.FILTER_CARD_CARDS)); // Target player draws X cards. Channeled Force deals X damage to up to one target creature or planeswalker. this.getSpellAbility().addEffect(new ChanneledForceEffect()); diff --git a/Mage.Sets/src/mage/cards/c/ChaosCharm.java b/Mage.Sets/src/mage/cards/c/ChaosCharm.java index 635794fdf76..a840b36e5b8 100644 --- a/Mage.Sets/src/mage/cards/c/ChaosCharm.java +++ b/Mage.Sets/src/mage/cards/c/ChaosCharm.java @@ -35,13 +35,11 @@ public final class ChaosCharm extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent(filter)); // or Chaos Charm deals 1 damage to target creature - Mode mode = new Mode(); - mode.addEffect(new DamageTargetEffect(1)); + Mode mode = new Mode(new DamageTargetEffect(1)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or target creature gains haste until end of turn. - mode = new Mode(); - mode.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn)); + mode = new Mode(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/ChaosHarlequin.java b/Mage.Sets/src/mage/cards/c/ChaosHarlequin.java index 09751d57866..9137e0b68d7 100644 --- a/Mage.Sets/src/mage/cards/c/ChaosHarlequin.java +++ b/Mage.Sets/src/mage/cards/c/ChaosHarlequin.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -11,16 +9,13 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect; 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.SubType; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author L_J */ public final class ChaosHarlequin extends CardImpl { @@ -32,7 +27,7 @@ public final class ChaosHarlequin extends CardImpl { this.toughness = new MageInt(4); // {R}: Exile the top card of your library. If that card is a land card, Chaos Harlequin gets -4/-0 until end of turn. Otherwise, Chaos Harlequin gets +2/+0 until end of turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ChaosHarlequinEffect(), new ManaCostsImpl("{R}"))); + this.addAbility(new SimpleActivatedAbility(new ChaosHarlequinEffect(), new ManaCostsImpl<>("{R}"))); } private ChaosHarlequin(final ChaosHarlequin card) { @@ -49,7 +44,8 @@ class ChaosHarlequinEffect extends OneShotEffect { public ChaosHarlequinEffect() { super(Outcome.Benefit); - this.staticText = "Exile the top card of your library. If that card is a land card, {this} gets -4/-0 until end of turn. Otherwise, {this} gets +2/+0 until end of turn"; + this.staticText = "Exile the top card of your library. If that card is a land card, " + + "{this} gets -4/-0 until end of turn. Otherwise, {this} gets +2/+0 until end of turn"; } public ChaosHarlequinEffect(final ChaosHarlequinEffect effect) { @@ -64,18 +60,15 @@ class ChaosHarlequinEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - Card card = player.getLibrary().getFromTop(game); - if (card != null) { - player.moveCardToExileWithInfo(card, null, "", source, game, Zone.LIBRARY, true); - if (card.isLand(game)) { - game.addEffect(new BoostSourceEffect(-4, 0, Duration.EndOfTurn), source); - } else { - game.addEffect(new BoostSourceEffect(2, 0, Duration.EndOfTurn), source); - } - } - return true; + if (player == null) { + return false; } - return false; + Card card = player.getLibrary().getFromTop(game); + if (card == null) { + return false; + } + player.moveCards(card, Zone.EXILED, source, game); + game.addEffect(new BoostSourceEffect(card.isLand(game) ? -4 : 2, 0, Duration.EndOfTurn), source); + return true; } } diff --git a/Mage.Sets/src/mage/cards/c/ChaosMoon.java b/Mage.Sets/src/mage/cards/c/ChaosMoon.java index 6741496ba70..b389e080d3f 100644 --- a/Mage.Sets/src/mage/cards/c/ChaosMoon.java +++ b/Mage.Sets/src/mage/cards/c/ChaosMoon.java @@ -81,7 +81,7 @@ class ChaosMoonEffect extends OneShotEffect { return false; } int permanentsInPlay = game.getBattlefield().count( - StaticFilters.FILTER_PERMANENT, source.getSourceId(), source.getControllerId(), game + StaticFilters.FILTER_PERMANENT, source.getControllerId(), source, game ); // Odd if (permanentsInPlay % 2 == 1) { diff --git a/Mage.Sets/src/mage/cards/c/ChaosWand.java b/Mage.Sets/src/mage/cards/c/ChaosWand.java index 9fc955531ee..0f9fd6e5693 100644 --- a/Mage.Sets/src/mage/cards/c/ChaosWand.java +++ b/Mage.Sets/src/mage/cards/c/ChaosWand.java @@ -12,9 +12,9 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetOpponent; +import mage.util.CardUtil; import java.util.UUID; -import mage.ApprovingObject; /** * @author TheElk801 @@ -28,10 +28,7 @@ public final class ChaosWand extends CardImpl { // until they exile an instant or sorcery card. You may cast that card // without paying its mana cost. Then put the exiled cards that weren't // cast this way on the bottom of that library in a random order. - Ability ability = new SimpleActivatedAbility( - new ChaosWandEffect(), - new GenericManaCost(4) - ); + Ability ability = new SimpleActivatedAbility(new ChaosWandEffect(), new GenericManaCost(4)); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetOpponent()); this.addAbility(ability); @@ -80,25 +77,15 @@ class ChaosWandEffect extends OneShotEffect { if (card == null) { break; } + cardsToShuffle.add(card); opponent.moveCards(card, Zone.EXILED, source, game); - controller.revealCards(source, new CardsImpl(card), game); if (card.isInstantOrSorcery(game)) { - boolean cardWasCast = false; - if (controller.chooseUse(Outcome.PlayForFree, "Cast " + card.getName() - + " without paying its mana cost?", source, game)) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - } - if (!cardWasCast) { - cardsToShuffle.add(card); - } + CardUtil.castSpellWithAttributesForFree(controller, source, game, card); break; - } else { - cardsToShuffle.add(card); } } + cardsToShuffle.retainZone(Zone.EXILED, game); + controller.revealCards(source, cardsToShuffle, game); return opponent.putCardsOnBottomOfLibrary(cardsToShuffle, game, source, false); } } diff --git a/Mage.Sets/src/mage/cards/c/ChaosWarp.java b/Mage.Sets/src/mage/cards/c/ChaosWarp.java index 3d24bfa2ec7..06308ce2694 100644 --- a/Mage.Sets/src/mage/cards/c/ChaosWarp.java +++ b/Mage.Sets/src/mage/cards/c/ChaosWarp.java @@ -98,7 +98,7 @@ class ChaosWarpRevealEffect extends OneShotEffect { return false; } Player owner = game.getPlayer(permanent.getOwnerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (owner == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/c/Chaosphere.java b/Mage.Sets/src/mage/cards/c/Chaosphere.java index 166e589e985..ae385300615 100644 --- a/Mage.Sets/src/mage/cards/c/Chaosphere.java +++ b/Mage.Sets/src/mage/cards/c/Chaosphere.java @@ -74,7 +74,7 @@ class ChaosphereEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filter.match(permanent, source.getControllerId(), source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/c/ChargingSlateback.java b/Mage.Sets/src/mage/cards/c/ChargingSlateback.java index 455426b6bef..af0cfb5bb5a 100644 --- a/Mage.Sets/src/mage/cards/c/ChargingSlateback.java +++ b/Mage.Sets/src/mage/cards/c/ChargingSlateback.java @@ -26,7 +26,7 @@ public final class ChargingSlateback extends CardImpl { // Charging Slateback can't block. this.addAbility(new CantBlockAbility()); // Morph {4}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{R}"))); } private ChargingSlateback(final ChargingSlateback card) { diff --git a/Mage.Sets/src/mage/cards/c/CharmedGriffin.java b/Mage.Sets/src/mage/cards/c/CharmedGriffin.java index b751cbf3692..d5ab22e938d 100644 --- a/Mage.Sets/src/mage/cards/c/CharmedGriffin.java +++ b/Mage.Sets/src/mage/cards/c/CharmedGriffin.java @@ -76,9 +76,9 @@ class CharmedGriffinEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null) { TargetCardInHand target = new TargetCardInHand(new FilterArtifactOrEnchantmentCard()); - if (target.canChoose(source.getSourceId(), playerId, game) + if (target.canChoose(playerId, source, game) && player.chooseUse(Outcome.Neutral, "Put an artifact or enchantment card from your hand onto the battlefield?", source, game) - && player.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { + && player.choose(Outcome.PutCardInPlay, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { toBattlefield.add(card); diff --git a/Mage.Sets/src/mage/cards/c/CharmingPrince.java b/Mage.Sets/src/mage/cards/c/CharmingPrince.java index da9fde85774..16623a0ebca 100644 --- a/Mage.Sets/src/mage/cards/c/CharmingPrince.java +++ b/Mage.Sets/src/mage/cards/c/CharmingPrince.java @@ -90,7 +90,7 @@ class CharmingPrinceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } @@ -98,9 +98,7 @@ class CharmingPrinceEffect extends OneShotEffect { if (permanent == null) { return false; } - if (!controller.moveCardToExileWithInfo(permanent, source.getSourceId(), sourceObject.getIdName(), source, game, Zone.BATTLEFIELD, true)) { - return false; - } + controller.moveCards(permanent, Zone.EXILED, source, game); //create delayed triggered ability Effect effect = new ReturnToBattlefieldUnderYourControlTargetEffect(); effect.setText("Return it to the battlefield under your control at the beginning of the next end step"); diff --git a/Mage.Sets/src/mage/cards/c/ChecksAndBalances.java b/Mage.Sets/src/mage/cards/c/ChecksAndBalances.java index f6fb669a3a3..2e44f6c2c66 100644 --- a/Mage.Sets/src/mage/cards/c/ChecksAndBalances.java +++ b/Mage.Sets/src/mage/cards/c/ChecksAndBalances.java @@ -11,7 +11,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SetTargetPointer; -import mage.filter.FilterSpell; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.stack.Spell; @@ -103,7 +102,7 @@ class ChecksAndBalancesEffect extends OneShotEffect { Player player = game.getPlayer(uuid); if (player != null && !player.getHand().isEmpty()) { TargetCardInHand target = new TargetCardInHand(); - if (player.choose(Outcome.Discard, target, source.getSourceId(), game)) { + if (player.choose(Outcome.Discard, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); player.discard(card, false, source, game); } diff --git a/Mage.Sets/src/mage/cards/c/ChemistersTrick.java b/Mage.Sets/src/mage/cards/c/ChemistersTrick.java index 812b25bfdac..a8d4b4527b4 100644 --- a/Mage.Sets/src/mage/cards/c/ChemistersTrick.java +++ b/Mage.Sets/src/mage/cards/c/ChemistersTrick.java @@ -64,7 +64,7 @@ class ChemistersTrickEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL, source.getControllerId(), source, game)) { AttacksIfAbleTargetEffect effect = new AttacksIfAbleTargetEffect(Duration.EndOfTurn); effect.setTargetPointer(new FixedTarget(creature.getId(), game)); game.addEffect(effect, source); diff --git a/Mage.Sets/src/mage/cards/c/ChillingGrasp.java b/Mage.Sets/src/mage/cards/c/ChillingGrasp.java index 814e23d5e98..8e8c8fad06c 100644 --- a/Mage.Sets/src/mage/cards/c/ChillingGrasp.java +++ b/Mage.Sets/src/mage/cards/c/ChillingGrasp.java @@ -26,7 +26,7 @@ public final class ChillingGrasp extends CardImpl { this.getSpellAbility().addEffect(new DontUntapInControllersNextUntapStepTargetEffect("Those creatures")); // Madness {3}{U} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{3}{U}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{3}{U}"))); } private ChillingGrasp(final ChillingGrasp card) { diff --git a/Mage.Sets/src/mage/cards/c/ChimneyImp.java b/Mage.Sets/src/mage/cards/c/ChimneyImp.java index 8c50b7c30f7..f817a846733 100644 --- a/Mage.Sets/src/mage/cards/c/ChimneyImp.java +++ b/Mage.Sets/src/mage/cards/c/ChimneyImp.java @@ -75,7 +75,7 @@ class ChimneyImpEffect extends OneShotEffect { TargetCardInHand target = new TargetCardInHand(); target.setNotTarget(true); target.setTargetName("a card from your hand to put on top of your library"); - targetOpponent.choose(Outcome.Detriment, target, source.getSourceId(), game); + targetOpponent.choose(Outcome.Detriment, target, source, game); Card card = targetOpponent.getHand().get(target.getFirstTarget(), game); if (card != null) { targetOpponent.moveCardToLibraryWithInfo(card, source, game, Zone.HAND, true, false); diff --git a/Mage.Sets/src/mage/cards/c/ChishiroTheShatteredBlade.java b/Mage.Sets/src/mage/cards/c/ChishiroTheShatteredBlade.java index fc1d21fec3b..6f7b759adc6 100644 --- a/Mage.Sets/src/mage/cards/c/ChishiroTheShatteredBlade.java +++ b/Mage.Sets/src/mage/cards/c/ChishiroTheShatteredBlade.java @@ -13,7 +13,7 @@ import mage.constants.SuperType; import mage.constants.TargetController; import mage.counters.CounterType; import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.ModifiedPredicate; import mage.game.permanent.token.SpiritRedToken; @@ -26,7 +26,7 @@ import java.util.UUID; public final class ChishiroTheShatteredBlade extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("an Aura or Equipment"); - private static final FilterPermanent filter2 = new FilterControlledPermanent("modified creature you control"); + private static final FilterPermanent filter2 = new FilterControlledCreaturePermanent("modified creature you control"); static { filter.add(Predicates.or( diff --git a/Mage.Sets/src/mage/cards/c/ChitteringRats.java b/Mage.Sets/src/mage/cards/c/ChitteringRats.java index 6e9a871b659..a9ff004eda8 100644 --- a/Mage.Sets/src/mage/cards/c/ChitteringRats.java +++ b/Mage.Sets/src/mage/cards/c/ChitteringRats.java @@ -72,7 +72,7 @@ class ChitteringRatsEffect extends OneShotEffect { TargetCardInHand target = new TargetCardInHand(); target.setNotTarget(true); target.setTargetName("a card from your hand to put on top of your library"); - targetOpponent.choose(Outcome.Detriment, target, source.getSourceId(), game); + targetOpponent.choose(Outcome.Detriment, target, source, game); Card card = targetOpponent.getHand().get(target.getFirstTarget(), game); if (card != null) { targetOpponent.moveCardToLibraryWithInfo(card, source, game, Zone.HAND, true, false); diff --git a/Mage.Sets/src/mage/cards/c/ChoArrimAlchemist.java b/Mage.Sets/src/mage/cards/c/ChoArrimAlchemist.java index d4ce9c681e4..867c5d4b3a3 100644 --- a/Mage.Sets/src/mage/cards/c/ChoArrimAlchemist.java +++ b/Mage.Sets/src/mage/cards/c/ChoArrimAlchemist.java @@ -79,7 +79,7 @@ class ChoArrimAlchemistEffect extends PreventionEffectImpl { @Override public void init(Ability source, Game game) { - this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/c/ChromeCat.java b/Mage.Sets/src/mage/cards/c/ChromeCat.java new file mode 100644 index 00000000000..deaa1954c71 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChromeCat.java @@ -0,0 +1,37 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ChromeCat extends CardImpl { + + public ChromeCat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); + + this.subtype.add(SubType.CAT); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // When Chrome Cat enters the battlefield, scry 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(1, false))); + } + + private ChromeCat(final ChromeCat card) { + super(card); + } + + @Override + public ChromeCat copy() { + return new ChromeCat(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ChromeMox.java b/Mage.Sets/src/mage/cards/c/ChromeMox.java index 0b7ccdc18c4..0c5f47e9c4f 100644 --- a/Mage.Sets/src/mage/cards/c/ChromeMox.java +++ b/Mage.Sets/src/mage/cards/c/ChromeMox.java @@ -81,7 +81,7 @@ class ChromeMoxEffect extends OneShotEffect { target.setNotTarget(true); Card cardToImprint = null; Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (!controller.getHand().isEmpty() && controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + if (!controller.getHand().isEmpty() && controller.choose(Outcome.Benefit, target, source, game)) { cardToImprint = controller.getHand().get(target.getFirstTarget(), game); } if (sourcePermanent != null) { diff --git a/Mage.Sets/src/mage/cards/c/ChromeReplicator.java b/Mage.Sets/src/mage/cards/c/ChromeReplicator.java index 3bfecae7b0c..ea8e2c44bb2 100644 --- a/Mage.Sets/src/mage/cards/c/ChromeReplicator.java +++ b/Mage.Sets/src/mage/cards/c/ChromeReplicator.java @@ -70,7 +70,7 @@ enum ChromeReplicatorCondition implements Condition { return game .getBattlefield() .getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game ).stream() .filter(Objects::nonNull) .map(MageObject::getName) diff --git a/Mage.Sets/src/mage/cards/c/ChromeshellCrab.java b/Mage.Sets/src/mage/cards/c/ChromeshellCrab.java index 9a59d61658c..2f3fc4ab1eb 100644 --- a/Mage.Sets/src/mage/cards/c/ChromeshellCrab.java +++ b/Mage.Sets/src/mage/cards/c/ChromeshellCrab.java @@ -34,7 +34,7 @@ public final class ChromeshellCrab extends CardImpl { this.toughness = new MageInt(3); // Morph {4}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{U}"))); // When Chromeshell Crab is turned face up, you may exchange control of target creature you control and target creature an opponent controls. Effect effect = new ExchangeControlTargetEffect(Duration.EndOfGame, rule, false, true); diff --git a/Mage.Sets/src/mage/cards/c/ChronomanticEscape.java b/Mage.Sets/src/mage/cards/c/ChronomanticEscape.java index a6057b39bc5..955d974369c 100644 --- a/Mage.Sets/src/mage/cards/c/ChronomanticEscape.java +++ b/Mage.Sets/src/mage/cards/c/ChronomanticEscape.java @@ -30,7 +30,7 @@ public final class ChronomanticEscape extends CardImpl { getSpellAbility().addEffect(new CantAttackYouAllEffect(Duration.UntilYourNextTurn, StaticFilters.FILTER_PERMANENT_CREATURES)); getSpellAbility().addEffect(new ExileSpellEffect()); Effect effect = new AddCountersSourceEffect(CounterType.TIME.createInstance(), StaticValue.get(3), true, true); - effect.setText("with 3 time counters on it"); + effect.setText("with three time counters on it"); getSpellAbility().addEffect(effect); // Suspend 3-{2}{W} diff --git a/Mage.Sets/src/mage/cards/c/ChunLiCountlessKicks.java b/Mage.Sets/src/mage/cards/c/ChunLiCountlessKicks.java new file mode 100644 index 00000000000..eb60a646108 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChunLiCountlessKicks.java @@ -0,0 +1,156 @@ +package mage.cards.c; + +import mage.ApprovingObject; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.MultikickerCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.MultikickerAbility; +import mage.cards.*; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; +import org.apache.log4j.Logger; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ChunLiCountlessKicks extends CardImpl { + + public ChunLiCountlessKicks(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Multikicker {W/U} + this.addAbility(new MultikickerAbility("{W/U}")); + + // When Chun-Li enters the battlefield, exile up to X target instant cards from your graveyard, where X is the number of times Chun-Li was kicked. Put a kick counter on each of them. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ChunLiCountlessKicksExileEffect()) + .setTargetAdjuster(ChunLiCountlessKicksAdjuster.instance)); + + // Lightning Kick—Whenever Chun-Li attacks, copy each exiled card you own with a kick counter on it. You may cast the copies. + this.addAbility(new AttacksTriggeredAbility(new ChunLiCountlessKicksCastEffect()).withFlavorWord("Lightning Kick")); + } + + private ChunLiCountlessKicks(final ChunLiCountlessKicks card) { + super(card); + } + + @Override + public ChunLiCountlessKicks copy() { + return new ChunLiCountlessKicks(this); + } +} + +enum ChunLiCountlessKicksAdjuster implements TargetAdjuster { + instance; + private static final FilterCard filter = new FilterCard("instant cards from your graveyard"); + + static { + filter.add(CardType.INSTANT.getPredicate()); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + int count = MultikickerCount.instance.calculate(game, ability, null); + ability.getTargets().clear(); + ability.addTarget(new TargetCardInYourGraveyard(0, count, filter)); + } +} + +class ChunLiCountlessKicksExileEffect extends OneShotEffect { + + ChunLiCountlessKicksExileEffect() { + super(Outcome.Benefit); + staticText = "exile up to X target instant cards from your graveyard, " + + "where X is the number of times {this} was kicked. Put a kick counter on each of them"; + } + + private ChunLiCountlessKicksExileEffect(final ChunLiCountlessKicksExileEffect effect) { + super(effect); + } + + @Override + public ChunLiCountlessKicksExileEffect copy() { + return new ChunLiCountlessKicksExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Cards cards = new CardsImpl(getTargetPointer().getTargets(game, source)); + if (player == null || cards.isEmpty()) { + return false; + } + player.moveCards(cards, Zone.EXILED, source, game); + cards.getCards(game).forEach(card -> card.addCounters(CounterType.KICK.createInstance(), source, game)); + return true; + } +} + +class ChunLiCountlessKicksCastEffect extends OneShotEffect { + + ChunLiCountlessKicksCastEffect() { + super(Outcome.Benefit); + staticText = "copy each exiled card you own with a kick counter on it. You may cast the copies"; + } + + private ChunLiCountlessKicksCastEffect(final ChunLiCountlessKicksCastEffect effect) { + super(effect); + } + + @Override + public ChunLiCountlessKicksCastEffect copy() { + return new ChunLiCountlessKicksCastEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(game.getExile().getAllCards(game, source.getControllerId())); + cards.removeIf(uuid -> !game.getCard(uuid).getCounters(game).containsKey(CounterType.KICK)); + if (cards.isEmpty()) { + return false; + } + Cards copies = new CardsImpl(); + for (Card card : cards.getCards(game)) { + Card copiedCard = game.copyCard(card, source, source.getControllerId()); + game.getExile().add(source.getSourceId(), "", copiedCard); + game.getState().setZone(copiedCard.getId(), Zone.EXILED); + copies.add(copiedCard); + } + for (Card copiedCard : copies.getCards(game)) { + if (!player.chooseUse(outcome, "Cast the copied card?", source, game)) { + continue; + } + if (copiedCard.getSpellAbility() != null) { + game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), Boolean.TRUE); + player.cast( + player.chooseAbilityForCast(copiedCard, game, false), + game, false, new ApprovingObject(source, game) + ); + game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), null); + } else { + Logger.getLogger(ChunLiCountlessKicksCastEffect.class).error("Chun Li, Countless Kicks: " + + "spell ability == null " + copiedCard.getName()); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CinderWall.java b/Mage.Sets/src/mage/cards/c/CinderWall.java index ad72fee897c..28291f49188 100644 --- a/Mage.Sets/src/mage/cards/c/CinderWall.java +++ b/Mage.Sets/src/mage/cards/c/CinderWall.java @@ -1,4 +1,3 @@ - package mage.cards.c; import java.util.UUID; @@ -29,10 +28,13 @@ public final class CinderWall extends CardImpl { // Defender this.addAbility(DefenderAbility.getInstance()); // When Cinder Wall blocks, destroy it at end of combat. - this.addAbility(new BlocksSourceTriggeredAbility( - new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(new DestroySourceEffect())), - false, false, true - )); + this.addAbility( + new BlocksSourceTriggeredAbility( + new CreateDelayedTriggeredAbilityEffect( + new AtTheEndOfCombatDelayedTriggeredAbility(new DestroySourceEffect()) + ).setText("destroy it at end of combat") + ).setTriggerPhrase("When {this} blocks, ") + ); } private CinderWall(final CinderWall card) { diff --git a/Mage.Sets/src/mage/cards/c/CinderheartGiant.java b/Mage.Sets/src/mage/cards/c/CinderheartGiant.java index 4dc474cf9fe..41edce72e3b 100644 --- a/Mage.Sets/src/mage/cards/c/CinderheartGiant.java +++ b/Mage.Sets/src/mage/cards/c/CinderheartGiant.java @@ -70,7 +70,7 @@ class CinderheartGiantEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player == null || game.getBattlefield().count( StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, - source.getSourceId(), source.getControllerId(), game + source.getControllerId(), source, game ) < 1) { return false; } diff --git a/Mage.Sets/src/mage/cards/c/CircleOfProtectionArtifacts.java b/Mage.Sets/src/mage/cards/c/CircleOfProtectionArtifacts.java index aa1ed0ccb71..4439aa712fd 100644 --- a/Mage.Sets/src/mage/cards/c/CircleOfProtectionArtifacts.java +++ b/Mage.Sets/src/mage/cards/c/CircleOfProtectionArtifacts.java @@ -30,7 +30,7 @@ public final class CircleOfProtectionArtifacts extends CardImpl { // {2}: The next time an artifact source of your choice would deal damage to you this turn, prevent that damage. Effect effect = new PreventNextDamageFromChosenSourceToYouEffect(Duration.EndOfTurn, filter); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("2"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{2}"))); } private CircleOfProtectionArtifacts(final CircleOfProtectionArtifacts card) { diff --git a/Mage.Sets/src/mage/cards/c/CircleOfProtectionBlack.java b/Mage.Sets/src/mage/cards/c/CircleOfProtectionBlack.java index 3f2f5a3ed25..04ae99ce2c9 100644 --- a/Mage.Sets/src/mage/cards/c/CircleOfProtectionBlack.java +++ b/Mage.Sets/src/mage/cards/c/CircleOfProtectionBlack.java @@ -33,7 +33,7 @@ public final class CircleOfProtectionBlack extends CardImpl { // {1}: The next time a black source of your choice would deal damage to you this turn, prevent that damage. Effect effect = new PreventNextDamageFromChosenSourceToYouEffect(Duration.EndOfTurn, filter); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("1"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{1}"))); } private CircleOfProtectionBlack(final CircleOfProtectionBlack card) { diff --git a/Mage.Sets/src/mage/cards/c/CircleOfProtectionBlue.java b/Mage.Sets/src/mage/cards/c/CircleOfProtectionBlue.java index 9ffe0cc9ac5..f8427073049 100644 --- a/Mage.Sets/src/mage/cards/c/CircleOfProtectionBlue.java +++ b/Mage.Sets/src/mage/cards/c/CircleOfProtectionBlue.java @@ -33,7 +33,7 @@ public final class CircleOfProtectionBlue extends CardImpl { // {1}: The next time a blue source of your choice would deal damage to you this turn, prevent that damage. Effect effect = new PreventNextDamageFromChosenSourceToYouEffect(Duration.EndOfTurn, filter); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("1"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{1}"))); } private CircleOfProtectionBlue(final CircleOfProtectionBlue card) { diff --git a/Mage.Sets/src/mage/cards/c/CircleOfProtectionGreen.java b/Mage.Sets/src/mage/cards/c/CircleOfProtectionGreen.java index dc7be67826e..642c7a50783 100644 --- a/Mage.Sets/src/mage/cards/c/CircleOfProtectionGreen.java +++ b/Mage.Sets/src/mage/cards/c/CircleOfProtectionGreen.java @@ -33,7 +33,7 @@ public final class CircleOfProtectionGreen extends CardImpl { // {1}: The next time a green source of your choice would deal damage to you this turn, prevent that damage. Effect effect = new PreventNextDamageFromChosenSourceToYouEffect(Duration.EndOfTurn, filter); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("1"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{1}"))); } private CircleOfProtectionGreen(final CircleOfProtectionGreen card) { diff --git a/Mage.Sets/src/mage/cards/c/CircleOfProtectionRed.java b/Mage.Sets/src/mage/cards/c/CircleOfProtectionRed.java index 6d9e177df40..97f0bece75a 100644 --- a/Mage.Sets/src/mage/cards/c/CircleOfProtectionRed.java +++ b/Mage.Sets/src/mage/cards/c/CircleOfProtectionRed.java @@ -33,7 +33,7 @@ public final class CircleOfProtectionRed extends CardImpl { // {1}: The next time a red source of your choice would deal damage to you this turn, prevent that damage. Effect effect = new PreventNextDamageFromChosenSourceToYouEffect(Duration.EndOfTurn, filter); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("1"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{1}"))); } private CircleOfProtectionRed(final CircleOfProtectionRed card) { diff --git a/Mage.Sets/src/mage/cards/c/CircleOfProtectionShadow.java b/Mage.Sets/src/mage/cards/c/CircleOfProtectionShadow.java index 62aa70f0756..a3a8f069dfa 100644 --- a/Mage.Sets/src/mage/cards/c/CircleOfProtectionShadow.java +++ b/Mage.Sets/src/mage/cards/c/CircleOfProtectionShadow.java @@ -33,7 +33,7 @@ public final class CircleOfProtectionShadow extends CardImpl { // {1}: The next time a creature of your choice with shadow would deal damage to you this turn, prevent that damage. Effect effect = new PreventNextDamageFromChosenSourceToYouEffect(Duration.EndOfTurn, filter); effect.setText("The next time a creature of your choice with shadow would deal damage to you this turn, prevent that damage"); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("1"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{1}"))); } private CircleOfProtectionShadow(final CircleOfProtectionShadow card) { diff --git a/Mage.Sets/src/mage/cards/c/CircleOfProtectionWhite.java b/Mage.Sets/src/mage/cards/c/CircleOfProtectionWhite.java index dae973e3811..b94573a3df2 100644 --- a/Mage.Sets/src/mage/cards/c/CircleOfProtectionWhite.java +++ b/Mage.Sets/src/mage/cards/c/CircleOfProtectionWhite.java @@ -33,7 +33,7 @@ public final class CircleOfProtectionWhite extends CardImpl { // {1}: The next time a white source of your choice would deal damage to you this turn, prevent that damage. Effect effect = new PreventNextDamageFromChosenSourceToYouEffect(Duration.EndOfTurn, filter); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("1"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{1}"))); } private CircleOfProtectionWhite(final CircleOfProtectionWhite card) { diff --git a/Mage.Sets/src/mage/cards/c/CircuDimirLobotomist.java b/Mage.Sets/src/mage/cards/c/CircuDimirLobotomist.java index b1940d5e158..c10debb4e46 100644 --- a/Mage.Sets/src/mage/cards/c/CircuDimirLobotomist.java +++ b/Mage.Sets/src/mage/cards/c/CircuDimirLobotomist.java @@ -8,7 +8,6 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -17,8 +16,6 @@ import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.ExileZone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPlayer; import mage.util.CardUtil; @@ -58,7 +55,7 @@ public final class CircuDimirLobotomist extends CardImpl { this.addAbility(ability); // Your opponents can't cast nonland cards with the same name as a card exiled with Circu, Dimir Lobotomist. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CircuDimirLobotomistRuleModifyingEffect())); + this.addAbility(new SimpleStaticAbility(new CircuDimirLobotomistRuleModifyingEffect())); } private CircuDimirLobotomist(final CircuDimirLobotomist card) { @@ -91,14 +88,14 @@ class CircuDimirLobotomistEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Player playerTargetLibrary = game.getPlayer(getTargetPointer().getFirst(game, source)); - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (controller != null && playerTargetLibrary != null && sourcePermanent != null) { - UUID exileId = CardUtil.getCardExileZoneId(game, source); - controller.moveCardToExileWithInfo(playerTargetLibrary.getLibrary().getFromTop(game), exileId, - sourcePermanent.getIdName() + " (" + sourcePermanent.getZoneChangeCounter(game) + ')', source, game, Zone.BATTLEFIELD, true); - return true; + if (controller == null || playerTargetLibrary == null) { + return false; } - return false; + controller.moveCardsToExile( + playerTargetLibrary.getLibrary().getFromTop(game), source, game, true, + CardUtil.getCardExileZoneId(game, source), CardUtil.getSourceName(game, source) + ); + return true; } } @@ -120,28 +117,23 @@ class CircuDimirLobotomistRuleModifyingEffect extends ContinuousRuleModifyingEff @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); - if (mageObject != null) { - return "You can't cast this spell because a card with the same name is exiled by " + mageObject.getLogName() + '.'; - } - return null; + return "You can't cast this spell because a card with the same name is exiled by " + CardUtil.getSourceName(game, source) + '.'; } @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.CAST_SPELL && game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { - MageObject object = game.getObject(event.getSourceId()); - if (object != null) { - ExileZone exileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); - if ((exileZone != null)) { - for (Card card : exileZone.getCards(game)) { - if (CardUtil.haveSameNames(card, object)) { - return true; - } - } - } - } + if (event.getType() != GameEvent.EventType.CAST_SPELL + || !game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { + return false; } - return false; + MageObject object = game.getObject(event.getSourceId()); + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); + return object != null + && exileZone != null + && !exileZone.isEmpty() + && exileZone + .getCards(game) + .stream() + .anyMatch(card -> CardUtil.haveSameNames(card, object)); } } diff --git a/Mage.Sets/src/mage/cards/c/CircularLogic.java b/Mage.Sets/src/mage/cards/c/CircularLogic.java index 99a28b12469..2ded66eb0c9 100644 --- a/Mage.Sets/src/mage/cards/c/CircularLogic.java +++ b/Mage.Sets/src/mage/cards/c/CircularLogic.java @@ -28,7 +28,7 @@ public final class CircularLogic extends CardImpl { this.getSpellAbility().addTarget(new TargetSpell()); // Madness {U} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{U}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{U}"))); } private CircularLogic(final CircularLogic card) { diff --git a/Mage.Sets/src/mage/cards/c/CitizensCrowbar.java b/Mage.Sets/src/mage/cards/c/CitizensCrowbar.java new file mode 100644 index 00000000000..40c9431b094 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CitizensCrowbar.java @@ -0,0 +1,60 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.SacrificeAttachmentCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenAttachSourceEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityWithAttachmentEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.CitizenGreenWhiteToken; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CitizensCrowbar extends CardImpl { + + public CitizensCrowbar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{W}"); + + this.subtype.add(SubType.EQUIPMENT); + + // When Citizen's Crowbar enters the battlefield, create a 1/1 green and white Citizen creature token, then attach Citizen's Crowbar to it. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new CreateTokenAttachSourceEffect(new CitizenGreenWhiteToken()) + )); + + // Equipped creature gets +1/+1 and has "{W}, {T}, Sacrifice Citizen's Crowbar: Destroy target artifact or enchantment." + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(1, 1)); + ability.addEffect(new GainAbilityWithAttachmentEffect( + "and has \"{W}, {T}, Sacrifice {this}: Destroy target artifact or enchantment.\"", + new DestroyTargetEffect(), new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT), + new SacrificeAttachmentCost(), new ManaCostsImpl<>("{W}"), new TapSourceCost() + )); + this.addAbility(ability); + + // Equip {2} + this.addAbility(new EquipAbility(2)); + } + + private CitizensCrowbar(final CitizensCrowbar card) { + super(card); + } + + @Override + public CitizensCrowbar copy() { + return new CitizensCrowbar(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CityInABottle.java b/Mage.Sets/src/mage/cards/c/CityInABottle.java index 30d668281d3..2177c78905e 100644 --- a/Mage.Sets/src/mage/cards/c/CityInABottle.java +++ b/Mage.Sets/src/mage/cards/c/CityInABottle.java @@ -158,7 +158,7 @@ class CityInABottleStateTriggeredAbility extends StateTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - return game.getBattlefield().contains(filter, this.getSourceId(), this.getControllerId(), game, 1); + return game.getBattlefield().contains(filter, this.getSourceId(), this.getControllerId(), this, game, 1); } @Override @@ -192,7 +192,7 @@ class CityInABottleSacrificeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanent.sacrifice(source, game); } return true; @@ -239,6 +239,6 @@ class CityInABottleCantPlayEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { Card card = game.getCard(event.getSourceId()); - return filter.match(card, source.getSourceId(), source.getControllerId(), game); + return filter.match(card, source.getControllerId(), source, game); } } diff --git a/Mage.Sets/src/mage/cards/c/CityOfSolitude.java b/Mage.Sets/src/mage/cards/c/CityOfSolitude.java index fdb24401c75..409048a05e4 100644 --- a/Mage.Sets/src/mage/cards/c/CityOfSolitude.java +++ b/Mage.Sets/src/mage/cards/c/CityOfSolitude.java @@ -57,7 +57,7 @@ class CityOfSolitudeEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); MageObject eventObject = game.getObject(event.getSourceId()); if (sourceObject != null && eventObject != null) { return "You can cast or activate anability of " + eventObject.getIdName() + " only during your own turns (" + sourceObject.getIdName() + "). "; diff --git a/Mage.Sets/src/mage/cards/c/CitystalkerConnoisseur.java b/Mage.Sets/src/mage/cards/c/CitystalkerConnoisseur.java new file mode 100644 index 00000000000..746a87e1ac8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CitystalkerConnoisseur.java @@ -0,0 +1,101 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.token.BloodToken; +import mage.players.Player; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CitystalkerConnoisseur extends CardImpl { + + public CitystalkerConnoisseur(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // When Citystalker Connoisseur enters the battlefield, target opponent discards a card with the greatest mana value among cards in their hand. Create a Blood token. + Ability ability = new EntersBattlefieldTriggeredAbility(new CitystalkerConnoisseurEffect()); + ability.addEffect(new CreateTokenEffect(new BloodToken())); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + private CitystalkerConnoisseur(final CitystalkerConnoisseur card) { + super(card); + } + + @Override + public CitystalkerConnoisseur copy() { + return new CitystalkerConnoisseur(this); + } +} + +class CitystalkerConnoisseurEffect extends OneShotEffect { + + CitystalkerConnoisseurEffect() { + super(Outcome.Discard); + staticText = "target opponent discards a card with the greatest mana value among cards in their hand"; + } + + private CitystalkerConnoisseurEffect(final CitystalkerConnoisseurEffect effect) { + super(effect); + } + + @Override + public CitystalkerConnoisseurEffect copy() { + return new CitystalkerConnoisseurEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getFirstTarget()); + if (player == null || player.getHand().isEmpty()) { + return false; + } + if (player.getHand().size() == 1) { + player.discard(player.getHand(), false, source, game); + return true; + } + int maxValue = player + .getHand() + .getCards(game) + .stream() + .mapToInt(MageObject::getManaValue) + .max() + .orElse(0); + Cards cards = new CardsImpl(player.getHand()); + cards.removeIf(uuid -> game.getCard(uuid).getManaValue() < maxValue); + if (cards.size() == 1) { + player.discard(cards, false, source, game); + return true; + } + TargetCardInHand target = new TargetCardInHand(); + player.choose(outcome, cards, target, game); + player.discard(cards.get(target.getFirstTarget(), game), false, source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CivicGardener.java b/Mage.Sets/src/mage/cards/c/CivicGardener.java new file mode 100644 index 00000000000..61dac145b2b --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CivicGardener.java @@ -0,0 +1,50 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; + +/** + * + * @author weirddan455 + */ +public final class CivicGardener extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("creature or land"); + + static { + filter.add(Predicates.or(CardType.CREATURE.getPredicate(), CardType.LAND.getPredicate())); + } + + public CivicGardener(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever Civic Gardener attacks, untap target creature or land. + Ability ability = new AttacksTriggeredAbility(new UntapTargetEffect()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private CivicGardener(final CivicGardener card) { + super(card); + } + + @Override + public CivicGardener copy() { + return new CivicGardener(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CivilServant.java b/Mage.Sets/src/mage/cards/c/CivilServant.java new file mode 100644 index 00000000000..52d80ba5126 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CivilServant.java @@ -0,0 +1,60 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CivilServant extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledPermanent(SubType.CITIZEN, "another untapped Citizen you control"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(TappedPredicate.UNTAPPED); + } + + public CivilServant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}"); + + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Whenever Civil Servant attacks, you may tap another untapped Citizen you control. If you do, Civil Servant gets +1/+0 and gains lifelink until end of turn. + this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( + new BoostSourceEffect(1, 0, Duration.EndOfTurn).setText("{this} gets +1/+0"), + new TapTargetCost(new TargetControlledPermanent(filter)) + ).addEffect(new GainAbilitySourceEffect( + LifelinkAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains lifelink until end of turn")))); + } + + private CivilServant(final CivilServant card) { + super(card); + } + + @Override + public CivilServant copy() { + return new CivilServant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ClackbridgeTroll.java b/Mage.Sets/src/mage/cards/c/ClackbridgeTroll.java index 0388d41c922..12609ef38c0 100644 --- a/Mage.Sets/src/mage/cards/c/ClackbridgeTroll.java +++ b/Mage.Sets/src/mage/cards/c/ClackbridgeTroll.java @@ -94,9 +94,9 @@ class ClackbridgeTrollEffect extends OneShotEffect { } TargetControlledPermanent target = new TargetControlledPermanent(filter); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), opponent.getId(), game) + if (!target.canChoose(opponent.getId(), source, game) || !opponent.chooseUse(Outcome.AIDontUseIt, "Sacrifice a creature?", source, game) - || !opponent.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) { + || !opponent.choose(Outcome.Sacrifice, target, source, game)) { continue; } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/c/Clambassadors.java b/Mage.Sets/src/mage/cards/c/Clambassadors.java index f1a37fd465b..ddf3f37cc3e 100644 --- a/Mage.Sets/src/mage/cards/c/Clambassadors.java +++ b/Mage.Sets/src/mage/cards/c/Clambassadors.java @@ -81,8 +81,8 @@ class ClambassadorsEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Target target = new TargetControlledPermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - while (!target.isChosen() && target.canChoose(source.getSourceId(), controller.getId(), game) && controller.canRespond()) { + if (target.canChoose(controller.getId(), source, game)) { + while (!target.isChosen() && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target, source, game); } } diff --git a/Mage.Sets/src/mage/cards/c/ClanDefiance.java b/Mage.Sets/src/mage/cards/c/ClanDefiance.java index 4ae9cb1daa6..a1a622f778d 100644 --- a/Mage.Sets/src/mage/cards/c/ClanDefiance.java +++ b/Mage.Sets/src/mage/cards/c/ClanDefiance.java @@ -38,13 +38,11 @@ public final class ClanDefiance extends CardImpl { this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.REGULAR)); this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterFlying).withChooseHint("deals X damage, with flying")); // Clan Defiance deals X damage to target creature without flying; - Mode mode1 = new Mode(); - mode1.addEffect(new DamageTargetEffect(ManacostVariableValue.REGULAR)); + Mode mode1 = new Mode(new DamageTargetEffect(ManacostVariableValue.REGULAR)); mode1.addTarget(new TargetCreaturePermanent(filterWithoutFlying).withChooseHint("deals X damage, without flying")); this.getSpellAbility().addMode(mode1); // and/or Clan Defiance deals X damage to target player. - Mode mode2 = new Mode(); - mode2.addEffect(new DamageTargetEffect(ManacostVariableValue.REGULAR)); + Mode mode2 = new Mode(new DamageTargetEffect(ManacostVariableValue.REGULAR)); mode2.addTarget(new TargetPlayerOrPlaneswalker().withChooseHint("deals X damage")); this.getSpellAbility().addMode(mode2); diff --git a/Mage.Sets/src/mage/cards/c/ClarionUltimatum.java b/Mage.Sets/src/mage/cards/c/ClarionUltimatum.java index 53c5deacce1..2835ac886e3 100644 --- a/Mage.Sets/src/mage/cards/c/ClarionUltimatum.java +++ b/Mage.Sets/src/mage/cards/c/ClarionUltimatum.java @@ -69,11 +69,11 @@ class ClarionUltimatumEffect extends OneShotEffect { } int permCount = game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_PERMANENT, - source.getSourceId(), source.getControllerId(), game + source.getControllerId(), source, game ); TargetPermanent targetPermanent = new TargetControlledPermanent(Math.max(permCount, 5)); targetPermanent.setNotTarget(true); - player.choose(outcome, targetPermanent, source.getSourceId(), game); + player.choose(outcome, targetPermanent, source, game); Set names = targetPermanent .getTargets() .stream() diff --git a/Mage.Sets/src/mage/cards/c/ClawsOfValakut.java b/Mage.Sets/src/mage/cards/c/ClawsOfValakut.java index 0684f8d3680..ab25ad766ce 100644 --- a/Mage.Sets/src/mage/cards/c/ClawsOfValakut.java +++ b/Mage.Sets/src/mage/cards/c/ClawsOfValakut.java @@ -42,7 +42,7 @@ public final class ClawsOfValakut extends CardImpl { SimpleStaticAbility ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(new PermanentsOnBattlefieldCount(filter, 1), new PermanentsOnBattlefieldCount(filter, 0), Duration.WhileOnBattlefield)); - ability.addEffect(new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.AURA)); + ability.addEffect(new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.AURA).setText("and has first strike")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CleansingMeditation.java b/Mage.Sets/src/mage/cards/c/CleansingMeditation.java index 1c7a6a19ea6..b3716a38538 100644 --- a/Mage.Sets/src/mage/cards/c/CleansingMeditation.java +++ b/Mage.Sets/src/mage/cards/c/CleansingMeditation.java @@ -9,6 +9,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -46,7 +47,7 @@ class CleansingMeditationEffect extends OneShotEffect { public CleansingMeditationEffect() { super(Outcome.DestroyPermanent); - this.staticText = "Destroy all enchantments.
Threshold - If seven or more cards are in your graveyard, instead destroy all enchantments, then return all cards in your graveyard destroyed this way to the battlefield."; + this.staticText = "Destroy all enchantments.
" + AbilityWord.THRESHOLD.formatWord() + "If seven or more cards are in your graveyard, instead destroy all enchantments, then return all cards in your graveyard destroyed this way to the battlefield."; } public CleansingMeditationEffect(final CleansingMeditationEffect effect) { @@ -72,7 +73,7 @@ class CleansingMeditationEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_ENCHANTMENT, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_ENCHANTMENT, source.getControllerId(), source, game)) { if (permanent != null && permanent.destroy(source, game, false)) { if (threshold && controller != null && permanent.isOwnedBy(controller.getId())) { cardsToBattlefield.add(permanent); diff --git a/Mage.Sets/src/mage/cards/c/CleansingNova.java b/Mage.Sets/src/mage/cards/c/CleansingNova.java index ce6652ee4c1..f4ac94234f4 100644 --- a/Mage.Sets/src/mage/cards/c/CleansingNova.java +++ b/Mage.Sets/src/mage/cards/c/CleansingNova.java @@ -26,8 +26,7 @@ public final class CleansingNova extends CardImpl { this.getSpellAbility().addEffect(new DestroyAllEffect(StaticFilters.FILTER_PERMANENT_CREATURES)); // • Destroy all artifacts and enchantments. - Mode mode = new Mode(); - mode.addEffect(new DestroyAllEffect(filter)); + Mode mode = new Mode(new DestroyAllEffect(filter)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/CleansingRay.java b/Mage.Sets/src/mage/cards/c/CleansingRay.java index d1bed44724a..4a3db217e91 100644 --- a/Mage.Sets/src/mage/cards/c/CleansingRay.java +++ b/Mage.Sets/src/mage/cards/c/CleansingRay.java @@ -29,8 +29,7 @@ public final class CleansingRay extends CardImpl { getSpellAbility().addTarget(new TargetPermanent(filter)); // - Destroy target enchantment. - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetEnchantmentPermanent()); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/c/CleanupCrew.java b/Mage.Sets/src/mage/cards/c/CleanupCrew.java new file mode 100644 index 00000000000..d743613bd76 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CleanupCrew.java @@ -0,0 +1,57 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetArtifactPermanent; +import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetEnchantmentPermanent; + +/** + * + * @author weirddan455 + */ +public final class CleanupCrew extends CardImpl { + + public CleanupCrew(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // When Cleanup Crew enters the battlefield, choose one — + // • Destroy target artifact. + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()); + ability.addTarget(new TargetArtifactPermanent()); + + // • Destroy target enchantment. + ability.addMode(new Mode(new DestroyTargetEffect()).addTarget(new TargetEnchantmentPermanent())); + + // • Exile target card from a graveyard. + ability.addMode(new Mode(new ExileTargetEffect()).addTarget(new TargetCardInGraveyard())); + + // • You gain 4 life. + ability.addMode(new Mode(new GainLifeEffect(4))); + this.addAbility(ability); + } + + private CleanupCrew(final CleanupCrew card) { + super(card); + } + + @Override + public CleanupCrew copy() { + return new CleanupCrew(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CleavingSliver.java b/Mage.Sets/src/mage/cards/c/CleavingSliver.java index b3da1f12439..276865cf0c5 100644 --- a/Mage.Sets/src/mage/cards/c/CleavingSliver.java +++ b/Mage.Sets/src/mage/cards/c/CleavingSliver.java @@ -27,7 +27,7 @@ public final class CleavingSliver extends CardImpl { // Sliver creatures you control get +2/+0. this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( 2, 0, Duration.WhileOnBattlefield, - StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS + StaticFilters.FILTER_PERMANENT_SLIVERS ))); } diff --git a/Mage.Sets/src/mage/cards/c/ClericOfChillDepths.java b/Mage.Sets/src/mage/cards/c/ClericOfChillDepths.java index 8e02967bcf0..f74a5a12d9a 100644 --- a/Mage.Sets/src/mage/cards/c/ClericOfChillDepths.java +++ b/Mage.Sets/src/mage/cards/c/ClericOfChillDepths.java @@ -1,7 +1,7 @@ package mage.cards.c; import mage.MageInt; -import mage.abilities.common.BlocksSourceTriggeredAbility; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -24,8 +24,8 @@ public final class ClericOfChillDepths extends CardImpl { this.toughness = new MageInt(3); // Whenever Cleric of Chill Depths blocks a creature, that creature doesn't untap during its controller's next untap step. - this.addAbility(new BlocksSourceTriggeredAbility( - new DontUntapInControllersNextUntapStepTargetEffect("that creature"), false, true + this.addAbility(new BlocksCreatureTriggeredAbility( + new DontUntapInControllersNextUntapStepTargetEffect("that creature") )); } diff --git a/Mage.Sets/src/mage/cards/c/ClingingMists.java b/Mage.Sets/src/mage/cards/c/ClingingMists.java index 7506823282f..bed1c919805 100644 --- a/Mage.Sets/src/mage/cards/c/ClingingMists.java +++ b/Mage.Sets/src/mage/cards/c/ClingingMists.java @@ -63,7 +63,7 @@ class ClingingMistsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { List doNotUntapNextUntapStep = new ArrayList<>(); - for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_ATTACKING_CREATURES, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_ATTACKING_CREATURES, source.getControllerId(), source, game)) { creature.tap(source, game); doNotUntapNextUntapStep.add(creature); } diff --git a/Mage.Sets/src/mage/cards/c/CloakAndDagger.java b/Mage.Sets/src/mage/cards/c/CloakAndDagger.java index 914d65b2248..68ebe8cc4cb 100644 --- a/Mage.Sets/src/mage/cards/c/CloakAndDagger.java +++ b/Mage.Sets/src/mage/cards/c/CloakAndDagger.java @@ -1,4 +1,3 @@ - package mage.cards.c; import java.util.UUID; @@ -23,11 +22,7 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class CloakAndDagger extends CardImpl { - private static final FilterPermanent filter = new FilterCreaturePermanent("a Rogue creature"); - - static { - filter.add(SubType.ROGUE.getPredicate()); - } + private static final FilterPermanent filter = new FilterCreaturePermanent(SubType.ROGUE, "a Rogue creature"); public CloakAndDagger(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.TRIBAL, CardType.ARTIFACT}, "{2}"); diff --git a/Mage.Sets/src/mage/cards/c/ClotSliver.java b/Mage.Sets/src/mage/cards/c/ClotSliver.java index be39f61fb12..d0c769b9383 100644 --- a/Mage.Sets/src/mage/cards/c/ClotSliver.java +++ b/Mage.Sets/src/mage/cards/c/ClotSliver.java @@ -1,4 +1,3 @@ - package mage.cards.c; import mage.MageInt; @@ -12,7 +11,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterPermanent; import java.util.UUID; @@ -22,19 +20,19 @@ import java.util.UUID; */ public final class ClotSliver extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("Slivers"); - - static { - filter.add(SubType.SLIVER.getPredicate()); - } + private static final FilterPermanent filter = new FilterPermanent(SubType.SLIVER, "all Slivers"); public ClotSliver(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.SLIVER); this.power = new MageInt(1); this.toughness = new MageInt(1); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect("this permanent"), new GenericManaCost(2)), Duration.WhileOnBattlefield, filter, false))); + this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( + new SimpleActivatedAbility( + new RegenerateSourceEffect("this permanent"), new GenericManaCost(2) + ), Duration.WhileOnBattlefield, filter, false + ))); } private ClotSliver(final ClotSliver card) { diff --git a/Mage.Sets/src/mage/cards/c/CloudshredderSliver.java b/Mage.Sets/src/mage/cards/c/CloudshredderSliver.java index 15a194d3a3a..203142ec60e 100644 --- a/Mage.Sets/src/mage/cards/c/CloudshredderSliver.java +++ b/Mage.Sets/src/mage/cards/c/CloudshredderSliver.java @@ -30,11 +30,11 @@ public final class CloudshredderSliver extends CardImpl { // Sliver creatures you control have flying and haste. Ability ability = new SimpleStaticAbility(new GainAbilityControlledEffect( FlyingAbility.getInstance(), Duration.WhileOnBattlefield, - StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS + StaticFilters.FILTER_PERMANENT_ALL_SLIVERS ).setText("Sliver creatures you control have flying")); ability.addEffect(new GainAbilityControlledEffect( HasteAbility.getInstance(), Duration.WhileOnBattlefield, - StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS + StaticFilters.FILTER_PERMANENT_ALL_SLIVERS ).setText("and haste")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CloudstoneCurio.java b/Mage.Sets/src/mage/cards/c/CloudstoneCurio.java index 1f092551139..0c60bfbff9b 100644 --- a/Mage.Sets/src/mage/cards/c/CloudstoneCurio.java +++ b/Mage.Sets/src/mage/cards/c/CloudstoneCurio.java @@ -82,7 +82,7 @@ class CloudstoneCurioEffect extends OneShotEffect { )); TargetPermanent target = new TargetPermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), controller.getId(), game) && controller.chooseTarget(outcome, target, source, game)) { + if (target.canChoose(controller.getId(), source, game) && controller.chooseTarget(outcome, target, source, game)) { Permanent returningCreature = game.getPermanent(target.getFirstTarget()); if (returningCreature != null) { controller.moveCards(returningCreature, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/c/Cloudthresher.java b/Mage.Sets/src/mage/cards/c/Cloudthresher.java index 0139ffd66e9..7b16baa23f2 100644 --- a/Mage.Sets/src/mage/cards/c/Cloudthresher.java +++ b/Mage.Sets/src/mage/cards/c/Cloudthresher.java @@ -42,7 +42,7 @@ public final class Cloudthresher extends CardImpl { this.addAbility(ReachAbility.getInstance()); // When Cloudthresher enters the battlefield, it deals 2 damage to each creature with flying and each player. Ability ability = new EntersBattlefieldTriggeredAbility(new DamageAllEffect(2, "it", filter)); - ability.addEffect(new DamagePlayersEffect(2)); + ability.addEffect(new DamagePlayersEffect(2).setText("and each player")); this.addAbility(ability); // Evoke {2}{G}{G} this.addAbility(new EvokeAbility("{2}{G}{G}")); diff --git a/Mage.Sets/src/mage/cards/c/CoalhaulerSwine.java b/Mage.Sets/src/mage/cards/c/CoalhaulerSwine.java index 87acbeb4bf3..fb9fbb57ffe 100644 --- a/Mage.Sets/src/mage/cards/c/CoalhaulerSwine.java +++ b/Mage.Sets/src/mage/cards/c/CoalhaulerSwine.java @@ -28,8 +28,7 @@ public final class CoalhaulerSwine extends CardImpl { // Whenever Coalhauler Swine is dealt damage, it deals that much damage to each player. this.addAbility(new DealtDamageToSourceTriggeredAbility(new DamagePlayersEffect( - Outcome.Neutral, SavedDamageValue.instance, TargetController.ANY, "it" - ), false, false)); + Outcome.Damage, SavedDamageValue.MUCH, TargetController.ANY, "it"), false)); } private CoalhaulerSwine(final CoalhaulerSwine card) { diff --git a/Mage.Sets/src/mage/cards/c/CoalitionVictory.java b/Mage.Sets/src/mage/cards/c/CoalitionVictory.java index a39235a3e78..ff12aa73d88 100644 --- a/Mage.Sets/src/mage/cards/c/CoalitionVictory.java +++ b/Mage.Sets/src/mage/cards/c/CoalitionVictory.java @@ -68,33 +68,33 @@ class CoalitionVictoryCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - if (game.getBattlefield().count(CoalitionVictory.filterPlains, source.getSourceId(), source.getControllerId(), game) < 1) { + if (game.getBattlefield().count(CoalitionVictory.filterPlains, source.getControllerId(), source, game) < 1) { return false; } - if (game.getBattlefield().count(CoalitionVictory.filterIsland, source.getSourceId(), source.getControllerId(), game) < 1) { + if (game.getBattlefield().count(CoalitionVictory.filterIsland, source.getControllerId(), source, game) < 1) { return false; } - if (game.getBattlefield().count(CoalitionVictory.filterSwamp, source.getSourceId(), source.getControllerId(), game) < 1) { + if (game.getBattlefield().count(CoalitionVictory.filterSwamp, source.getControllerId(), source, game) < 1) { return false; } - if (game.getBattlefield().count(CoalitionVictory.filterMountain, source.getSourceId(), source.getControllerId(), game) < 1) { + if (game.getBattlefield().count(CoalitionVictory.filterMountain, source.getControllerId(), source, game) < 1) { return false; } - if (game.getBattlefield().count(CoalitionVictory.filterForest, source.getSourceId(), source.getControllerId(), game) < 1) { + if (game.getBattlefield().count(CoalitionVictory.filterForest, source.getControllerId(), source, game) < 1) { return false; } - if (game.getBattlefield().count(CoalitionVictory.filterWhite, source.getSourceId(), source.getControllerId(), game) < 1) { + if (game.getBattlefield().count(CoalitionVictory.filterWhite, source.getControllerId(), source, game) < 1) { return false; } - if (game.getBattlefield().count(CoalitionVictory.filterBlue, source.getSourceId(), source.getControllerId(), game) < 1) { + if (game.getBattlefield().count(CoalitionVictory.filterBlue, source.getControllerId(), source, game) < 1) { return false; } - if (game.getBattlefield().count(CoalitionVictory.filterBlack, source.getSourceId(), source.getControllerId(), game) < 1) { + if (game.getBattlefield().count(CoalitionVictory.filterBlack, source.getControllerId(), source, game) < 1) { return false; } - if (game.getBattlefield().count(CoalitionVictory.filterRed, source.getSourceId(), source.getControllerId(), game) < 1) { + if (game.getBattlefield().count(CoalitionVictory.filterRed, source.getControllerId(), source, game) < 1) { return false; } - return game.getBattlefield().count(CoalitionVictory.filterGreen, source.getSourceId(), source.getControllerId(), game) >= 1; + return game.getBattlefield().count(CoalitionVictory.filterGreen, source.getControllerId(), source, game) >= 1; } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CodexShredder.java b/Mage.Sets/src/mage/cards/c/CodexShredder.java index 3f5d319a4d5..4b6743cd198 100644 --- a/Mage.Sets/src/mage/cards/c/CodexShredder.java +++ b/Mage.Sets/src/mage/cards/c/CodexShredder.java @@ -1,40 +1,41 @@ - package mage.cards.c; -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.PutLibraryIntoGraveTargetEffect; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.target.TargetPlayer; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** * @author LevelX2 */ public final class CodexShredder extends CardImpl { public CodexShredder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); // {T}: Target player puts the top card of their library into their graveyard. - SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutLibraryIntoGraveTargetEffect(1), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility( + new PutLibraryIntoGraveTargetEffect(1), new TapSourceCost() + ); ability.addTarget(new TargetPlayer()); this.addAbility(ability); - + // {5}, {T}, Sacrifice Codex Shredder: Return target card from your graveyard to your hand. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{5}")); + ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl<>("{5}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetCardInYourGraveyard()); this.addAbility(ability); - } private CodexShredder(final CodexShredder card) { diff --git a/Mage.Sets/src/mage/cards/c/ColdEyedSelkie.java b/Mage.Sets/src/mage/cards/c/ColdEyedSelkie.java index 02a67433c38..58428ba40e0 100644 --- a/Mage.Sets/src/mage/cards/c/ColdEyedSelkie.java +++ b/Mage.Sets/src/mage/cards/c/ColdEyedSelkie.java @@ -1,19 +1,15 @@ - package mage.cards.c; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.IslandwalkAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Outcome; -import mage.game.Game; -import mage.players.Player; /** * @@ -31,9 +27,11 @@ public final class ColdEyedSelkie extends CardImpl { // Islandwalk this.addAbility(new IslandwalkAbility()); - // Whenever Cold-Eyed Selkie deals combat damage to a player, you may draw that many cards. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new ColdEyeSelkieEffect(), true, true)); + // Whenever Cold-Eyed Selkie deals combat damage to a player, you may draw that many cards. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DrawCardSourceControllerEffect(SavedDamageValue.MANY), + true, true)); } private ColdEyedSelkie(final ColdEyedSelkie card) { @@ -45,33 +43,3 @@ public final class ColdEyedSelkie extends CardImpl { return new ColdEyedSelkie(this); } } - -class ColdEyeSelkieEffect extends OneShotEffect { - - public ColdEyeSelkieEffect() { - super(Outcome.DrawCard); - this.staticText = "draw that many cards"; - } - - public ColdEyeSelkieEffect(final ColdEyeSelkieEffect effect) { - super(effect); - } - - @Override - public ColdEyeSelkieEffect copy() { - return new ColdEyeSelkieEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int amount = (Integer) getValue("damage"); - if (amount > 0) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - controller.drawCards(amount, source, game); - return true; - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/c/ColdStorage.java b/Mage.Sets/src/mage/cards/c/ColdStorage.java index db7f195974c..c2e91ed5c0c 100644 --- a/Mage.Sets/src/mage/cards/c/ColdStorage.java +++ b/Mage.Sets/src/mage/cards/c/ColdStorage.java @@ -1,36 +1,39 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ExileTargetEffect; -import mage.abilities.effects.common.ReturnCreaturesFromExileEffect; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetForSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.Zone; +import mage.game.ExileZone; +import mage.game.Game; +import mage.players.Player; import mage.target.common.TargetControlledCreaturePermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author Plopman */ public final class ColdStorage extends CardImpl { public ColdStorage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // {3}: Exile target creature you control. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(this.getId(), this.getIdName()), new ManaCostsImpl("{3}")); + Ability ability = new SimpleActivatedAbility(new ExileTargetForSourceEffect(), new GenericManaCost(3)); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); + // Sacrifice Cold Storage: Return each creature card exiled with Cold Storage to the battlefield under your control. - ReturnCreaturesFromExileEffect returnFromExileEffect = new ReturnCreaturesFromExileEffect(this.getId(), false, "Return each creature card exiled with {this} to the battlefield under your control"); - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, returnFromExileEffect, new SacrificeSourceCost()); - this.addAbility(ability); + this.addAbility(new SimpleActivatedAbility(new ColdStorageEffect(), new SacrificeSourceCost())); } private ColdStorage(final ColdStorage card) { @@ -42,3 +45,30 @@ public final class ColdStorage extends CardImpl { return new ColdStorage(this); } } + +class ColdStorageEffect extends OneShotEffect { + + ColdStorageEffect() { + super(Outcome.Benefit); + staticText = "return each creature card exiled with {this} to the battlefield under your control"; + } + + private ColdStorageEffect(final ColdStorageEffect effect) { + super(effect); + } + + @Override + public ColdStorageEffect copy() { + return new ColdStorageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + return player != null + && exileZone != null + && !exileZone.isEmpty() + && player.moveCards(exileZone, Zone.BATTLEFIELD, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ColfenorsPlans.java b/Mage.Sets/src/mage/cards/c/ColfenorsPlans.java index ec9e1197732..8c461e68ae1 100644 --- a/Mage.Sets/src/mage/cards/c/ColfenorsPlans.java +++ b/Mage.Sets/src/mage/cards/c/ColfenorsPlans.java @@ -150,7 +150,7 @@ class ColfenorsPlansLookAtCardEffect extends AsThoughEffectImpl { if (affectedControllerId.equals(source.getControllerId())) { Card card = game.getCard(objectId); if (card != null) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/c/ColfenorsUrn.java b/Mage.Sets/src/mage/cards/c/ColfenorsUrn.java index 5ffe45ee082..da26d1ad12f 100644 --- a/Mage.Sets/src/mage/cards/c/ColfenorsUrn.java +++ b/Mage.Sets/src/mage/cards/c/ColfenorsUrn.java @@ -44,7 +44,7 @@ public final class ColfenorsUrn extends CardImpl { new ExileTargetForSourceEffect().setText("exile it"), true, filter, true, true)); // At the beginning of the end step, if three or more cards have been exiled with Colfenor's Urn, sacrifice it. If you do, return those cards to the battlefield under their owner's control. - this.addAbility(new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD, new ColfenorsUrnEffect(), TargetController.ANY, new ColfenorsUrnCondition(), false)); + this.addAbility(new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD, new ColfenorsUrnEffect(), TargetController.NEXT, new ColfenorsUrnCondition(), false)); } private ColfenorsUrn(final ColfenorsUrn card) { @@ -95,7 +95,7 @@ class ColfenorsUrnCondition implements Condition { @Override public final boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { UUID exileId = CardUtil.getCardExileZoneId(game, source); ExileZone exile = game.getExile().getExileZone(exileId); diff --git a/Mage.Sets/src/mage/cards/c/CollapsingBorders.java b/Mage.Sets/src/mage/cards/c/CollapsingBorders.java index 9a066fe61a3..934e031adc2 100644 --- a/Mage.Sets/src/mage/cards/c/CollapsingBorders.java +++ b/Mage.Sets/src/mage/cards/c/CollapsingBorders.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.dynamicvalue.common.DomainValue; @@ -15,10 +13,10 @@ import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.TargetController; +import java.util.UUID; + /** - * * @author LoneFox - * */ public final class CollapsingBorders extends CardImpl { @@ -26,7 +24,7 @@ public final class CollapsingBorders extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); // Domain - At the beginning of each player's upkeep, that player gains 1 life for each basic land type among lands they control. Then Collapsing Borders deals 3 damage to that player. - Effect effect = new GainLifeTargetEffect(new DomainValue(true)); + Effect effect = new GainLifeTargetEffect(DomainValue.TARGET); effect.setText("that player gains 1 life for each basic land type among lands they control"); Ability ability = new BeginningOfUpkeepTriggeredAbility(effect, TargetController.ANY, false); effect = new DamageTargetEffect(3); diff --git a/Mage.Sets/src/mage/cards/c/CollectedCompany.java b/Mage.Sets/src/mage/cards/c/CollectedCompany.java index 8035c40fd81..a41f1b164e0 100644 --- a/Mage.Sets/src/mage/cards/c/CollectedCompany.java +++ b/Mage.Sets/src/mage/cards/c/CollectedCompany.java @@ -1,14 +1,14 @@ - package mage.cards.c; import java.util.UUID; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; -import mage.constants.Zone; import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.ManaValuePredicate; /** @@ -17,20 +17,18 @@ import mage.filter.predicate.mageobject.ManaValuePredicate; */ public final class CollectedCompany extends CardImpl { - private static final FilterCard filter = new FilterCard("up to two creature cards with mana value 3 or less"); + private static final FilterCard filter = new FilterCreatureCard("creature cards with mana value 3 or less"); static { - filter.add(CardType.CREATURE.getPredicate()); filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); } public CollectedCompany(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{G}"); - // Look at the top six cards of your library. Put up to two creature cards with converted mana cost 3 or less from among them onto the battlefield. + // Look at the top six cards of your library. Put up to two creature cards with mana value 3 or less from among them onto the battlefield. // Put the rest on the bottom of your library in any order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(6, 2, filter, false, true, Zone.BATTLEFIELD, false)); - + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(6, 2, filter, PutCards.BATTLEFIELD, PutCards.BOTTOM_ANY, false)); } private CollectedCompany(final CollectedCompany card) { diff --git a/Mage.Sets/src/mage/cards/c/CollectedConjuring.java b/Mage.Sets/src/mage/cards/c/CollectedConjuring.java index f46fe78b9d4..b838db5ce86 100644 --- a/Mage.Sets/src/mage/cards/c/CollectedConjuring.java +++ b/Mage.Sets/src/mage/cards/c/CollectedConjuring.java @@ -1,10 +1,11 @@ package mage.cards.c; -import mage.ApprovingObject; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.Outcome; @@ -13,7 +14,7 @@ import mage.filter.FilterCard; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; +import mage.util.CardUtil; import java.util.UUID; @@ -51,12 +52,6 @@ class CollectedConjuringEffect extends OneShotEffect { filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); } - private static final FilterCard filter2 = filter.copy(); - - static { - filter2.setMessage("sorcery card with mana value 3 or less"); - } - CollectedConjuringEffect() { super(Outcome.PlayForFree); this.staticText = "exile the top six cards of your library. You may cast up to two sorcery spells " + @@ -76,42 +71,12 @@ class CollectedConjuringEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (controller == null - || sourceObject == null) { + if (controller == null) { return false; } Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 6)); - Cards cardsToChoose = new CardsImpl(cards); controller.moveCards(cards, Zone.EXILED, source, game); - int cardsCast = 0; - while (!cardsToChoose.getCards(filter, source.getSourceId(), source.getControllerId(), game).isEmpty() - && cardsCast < 2) { - if (!controller.chooseUse(Outcome.PlayForFree, "Cast a card exiled with " - + sourceObject.getLogName() + " without paying its mana cost?", source, game)) { - break; - } - TargetCard targetCard = new TargetCard(1, Zone.EXILED, filter2); - if (!controller.choose(Outcome.PlayForFree, cardsToChoose, targetCard, game)) { - continue; - } - Card card = game.getCard(targetCard.getFirstTarget()); - if (card == null) { - continue; - } - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - cardsToChoose.remove(card); // remove on non cast too (infinite freeze fix) - if (cardWasCast) { - cards.remove(card); - cardsCast++; - } else { - game.informPlayer(controller, "You're not able to cast " - + card.getIdName() + " or you canceled the casting."); - } - } + CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, filter, 2); controller.putCardsOnBottomOfLibrary(cards, game, source, false); return true; } diff --git a/Mage.Sets/src/mage/cards/c/CollectiveBrutality.java b/Mage.Sets/src/mage/cards/c/CollectiveBrutality.java index c5367301280..a5242bb7fa0 100644 --- a/Mage.Sets/src/mage/cards/c/CollectiveBrutality.java +++ b/Mage.Sets/src/mage/cards/c/CollectiveBrutality.java @@ -49,14 +49,12 @@ public final class CollectiveBrutality extends CardImpl { this.getSpellAbility().addTarget(new TargetOpponent().withChooseHint("reveals hand, you choose to discard")); // Target creature gets -2/-2 until end of turn. - Mode mode = new Mode(); - mode.addEffect(new BoostTargetEffect(-2, -2, Duration.EndOfTurn)); + Mode mode = new Mode(new BoostTargetEffect(-2, -2, Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent().withChooseHint("gets -2/-2 until end of turn")); this.getSpellAbility().addMode(mode); // Target opponent loses 2 life and you gain 2 life. - mode = new Mode(); - mode.addEffect(new LoseLifeTargetEffect(2)); + mode = new Mode(new LoseLifeTargetEffect(2)); mode.addEffect(new GainLifeEffect(2).concatBy("and")); mode.addTarget(new TargetOpponent().withChooseHint("loses 2 life")); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/c/CollectiveDefiance.java b/Mage.Sets/src/mage/cards/c/CollectiveDefiance.java index 0cb729fa358..2fe28da5bef 100644 --- a/Mage.Sets/src/mage/cards/c/CollectiveDefiance.java +++ b/Mage.Sets/src/mage/cards/c/CollectiveDefiance.java @@ -44,18 +44,16 @@ public final class CollectiveDefiance extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterDiscard).withChooseHint("discards all cards and draws")); // Collective Defiance deals 4 damage to target creature.; - Mode mode = new Mode(); Effect effect = new DamageTargetEffect(4); effect.setText("{this} deals 4 damage to target creature"); - mode.addEffect(effect); + Mode mode = new Mode(effect); mode.addTarget(new TargetCreaturePermanent(filterCreature).withChooseHint("deals 4 damage to")); this.getSpellAbility().addMode(mode); // Collective Defiance deals 3 damage to target opponent or planeswalker. - mode = new Mode(); effect = new DamageTargetEffect(3); effect.setText("{this} deals 3 damage to target opponent or planeswalker"); - mode.addEffect(effect); + mode = new Mode(effect); mode.addTarget(new TargetOpponentOrPlaneswalker().withChooseHint("deals 3 damage to")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/CollectiveEffort.java b/Mage.Sets/src/mage/cards/c/CollectiveEffort.java index c5462be3fde..9dda7f30c1a 100644 --- a/Mage.Sets/src/mage/cards/c/CollectiveEffort.java +++ b/Mage.Sets/src/mage/cards/c/CollectiveEffort.java @@ -63,18 +63,16 @@ public final class CollectiveEffort extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterDestroyCreature).withChooseHint("destroy")); // Destroy target enchantment.; - Mode mode = new Mode(); Effect effect = new DestroyTargetEffect(); effect.setText("Destroy target enchantment"); - mode.addEffect(effect); + Mode mode = new Mode(effect); mode.addTarget(new TargetEnchantmentPermanent(filterDestroyEnchantment).withChooseHint("destroy")); this.getSpellAbility().addMode(mode); // Put a +1/+1 counter on each creature target player controls. - mode = new Mode(); effect = new CollectiveEffortEffect(); effect.setText("Put a +1/+1 counter on each creature target player controls"); - mode.addEffect(effect); + mode = new Mode(effect); mode.addTarget(new TargetPlayer(1, 1, false, filterPlayer).withChooseHint("put +1/+1 counter on each creature")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/CollectiveRestraint.java b/Mage.Sets/src/mage/cards/c/CollectiveRestraint.java index fc36ceb624d..df7d2435c88 100644 --- a/Mage.Sets/src/mage/cards/c/CollectiveRestraint.java +++ b/Mage.Sets/src/mage/cards/c/CollectiveRestraint.java @@ -56,7 +56,7 @@ class CollectiveRestraintPayManaToAttackAllEffect extends CantAttackYouUnlessPay @Override public ManaCosts getManaCostToPay(GameEvent event, Ability source, Game game) { - int domainValue = new DomainValue().calculate(game, source, this); + int domainValue = DomainValue.REGULAR.calculate(game, source, this); if (domainValue > 0) { return new ManaCostsImpl<>("{" + domainValue + '}'); } diff --git a/Mage.Sets/src/mage/cards/c/CollisionOfRealms.java b/Mage.Sets/src/mage/cards/c/CollisionOfRealms.java new file mode 100644 index 00000000000..0c85fa53d2b --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CollisionOfRealms.java @@ -0,0 +1,103 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentToken; +import mage.players.Player; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CollisionOfRealms extends CardImpl { + + public CollisionOfRealms(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{6}{R}"); + + // Each player shuffles all creatures they own into their library. Each player who shuffled a nontoken creature into their library this way reveals cards from the top of their library until they reveal a creature card, then puts that card onto the battlefield and the rest on the bottom of their library in a random order. + this.getSpellAbility().addEffect(new CollisionOfRealmsEffect()); + } + + private CollisionOfRealms(final CollisionOfRealms card) { + super(card); + } + + @Override + public CollisionOfRealms copy() { + return new CollisionOfRealms(this); + } +} + +class CollisionOfRealmsEffect extends OneShotEffect { + + CollisionOfRealmsEffect() { + super(Outcome.Benefit); + staticText = "each player shuffles all creatures they own into their library. " + + "Each player who shuffled a nontoken creature into their library this way reveals cards " + + "from the top of their library until they reveal a creature card, then puts that card " + + "onto the battlefield and the rest on the bottom of their library in a random order"; + } + + private CollisionOfRealmsEffect(final CollisionOfRealmsEffect effect) { + super(effect); + } + + @Override + public CollisionOfRealmsEffect copy() { + return new CollisionOfRealmsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + List players = new ArrayList<>(); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player == null) { + continue; + } + List permanents = game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, playerId, game + ); + boolean hasNonToken = permanents + .stream() + .filter(permanent -> !(permanent instanceof PermanentToken)) + .anyMatch(permanent -> permanent.isCreature(game)); + player.putCardsOnBottomOfLibrary(new CardsImpl(permanents), game, source, false); + player.shuffleLibrary(source, game); + if (hasNonToken) { + players.add(player); + } + } + for (Player player : players) { + Cards cards = new CardsImpl(); + Card creature = revealUntilCreature(cards, player, game); + player.revealCards(source, cards, game); + if (creature != null) { + player.moveCards(creature, Zone.BATTLEFIELD, source, game); + } + cards.retainZone(Zone.LIBRARY, game); + player.putCardsOnBottomOfLibrary(cards, game, source, false); + } + return true; + } + + private static Card revealUntilCreature(Cards cards, Player player, Game game) { + for (Card card : player.getLibrary().getCards(game)) { + cards.add(card); + if (card.isCreature(game)) { + return card; + } + } + return null; + } +} diff --git a/Mage.Sets/src/mage/cards/c/ColossalMight.java b/Mage.Sets/src/mage/cards/c/ColossalMight.java index 014cf982f2f..f569d4fee4e 100644 --- a/Mage.Sets/src/mage/cards/c/ColossalMight.java +++ b/Mage.Sets/src/mage/cards/c/ColossalMight.java @@ -1,8 +1,5 @@ - - package mage.cards.c; -import java.util.UUID; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.TrampleAbility; @@ -12,22 +9,26 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class ColossalMight extends CardImpl { - public ColossalMight (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}{G}"); - + public ColossalMight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}{G}"); + this.getSpellAbility().addEffect(new BoostTargetEffect( + 4, 2, Duration.EndOfTurn + ).setText("target creature gets +4/+2")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains trample until end of turn")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new BoostTargetEffect(4, 2, Duration.EndOfTurn)); - this.getSpellAbility().addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn)); } - public ColossalMight (final ColossalMight card) { + public ColossalMight(final ColossalMight card) { super(card); } @@ -35,5 +36,4 @@ public final class ColossalMight extends CardImpl { public ColossalMight copy() { return new ColossalMight(this); } - } diff --git a/Mage.Sets/src/mage/cards/c/CommuneWithDinosaurs.java b/Mage.Sets/src/mage/cards/c/CommuneWithDinosaurs.java index c4609faa067..e9ec1c7786a 100644 --- a/Mage.Sets/src/mage/cards/c/CommuneWithDinosaurs.java +++ b/Mage.Sets/src/mage/cards/c/CommuneWithDinosaurs.java @@ -1,9 +1,8 @@ - package mage.cards.c; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -30,7 +29,7 @@ public final class CommuneWithDinosaurs extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}"); //Look at the top five cards of your library. You may reveal a Dinosaur or land card from among them and put it into your hand. Put the rest on the bottom of your library in any order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(5), false, StaticValue.get(1), filter, false)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(5, 1, filter, PutCards.HAND, PutCards.BOTTOM_ANY)); } private CommuneWithDinosaurs(final CommuneWithDinosaurs card) { diff --git a/Mage.Sets/src/mage/cards/c/CommuneWithNature.java b/Mage.Sets/src/mage/cards/c/CommuneWithNature.java index 69a5a27fd96..9b216d38738 100644 --- a/Mage.Sets/src/mage/cards/c/CommuneWithNature.java +++ b/Mage.Sets/src/mage/cards/c/CommuneWithNature.java @@ -1,13 +1,12 @@ - package mage.cards.c; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; /** * @@ -18,12 +17,10 @@ public final class CommuneWithNature extends CardImpl { public CommuneWithNature(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}"); - // Look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in any order. - this.getSpellAbility().addEffect( - new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), new FilterCreatureCard("a creature card"), false - ) - ); + // Look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. + // Put the rest on the bottom of your library in any order. + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + 5, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_ANY)); } private CommuneWithNature(final CommuneWithNature card) { @@ -34,5 +31,4 @@ public final class CommuneWithNature extends CardImpl { public CommuneWithNature copy() { return new CommuneWithNature(this); } - } diff --git a/Mage.Sets/src/mage/cards/c/CommuneWithSpirits.java b/Mage.Sets/src/mage/cards/c/CommuneWithSpirits.java index 1614cb95261..f51fc750c52 100644 --- a/Mage.Sets/src/mage/cards/c/CommuneWithSpirits.java +++ b/Mage.Sets/src/mage/cards/c/CommuneWithSpirits.java @@ -1,11 +1,10 @@ package mage.cards.c; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; @@ -28,13 +27,9 @@ public final class CommuneWithSpirits extends CardImpl { public CommuneWithSpirits(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}"); - // Look at the top four cards of your library. You may reveal an enchantment or land card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(1), filter, Zone.LIBRARY, false, - true, false, Zone.HAND, true, false, false - ).setBackInRandomOrder(true).setText("look at the top four cards of your library. " + - "You may reveal an enchantment or land card from among them and put it into your hand. " + - "Put the rest on the bottom of your library in a random order")); + // Look at the top four cards of your library. You may reveal an enchantment or land card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(4, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM)); } private CommuneWithSpirits(final CommuneWithSpirits card) { diff --git a/Mage.Sets/src/mage/cards/c/CommuneWithTheGods.java b/Mage.Sets/src/mage/cards/c/CommuneWithTheGods.java index f9f80f6b0ed..eb688a01ec6 100644 --- a/Mage.Sets/src/mage/cards/c/CommuneWithTheGods.java +++ b/Mage.Sets/src/mage/cards/c/CommuneWithTheGods.java @@ -1,31 +1,35 @@ - package mage.cards.c; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.effects.common.RevealLibraryPickControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; /** * - * @author LevelX2 + * @author awjackson */ public final class CommuneWithTheGods extends CardImpl { + private static final FilterCard filter = new FilterCard("a creature or enchantment card"); + + static { + filter.add(Predicates.or( + CardType.CREATURE.getPredicate(), + CardType.ENCHANTMENT.getPredicate() + )); + } + public CommuneWithTheGods(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); - // Reveal the top five cards of your library. You may put a creature or enchantment card from among them into your hand. Put the rest into your graveyard. - this.getSpellAbility().addEffect(new CommuneWithTheGodsEffect()); - + // Reveal the top five cards of your library. You may put a creature or enchantment card from among them into your hand. + // Put the rest into your graveyard. + this.getSpellAbility().addEffect(new RevealLibraryPickControllerEffect(5, 1, filter, PutCards.HAND, PutCards.GRAVEYARD)); } private CommuneWithTheGods(final CommuneWithTheGods card) { @@ -37,47 +41,3 @@ public final class CommuneWithTheGods extends CardImpl { return new CommuneWithTheGods(this); } } - -class CommuneWithTheGodsEffect extends OneShotEffect { - - public CommuneWithTheGodsEffect() { - super(Outcome.DrawCard); - this.staticText = "Reveal the top five cards of your library. You may put a creature or enchantment card from among them into your hand. Put the rest into your graveyard"; - } - - public CommuneWithTheGodsEffect(final CommuneWithTheGodsEffect effect) { - super(effect); - } - - @Override - public CommuneWithTheGodsEffect copy() { - return new CommuneWithTheGodsEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5)); - if (!cards.isEmpty()) { - FilterCard filterPutInHand = new FilterCard("creature or enchantment card to put in hand"); - filterPutInHand.add(Predicates.or(CardType.CREATURE.getPredicate(), CardType.ENCHANTMENT.getPredicate())); - controller.revealCards(source, cards, game); - if (cards.count(filterPutInHand, source.getSourceId(), source.getControllerId(), game) > 0) { - TargetCard target = new TargetCard(0, 1, Zone.LIBRARY, filterPutInHand); - if (controller.choose(Outcome.DrawCard, cards, target, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - cards.remove(card); - controller.moveCards(card, Zone.HAND, source, game); - } - - } - } - controller.moveCards(cards, Zone.GRAVEYARD, source, game); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/c/CompulsiveResearch.java b/Mage.Sets/src/mage/cards/c/CompulsiveResearch.java index 840f57400ec..e7eaa81f986 100644 --- a/Mage.Sets/src/mage/cards/c/CompulsiveResearch.java +++ b/Mage.Sets/src/mage/cards/c/CompulsiveResearch.java @@ -67,7 +67,7 @@ class CompulsiveResearchDiscardEffect extends OneShotEffect { return !targetPlayer.discard(2, false, false, source, game).isEmpty(); } TargetDiscard target = new TargetDiscard(StaticFilters.FILTER_CARD_LAND_A, targetPlayer.getId()); - targetPlayer.choose(Outcome.Discard, target, source.getSourceId(), game); + targetPlayer.choose(Outcome.Discard, target, source, game); Card card = targetPlayer.getHand().get(target.getFirstTarget(), game); if (card != null && targetPlayer.discard(card, false, source, game)) { return true; diff --git a/Mage.Sets/src/mage/cards/c/ConchHorn.java b/Mage.Sets/src/mage/cards/c/ConchHorn.java index 1fd78493047..a73e76cc1a7 100644 --- a/Mage.Sets/src/mage/cards/c/ConchHorn.java +++ b/Mage.Sets/src/mage/cards/c/ConchHorn.java @@ -73,7 +73,7 @@ class ConchHornEffect extends OneShotEffect { private boolean putOnLibrary(Player player, Ability source, Game game) { TargetCardInHand target = new TargetCardInHand(); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.ReturnToHand, target, source, game); Card card = player.getHand().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/c/ConcordWithTheKami.java b/Mage.Sets/src/mage/cards/c/ConcordWithTheKami.java new file mode 100644 index 00000000000..841148ba064 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ConcordWithTheKami.java @@ -0,0 +1,91 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.CounterAnyPredicate; +import mage.filter.predicate.permanent.EnchantedPredicate; +import mage.filter.predicate.permanent.EquippedPredicate; +import mage.game.permanent.token.SpiritToken; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ConcordWithTheKami extends CardImpl { + + private static final FilterPermanent counterFilter + = new FilterCreaturePermanent("creature with a counter on it"); + private static final FilterPermanent enchantedFilter + = new FilterControlledCreaturePermanent(); + private static final FilterPermanent equippedFilter + = new FilterControlledCreaturePermanent(); + + static { + counterFilter.add(CounterAnyPredicate.instance); + enchantedFilter.add(EnchantedPredicate.instance); + equippedFilter.add(EquippedPredicate.instance); + } + + private static final Condition enchantedCondition + = new PermanentsOnTheBattlefieldCondition(enchantedFilter); + private static final Condition equippedCondition + = new PermanentsOnTheBattlefieldCondition(equippedFilter); + private static final Hint enchantedHint + = new ConditionHint(enchantedCondition, "You control an enchanted creature"); + private static final Hint equippedHint + = new ConditionHint(equippedCondition, "You control an equipped creature"); + + public ConcordWithTheKami(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); + + // At the beginning of your end step, choose one or more — + // • Put a +1/+1 counter on target creature with a counter on it. + Ability ability = new BeginningOfEndStepTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), TargetController.YOU, false + ); + ability.addTarget(new TargetPermanent(counterFilter)); + ability.getModes().setMinModes(1); + ability.getModes().setMaxModes(3); + + // • Draw a card if you control an enchanted creature. + ability.addMode(new Mode(new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(1), enchantedCondition, + "draw a card if you control an enchanted creature" + ))); + + // • Create a 1/1 colorless Spirit creature token if you control an equipped creature. + ability.addMode(new Mode(new ConditionalOneShotEffect( + new CreateTokenEffect(new SpiritToken()), equippedCondition, + "create a 1/1 colorless Spirit creature token if you control an equipped creature" + ))); + this.addAbility(ability.addHint(enchantedHint).addHint(equippedHint)); + } + + private ConcordWithTheKami(final ConcordWithTheKami card) { + super(card); + } + + @Override + public ConcordWithTheKami copy() { + return new ConcordWithTheKami(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/Condemn.java b/Mage.Sets/src/mage/cards/c/Condemn.java index 57eb1a51afd..2871de61def 100644 --- a/Mage.Sets/src/mage/cards/c/Condemn.java +++ b/Mage.Sets/src/mage/cards/c/Condemn.java @@ -1,5 +1,3 @@ - - package mage.cards.c; import java.util.UUID; @@ -23,7 +21,7 @@ import mage.target.common.TargetAttackingCreature; public final class Condemn extends CardImpl { public Condemn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); // Put target attacking creature on the bottom of its owner's library. this.getSpellAbility().addTarget(new TargetAttackingCreature()); @@ -46,7 +44,7 @@ public final class Condemn extends CardImpl { class CondemnEffect extends OneShotEffect { public CondemnEffect() { - super(Outcome.GainLife); + super(Outcome.Detriment); staticText = "Its controller gains life equal to its toughness"; } @@ -61,7 +59,7 @@ class CondemnEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent)game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD); + Permanent permanent = (Permanent) game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD); if (permanent != null) { Player player = game.getPlayer(permanent.getControllerId()); if (player != null) { diff --git a/Mage.Sets/src/mage/cards/c/ConfoundingConundrum.java b/Mage.Sets/src/mage/cards/c/ConfoundingConundrum.java index f393c1e6cd6..e8ceb3d5a4a 100644 --- a/Mage.Sets/src/mage/cards/c/ConfoundingConundrum.java +++ b/Mage.Sets/src/mage/cards/c/ConfoundingConundrum.java @@ -106,10 +106,10 @@ class ConfoundingConundrumEffect extends OneShotEffect { } TargetPermanent target = new TargetPermanent(1, StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), player.getId(), game)) { + if (!target.canChoose(player.getId(), source, game)) { return false; } - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); return player.moveCards(game.getCard(target.getFirstTarget()), Zone.HAND, source, game); } } diff --git a/Mage.Sets/src/mage/cards/c/ConfrontThePast.java b/Mage.Sets/src/mage/cards/c/ConfrontThePast.java index 8cafe8f05d2..310ae0c0e8e 100644 --- a/Mage.Sets/src/mage/cards/c/ConfrontThePast.java +++ b/Mage.Sets/src/mage/cards/c/ConfrontThePast.java @@ -43,8 +43,7 @@ public final class ConfrontThePast extends CardImpl { this.getSpellAbility().setTargetAdjuster(ConfrontThePastAdjuster.instance); // • Remove twice X loyalty counters from target planeswalker an opponent controls. - Mode mode = new Mode(); - mode.addEffect(new ConfrontThePastLoyaltyEffect()); + Mode mode = new Mode(new ConfrontThePastLoyaltyEffect()); mode.addTarget(new TargetPlaneswalkerPermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/CongregationAtDawn.java b/Mage.Sets/src/mage/cards/c/CongregationAtDawn.java index 3c106d17b35..d1d604e46f5 100644 --- a/Mage.Sets/src/mage/cards/c/CongregationAtDawn.java +++ b/Mage.Sets/src/mage/cards/c/CongregationAtDawn.java @@ -61,14 +61,14 @@ class CongregationAtDawnEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, 3, new FilterCreatureCard("creature cards")); if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards revealed = new CardsImpl(); for (UUID cardId : target.getTargets()) { - Card card = controller.getLibrary().remove(cardId, game); + Card card = controller.getLibrary().getCard(cardId, game); revealed.add(card); } controller.revealCards(sourceObject.getName(), revealed, game); diff --git a/Mage.Sets/src/mage/cards/c/ConniveConcoct.java b/Mage.Sets/src/mage/cards/c/ConniveConcoct.java index d6144105e87..5cd00455179 100644 --- a/Mage.Sets/src/mage/cards/c/ConniveConcoct.java +++ b/Mage.Sets/src/mage/cards/c/ConniveConcoct.java @@ -93,7 +93,7 @@ class ConcoctEffect extends OneShotEffect { player.surveil(3, source, game); Target target = new TargetCardInYourGraveyard(filter); target.setNotTarget(true); - if (player.choose(outcome, target, source.getSourceId(), game)) { + if (player.choose(outcome, target, source, game)) { Effect effect = new ReturnFromGraveyardToBattlefieldTargetEffect(); effect.setTargetPointer(new FixedTarget(target.getFirstTarget(), game)); effect.apply(game, source); diff --git a/Mage.Sets/src/mage/cards/c/ConstrictingSliver.java b/Mage.Sets/src/mage/cards/c/ConstrictingSliver.java index 4a746bf8609..4d352e5fdaf 100644 --- a/Mage.Sets/src/mage/cards/c/ConstrictingSliver.java +++ b/Mage.Sets/src/mage/cards/c/ConstrictingSliver.java @@ -39,7 +39,7 @@ public final class ConstrictingSliver extends CardImpl { ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility())); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(ability, - Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS) + Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS) .setText("Sliver creatures you control have \"When this creature enters the battlefield, " + "you may exile target creature an opponent controls until this creature leaves the battlefield.\""))); diff --git a/Mage.Sets/src/mage/cards/c/ConsultTheNecrosages.java b/Mage.Sets/src/mage/cards/c/ConsultTheNecrosages.java index de4b36fde6b..8808843a003 100644 --- a/Mage.Sets/src/mage/cards/c/ConsultTheNecrosages.java +++ b/Mage.Sets/src/mage/cards/c/ConsultTheNecrosages.java @@ -23,9 +23,8 @@ public final class ConsultTheNecrosages extends CardImpl { // Choose one - Target player draws two cards; or target player discards two cards. this.getSpellAbility().addTarget(new TargetPlayer()); this.getSpellAbility().addEffect(new DrawCardTargetEffect(2)); - Mode mode = new Mode(); + Mode mode = new Mode(new DiscardTargetEffect(2)); mode.addTarget(new TargetPlayer()); - mode.addEffect(new DiscardTargetEffect(2)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/ConsumingBonfire.java b/Mage.Sets/src/mage/cards/c/ConsumingBonfire.java index b2dee98163a..30ce0c08c92 100644 --- a/Mage.Sets/src/mage/cards/c/ConsumingBonfire.java +++ b/Mage.Sets/src/mage/cards/c/ConsumingBonfire.java @@ -38,8 +38,7 @@ public final class ConsumingBonfire extends CardImpl { this.getSpellAbility().addEffect(new DamageTargetEffect(4)); //or Consuming Bonfire deals 7 damage to target Treefolk creature. - Mode mode = new Mode(); - mode.addEffect(new DamageTargetEffect(7)); + Mode mode = new Mode(new DamageTargetEffect(7)); mode.addTarget(new TargetPermanent(filter2)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/ConsumingSinkhole.java b/Mage.Sets/src/mage/cards/c/ConsumingSinkhole.java index 4a93844061b..5b1c94faafc 100644 --- a/Mage.Sets/src/mage/cards/c/ConsumingSinkhole.java +++ b/Mage.Sets/src/mage/cards/c/ConsumingSinkhole.java @@ -39,8 +39,7 @@ public final class ConsumingSinkhole extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); // Consuming Sinkhole deals 4 damage to target player. - Mode mode = new Mode(); - mode.addEffect(new DamageTargetEffect(4)); + Mode mode = new Mode(new DamageTargetEffect(4)); mode.addTarget(new TargetPlayerOrPlaneswalker()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/ConsumingTide.java b/Mage.Sets/src/mage/cards/c/ConsumingTide.java index 3e71ee8ec1c..01834bd2d68 100644 --- a/Mage.Sets/src/mage/cards/c/ConsumingTide.java +++ b/Mage.Sets/src/mage/cards/c/ConsumingTide.java @@ -70,7 +70,7 @@ class ConsumingTideEffect extends OneShotEffect { if (player != null) { TargetNonlandPermanent target = new TargetNonlandPermanent(); target.setNotTarget(true); - player.choose(Outcome.Benefit, target, source.getSourceId(), game); + player.choose(Outcome.Benefit, target, source, game); UUID permId = target.getFirstTarget(); if (permId != null) { chosenPermanents.add(permId); @@ -78,7 +78,7 @@ class ConsumingTideEffect extends OneShotEffect { } } HashSet permanentsToHand = new HashSet<>(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_NON_LAND, controller.getId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_NON_LAND, controller.getId(), source, game)) { if (!chosenPermanents.contains(permanent.getId())) { permanentsToHand.add(permanent); } diff --git a/Mage.Sets/src/mage/cards/c/ConsumingVapors.java b/Mage.Sets/src/mage/cards/c/ConsumingVapors.java index f78dfbe7333..487f6ebb6c5 100644 --- a/Mage.Sets/src/mage/cards/c/ConsumingVapors.java +++ b/Mage.Sets/src/mage/cards/c/ConsumingVapors.java @@ -64,8 +64,8 @@ class ConsumingVaporsEffect extends OneShotEffect { filter.add(TargetController.YOU.getControllerPredicate()); TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); - if (player != null && target.canChoose(source.getSourceId(), player.getId(), game)) { - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + if (player != null && target.canChoose(player.getId(), source, game)) { + player.choose(Outcome.Sacrifice, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/c/Contagion.java b/Mage.Sets/src/mage/cards/c/Contagion.java index 4a951ba2189..c1e223c9079 100644 --- a/Mage.Sets/src/mage/cards/c/Contagion.java +++ b/Mage.Sets/src/mage/cards/c/Contagion.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.costs.AlternativeCostSourceAbility; import mage.abilities.costs.common.ExileFromHandCost; @@ -12,24 +10,26 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.counters.CounterType; import mage.filter.common.FilterOwnedCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCreaturePermanentAmount; +import java.util.UUID; + /** - * * @author Plopman */ public final class Contagion extends CardImpl { - public Contagion(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{B}{B}"); + private static final FilterOwnedCard filter + = new FilterOwnedCard("a black card from your hand"); - FilterOwnedCard filter = new FilterOwnedCard("black card from your hand"); + static { filter.add(new ColorPredicate(ObjectColor.BLACK)); - filter.add(Predicates.not(new CardIdPredicate(this.getId()))); // the exile cost can never be paid with the card itself + } + + public Contagion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}{B}"); // You may pay 1 life and exile a black card from your hand rather than pay Contagion's mana cost. AlternativeCostSourceAbility ability = new AlternativeCostSourceAbility(new PayLifeCost(1)); @@ -38,7 +38,10 @@ public final class Contagion extends CardImpl { // Distribute two -2/-1 counters among one or two target creatures. this.getSpellAbility().addTarget(new TargetCreaturePermanentAmount(2)); - this.getSpellAbility().addEffect(new DistributeCountersEffect(CounterType.M2M1, 2, false, "one or two target creatures")); + this.getSpellAbility().addEffect(new DistributeCountersEffect( + CounterType.M2M1, 2, false, + "one or two target creatures" + )); } private Contagion(final Contagion card) { diff --git a/Mage.Sets/src/mage/cards/c/ContainmentConstruct.java b/Mage.Sets/src/mage/cards/c/ContainmentConstruct.java new file mode 100644 index 00000000000..47de50387c3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ContainmentConstruct.java @@ -0,0 +1,121 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; +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.players.Player; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +/** + * @author jeffwadsworth + */ +public final class ContainmentConstruct extends CardImpl { + + public ContainmentConstruct(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); + + this.subtype.add(SubType.CONSTRUCT); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Whenever you discard a card, you may exile that card from your graveyard. If you do, you may play that card this turn. + this.addAbility(new ContainmentConstructTriggeredAbility()); + + } + + private ContainmentConstruct(final ContainmentConstruct card) { + super(card); + } + + @Override + public ContainmentConstruct copy() { + return new ContainmentConstruct(this); + } +} + +class ContainmentConstructTriggeredAbility extends TriggeredAbilityImpl { + + public ContainmentConstructTriggeredAbility() { + super(Zone.BATTLEFIELD, new ContainmentConstructEffect(), false); + } + + public ContainmentConstructTriggeredAbility(final ContainmentConstructTriggeredAbility ability) { + super(ability); + } + + @Override + public ContainmentConstructTriggeredAbility copy() { + return new ContainmentConstructTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DISCARDED_CARD; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getPlayerId() == this.getControllerId() + && game.getState().getZone(event.getTargetId()) == Zone.GRAVEYARD) { + this.getEffects().get(0).setTargetPointer(new FixedTarget(event.getTargetId())); + return true; + } + return false; + } + + @Override + public String getTriggerPhrase() { + return "Whenever you discard a card, "; + } +} + +class ContainmentConstructEffect extends OneShotEffect { + + public ContainmentConstructEffect() { + super(Outcome.Benefit); + this.staticText = "you may exile that card from your graveyard. If you do, you may play that card this turn"; + } + + public ContainmentConstructEffect(final ContainmentConstructEffect effect) { + super(effect); + } + + @Override + public ContainmentConstructEffect copy() { + return new ContainmentConstructEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Card discardedCard = game.getCard(targetPointer.getFirst(game, source)); + Card containmentConstruct = game.getCard(source.getSourceId()); + if (discardedCard != null + && containmentConstruct != null) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller.chooseUse(Outcome.Benefit, "Do you want to exile the discarded card? You may play it this turn from exile.", source, game)) { + UUID exileId = CardUtil.getExileZoneId(game, source); + controller.moveCardsToExile(discardedCard, source, game, true, exileId, "Exiled by " + containmentConstruct.getIdName()); + PlayFromNotOwnHandZoneTargetEffect effect = new PlayFromNotOwnHandZoneTargetEffect(Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(discardedCard.getId(), game)); + game.addEffect(effect, source); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/c/ContingencyPlan.java b/Mage.Sets/src/mage/cards/c/ContingencyPlan.java index 18cf5006f1e..e3aefc29b9e 100644 --- a/Mage.Sets/src/mage/cards/c/ContingencyPlan.java +++ b/Mage.Sets/src/mage/cards/c/ContingencyPlan.java @@ -1,14 +1,11 @@ - package mage.cards.c; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.FilterCard; /** * @@ -20,9 +17,7 @@ public final class ContingencyPlan extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{U}"); // Look at the top five cards of your library. Put any number of them into your graveyard and the rest back on top of your library in any order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(5), false, StaticValue.get(5), - new FilterCard("cards"), Zone.LIBRARY, true, false, true, Zone.GRAVEYARD, false)); - + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(5, Integer.MAX_VALUE, PutCards.GRAVEYARD, PutCards.TOP_ANY)); } private ContingencyPlan(final ContingencyPlan card) { diff --git a/Mage.Sets/src/mage/cards/c/ContrabandKingpin.java b/Mage.Sets/src/mage/cards/c/ContrabandKingpin.java index b32c69e4b55..696bd8569bb 100644 --- a/Mage.Sets/src/mage/cards/c/ContrabandKingpin.java +++ b/Mage.Sets/src/mage/cards/c/ContrabandKingpin.java @@ -1,26 +1,25 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.effects.keyword.ScryEffect; import mage.abilities.keyword.LifelinkAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author fireshoes */ public final class ContrabandKingpin extends CardImpl { public ContrabandKingpin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{U}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{B}"); this.subtype.add(SubType.AETHERBORN); this.subtype.add(SubType.ROGUE); this.power = new MageInt(1); @@ -30,7 +29,10 @@ public final class ContrabandKingpin extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // Whenever an artifact enters the battlefield under your control, scry 1. - this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new ScryEffect(1, false), new FilterControlledArtifactPermanent(), false, null, true)); + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + new ScryEffect(1, false), + StaticFilters.FILTER_PERMANENT_ARTIFACT_AN + )); } private ContrabandKingpin(final ContrabandKingpin card) { diff --git a/Mage.Sets/src/mage/cards/c/Conviction.java b/Mage.Sets/src/mage/cards/c/Conviction.java index 46151f22199..f3339222029 100644 --- a/Mage.Sets/src/mage/cards/c/Conviction.java +++ b/Mage.Sets/src/mage/cards/c/Conviction.java @@ -41,7 +41,7 @@ public final class Conviction extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 3, Duration.WhileOnBattlefield))); // {W}: Return Conviction to its owner's hand. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandSourceEffect(true), new ManaCostsImpl("W"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandSourceEffect(true), new ManaCostsImpl<>("{W}"))); } private Conviction(final Conviction card) { diff --git a/Mage.Sets/src/mage/cards/c/CoordinatedBarrage.java b/Mage.Sets/src/mage/cards/c/CoordinatedBarrage.java index 91cdb882c24..592ff34873f 100644 --- a/Mage.Sets/src/mage/cards/c/CoordinatedBarrage.java +++ b/Mage.Sets/src/mage/cards/c/CoordinatedBarrage.java @@ -60,12 +60,12 @@ class CoordinatedBarrageEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - Choice choice = new ChoiceCreatureType(game.getObject(source.getSourceId())); + Choice choice = new ChoiceCreatureType(game.getObject(source)); if (controller.choose(Outcome.Damage, choice, game)) { String chosenType = choice.getChoice(); FilterControlledPermanent filter = new FilterControlledPermanent(); filter.add(SubType.byDescription(chosenType).getPredicate()); - int damageDealt = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int damageDealt = game.getBattlefield().count(filter, source.getControllerId(), source, game); Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); if (permanent != null) { permanent.damage(damageDealt, source.getSourceId(), source, game, false, true); diff --git a/Mage.Sets/src/mage/cards/c/CopperhornScout.java b/Mage.Sets/src/mage/cards/c/CopperhornScout.java index 7be18f955d6..2887e93527c 100644 --- a/Mage.Sets/src/mage/cards/c/CopperhornScout.java +++ b/Mage.Sets/src/mage/cards/c/CopperhornScout.java @@ -16,7 +16,6 @@ import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; /** @@ -91,7 +90,7 @@ class CopperhornScoutUntapEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - List creatures = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List creatures = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); for ( Permanent creature : creatures ) { if ( !creature.getId().equals(source.getSourceId()) ) { diff --git a/Mage.Sets/src/mage/cards/c/CoralTrickster.java b/Mage.Sets/src/mage/cards/c/CoralTrickster.java index 7db134ee8b0..d329e648b35 100644 --- a/Mage.Sets/src/mage/cards/c/CoralTrickster.java +++ b/Mage.Sets/src/mage/cards/c/CoralTrickster.java @@ -28,7 +28,7 @@ public final class CoralTrickster extends CardImpl { this.toughness = new MageInt(1); // Morph {U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{U}"))); // When Coral Trickster is turned face up, you may tap or untap target permanent. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new MayTapOrUntapTargetEffect()); ability.addTarget(new TargetPermanent()); diff --git a/Mage.Sets/src/mage/cards/c/CoralhelmChronicler.java b/Mage.Sets/src/mage/cards/c/CoralhelmChronicler.java index e13ee671217..13a9d9baaf0 100644 --- a/Mage.Sets/src/mage/cards/c/CoralhelmChronicler.java +++ b/Mage.Sets/src/mage/cards/c/CoralhelmChronicler.java @@ -3,15 +3,14 @@ package mage.cards.c; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.predicate.mageobject.AbilityPredicate; @@ -45,11 +44,7 @@ public final class CoralhelmChronicler extends CardImpl { // When Coralhelm Chronicler enters the battlefield, look at the top five cards of your library. You may reveal a card with a kicker ability from among them and put it into your hand. Put the rest on the bottom of your library in a random order. this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), filter, Zone.LIBRARY, false, - true, false, Zone.HAND, true, false, false - ).setBackInRandomOrder(true).setText("look at the top five cards of your library. " + - "You may reveal a card with a kicker ability from among them and put it into your hand. " + - "Put the rest on the bottom of your library in a random order"))); + 5, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM))); } private CoralhelmChronicler(final CoralhelmChronicler card) { diff --git a/Mage.Sets/src/mage/cards/c/CormelaGlamourThief.java b/Mage.Sets/src/mage/cards/c/CormelaGlamourThief.java new file mode 100644 index 00000000000..8c387bc0165 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CormelaGlamourThief.java @@ -0,0 +1,65 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.mana.ConditionalColoredManaAbility; +import mage.abilities.mana.builder.common.InstantOrSorcerySpellManaBuilder; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CormelaGlamourThief extends CardImpl { + + public CormelaGlamourThief(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // {1}, {T}: Add {U}{B}{R}. Spend this mana only to cast instant and/or sorcery spells. + Ability ability = new ConditionalColoredManaAbility( + new GenericManaCost(1), + new Mana(0, 1, 1, 1, 0, 0, 0, 0), + new InstantOrSorcerySpellManaBuilder() + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + + // When Cormela, Glamour Thief dies, return up to one target instant or sorcery card from your graveyard to your hand. + ability = new DiesSourceTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), false); + ability.addTarget(new TargetCardInYourGraveyard( + 0, 1, StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD + )); + this.addAbility(ability); + } + + private CormelaGlamourThief(final CormelaGlamourThief card) { + super(card); + } + + @Override + public CormelaGlamourThief copy() { + return new CormelaGlamourThief(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CorpseAppraiser.java b/Mage.Sets/src/mage/cards/c/CorpseAppraiser.java new file mode 100644 index 00000000000..356eab6dd42 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CorpseAppraiser.java @@ -0,0 +1,92 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CorpseAppraiser extends CardImpl { + + public CorpseAppraiser(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{B}{R}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Corpse Appraiser enters the battlefield, exile up to one target creature card from a graveyard. If a card is put into exile this way, look at the top three cards of your library, then put one of those cards into your hand and the rest into your graveyard. + Ability ability = new EntersBattlefieldTriggeredAbility(new CorpseAppraiserEffect()); + ability.addTarget(new TargetCardInGraveyard( + 0, 1, StaticFilters.FILTER_CARD_CREATURE + )); + this.addAbility(ability); + } + + private CorpseAppraiser(final CorpseAppraiser card) { + super(card); + } + + @Override + public CorpseAppraiser copy() { + return new CorpseAppraiser(this); + } +} + +class CorpseAppraiserEffect extends OneShotEffect { + + CorpseAppraiserEffect() { + super(Outcome.Benefit); + staticText = "exile up to one target creature card from a graveyard. " + + "If a card is put into exile this way, look at the top three cards of your library, " + + "then put one of those cards into your hand and the rest into your graveyard"; + } + + private CorpseAppraiserEffect(final CorpseAppraiserEffect effect) { + super(effect); + } + + @Override + public CorpseAppraiserEffect copy() { + return new CorpseAppraiserEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + if (player == null || card == null) { + return false; + } + player.moveCards(card, Zone.EXILED, source, game); + if (!Zone.EXILED.match(game.getState().getZone(card.getId()))) { + return true; + } + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 3)); + if (cards.isEmpty()) { + return true; + } + TargetCard target = new TargetCardInLibrary(); + player.choose(outcome, cards, target, game); + player.moveCards(cards.get(target.getFirstTarget(), game), Zone.HAND, source, game); + cards.retainZone(Zone.LIBRARY, game); + player.moveCards(cards, Zone.GRAVEYARD, source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CorpseChurn.java b/Mage.Sets/src/mage/cards/c/CorpseChurn.java index e27a3ade3a0..dd337e59ea5 100644 --- a/Mage.Sets/src/mage/cards/c/CorpseChurn.java +++ b/Mage.Sets/src/mage/cards/c/CorpseChurn.java @@ -64,9 +64,9 @@ class CorpseChurnEffect extends OneShotEffect { } TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + if (target.canChoose(source.getControllerId(), source, game) && controller.chooseUse(outcome, "Return a creature card from your graveyard to hand?", source, game) - && controller.choose(Outcome.ReturnToHand, target, source.getSourceId(), game)) { + && controller.choose(Outcome.ReturnToHand, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { controller.moveCards(card, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/c/CorpseCur.java b/Mage.Sets/src/mage/cards/c/CorpseCur.java index b41f588765f..f7c59480b54 100644 --- a/Mage.Sets/src/mage/cards/c/CorpseCur.java +++ b/Mage.Sets/src/mage/cards/c/CorpseCur.java @@ -1,46 +1,45 @@ - - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.InfectAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Loki */ public final class CorpseCur extends CardImpl { - private static final FilterCard filter = new FilterCard("creature card with infect from your graveyard"); + private static final FilterCard filter = new FilterCreatureCard("creature card with infect from your graveyard"); static { filter.add(new AbilityPredicate(InfectAbility.class)); } - public CorpseCur (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + public CorpseCur(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DOG); this.power = new MageInt(2); this.toughness = new MageInt(2); this.addAbility(InfectAbility.getInstance()); - Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); } - public CorpseCur (final CorpseCur card) { + public CorpseCur(final CorpseCur card) { super(card); } @@ -48,5 +47,4 @@ public final class CorpseCur extends CardImpl { public CorpseCur copy() { return new CorpseCur(this); } - } diff --git a/Mage.Sets/src/mage/cards/c/CorpseExplosion.java b/Mage.Sets/src/mage/cards/c/CorpseExplosion.java new file mode 100644 index 00000000000..d96a94f6f03 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CorpseExplosion.java @@ -0,0 +1,82 @@ +package mage.cards.c; + +import java.util.List; +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.ExileFromGraveCost; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author weirddan455 + */ +public final class CorpseExplosion extends CardImpl { + + public CorpseExplosion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{R}"); + + // As an additional cost to cast this spell, exile a creature card from your graveyard. + this.getSpellAbility().addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD))); + + // Corpse Explosion deals damage equal to the exiled card's power to each creature and each planeswalker. + this.getSpellAbility().addEffect(new CorpseExplosionEffect()); + } + + private CorpseExplosion(final CorpseExplosion card) { + super(card); + } + + @Override + public CorpseExplosion copy() { + return new CorpseExplosion(this); + } +} + +class CorpseExplosionEffect extends OneShotEffect { + + public CorpseExplosionEffect() { + super(Outcome.Damage); + this.staticText = "{this} deals damage equal to the exiled card's power to each creature and each planeswalker"; + } + + private CorpseExplosionEffect(final CorpseExplosionEffect effect) { + super(effect); + } + + @Override + public CorpseExplosionEffect copy() { + return new CorpseExplosionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int power = 0; + for (Cost cost : source.getCosts()) { + if (cost instanceof ExileFromGraveCost) { + List exiledCards = ((ExileFromGraveCost) cost).getExiledCards(); + if (!exiledCards.isEmpty()) { + power = exiledCards.get(0).getPower().getValue(); + break; + } + } + } + if (power < 1) { + return false; + } + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE_OR_PLANESWALKER, source.getControllerId(), source, game)) { + permanent.damage(power, source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CorpseHauler.java b/Mage.Sets/src/mage/cards/c/CorpseHauler.java index 443a0974058..7f98451e9ed 100644 --- a/Mage.Sets/src/mage/cards/c/CorpseHauler.java +++ b/Mage.Sets/src/mage/cards/c/CorpseHauler.java @@ -14,7 +14,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.common.TargetCardInYourGraveyard; /** @@ -26,7 +26,7 @@ public final class CorpseHauler extends CardImpl { private static final FilterCard filter = new FilterCard("another target creature card from your graveyard"); static { filter.add(CardType.CREATURE.getPredicate()); - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); } public CorpseHauler(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/Corrosion.java b/Mage.Sets/src/mage/cards/c/Corrosion.java index 309a29fadd2..665c49792f5 100644 --- a/Mage.Sets/src/mage/cards/c/Corrosion.java +++ b/Mage.Sets/src/mage/cards/c/Corrosion.java @@ -82,7 +82,7 @@ class CorrosionUpkeepEffect extends OneShotEffect { } } // destroy each artifact with converted mana cost less than or equal to the number of rust counters on it - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (permanent.getManaValue() <= permanent.getCounters(game).getCount(CounterType.RUST)) { permanent.destroy(source, game, true); } diff --git a/Mage.Sets/src/mage/cards/c/Corrupt.java b/Mage.Sets/src/mage/cards/c/Corrupt.java index 6931d7489f4..09efcf60797 100644 --- a/Mage.Sets/src/mage/cards/c/Corrupt.java +++ b/Mage.Sets/src/mage/cards/c/Corrupt.java @@ -60,7 +60,7 @@ class CorruptEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int amount = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int amount = game.getBattlefield().count(filter, source.getControllerId(), source, game); if (amount > 0) { int damageDealt = amount; Permanent permanent = game.getPermanent(source.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/c/CorruptedCrossroads.java b/Mage.Sets/src/mage/cards/c/CorruptedCrossroads.java index b8d17d2578c..e915c4aeeb1 100644 --- a/Mage.Sets/src/mage/cards/c/CorruptedCrossroads.java +++ b/Mage.Sets/src/mage/cards/c/CorruptedCrossroads.java @@ -69,7 +69,7 @@ class BlightedCrossroadsConditionalMana extends ConditionalMana { class BlightedCrossroadsManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object != null) { for (Ability ability: object.getAbilities()) { if (ability instanceof DevoidAbility) { diff --git a/Mage.Sets/src/mage/cards/c/CosisRavager.java b/Mage.Sets/src/mage/cards/c/CosisRavager.java index 91e9555d6de..e968d862939 100644 --- a/Mage.Sets/src/mage/cards/c/CosisRavager.java +++ b/Mage.Sets/src/mage/cards/c/CosisRavager.java @@ -24,7 +24,7 @@ public final class CosisRavager extends CardImpl { this.color.setRed(true); this.power = new MageInt(2); this.toughness = new MageInt(2); - Ability ability = new LandfallAbility(new DamageTargetEffect(1), false); + Ability ability = new LandfallAbility(new DamageTargetEffect(1), true); ability.addTarget(new TargetPlayerOrPlaneswalker()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CouncilGuardian.java b/Mage.Sets/src/mage/cards/c/CouncilGuardian.java index 21e9fcf94b2..967ace3d593 100644 --- a/Mage.Sets/src/mage/cards/c/CouncilGuardian.java +++ b/Mage.Sets/src/mage/cards/c/CouncilGuardian.java @@ -10,10 +10,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.choices.ChoiceColor; import mage.choices.VoteHandler; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; +import mage.constants.*; import mage.game.Game; import mage.players.Player; @@ -38,7 +35,7 @@ public final class CouncilGuardian extends CardImpl { // Will of the council - When Council Guardian enters the battlefield, starting with you, each player votes for blue, black, red, or green. Council Guardian gains protection from each color with the most votes or tied for most votes. this.addAbility(new EntersBattlefieldTriggeredAbility( new CouncilsGuardianEffect(), false) - .withFlavorWord("Will of the council") + .setAbilityWord(AbilityWord.WILL_OF_THE_COUNCIL) ); } diff --git a/Mage.Sets/src/mage/cards/c/CouncilOfTheAbsolute.java b/Mage.Sets/src/mage/cards/c/CouncilOfTheAbsolute.java index 54da84be391..69990b3afc8 100644 --- a/Mage.Sets/src/mage/cards/c/CouncilOfTheAbsolute.java +++ b/Mage.Sets/src/mage/cards/c/CouncilOfTheAbsolute.java @@ -76,7 +76,7 @@ class CouncilOfTheAbsoluteReplacementEffect extends ContinuousRuleModifyingEffec @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast a spell with that name (" + mageObject.getName() + " in play)."; } diff --git a/Mage.Sets/src/mage/cards/c/CouncilsJudgment.java b/Mage.Sets/src/mage/cards/c/CouncilsJudgment.java index 1c722445761..bc6f5f584e0 100644 --- a/Mage.Sets/src/mage/cards/c/CouncilsJudgment.java +++ b/Mage.Sets/src/mage/cards/c/CouncilsJudgment.java @@ -17,7 +17,6 @@ import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.Target; import mage.target.TargetPermanent; import java.util.LinkedHashSet; @@ -95,13 +94,13 @@ class CouncilsJudgmentVote extends VoteHandler { @Override public Permanent playerChoose(String voteInfo, Player player, Player decidingPlayer, Ability source, Game game) { - if (game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) < 1) { + if (game.getBattlefield().count(filter, source.getControllerId(), source, game) < 1) { return null; } TargetPermanent target = new TargetPermanent(1, filter); target.withChooseHint(voteInfo + " (to exile)"); target.setNotTarget(true); - decidingPlayer.choose(Outcome.Exile, target, source.getSourceId(), game); + decidingPlayer.choose(Outcome.Exile, target, source, game); return game.getPermanent(target.getFirstTarget()); } diff --git a/Mage.Sets/src/mage/cards/c/Counterbore.java b/Mage.Sets/src/mage/cards/c/Counterbore.java index 23c6b437561..e32a041c13a 100644 --- a/Mage.Sets/src/mage/cards/c/Counterbore.java +++ b/Mage.Sets/src/mage/cards/c/Counterbore.java @@ -21,7 +21,7 @@ public final class Counterbore extends CardImpl { // Counter target spell. // Search its controller's graveyard, hand, and library for all cards with the same name as that spell and exile them. Then that player shuffles their library. this.getSpellAbility().addTarget(new TargetSpell()); - this.getSpellAbility().addEffect(new CounterTargetAndSearchGraveyardHandLibraryEffect()); + this.getSpellAbility().addEffect(new CounterTargetAndSearchGraveyardHandLibraryEffect().concatBy(".")); } private Counterbore(final Counterbore card) { diff --git a/Mage.Sets/src/mage/cards/c/Counterlash.java b/Mage.Sets/src/mage/cards/c/Counterlash.java index 2e7eda53d13..458d03b8b14 100644 --- a/Mage.Sets/src/mage/cards/c/Counterlash.java +++ b/Mage.Sets/src/mage/cards/c/Counterlash.java @@ -1,15 +1,11 @@ package mage.cards.c; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import mage.ApprovingObject; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.filter.FilterCard; @@ -19,10 +15,13 @@ import mage.game.Game; import mage.game.stack.StackObject; import mage.players.Player; import mage.target.TargetSpell; -import mage.target.common.TargetCardInHand; +import mage.util.CardUtil; + +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; /** - * * @author BetaSteward */ public final class Counterlash extends CardImpl { @@ -50,9 +49,9 @@ class CounterlashEffect extends OneShotEffect { public CounterlashEffect() { super(Outcome.Detriment); - this.staticText = "Counter target spell. You may cast a nonland " - + "card in your hand that shares a card type with that " - + "spell without paying its mana cost"; + this.staticText = "Counter target spell. You may cast a spell " + + "that shares a card type with it from your hand " + + "without paying its mana cost"; } public CounterlashEffect(final CounterlashEffect effect) { @@ -68,32 +67,21 @@ class CounterlashEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { StackObject stackObject = game.getStack().getStackObject(source.getFirstTarget()); Player controller = game.getPlayer(source.getControllerId()); - if (stackObject != null - && controller != null) { - game.getStack().counter(source.getFirstTarget(), source, game); - if (controller.chooseUse(Outcome.PlayForFree, "Cast a nonland card in your hand that " - + "shares a card type with that spell without paying its mana cost?", source, game)) { - FilterCard filter = new FilterCard(); - List> types = new ArrayList<>(); - for (CardType type : stackObject.getCardType(game)) { - if (type != CardType.LAND) { - types.add(type.getPredicate()); - } - } - filter.add(Predicates.or(types)); - TargetCardInHand target = new TargetCardInHand(filter); - if (controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { - Card card = controller.getHand().get(target.getFirstTarget(), game); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - } - } - } + if (stackObject == null || controller == null) { + return false; + } + Set> predicates = stackObject + .getCardType(game) + .stream() + .map(CardType::getPredicate) + .collect(Collectors.toSet()); + game.getStack().counter(source.getFirstTarget(), source, game); + if (predicates.isEmpty()) { return true; } - return false; + FilterCard filter = new FilterCard(); + filter.add(Predicates.or(predicates)); + CardUtil.castSpellWithAttributesForFree(controller, source, game, new CardsImpl(controller.getHand()), filter); + return true; } } diff --git a/Mage.Sets/src/mage/cards/c/CountlessGearsRenegade.java b/Mage.Sets/src/mage/cards/c/CountlessGearsRenegade.java index 374e9212c7a..96974b33217 100644 --- a/Mage.Sets/src/mage/cards/c/CountlessGearsRenegade.java +++ b/Mage.Sets/src/mage/cards/c/CountlessGearsRenegade.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -16,6 +14,8 @@ import mage.constants.SubType; import mage.game.permanent.token.ServoToken; import mage.watchers.common.RevoltWatcher; +import java.util.UUID; + /** * @author JRHerlehy */ @@ -31,13 +31,13 @@ public final class CountlessGearsRenegade extends CardImpl { // Revolt — When Countless Gears Renegade enters the battlefield, if a permanent you controlled // left the battlefield this turn, create a 1/1 colorless Servo artifact creature token. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( - new CreateTokenEffect(new ServoToken(), 1), false), RevoltCondition.instance, - "Revolt — When {this} enters the battlefield, if a permanent you controlled left" - + " the battlefield this turn, create a 1/1 colorless Servo artifact creature token."); + Ability ability = new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ServoToken()), false), + RevoltCondition.instance, "When {this} enters the battlefield, if a permanent you controlled " + + "left the battlefield this turn, create a 1/1 colorless Servo artifact creature token." + ); ability.setAbilityWord(AbilityWord.REVOLT); - ability.addWatcher(new RevoltWatcher()); - this.addAbility(ability); + this.addAbility(ability, new RevoltWatcher()); } private CountlessGearsRenegade(final CountlessGearsRenegade card) { diff --git a/Mage.Sets/src/mage/cards/c/CourageousOutrider.java b/Mage.Sets/src/mage/cards/c/CourageousOutrider.java index 68d726c52ee..5ef2464947f 100644 --- a/Mage.Sets/src/mage/cards/c/CourageousOutrider.java +++ b/Mage.Sets/src/mage/cards/c/CourageousOutrider.java @@ -1,11 +1,10 @@ - package mage.cards.c; import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -33,7 +32,8 @@ public final class CourageousOutrider extends CardImpl { // When Courageous Outrider enters the battlefield, look at the top four cards of your library. You may reveal a Human card from among them // and put it into your hand. Put the rest on the bottom of your library in any order. - this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect(StaticValue.get(4), false, StaticValue.get(1), filter, false) , false)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 4, 1, filter, PutCards.HAND, PutCards.BOTTOM_ANY))); } private CourageousOutrider(final CourageousOutrider card) { diff --git a/Mage.Sets/src/mage/cards/c/CouriersBriefcase.java b/Mage.Sets/src/mage/cards/c/CouriersBriefcase.java new file mode 100644 index 00000000000..5297235f442 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CouriersBriefcase.java @@ -0,0 +1,55 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +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.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.mana.AnyColorManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.CitizenGreenWhiteToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CouriersBriefcase extends CardImpl { + + public CouriersBriefcase(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{G}"); + + this.subtype.add(SubType.TREASURE); + + // When Courier's Briefcase enters the battlefield, create a 1/1 green and white Citizen creature token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new CitizenGreenWhiteToken()))); + + // {T}, Sacrifice Courier's Briefcase: Add one mana of any color. + Ability ability = new AnyColorManaAbility(); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + + // {W}{U}{B}{R}{G}, {T}, Sacrifice Courier's Briefcase: Draw three cards. + ability = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(3), new ManaCostsImpl<>("{W}{U}{B}{R}{G}") + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private CouriersBriefcase(final CouriersBriefcase card) { + super(card); + } + + @Override + public CouriersBriefcase copy() { + return new CouriersBriefcase(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CourtHomunculus.java b/Mage.Sets/src/mage/cards/c/CourtHomunculus.java index f1c52d18e70..6d02aa9b1e3 100644 --- a/Mage.Sets/src/mage/cards/c/CourtHomunculus.java +++ b/Mage.Sets/src/mage/cards/c/CourtHomunculus.java @@ -54,7 +54,7 @@ class ControlsAnotherArtifactCondition implements Condition { public boolean apply(Game game, Ability source) { List controlledArtifacts = game.getBattlefield().getAllActivePermanents(new FilterArtifactPermanent(), source.getControllerId(), game); for (Permanent permanent : controlledArtifacts) { - if (!permanent.getId().equals(game.getObject(source.getSourceId()).getId())) { + if (!permanent.getId().equals(game.getObject(source).getId())) { return true; } } diff --git a/Mage.Sets/src/mage/cards/c/CourtHussar.java b/Mage.Sets/src/mage/cards/c/CourtHussar.java index 4808edfac53..af4d720f610 100644 --- a/Mage.Sets/src/mage/cards/c/CourtHussar.java +++ b/Mage.Sets/src/mage/cards/c/CourtHussar.java @@ -1,12 +1,11 @@ - package mage.cards.c; import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.ManaWasSpentCondition; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.SacrificeSourceUnlessConditionEffect; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; @@ -14,8 +13,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.ColoredManaSymbol; -import mage.constants.Zone; -import mage.filter.FilterCard; /** * @@ -34,9 +31,7 @@ public final class CourtHussar extends CardImpl { // Vigilance this.addAbility(VigilanceAbility.getInstance()); // When Court Hussar enters the battlefield, look at the top three cards of your library, then put one of them into your hand and the rest on the bottom of your library in any order. - this.addAbility(new EntersBattlefieldTriggeredAbility( - new LookLibraryAndPickControllerEffect(StaticValue.get(3), false, StaticValue.get(1), new FilterCard(), Zone.LIBRARY, false, false), - false)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.BOTTOM_ANY))); // When Court Hussar enters the battlefield, sacrifice it unless {W} was spent to cast it. this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessConditionEffect(new ManaWasSpentCondition(ColoredManaSymbol.W)), false)); } @@ -50,4 +45,3 @@ public final class CourtHussar extends CardImpl { return new CourtHussar(this); } } - diff --git a/Mage.Sets/src/mage/cards/c/CourtOfAmbition.java b/Mage.Sets/src/mage/cards/c/CourtOfAmbition.java index 453c0f88b8f..9cf70bf1ce5 100644 --- a/Mage.Sets/src/mage/cards/c/CourtOfAmbition.java +++ b/Mage.Sets/src/mage/cards/c/CourtOfAmbition.java @@ -82,7 +82,7 @@ class CourtOfAmbitionEffect extends OneShotEffect { continue; } TargetDiscard target = new TargetDiscard(discardCount, StaticFilters.FILTER_CARD, playerId); - player.choose(Outcome.Discard, target, source.getSourceId(), game); + player.choose(Outcome.Discard, target, source, game); discardMap.put(playerId, new CardsImpl(target.getTargets())); } for (Map.Entry entry : discardMap.entrySet()) { diff --git a/Mage.Sets/src/mage/cards/c/CourtOfBounty.java b/Mage.Sets/src/mage/cards/c/CourtOfBounty.java index 3e6828b6f9f..392ba066553 100644 --- a/Mage.Sets/src/mage/cards/c/CourtOfBounty.java +++ b/Mage.Sets/src/mage/cards/c/CourtOfBounty.java @@ -10,9 +10,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TargetController; -import mage.filter.FilterCard; import mage.filter.StaticFilters; -import mage.filter.predicate.Predicates; import java.util.UUID; @@ -21,15 +19,6 @@ import java.util.UUID; */ public final class CourtOfBounty extends CardImpl { - private static final FilterCard filter = new FilterCard("a creature or land card"); - - static { - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.LAND.getPredicate() - )); - } - public CourtOfBounty(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{G}"); @@ -38,7 +27,7 @@ public final class CourtOfBounty extends CardImpl { // At the beginning of your upkeep, you may put a land card from your hand onto the battlefield. If you're the monarch, instead you may put a creature or land card from your hand onto the battlefield. this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ConditionalOneShotEffect( - new PutCardFromHandOntoBattlefieldEffect(filter), + new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_CREATURE_OR_LAND), new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_LAND_A), MonarchIsSourceControllerCondition.instance, "you may put a land card " + "from your hand onto the battlefield. If you're the monarch, " + diff --git a/Mage.Sets/src/mage/cards/c/CoverOfDarkness.java b/Mage.Sets/src/mage/cards/c/CoverOfDarkness.java index c3b97c757dc..e525d953b48 100644 --- a/Mage.Sets/src/mage/cards/c/CoverOfDarkness.java +++ b/Mage.Sets/src/mage/cards/c/CoverOfDarkness.java @@ -1,7 +1,7 @@ package mage.cards.c; -import java.util.UUID; +import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.ChooseCreatureTypeEffect; @@ -14,8 +14,9 @@ import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class CoverOfDarkness extends CardImpl { @@ -58,10 +59,10 @@ class FilterCoverOfDarkness extends FilterCreaturePermanent { } @Override - public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { - if (super.match(permanent, sourceId, playerId, game)) { + public boolean match(Permanent permanent, UUID playerId, Ability source, Game game) { + if (super.match(permanent, playerId, source, game)) { if (subType == null) { - subType = ChooseCreatureTypeEffect.getChosenCreatureType(sourceId, game); + subType = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game); if (subType == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/c/CovetedPrize.java b/Mage.Sets/src/mage/cards/c/CovetedPrize.java index 5fd841994c9..95a0aee9705 100644 --- a/Mage.Sets/src/mage/cards/c/CovetedPrize.java +++ b/Mage.Sets/src/mage/cards/c/CovetedPrize.java @@ -4,14 +4,17 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.FullPartyCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.dynamicvalue.common.PartyCount; -import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect; +import mage.abilities.effects.common.cost.CastFromHandForFreeEffect; import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.hint.common.PartyCountHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.target.common.TargetCardInLibrary; import java.util.UUID; @@ -21,6 +24,12 @@ import java.util.UUID; */ public final class CovetedPrize extends CardImpl { + private static final FilterCard filter = new FilterCard("a spell with mana value 4 or less"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 5)); + } + public CovetedPrize(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); @@ -32,7 +41,7 @@ public final class CovetedPrize extends CardImpl { // Search your library for a card, put it into your hand, then shuffle your library. If you have a full party, you may cast a spell with converted mana cost 4 or less from your hand without paying its mana cost. this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary())); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new CastWithoutPayingManaCostEffect(4), + new CastFromHandForFreeEffect(filter), FullPartyCondition.instance, "If you have a full party, " + "you may cast a spell with mana value 4 or less from your hand without paying its mana cost." )); diff --git a/Mage.Sets/src/mage/cards/c/CowerInFear.java b/Mage.Sets/src/mage/cards/c/CowerInFear.java index 3a29280e2a5..7e089889e77 100644 --- a/Mage.Sets/src/mage/cards/c/CowerInFear.java +++ b/Mage.Sets/src/mage/cards/c/CowerInFear.java @@ -1,4 +1,3 @@ - package mage.cards.c; import java.util.UUID; @@ -7,8 +6,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; /** * @@ -16,18 +14,11 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class CowerInFear extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public CowerInFear(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}{B}"); - // Creatures your opponents control get -1/-1 until end of turn. - this.getSpellAbility().addEffect(new BoostAllEffect(-1, -1, Duration.EndOfTurn, filter, false)); + this.getSpellAbility().addEffect(new BoostAllEffect(-1, -1, Duration.EndOfTurn, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, false)); } private CowerInFear(final CowerInFear card) { diff --git a/Mage.Sets/src/mage/cards/c/Crackleburr.java b/Mage.Sets/src/mage/cards/c/Crackleburr.java index 7b19db74d84..f3a6900fbd1 100644 --- a/Mage.Sets/src/mage/cards/c/Crackleburr.java +++ b/Mage.Sets/src/mage/cards/c/Crackleburr.java @@ -32,8 +32,8 @@ import mage.target.common.TargetCreaturePermanent; */ public final class Crackleburr extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("two untapped red creatures you control"); - private static final FilterControlledCreaturePermanent filter2 = new FilterControlledCreaturePermanent("two tapped blue creatures you control"); + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped red creatures you control"); + private static final FilterControlledCreaturePermanent filter2 = new FilterControlledCreaturePermanent("tapped blue creature you control"); static { filter.add(new ColorPredicate(ObjectColor.RED)); diff --git a/Mage.Sets/src/mage/cards/c/CracklingDoom.java b/Mage.Sets/src/mage/cards/c/CracklingDoom.java index e7a57c37b0f..e3d85a853be 100644 --- a/Mage.Sets/src/mage/cards/c/CracklingDoom.java +++ b/Mage.Sets/src/mage/cards/c/CracklingDoom.java @@ -93,7 +93,7 @@ class CracklingDoomEffect extends OneShotEffect { FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature to sacrifice with power equal to " + greatestPower); filter.add(new PowerPredicate(ComparisonType.EQUAL_TO, greatestPower)); Target target = new TargetControlledCreaturePermanent(filter); - if (opponent.choose(outcome, target, playerId, game)) { + if (opponent.choose(outcome, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { toSacrifice.add(permanent); diff --git a/Mage.Sets/src/mage/cards/c/CracklingEmergence.java b/Mage.Sets/src/mage/cards/c/CracklingEmergence.java new file mode 100644 index 00000000000..b4756ff1419 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CracklingEmergence.java @@ -0,0 +1,113 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BecomesCreatureAttachedEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.IndestructibleAbility; +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.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.custom.CreatureToken; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CracklingEmergence extends CardImpl { + + public CracklingEmergence(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + + this.subtype.add(SubType.AURA); + + // Enchant land you control + TargetPermanent auraTarget = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // Enchanted land is a 3/3 red Spirit creature with haste. It's still a land. + this.addAbility(new SimpleStaticAbility(new BecomesCreatureAttachedEffect( + new CreatureToken(3, 3) + .withColor("R") + .withSubType(SubType.SPIRIT) + .withAbility(HasteAbility.getInstance()), + "enchanted land is a 3/3 red Spirit creature with haste. It's still a land", + Duration.WhileOnBattlefield, BecomesCreatureAttachedEffect.LoseType.COLOR + ))); + + // If enchanted land would be destroyed, instead sacrifice Crackling Emergence and that land gains indestructible until end of turn. + this.addAbility(new SimpleStaticAbility(new CracklingEmergenceEffect())); + } + + private CracklingEmergence(final CracklingEmergence card) { + super(card); + } + + @Override + public CracklingEmergence copy() { + return new CracklingEmergence(this); + } +} + +class CracklingEmergenceEffect extends ReplacementEffectImpl { + + CracklingEmergenceEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "if enchanted land would be destroyed, instead sacrifice " + + "{this} and that land gains indestructible until end of turn"; + } + + private CracklingEmergenceEffect(final CracklingEmergenceEffect effect) { + super(effect); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + Permanent enchantedPermanent = game.getPermanent(event.getTargetId()); + if (sourcePermanent == null || enchantedPermanent == null) { + return false; + } + sourcePermanent.sacrifice(source, game); + game.addEffect(new GainAbilityTargetEffect(IndestructibleAbility.getInstance()) + .setTargetPointer(new FixedTarget(enchantedPermanent, game)), source); + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DESTROY_PERMANENT; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + return sourcePermanent != null && event.getTargetId().equals(sourcePermanent.getAttachedTo()); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public CracklingEmergenceEffect copy() { + return new CracklingEmergenceEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CragganwickCremator.java b/Mage.Sets/src/mage/cards/c/CragganwickCremator.java index 2106008dfeb..e8eddeca762 100644 --- a/Mage.Sets/src/mage/cards/c/CragganwickCremator.java +++ b/Mage.Sets/src/mage/cards/c/CragganwickCremator.java @@ -52,7 +52,7 @@ class CragganwickCrematorEffect extends OneShotEffect { public CragganwickCrematorEffect() { super(Outcome.Neutral); - this.staticText = "discard a card at random. If you discard a creature card this way, {this} deals damage equal to that card's power to target player"; + this.staticText = "discard a card at random. If you discard a creature card this way, {this} deals damage equal to that card's power to target player or planeswalker"; } public CragganwickCrematorEffect(final CragganwickCrematorEffect effect) { diff --git a/Mage.Sets/src/mage/cards/c/CrashTheParty.java b/Mage.Sets/src/mage/cards/c/CrashTheParty.java new file mode 100644 index 00000000000..33ea58a6374 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrashTheParty.java @@ -0,0 +1,51 @@ +package mage.cards.c; + +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.permanent.token.RhinoWarriorToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CrashTheParty extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("tapped creature you control"); + + static { + filter.add(TappedPredicate.TAPPED); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter, 1); + private static final Hint hint = new ValueHint("Tapped creatures you control", xValue); + + public CrashTheParty(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{5}{G}"); + + // Create a tapped 4/4 green Rhino Warrior creature token for each tapped creature you control. + this.getSpellAbility().addEffect(new CreateTokenEffect( + new RhinoWarriorToken(), xValue, true, false + )); + this.getSpellAbility().addHint(hint); + } + + private CrashTheParty(final CrashTheParty card) { + super(card); + } + + @Override + public CrashTheParty copy() { + return new CrashTheParty(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CrashingBoars.java b/Mage.Sets/src/mage/cards/c/CrashingBoars.java index b9e66a2c13f..d2c5a1e4c71 100644 --- a/Mage.Sets/src/mage/cards/c/CrashingBoars.java +++ b/Mage.Sets/src/mage/cards/c/CrashingBoars.java @@ -74,7 +74,7 @@ class CrashingBoarsEffect extends OneShotEffect { Player defendingPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); if (defendingPlayer != null) { Target target = new TargetControlledCreaturePermanent(1, 1, filter, true); - if (target.choose(Outcome.Neutral, defendingPlayer.getId(), source.getSourceId(), game)) { + if (target.choose(Outcome.Neutral, defendingPlayer.getId(), source.getSourceId(), source, game)) { RequirementEffect effect = new MustBeBlockedByTargetSourceEffect(); effect.setTargetPointer(new FixedTarget(target.getFirstTarget(), game)); game.addEffect(effect, source); diff --git a/Mage.Sets/src/mage/cards/c/CreamOfTheCrop.java b/Mage.Sets/src/mage/cards/c/CreamOfTheCrop.java index 0a66219f2cb..112a06f0fe3 100644 --- a/Mage.Sets/src/mage/cards/c/CreamOfTheCrop.java +++ b/Mage.Sets/src/mage/cards/c/CreamOfTheCrop.java @@ -36,7 +36,7 @@ public final class CreamOfTheCrop extends CardImpl { + "you may look at the top X cards of your library, where X " + "is that creature's power. If you do, put one of those cards " + "on top of your library and the rest on the bottom of " - + "your library in any order")); + + "your library in any order.")); } private CreamOfTheCrop(final CreamOfTheCrop card) { diff --git a/Mage.Sets/src/mage/cards/c/CreativeOutburst.java b/Mage.Sets/src/mage/cards/c/CreativeOutburst.java index 2c39e9e4dfc..9dbe0bb2675 100644 --- a/Mage.Sets/src/mage/cards/c/CreativeOutburst.java +++ b/Mage.Sets/src/mage/cards/c/CreativeOutburst.java @@ -4,15 +4,14 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.DiscardSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; -import mage.filter.StaticFilters; import mage.game.permanent.token.TreasureToken; import mage.target.common.TargetAnyTarget; @@ -28,11 +27,7 @@ public final class CreativeOutburst extends CardImpl { // Creative Outburst deals 5 damage to any target. Look at the top five cards of your library. Put one of them into your hand and the rest on the bottom of your library in a random order. this.getSpellAbility().addEffect(new DamageTargetEffect(5)); - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.LIBRARY, false, false - ).setBackInRandomOrder(true).setText("Look at the top five cards of your library. " + - "Put one of them into your hand and the rest on the bottom of your library in a random order")); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(5, 1, PutCards.HAND, PutCards.BOTTOM_RANDOM)); this.getSpellAbility().addTarget(new TargetAnyTarget()); // {U/R}{U/R}, Discard Creative Outburst: Create a Treasure token. diff --git a/Mage.Sets/src/mage/cards/c/CreativeTechnique.java b/Mage.Sets/src/mage/cards/c/CreativeTechnique.java index 8ad5c336c5a..a243785617b 100644 --- a/Mage.Sets/src/mage/cards/c/CreativeTechnique.java +++ b/Mage.Sets/src/mage/cards/c/CreativeTechnique.java @@ -1,6 +1,5 @@ package mage.cards.c; -import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.DemonstrateAbility; @@ -10,6 +9,7 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import mage.util.CardUtil; import java.util.UUID; @@ -78,18 +78,7 @@ class CreativeTechniqueEffect extends OneShotEffect { player.moveCards(toCast, Zone.EXILED, source, game); } player.putCardsOnBottomOfLibrary(cards, game, source, false); - if (toCast == null || !player.chooseUse( - Outcome.PlayForFree, "Cast " + toCast.getIdName() - + " without paying its mana cost?", source, game - )) { - return true; - } - game.getState().setValue("PlayFromNotOwnHandZone" + toCast.getId(), Boolean.TRUE); - player.cast( - player.chooseAbilityForCast(toCast, game, true), - game, true, new ApprovingObject(source, game) - ); - game.getState().setValue("PlayFromNotOwnHandZone" + toCast.getId(), null); + CardUtil.castSpellWithAttributesForFree(player, source, game, toCast); return true; } } diff --git a/Mage.Sets/src/mage/cards/c/CreatureBond.java b/Mage.Sets/src/mage/cards/c/CreatureBond.java index 9e19b52bdbb..eb28133c1a1 100644 --- a/Mage.Sets/src/mage/cards/c/CreatureBond.java +++ b/Mage.Sets/src/mage/cards/c/CreatureBond.java @@ -1,10 +1,10 @@ - package mage.cards.c; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DiesAttachedTriggeredAbility; -import mage.abilities.dynamicvalue.common.AttachedPermanentToughnessValue; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.DamageAttachedControllerEffect; import mage.abilities.keyword.EnchantAbility; @@ -13,6 +13,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -24,18 +27,19 @@ public final class CreatureBond extends CardImpl { public CreatureBond(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); - + this.subtype.add(SubType.AURA); // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // When enchanted creature dies, Creature Bond deals damage equal to that creature's toughness to the creature's controller. - this.addAbility( new DiesAttachedTriggeredAbility(new DamageAttachedControllerEffect(AttachedPermanentToughnessValue.instance), "enchanted creature")); + Effect effect = new DamageAttachedControllerEffect(CreatureBondValue.instance); + effect.setText("{this} deals damage equal to that creature's toughness to the creature's controller"); + this.addAbility(new DiesAttachedTriggeredAbility(effect, "enchanted creature")); } private CreatureBond(final CreatureBond card) { @@ -47,3 +51,32 @@ public final class CreatureBond extends CardImpl { return new CreatureBond(this); } } + +enum CreatureBondValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + // In the case that the enchantment is blinked + Permanent enchantment = (Permanent) game.getLastKnownInformation(sourceAbility.getSourceId(), Zone.BATTLEFIELD); + if (enchantment == null) { + // It was not blinked, use the standard method + enchantment = game.getPermanentOrLKIBattlefield(sourceAbility.getSourceId()); + } + if (enchantment == null) { + return 0; + } + Permanent enchanted = game.getPermanentOrLKIBattlefield(enchantment.getAttachedTo()); + return enchanted.getToughness().getValue(); + } + + @Override + public CreatureBondValue copy() { + return instance; + } + + @Override + public String getMessage() { + return "that creature's toughness"; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CreditVoucher.java b/Mage.Sets/src/mage/cards/c/CreditVoucher.java index 2fdc5e4bc6a..5b7a871fa5e 100644 --- a/Mage.Sets/src/mage/cards/c/CreditVoucher.java +++ b/Mage.Sets/src/mage/cards/c/CreditVoucher.java @@ -65,13 +65,13 @@ class CreditVoucherEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { FilterCard filter = new FilterCard("card in your hand to shuffle away"); TargetCardInHand target = new TargetCardInHand(0, controller.getHand().size(), filter); target.setRequired(false); int amountShuffled = 0; - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) && target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), game)) { + if (target.canChoose(source.getControllerId(), source, game) && target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), source, game)) { if (!target.getTargets().isEmpty()) { amountShuffled = target.getTargets().size(); controller.moveCards(new CardsImpl(target.getTargets()), Zone.LIBRARY, source, game); diff --git a/Mage.Sets/src/mage/cards/c/CreepingInn.java b/Mage.Sets/src/mage/cards/c/CreepingInn.java index 5ba7b0aa98c..81125611374 100644 --- a/Mage.Sets/src/mage/cards/c/CreepingInn.java +++ b/Mage.Sets/src/mage/cards/c/CreepingInn.java @@ -84,8 +84,8 @@ class CreepingInnEffect extends OneShotEffect { UUID exileId = CardUtil.getExileZoneId(game, source); TargetCardInGraveyard target = new TargetCardInGraveyard(0, 1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { - if (player.choose(Outcome.Exile, target, source.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { + if (player.choose(Outcome.Exile, target, source, game)) { Card cardChosen = game.getCard(target.getFirstTarget()); if (cardChosen != null) { int lifeAmount = 0; diff --git a/Mage.Sets/src/mage/cards/c/CreepingRenaissance.java b/Mage.Sets/src/mage/cards/c/CreepingRenaissance.java index 10f09e1f1d3..23cbf17c3ae 100644 --- a/Mage.Sets/src/mage/cards/c/CreepingRenaissance.java +++ b/Mage.Sets/src/mage/cards/c/CreepingRenaissance.java @@ -10,7 +10,6 @@ import mage.choices.Choice; import mage.choices.ChoiceCardType; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.TimingRule; import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; @@ -76,7 +75,7 @@ class CreepingRenaissanceEffect extends OneShotEffect { } FilterCard filter = new FilterCard(chosenType.toString().toLowerCase(Locale.ENGLISH) + " card"); filter.add(chosenType.getPredicate()); - return controller.moveCards(controller.getGraveyard().getCards(filter, source.getSourceId(), controller.getId(), game), Zone.HAND, source, game); + return controller.moveCards(controller.getGraveyard().getCards(filter, controller.getId(), source, game), Zone.HAND, source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/c/CrewCaptain.java b/Mage.Sets/src/mage/cards/c/CrewCaptain.java new file mode 100644 index 00000000000..fa70c900e80 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrewCaptain.java @@ -0,0 +1,65 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CrewCaptain extends CardImpl { + + public CrewCaptain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{R}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Crew Captain has indestructible as long as it entered the battlefield this turn. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(IndestructibleAbility.getInstance()), CrewCaptainCondition.instance, + "{this} has indestructible as long as it entered the battlefield this turn" + ))); + } + + private CrewCaptain(final CrewCaptain card) { + super(card); + } + + @Override + public CrewCaptain copy() { + return new CrewCaptain(this); + } +} + +enum CrewCaptainCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return Optional.of(source.getSourcePermanentIfItStillExists(game)) + .filter(Objects::nonNull) + .map(Permanent::getTurnsOnBattlefield) + .orElseGet(() -> -1) == 0; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CrimsonRoc.java b/Mage.Sets/src/mage/cards/c/CrimsonRoc.java index 72d8899a991..f6094a32d18 100644 --- a/Mage.Sets/src/mage/cards/c/CrimsonRoc.java +++ b/Mage.Sets/src/mage/cards/c/CrimsonRoc.java @@ -1,7 +1,10 @@ package mage.cards.c; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.BlocksCreatureTriggeredAbility; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FirstStrikeAbility; @@ -12,6 +15,9 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -23,6 +29,12 @@ import java.util.UUID; */ public final class CrimsonRoc extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature without flying"); + + static { + filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); + } + public CrimsonRoc(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); @@ -34,7 +46,13 @@ public final class CrimsonRoc extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever Crimson Roc blocks a creature without flying, Crimson Roc gets +1/+0 and gains first strike until end of turn. - this.addAbility(new CrimsonRocTriggeredAbility()); + Ability ability = new BlocksCreatureTriggeredAbility(new BoostSourceEffect( + 1, 0, Duration.EndOfTurn + ).setText("{this} gets +1/+0"), filter, false); + ability.addEffect(new GainAbilitySourceEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains first strike until end of turn")); + this.addAbility(ability); } private CrimsonRoc(final CrimsonRoc card) { @@ -45,43 +63,4 @@ public final class CrimsonRoc extends CardImpl { public CrimsonRoc copy() { return new CrimsonRoc(this); } -} - -class CrimsonRocTriggeredAbility extends TriggeredAbilityImpl { - - CrimsonRocTriggeredAbility() { - super(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn), false); - this.addEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn)); - } - - private CrimsonRocTriggeredAbility(final CrimsonRocTriggeredAbility ability) { - super(ability); - } - - @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())) { - return false; - } - Permanent permanent = game.getPermanent(event.getTargetId()); - return permanent != null - && permanent.isCreature(game) - && !permanent.hasAbility(FlyingAbility.getInstance(), game); - } - - @Override - public String getRule() { - return "Whenever {this} blocks a creature without flying, " + - "{this} gets +1/+0 and gains first strike until end of turn."; - } - - @Override - public CrimsonRocTriggeredAbility copy() { - return new CrimsonRocTriggeredAbility(this); - } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CrimsonWisps.java b/Mage.Sets/src/mage/cards/c/CrimsonWisps.java index 1d45f2931bb..7d0bcb5d883 100644 --- a/Mage.Sets/src/mage/cards/c/CrimsonWisps.java +++ b/Mage.Sets/src/mage/cards/c/CrimsonWisps.java @@ -1,8 +1,5 @@ - - package mage.cards.c; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.BecomesColorTargetEffect; @@ -14,25 +11,30 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX */ public final class CrimsonWisps extends CardImpl { - public CrimsonWisps (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}"); + public CrimsonWisps(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); // Target creature becomes red and gains haste until end of turn. + this.getSpellAbility().addEffect(new BecomesColorTargetEffect( + ObjectColor.RED, Duration.EndOfTurn + ).setText("target creature becomes red")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains haste until end of turn")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new BecomesColorTargetEffect(ObjectColor.RED, Duration.EndOfTurn)); - this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn)); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } - public CrimsonWisps (final CrimsonWisps card) { + public CrimsonWisps(final CrimsonWisps card) { super(card); } @@ -40,6 +42,4 @@ public final class CrimsonWisps extends CardImpl { public CrimsonWisps copy() { return new CrimsonWisps(this); } - } - diff --git a/Mage.Sets/src/mage/cards/c/Cromat.java b/Mage.Sets/src/mage/cards/c/Cromat.java index ce52d89df43..dc49bb0e3e4 100644 --- a/Mage.Sets/src/mage/cards/c/Cromat.java +++ b/Mage.Sets/src/mage/cards/c/Cromat.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -15,24 +13,30 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.BlockedByIdPredicate; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class Cromat extends CardImpl { - + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature blocking or blocked by {this}"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.EITHER); + } + public Cromat(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{U}{B}{R}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}{B}{R}{G}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ILLUSION); @@ -40,20 +44,31 @@ public final class Cromat extends CardImpl { this.toughness = new MageInt(5); // {W}{B}: Destroy target creature blocking or blocked by Cromat. - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking or blocked by Cromat"); - filter.add(Predicates.or(new BlockedByIdPredicate(this.getId()), - new BlockingAttackerIdPredicate(this.getId()))); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{W}{B}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + Ability ability = new SimpleActivatedAbility( + new DestroyTargetEffect(), new ManaCostsImpl<>("{W}{B}") + ); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); + // {U}{R}: Cromat gains flying until end of turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{U}{R}"))); + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl<>("{U}{R}"))); + // {B}{G}: Regenerate Cromat. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{B}{G}"))); + this.addAbility(new SimpleActivatedAbility( + new RegenerateSourceEffect(), new ManaCostsImpl<>("{B}{G}") + )); + // {R}{W}: Cromat gets +1/+1 until end of turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1,1, Duration.EndOfTurn), new ManaCostsImpl("{R}{W}"))); + this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect( + 1, 1, Duration.EndOfTurn + ), new ManaCostsImpl<>("{R}{W}"))); + // {G}{U}: Put Cromat on top of its owner's library. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutOnLibrarySourceEffect(true), new ManaCostsImpl("{G}{U}"))); + this.addAbility(new SimpleActivatedAbility( + new PutOnLibrarySourceEffect(true), new ManaCostsImpl<>("{G}{U}") + )); } private Cromat(final Cromat card) { diff --git a/Mage.Sets/src/mage/cards/c/CrookedCustodian.java b/Mage.Sets/src/mage/cards/c/CrookedCustodian.java new file mode 100644 index 00000000000..fb4963065ef --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrookedCustodian.java @@ -0,0 +1,37 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author weirddan455 + */ +public final class CrookedCustodian extends CardImpl { + + public CrookedCustodian(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Crooked Custodian enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + } + + private CrookedCustodian(final CrookedCustodian card) { + super(card); + } + + @Override + public CrookedCustodian copy() { + return new CrookedCustodian(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CrosissCharm.java b/Mage.Sets/src/mage/cards/c/CrosissCharm.java index ba0c61798fa..6b1f220a260 100644 --- a/Mage.Sets/src/mage/cards/c/CrosissCharm.java +++ b/Mage.Sets/src/mage/cards/c/CrosissCharm.java @@ -26,13 +26,11 @@ public final class CrosissCharm extends CardImpl { this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent()); // or destroy target nonblack creature, and it can't be regenerated; - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect(true)); + Mode mode = new Mode(new DestroyTargetEffect(true)); mode.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); this.getSpellAbility().addMode(mode); // or destroy target artifact. - mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + mode = new Mode(new DestroyTargetEffect()); Target target = new TargetArtifactPermanent(); mode.addTarget(target); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/c/CrownOfConvergence.java b/Mage.Sets/src/mage/cards/c/CrownOfConvergence.java index c23faefedb9..d344968c4b6 100644 --- a/Mage.Sets/src/mage/cards/c/CrownOfConvergence.java +++ b/Mage.Sets/src/mage/cards/c/CrownOfConvergence.java @@ -75,7 +75,7 @@ class CrownOfConvergenceColorBoostEffect extends BoostAllEffect { if (you != null) { Card topCard = you.getLibrary().getFromTop(game); if (topCard != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_CREATURE, source.getControllerId(), source, game)) { if (permanent.getColor(game).shares(topCard.getColor(game)) && !permanent.getColor(game).isColorless()) { permanent.addPower(power.calculate(game, source, this)); permanent.addToughness(toughness.calculate(game, source, this)); diff --git a/Mage.Sets/src/mage/cards/c/CrownOfDoom.java b/Mage.Sets/src/mage/cards/c/CrownOfDoom.java index 5fcb5a82d9c..0d05fa45b1d 100644 --- a/Mage.Sets/src/mage/cards/c/CrownOfDoom.java +++ b/Mage.Sets/src/mage/cards/c/CrownOfDoom.java @@ -78,7 +78,7 @@ enum CrownOfDoomPredicate implements ObjectSourcePlayerPredicate { @Override public boolean apply(ObjectSourcePlayer input, Game game) { Player targetPlayer = input.getObject(); - Permanent sourceObject = game.getPermanentOrLKIBattlefield(input.getSourceId()); + Permanent sourceObject = input.getSource().getSourcePermanentOrLKI(game); if (targetPlayer == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/c/CrownOfTheAges.java b/Mage.Sets/src/mage/cards/c/CrownOfTheAges.java index 2dfd51581aa..2201e4b4702 100644 --- a/Mage.Sets/src/mage/cards/c/CrownOfTheAges.java +++ b/Mage.Sets/src/mage/cards/c/CrownOfTheAges.java @@ -91,8 +91,8 @@ class CrownOfTheAgesEffect extends OneShotEffect { Target chosenCreatureToAttachAura = new TargetPermanent(filterChoice); chosenCreatureToAttachAura.setNotTarget(true); - if (chosenCreatureToAttachAura.canChoose(source.getSourceId(), source.getControllerId(), game) - && controller.choose(Outcome.Neutral, chosenCreatureToAttachAura, source.getSourceId(), game)) { + if (chosenCreatureToAttachAura.canChoose(source.getControllerId(), source, game) + && controller.choose(Outcome.Neutral, chosenCreatureToAttachAura, source, game)) { Permanent creatureToAttachAura = game.getPermanent(chosenCreatureToAttachAura.getFirstTarget()); if (creatureToAttachAura != null) { if (passed) { diff --git a/Mage.Sets/src/mage/cards/c/CrucibleOfTheSpiritDragon.java b/Mage.Sets/src/mage/cards/c/CrucibleOfTheSpiritDragon.java index ea8181859f4..9d089af6268 100644 --- a/Mage.Sets/src/mage/cards/c/CrucibleOfTheSpiritDragon.java +++ b/Mage.Sets/src/mage/cards/c/CrucibleOfTheSpiritDragon.java @@ -89,7 +89,7 @@ class CrucibleOfTheSpiritDragonManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object != null && object.hasSubtype(SubType.DRAGON, game)) { return true; } diff --git a/Mage.Sets/src/mage/cards/c/CrudeRampart.java b/Mage.Sets/src/mage/cards/c/CrudeRampart.java index 155f1176142..31fc79d5f8f 100644 --- a/Mage.Sets/src/mage/cards/c/CrudeRampart.java +++ b/Mage.Sets/src/mage/cards/c/CrudeRampart.java @@ -26,7 +26,7 @@ public final class CrudeRampart extends CardImpl { // Defender this.addAbility(DefenderAbility.getInstance()); // Morph {4}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{W}"))); } private CrudeRampart(final CrudeRampart card) { diff --git a/Mage.Sets/src/mage/cards/c/CruelFate.java b/Mage.Sets/src/mage/cards/c/CruelFate.java index b76e2edb42e..6c5a44dbaa6 100644 --- a/Mage.Sets/src/mage/cards/c/CruelFate.java +++ b/Mage.Sets/src/mage/cards/c/CruelFate.java @@ -40,7 +40,7 @@ public final class CruelFate extends CardImpl { class CruelFateEffect extends OneShotEffect { CruelFateEffect() { - super(Outcome.DrawCard); + super(Outcome.Detriment); this.staticText = "Look at the top five cards of target opponent's library. " + "Put one of those cards into that player's graveyard and the rest on top of their library in any order"; } @@ -75,6 +75,6 @@ class CruelFateEffect extends OneShotEffect { controller.moveCards(card, Zone.GRAVEYARD, source, game); cards.remove(card); } - return controller.putCardsOnTopOfLibrary(card, game, source, true); + return controller.putCardsOnTopOfLibrary(cards, game, source, true); } } diff --git a/Mage.Sets/src/mage/cards/c/CruelReality.java b/Mage.Sets/src/mage/cards/c/CruelReality.java index e3249e40188..b80779dbeaf 100644 --- a/Mage.Sets/src/mage/cards/c/CruelReality.java +++ b/Mage.Sets/src/mage/cards/c/CruelReality.java @@ -86,8 +86,8 @@ class CruelRealityEffect extends OneShotEffect { } TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), cursedPlayer.getId(), game) - && cursedPlayer.choose(Outcome.Sacrifice, target, source.getId(), game)) { + if (target.canChoose(cursedPlayer.getId(), source, game) + && cursedPlayer.choose(Outcome.Sacrifice, target, source, game)) { Permanent objectToBeSacrificed = game.getPermanent(target.getFirstTarget()); if (objectToBeSacrificed != null) { if (objectToBeSacrificed.sacrifice(source, game)) { diff --git a/Mage.Sets/src/mage/cards/c/CruelUltimatum.java b/Mage.Sets/src/mage/cards/c/CruelUltimatum.java index 56c45460de6..6abad936cb2 100644 --- a/Mage.Sets/src/mage/cards/c/CruelUltimatum.java +++ b/Mage.Sets/src/mage/cards/c/CruelUltimatum.java @@ -2,8 +2,6 @@ package mage.cards.c; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.SacrificeEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; @@ -32,13 +30,13 @@ public final class CruelUltimatum extends CardImpl { // Target opponent sacrifices a creature, discards three cards, then loses 5 life. // You return a creature card from your graveyard to your hand, draw three cards, then gain 5 life. this.getSpellAbility().addTarget(new TargetOpponent()); - this.getSpellAbility().addEffect(new SacrificeEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, "Target opponent")); - this.getSpellAbility().addEffect(new DiscardTargetEffect(3)); - this.getSpellAbility().addEffect(new LoseLifeTargetEffect(5)); - + this.getSpellAbility().addEffect(new SacrificeEffect( + StaticFilters.FILTER_PERMANENT_CREATURE, + 1, "Target opponent" + )); + this.getSpellAbility().addEffect(new DiscardTargetEffect(3).setText(", discards three cards")); + this.getSpellAbility().addEffect(new LoseLifeTargetEffect(5).setText(", then loses 5 life")); this.getSpellAbility().addEffect(new CruelUltimatumEffect()); - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(3)); - this.getSpellAbility().addEffect(new GainLifeEffect(5)); } private CruelUltimatum(final CruelUltimatum card) { @@ -55,7 +53,8 @@ class CruelUltimatumEffect extends OneShotEffect { public CruelUltimatumEffect() { super(Outcome.ReturnToHand); - this.staticText = "Return a creature card from your graveyard to your hand"; + this.staticText = "You return a creature card from your graveyard " + + "to your hand, draw three cards, then gain 5 life"; } public CruelUltimatumEffect(final CruelUltimatumEffect effect) { @@ -74,14 +73,13 @@ class CruelUltimatumEffect extends OneShotEffect { return false; } 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) { - return false; - } - + controller.choose(Outcome.ReturnToHand, target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { return controller.moveCards(card, Zone.HAND, source, game); } + controller.drawCards(1, source, game); + controller.gainLife(1, game, source); return true; } } diff --git a/Mage.Sets/src/mage/cards/c/CrueltyOfTheSith.java b/Mage.Sets/src/mage/cards/c/CrueltyOfTheSith.java index 458c9acd38d..59655b30359 100644 --- a/Mage.Sets/src/mage/cards/c/CrueltyOfTheSith.java +++ b/Mage.Sets/src/mage/cards/c/CrueltyOfTheSith.java @@ -28,14 +28,12 @@ public final class CrueltyOfTheSith extends CardImpl { this.getSpellAbility().addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_NON_CREATURE)); // Target player sacrifices a creture. - Mode mode = new Mode(); - mode.addEffect(new SacrificeEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, "Target player")); + Mode mode = new Mode(new SacrificeEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, "Target player")); mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); // Cruelty of the Sith deals 3 damage to target player. That player discards a card. - mode = new Mode(); - mode.addEffect(new DamageTargetEffect(3)); + mode = new Mode(new DamageTargetEffect(3)); mode.addEffect(new DiscardTargetEffect(1)); mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/c/CrushContraband.java b/Mage.Sets/src/mage/cards/c/CrushContraband.java index 6cbb1125974..9ae9cf09ec5 100644 --- a/Mage.Sets/src/mage/cards/c/CrushContraband.java +++ b/Mage.Sets/src/mage/cards/c/CrushContraband.java @@ -26,8 +26,7 @@ public final class CrushContraband extends CardImpl { this.getSpellAbility().addEffect(new ExileTargetEffect()); this.getSpellAbility().addTarget(new TargetArtifactPermanent().withChooseHint("destroy")); - Mode mode1 = new Mode(); - mode1.addEffect(new ExileTargetEffect()); + Mode mode1 = new Mode(new ExileTargetEffect()); mode1.addTarget(new TargetEnchantmentPermanent().withChooseHint("destroy")); this.getSpellAbility().addMode(mode1); } diff --git a/Mage.Sets/src/mage/cards/c/CrushUnderfoot.java b/Mage.Sets/src/mage/cards/c/CrushUnderfoot.java index 0b2ceda2144..6ddb8c5ce71 100644 --- a/Mage.Sets/src/mage/cards/c/CrushUnderfoot.java +++ b/Mage.Sets/src/mage/cards/c/CrushUnderfoot.java @@ -72,7 +72,7 @@ class CrushUnderfootEffect extends OneShotEffect { if (controller != null) { // Choose a Giant creature you control (not targeted, happens during effect resolving ) Target target = new TargetControlledCreaturePermanent(1,1, filter,false); - if (target.canChoose(source.getSourceId(), controller.getId(), game) + if (target.canChoose(controller.getId(), source, game) && controller.chooseTarget(outcome, target, source, game)) { Permanent giant = game.getPermanent(target.getFirstTarget()); if (giant != null) { diff --git a/Mage.Sets/src/mage/cards/c/CrushingCanopy.java b/Mage.Sets/src/mage/cards/c/CrushingCanopy.java index 73303ad3a95..e55610d8772 100644 --- a/Mage.Sets/src/mage/cards/c/CrushingCanopy.java +++ b/Mage.Sets/src/mage/cards/c/CrushingCanopy.java @@ -33,9 +33,8 @@ public final class CrushingCanopy extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); // * Destroy target enchantment. - Mode mode = new Mode(); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetEnchantmentPermanent()); - mode.addEffect(new DestroyTargetEffect()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/CrushingVines.java b/Mage.Sets/src/mage/cards/c/CrushingVines.java index 97330fd2a5c..4492a1c88cb 100644 --- a/Mage.Sets/src/mage/cards/c/CrushingVines.java +++ b/Mage.Sets/src/mage/cards/c/CrushingVines.java @@ -32,9 +32,8 @@ public final class CrushingVines extends CardImpl { // Choose one - Destroy target creature with flying; or destroy target artifact. this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); - Mode mode = new Mode(); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetArtifactPermanent()); - mode.addEffect(new DestroyTargetEffect()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/CruxOfFate.java b/Mage.Sets/src/mage/cards/c/CruxOfFate.java index 29766422e8b..8b6b22051cb 100644 --- a/Mage.Sets/src/mage/cards/c/CruxOfFate.java +++ b/Mage.Sets/src/mage/cards/c/CruxOfFate.java @@ -30,8 +30,7 @@ public final class CruxOfFate extends CardImpl { // * Destroy all Dragon creatures. this.getSpellAbility().addEffect(new DestroyAllEffect(new FilterCreaturePermanent(SubType.DRAGON, "Dragon creatures"))); // * Destroy all non-Dragon creatures. - Mode mode = new Mode(); - mode.addEffect(new DestroyAllEffect(new FilterCreaturePermanent(filterNonDragon))); + Mode mode = new Mode(new DestroyAllEffect(new FilterCreaturePermanent(filterNonDragon))); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/CryOfTheCarnarium.java b/Mage.Sets/src/mage/cards/c/CryOfTheCarnarium.java index ba9584e3488..0079b741b7d 100644 --- a/Mage.Sets/src/mage/cards/c/CryOfTheCarnarium.java +++ b/Mage.Sets/src/mage/cards/c/CryOfTheCarnarium.java @@ -64,15 +64,14 @@ class CryOfTheCarnariumExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); CardsPutIntoGraveyardWatcher watcher = game.getState().getWatcher(CardsPutIntoGraveyardWatcher.class); - if (player == null || watcher == null) { - return false; - } - Cards cards = new CardsImpl(watcher.getCardsPutToGraveyardFromBattlefield(game)); + if (controller == null || watcher == null) { return false; } + + Cards cards = new CardsImpl(watcher.getCardsPutIntoGraveyardFromBattlefield(game)); cards.removeIf(uuid -> !game.getCard(uuid).isCreature(game)); - player.moveCards(cards, Zone.EXILED, source, game); - return true; + + return controller.moveCards(cards, Zone.EXILED, source, game); } } diff --git a/Mage.Sets/src/mage/cards/c/Crypsis.java b/Mage.Sets/src/mage/cards/c/Crypsis.java index 1046b126a47..16d69bb17fa 100644 --- a/Mage.Sets/src/mage/cards/c/Crypsis.java +++ b/Mage.Sets/src/mage/cards/c/Crypsis.java @@ -8,8 +8,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; @@ -19,23 +18,15 @@ import java.util.UUID; */ public final class Crypsis extends CardImpl { - static final FilterPermanent filter = new FilterPermanent("creatures your opponents control"); - - static { - filter.add(CardType.CREATURE.getPredicate()); - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public Crypsis(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Target creature you control gains protection from creatures your opponents control until end of turn. Untap it. - this.getSpellAbility().addEffect(new GainAbilityTargetEffect(new ProtectionAbility(filter), Duration.EndOfTurn)); - Effect effect = new UntapTargetEffect(); - effect.setText("Untap it."); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + new ProtectionAbility(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES), + Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new UntapTargetEffect("untap it")); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); - } private Crypsis(final Crypsis card) { diff --git a/Mage.Sets/src/mage/cards/c/CryptAngel.java b/Mage.Sets/src/mage/cards/c/CryptAngel.java index b975fcec681..03c8c823a6a 100644 --- a/Mage.Sets/src/mage/cards/c/CryptAngel.java +++ b/Mage.Sets/src/mage/cards/c/CryptAngel.java @@ -1,12 +1,10 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.ProtectionAbility; import mage.cards.CardImpl; @@ -18,8 +16,9 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author LoneFox */ public final class CryptAngel extends CardImpl { @@ -27,21 +26,26 @@ public final class CryptAngel extends CardImpl { private static final FilterCreatureCard filter2 = new FilterCreatureCard("blue or red creature card from your graveyard"); static { - filter2.add(Predicates.or(new ColorPredicate(ObjectColor.RED), new ColorPredicate(ObjectColor.BLUE))); + filter2.add(Predicates.or( + new ColorPredicate(ObjectColor.RED), + new ColorPredicate(ObjectColor.BLUE) + )); } public CryptAngel(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.ANGEL); this.power = new MageInt(3); this.toughness = new MageInt(3); // Flying this.addAbility(FlyingAbility.getInstance()); + // protection from white this.addAbility(ProtectionAbility.from(ObjectColor.WHITE)); + // When Crypt Angel enters the battlefield, return target blue or red creature card from your graveyard to your hand. - Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), false); ability.addTarget(new TargetCardInYourGraveyard(filter2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CryptChampion.java b/Mage.Sets/src/mage/cards/c/CryptChampion.java index fbf59417c09..1b30f26a4c2 100644 --- a/Mage.Sets/src/mage/cards/c/CryptChampion.java +++ b/Mage.Sets/src/mage/cards/c/CryptChampion.java @@ -89,7 +89,7 @@ class CryptChampionEffect extends OneShotEffect { filter.add(new OwnerIdPredicate(playerId)); filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); Target target = new TargetCardInGraveyard(filter); - if (target.canChoose(source.getSourceId(), playerId, game) + if (target.canChoose(playerId, source, game) && player.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/c/CryptLurker.java b/Mage.Sets/src/mage/cards/c/CryptLurker.java index 153d25dbef3..903b417678a 100644 --- a/Mage.Sets/src/mage/cards/c/CryptLurker.java +++ b/Mage.Sets/src/mage/cards/c/CryptLurker.java @@ -33,10 +33,9 @@ public final class CryptLurker extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new DoIfCostPaid( new DrawCardSourceControllerEffect(1), new OrCost( - new SacrificeTargetCost(new TargetControlledPermanent( + "sacrifice a creature or discard a creature card", new SacrificeTargetCost(new TargetControlledPermanent( StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT - )), new DiscardTargetCost(new TargetCardInHand(StaticFilters.FILTER_CARD_CREATURE_A)), - "sacrifice a creature or discard a creature card" + )), new DiscardTargetCost(new TargetCardInHand(StaticFilters.FILTER_CARD_CREATURE_A)) ) ))); } diff --git a/Mage.Sets/src/mage/cards/c/CryptSliver.java b/Mage.Sets/src/mage/cards/c/CryptSliver.java index 2fc6d710326..f7f025a6906 100644 --- a/Mage.Sets/src/mage/cards/c/CryptSliver.java +++ b/Mage.Sets/src/mage/cards/c/CryptSliver.java @@ -1,4 +1,3 @@ - package mage.cards.c; import java.util.UUID; @@ -15,8 +14,10 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** @@ -25,6 +26,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class CryptSliver extends CardImpl { + private static final FilterPermanent filter=new FilterPermanent(SubType.SLIVER,"Sliver"); public CryptSliver(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); this.subtype.add(SubType.SLIVER); @@ -33,9 +35,11 @@ public final class CryptSliver extends CardImpl { this.toughness = new MageInt(1); // All Slivers have "{tap}: Regenerate target Sliver." - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent(SubType.SLIVER, "Sliver"))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS))); + Ability ability = new SimpleActivatedAbility( new RegenerateTargetEffect(), new TapSourceCost()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(new SimpleStaticAbility( new GainAbilityAllEffect( + ability, Duration.WhileOnBattlefield, filter + ).setText("all Slivers have \"{T}: Regenerate target Sliver.\""))); } private CryptSliver(final CryptSliver card) { diff --git a/Mage.Sets/src/mage/cards/c/CrypticCommand.java b/Mage.Sets/src/mage/cards/c/CrypticCommand.java index ba26fac0186..c5f614dd13a 100644 --- a/Mage.Sets/src/mage/cards/c/CrypticCommand.java +++ b/Mage.Sets/src/mage/cards/c/CrypticCommand.java @@ -1,21 +1,15 @@ package mage.cards.c; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.Mode; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CounterTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.TapAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.TargetPermanent; import mage.target.TargetSpell; @@ -31,27 +25,22 @@ public final class CrypticCommand extends CardImpl { // Choose two - this.getSpellAbility().getModes().setMinModes(2); this.getSpellAbility().getModes().setMaxModes(2); + // Counter target spell; - Effect effect1 = new CounterTargetEffect(); - effect1.setText("Counter target spell."); - this.getSpellAbility().addEffect(effect1); + this.getSpellAbility().addEffect(new CounterTargetEffect()); this.getSpellAbility().addTarget(new TargetSpell()); + // or return target permanent to its owner's hand; - Mode mode = new Mode(); - Effect effect2 = new ReturnToHandTargetEffect(); - effect2.setText("Return target permanent to its owner's hand."); - mode.addEffect(effect2); + Mode mode = new Mode(new ReturnToHandTargetEffect()); mode.addTarget(new TargetPermanent()); this.getSpellAbility().getModes().addMode(mode); + // or tap all creatures your opponents control; - mode = new Mode(); - mode.addEffect(new CrypticCommandEffect()); + mode = new Mode(new TapAllEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES)); this.getSpellAbility().getModes().addMode(mode); + // or draw a card. - mode = new Mode(); - Effect effect3 = new DrawCardSourceControllerEffect(1); - mode.addEffect(effect3); - effect3.setText("Draw a card."); + mode = new Mode(new DrawCardSourceControllerEffect(1)); this.getSpellAbility().getModes().addMode(mode); } @@ -64,32 +53,3 @@ public final class CrypticCommand extends CardImpl { return new CrypticCommand(this); } } - -class CrypticCommandEffect extends OneShotEffect { - - public CrypticCommandEffect() { - super(Outcome.Tap); - staticText = "Tap all creatures your opponents control"; - } - - public CrypticCommandEffect(final CrypticCommandEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, player.getId(), source.getSourceId(), game)) { - creature.tap(source, game); - } - return true; - } - - @Override - public CrypticCommandEffect copy() { - return new CrypticCommandEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/c/CrypticGateway.java b/Mage.Sets/src/mage/cards/c/CrypticGateway.java index 28396688e11..68db417fc4e 100644 --- a/Mage.Sets/src/mage/cards/c/CrypticGateway.java +++ b/Mage.Sets/src/mage/cards/c/CrypticGateway.java @@ -1,31 +1,29 @@ package mage.cards.c; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.Cost; -import mage.abilities.costs.CostImpl; +import mage.abilities.costs.common.TapTargetCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.filter.FilterCard; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.Predicate; -import mage.filter.predicate.permanent.TappedPredicate; +import mage.filter.predicate.mageobject.SharesCreatureTypePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledPermanent; +import mage.util.CardUtil; -import java.util.HashSet; -import java.util.Set; +import java.util.List; +import java.util.stream.Collectors; import java.util.UUID; /** - * @author spjspj + * @author awjackson */ public final class CrypticGateway extends CardImpl { @@ -33,7 +31,9 @@ public final class CrypticGateway extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); // Tap two untapped creatures you control: You may put a creature card from your hand that shares a creature type with each creature tapped this way onto the battlefield. - this.addAbility(new SimpleActivatedAbility(new CrypticGatewayEffect(), new CrypticGatewayCost())); + this.addAbility(new SimpleActivatedAbility(new CrypticGatewayEffect(), new TapTargetCost( + new TargetControlledPermanent(2, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES) + ))); } private CrypticGateway(final CrypticGateway card) { @@ -46,70 +46,11 @@ public final class CrypticGateway extends CardImpl { } } -class CrypticGatewayCost extends CostImpl { - - private static final FilterControlledCreaturePermanent filter - = new FilterControlledCreaturePermanent("untapped creatures you control"); - - static { - filter.add(TappedPredicate.UNTAPPED); - } - - private final TargetControlledPermanent target = new TargetControlledPermanent(2, filter); - private CrypticGatewayPredicate predicate; - - public CrypticGatewayCost() { - this.text = "Tap two untapped creatures you control"; - } - - public CrypticGatewayCost(final CrypticGatewayCost cost) { - super(cost); - } - - @Override - public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - int numTargets = 0; - Set permanents = new HashSet<>(); - while (numTargets < 2 && target.choose(Outcome.Tap, controllerId, source.getSourceId(), game)) { - for (UUID targetId : target.getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent == null) { - return false; - } - paid |= permanent.tap(source, game); - if (paid) { - numTargets++; - target.clearChosen(); - permanents.add(permanent); - } - } - } - if (paid) { - this.predicate = new CrypticGatewayPredicate(permanents); - } - return paid; - } - - @Override - public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return target.canChoose(source.getSourceId(), controllerId, game); - } - - public CrypticGatewayPredicate getPredicate() { - return predicate; - } - - @Override - public CrypticGatewayCost copy() { - return new CrypticGatewayCost(this); - } -} - class CrypticGatewayEffect extends OneShotEffect { public CrypticGatewayEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "Put a creature card from your hand that shares a creature type with each creature tapped this way onto the battlefield"; + this.staticText = "you may put a creature card from your hand that shares a creature type with each creature tapped this way onto the battlefield"; } public CrypticGatewayEffect(final CrypticGatewayEffect effect) { @@ -123,36 +64,16 @@ class CrypticGatewayEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - if (source.getCosts() == null) { + List tapped = (List) getValue("tappedPermanents"); + if (tapped == null || tapped.isEmpty()) { return false; } - FilterCard filter = new FilterCreatureCard("creature card from your hand that shares a creature type with each creature tapped this way"); - for (Cost cost : source.getCosts()) { - if (cost instanceof CrypticGatewayCost) { - Predicate predicate = ((CrypticGatewayCost) cost).getPredicate(); - filter.add(predicate); - return new PutCardFromHandOntoBattlefieldEffect(filter).apply(game, source); - } + FilterCreatureCard filter = new FilterCreatureCard("creature card that shares a creature type with " + + CardUtil.concatWithAnd(tapped.stream().map(MageObject::getName).collect(Collectors.toList())) + ); + for (Permanent perm : tapped) { + filter.add(new SharesCreatureTypePredicate(perm)); } - return false; - } -} - -class CrypticGatewayPredicate implements Predicate { - - private final Set permanents = new HashSet<>(); - - CrypticGatewayPredicate(Set permanents) { - this.permanents.addAll(permanents); - } - - @Override - public boolean apply(Card input, Game game) { - for (Permanent permanent : permanents) { - if (!permanent.shareCreatureTypes(game, input)) { - return false; - } - } - return true; + return new PutCardFromHandOntoBattlefieldEffect(filter).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/c/CrystalChimes.java b/Mage.Sets/src/mage/cards/c/CrystalChimes.java index 4e55d14de5d..9e7fc9141fd 100644 --- a/Mage.Sets/src/mage/cards/c/CrystalChimes.java +++ b/Mage.Sets/src/mage/cards/c/CrystalChimes.java @@ -63,8 +63,8 @@ class CrystalChimesEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - return controller.moveCards(controller.getGraveyard().getCards(new FilterEnchantmentCard(), source.getSourceId(), - source.getControllerId(), game), Zone.HAND, source, game); + return controller.moveCards(controller.getGraveyard().getCards(new FilterEnchantmentCard(), + source.getControllerId(), source, game), Zone.HAND, source, game); } return false; } diff --git a/Mage.Sets/src/mage/cards/c/CrystalShard.java b/Mage.Sets/src/mage/cards/c/CrystalShard.java index a0a09fec637..ab32c2aa66d 100644 --- a/Mage.Sets/src/mage/cards/c/CrystalShard.java +++ b/Mage.Sets/src/mage/cards/c/CrystalShard.java @@ -34,9 +34,8 @@ public final class CrystalShard extends CardImpl { Ability ability = new SimpleActivatedAbility( new CrystalShardEffect(), new OrCost( - new CompositeCost(new GenericManaCost(3), new TapSourceCost(), "{3}, {T}"), - new CompositeCost(new ManaCostsImpl<>("{U}"), new TapSourceCost(), "{U}, {T}"), - "{3}, {T} or {U}, {T}" + "{3}, {T} or {U}, {T}", new CompositeCost(new GenericManaCost(3), new TapSourceCost(), "{3}, {T}"), + new CompositeCost(new ManaCostsImpl<>("{U}"), new TapSourceCost(), "{U}, {T}") ) ); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/c/CullingRitual.java b/Mage.Sets/src/mage/cards/c/CullingRitual.java index 4d1f414ecfb..d6bf290d208 100644 --- a/Mage.Sets/src/mage/cards/c/CullingRitual.java +++ b/Mage.Sets/src/mage/cards/c/CullingRitual.java @@ -71,7 +71,7 @@ class CullingRitualEffect extends OneShotEffect { } int counter = 0; for (Permanent permanent : game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game )) { counter += permanent.destroy(source, game, false) ? 1 : 0; } diff --git a/Mage.Sets/src/mage/cards/c/CullingScales.java b/Mage.Sets/src/mage/cards/c/CullingScales.java index 9bddf1d536c..eb804a02a8b 100644 --- a/Mage.Sets/src/mage/cards/c/CullingScales.java +++ b/Mage.Sets/src/mage/cards/c/CullingScales.java @@ -58,7 +58,7 @@ class HasLowestCMCAmongstNonlandPermanentsPredicate implements ObjectSourcePlaye public boolean apply(ObjectSourcePlayer input, Game game) { FilterPermanent filter = new FilterNonlandPermanent(); filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, input.getObject().getManaValue())); - return !game.getBattlefield().contains(filter, input.getSourceId(), input.getPlayerId(), game, 1); + return !game.getBattlefield().contains(filter, input.getSourceId(), input.getPlayerId(), input.getSource(), game, 1); } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CultOfTheWaxingMoon.java b/Mage.Sets/src/mage/cards/c/CultOfTheWaxingMoon.java index dad7df6f206..aac52d5533b 100644 --- a/Mage.Sets/src/mage/cards/c/CultOfTheWaxingMoon.java +++ b/Mage.Sets/src/mage/cards/c/CultOfTheWaxingMoon.java @@ -73,7 +73,7 @@ class CultOfTheWaxingMoonAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanent(event.getTargetId()); - return filter.match(permanent, getSourceId(), getControllerId(), game); + return filter.match(permanent, getControllerId(), this, game); } @Override diff --git a/Mage.Sets/src/mage/cards/c/Cultivate.java b/Mage.Sets/src/mage/cards/c/Cultivate.java index 579ebda3c3d..48fe88af542 100644 --- a/Mage.Sets/src/mage/cards/c/Cultivate.java +++ b/Mage.Sets/src/mage/cards/c/Cultivate.java @@ -63,7 +63,7 @@ class CultivateEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/c/CultivatorColossus.java b/Mage.Sets/src/mage/cards/c/CultivatorColossus.java index 1e30399f6eb..8689cf4afc9 100644 --- a/Mage.Sets/src/mage/cards/c/CultivatorColossus.java +++ b/Mage.Sets/src/mage/cards/c/CultivatorColossus.java @@ -82,7 +82,7 @@ class CultivatorColossusEffect extends OneShotEffect { TargetCard target = new TargetCardInHand( 0, 1, StaticFilters.FILTER_CARD_LAND ); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card == null) { break; diff --git a/Mage.Sets/src/mage/cards/c/CultivatorDrone.java b/Mage.Sets/src/mage/cards/c/CultivatorDrone.java index 8341e351bc8..9ad8d2038f5 100644 --- a/Mage.Sets/src/mage/cards/c/CultivatorDrone.java +++ b/Mage.Sets/src/mage/cards/c/CultivatorDrone.java @@ -80,7 +80,7 @@ class CultivatorDroneManaCondition extends ManaCondition implements Condition { @Override public boolean apply(Game game, Ability source, UUID originalId, Cost costToPay) { if (source instanceof SpellAbility) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object != null && object.getColor(game).isColorless()) { return true; } diff --git a/Mage.Sets/src/mage/cards/c/CulturalExchange.java b/Mage.Sets/src/mage/cards/c/CulturalExchange.java index 740d5c8f4f8..630f77988f6 100644 --- a/Mage.Sets/src/mage/cards/c/CulturalExchange.java +++ b/Mage.Sets/src/mage/cards/c/CulturalExchange.java @@ -73,17 +73,17 @@ class CulturalExchangeEffect extends OneShotEffect { FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creatures " + player2.getLogName() + " controls"); filter1.add(new ControllerIdPredicate(player1.getId())); filter2.add(new ControllerIdPredicate(player2.getId())); - int creatureCount1 = game.getBattlefield().count(filter1, source.getSourceId(), source.getControllerId(), game); - int creatureCount2 = game.getBattlefield().count(filter2, source.getSourceId(), source.getControllerId(), game); + int creatureCount1 = game.getBattlefield().count(filter1, source.getControllerId(), source, game); + int creatureCount2 = game.getBattlefield().count(filter2, source.getControllerId(), source, game); int creaturesToSwitch = Math.min(creatureCount1, creatureCount2); if (creaturesToSwitch == 0) { return true; } TargetCreaturePermanent target1 = new TargetCreaturePermanent(0, creaturesToSwitch, filter1, true); - if (target1.choose(Outcome.Benefit, controller.getId(), source.getSourceId(), game)) { + if (target1.choose(Outcome.Benefit, controller.getId(), source.getSourceId(), source, game)) { int otherToSwitch = target1.getTargets().size(); TargetCreaturePermanent target2 = new TargetCreaturePermanent(otherToSwitch, otherToSwitch, filter2, true); - if (target2.choose(Outcome.Benefit, controller.getId(), source.getSourceId(), game)) { + if (target2.choose(Outcome.Benefit, controller.getId(), source.getSourceId(), source, game)) { for (UUID creatureId : target1.getTargets()) { Permanent creature = game.getPermanent(creatureId); if (creature != null) { diff --git a/Mage.Sets/src/mage/cards/c/CunningAbduction.java b/Mage.Sets/src/mage/cards/c/CunningAbduction.java index b3f5c7f8dae..8346b21c01a 100644 --- a/Mage.Sets/src/mage/cards/c/CunningAbduction.java +++ b/Mage.Sets/src/mage/cards/c/CunningAbduction.java @@ -66,7 +66,7 @@ class CunningAbductionExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player opponent = game.getPlayer(targetPointer.getFirst(game, source)); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (opponent != null && sourceObject != null) { opponent.revealCards(sourceObject.getName(), opponent.getHand(), game); Player controller = game.getPlayer(source.getControllerId()); diff --git a/Mage.Sets/src/mage/cards/c/Curate.java b/Mage.Sets/src/mage/cards/c/Curate.java index 0f171aa3bc0..cb246a89ec7 100644 --- a/Mage.Sets/src/mage/cards/c/Curate.java +++ b/Mage.Sets/src/mage/cards/c/Curate.java @@ -1,23 +1,16 @@ package mage.cards.c; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; import java.util.UUID; /** - * @author TheElk801 + * @author awjackson */ public final class Curate extends CardImpl { @@ -25,8 +18,10 @@ public final class Curate extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Look at the top two cards of your library. Put any number of them into your graveyard and the rest back on top of your library in any order. + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(2, Integer.MAX_VALUE, PutCards.GRAVEYARD, PutCards.TOP_ANY)); + // Draw a card. - this.getSpellAbility().addEffect(new CurateEffect()); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private Curate(final Curate card) { @@ -38,40 +33,3 @@ public final class Curate extends CardImpl { return new Curate(this); } } - -class CurateEffect extends OneShotEffect { - - CurateEffect() { - super(Outcome.Benefit); - staticText = "look at the top two cards of your library. Put any number of them into your graveyard " + - "and the rest back on top of your library in any order.
Draw a card"; - } - - private CurateEffect(final CurateEffect effect) { - super(effect); - } - - @Override - public CurateEffect copy() { - return new CurateEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 2)); - if (!cards.isEmpty()) { - TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, StaticFilters.FILTER_CARD); - target.withChooseHint("to graveyard"); - player.chooseTarget(Outcome.Benefit, cards, target, source, game); - player.moveCards(new CardsImpl(target.getTargets()), Zone.GRAVEYARD, source, game); - cards.removeAll(target.getTargets()); - player.putCardsOnTopOfLibrary(cards, game, source, true); - } - player.drawCards(1, source, game); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/c/Curfew.java b/Mage.Sets/src/mage/cards/c/Curfew.java index 09962322f25..dfa61d4627a 100644 --- a/Mage.Sets/src/mage/cards/c/Curfew.java +++ b/Mage.Sets/src/mage/cards/c/Curfew.java @@ -3,7 +3,6 @@ package mage.cards.c; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -57,7 +56,7 @@ class CurfewEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null && game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game) > 0) { TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(1, 1, StaticFilters.FILTER_CONTROLLED_CREATURE, true); - player.choose(Outcome.ReturnToHand, target, source.getSourceId(), game); + player.choose(Outcome.ReturnToHand, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { player.moveCards(permanent, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/c/CurrencyConverter.java b/Mage.Sets/src/mage/cards/c/CurrencyConverter.java new file mode 100644 index 00000000000..1f68fc71078 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CurrencyConverter.java @@ -0,0 +1,133 @@ +package mage.cards.c; + +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.OneShotEffect; +import mage.abilities.effects.common.DiscardCardControllerTriggeredAbility; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +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.game.ExileZone; +import mage.game.Game; +import mage.game.permanent.token.RogueToken; +import mage.game.permanent.token.Token; +import mage.game.permanent.token.TreasureToken; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInExile; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CurrencyConverter extends CardImpl { + + public CurrencyConverter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + + // Whenever you discard a card, you may exile that card from your graveyard. + this.addAbility(new DiscardCardControllerTriggeredAbility(new CurrencyConverterExileEffect(), true)); + + // {2}, {T}: Draw a card, then discard a card. + Ability ability = new SimpleActivatedAbility( + new DrawDiscardControllerEffect(1, 1), new GenericManaCost(2) + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + + // {T}: Put a card exiled with Currency Converter into your graveyard. If it's a land card, create a Treasure token. If it's a nonland card, create a 2/2 black Rogue creature token. + this.addAbility(new SimpleActivatedAbility(new CurrencyConverterTokenEffect(), new TapSourceCost())); + } + + private CurrencyConverter(final CurrencyConverter card) { + super(card); + } + + @Override + public CurrencyConverter copy() { + return new CurrencyConverter(this); + } +} + +class CurrencyConverterExileEffect extends OneShotEffect { + + CurrencyConverterExileEffect() { + super(Outcome.Benefit); + staticText = "exile that card from your graveyard"; + } + + private CurrencyConverterExileEffect(final CurrencyConverterExileEffect effect) { + super(effect); + } + + @Override + public CurrencyConverterExileEffect copy() { + return new CurrencyConverterExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = (Card) getValue("discardedCard"); + if (player == null || card == null || !card.isOwnedBy(player.getId()) + || !Zone.GRAVEYARD.match(game.getState().getZone(card.getId()))) { + return false; + } + return player.moveCardsToExile( + card, source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + } +} + +class CurrencyConverterTokenEffect extends OneShotEffect { + + CurrencyConverterTokenEffect() { + super(Outcome.Benefit); + staticText = "put a card exiled with {this} into your graveyard. If it's a land card, " + + "create a Treasure token. If it's a nonland card, create a 2/2 black Rogue creature token"; + } + + private CurrencyConverterTokenEffect(final CurrencyConverterTokenEffect effect) { + super(effect); + } + + @Override + public CurrencyConverterTokenEffect copy() { + return new CurrencyConverterTokenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + ExileZone exileZone = game.getState().getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + if (player == null || exileZone == null || exileZone.isEmpty()) { + return false; + } + Card card; + if (exileZone.size() > 1) { + TargetCard target = new TargetCardInExile(StaticFilters.FILTER_CARD); + player.choose(outcome, exileZone, target, game); + card = exileZone.get(target.getFirstTarget(), game); + } else { + card = exileZone.getRandom(game); + } + if (card == null) { + return false; + } + player.moveCards(card, Zone.GRAVEYARD, source, game); + Token token = card.isLand(game) ? new TreasureToken() : new RogueToken(); + token.putOntoBattlefield(1, game, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CurseOfChains.java b/Mage.Sets/src/mage/cards/c/CurseOfChains.java index 0032d820260..e195ae14a83 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfChains.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfChains.java @@ -35,7 +35,7 @@ public final class CurseOfChains extends CardImpl { this.addAbility(ability); // At the beginning of each upkeep, tap enchanted creature. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TapEnchantedEffect(), TargetController.ANY, false)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new TapEnchantedEffect(), TargetController.EACH_PLAYER, false)); } private CurseOfChains(final CurseOfChains card) { diff --git a/Mage.Sets/src/mage/cards/c/CurseOfConformity.java b/Mage.Sets/src/mage/cards/c/CurseOfConformity.java index 41d8c9d9d19..08121eda261 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfConformity.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfConformity.java @@ -75,7 +75,7 @@ class CurseOfConformityEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { for (Permanent permanent : game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game )) { switch (layer) { case TypeChangingEffects_4: diff --git a/Mage.Sets/src/mage/cards/c/CurseOfFoolsWisdom.java b/Mage.Sets/src/mage/cards/c/CurseOfFoolsWisdom.java index 698752839ea..ebc0e55e591 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfFoolsWisdom.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfFoolsWisdom.java @@ -45,7 +45,7 @@ public final class CurseOfFoolsWisdom extends CardImpl { this.addAbility(new CurseOfFoolsWisdomTriggeredAbility()); // Madness {3}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{3}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{3}{B}"))); } private CurseOfFoolsWisdom(final CurseOfFoolsWisdom card) { diff --git a/Mage.Sets/src/mage/cards/c/CurseOfHospitality.java b/Mage.Sets/src/mage/cards/c/CurseOfHospitality.java index 28264cd8bdd..d24421778ba 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfHospitality.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfHospitality.java @@ -75,7 +75,7 @@ enum CurseOfHospitalityPredicate implements ObjectSourcePlayerPredicate input, Game game) { - Permanent permanent = game.getPermanent(input.getSourceId()); + Permanent permanent = input.getSource().getSourcePermanentIfItStillExists(game); UUID defenderId = game.getCombat().getDefenderId(input.getObject().getId()); return permanent != null && defenderId != null && defenderId.equals(permanent.getAttachedTo()); } diff --git a/Mage.Sets/src/mage/cards/c/CurseOfLeeches.java b/Mage.Sets/src/mage/cards/c/CurseOfLeeches.java index 8758a9d82b7..7f57e1ac4fd 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfLeeches.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfLeeches.java @@ -83,7 +83,7 @@ class CurseOfLeechesEffect extends ReplacementEffectImpl { } TargetPlayer target = new TargetPlayer(); target.withChooseHint("Player to attach to").setNotTarget(true); - controller.choose(Outcome.Detriment, target, source.getSourceId(), game); + controller.choose(Outcome.Detriment, target, source, game); Permanent permanent = source.getSourcePermanentIfItStillExists(game); if (permanent == null) { return false; diff --git a/Mage.Sets/src/mage/cards/c/CurseOfTheCabal.java b/Mage.Sets/src/mage/cards/c/CurseOfTheCabal.java index b5c96b950ca..2f12b0b3d5e 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfTheCabal.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfTheCabal.java @@ -85,10 +85,10 @@ class CurseOfTheCabalSacrificeEffect extends OneShotEffect { return true; } Target target = new TargetControlledPermanent(amount, amount, StaticFilters.FILTER_CONTROLLED_PERMANENT, true); - if (target.canChoose(source.getSourceId(), targetPlayer.getId(), game)) { + if (target.canChoose(targetPlayer.getId(), source, game)) { while (!target.isChosen() - && target.canChoose(source.getSourceId(), targetPlayer.getId(), game) && targetPlayer.canRespond()) { - targetPlayer.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + && target.canChoose(targetPlayer.getId(), source, game) && targetPlayer.canRespond()) { + targetPlayer.choose(Outcome.Sacrifice, target, source, game); } //sacrifice all chosen (non null) permanents target.getTargets().stream() @@ -111,7 +111,7 @@ class CurseOfTheCabalInterveningIfTriggeredAbility extends ConditionalIntervenin ), SuspendedCondition.instance, "At the beginning of each player's upkeep, if {this} is suspended, " - + "that player may sacrifice a permanent. If they do, " + + "that player may sacrifice a permanent. If the player does, " + "put two time counters on {this}." ); // controller has to sac a permanent diff --git a/Mage.Sets/src/mage/cards/c/CurseOfThePiercedHeart.java b/Mage.Sets/src/mage/cards/c/CurseOfThePiercedHeart.java index 1841f5cac30..d59cbc44296 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfThePiercedHeart.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfThePiercedHeart.java @@ -78,7 +78,7 @@ class CurseOfThePiercedHeartEffect extends OneShotEffect { if (controller == null || opponent == null) { return false; } - if (game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_PERMANENT_PLANESWALKER, source.getSourceId(), opponent.getId(), game) < 1 + if (game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_PERMANENT_PLANESWALKER, opponent.getId(), source, game) < 1 || !controller.chooseUse(Outcome.Damage, "Redirect to a planeswalker controlled by " + opponent.getLogName() + "?", source, game)) { return opponent.damage(1, source.getSourceId(), source, game) > 0; } @@ -86,7 +86,7 @@ class CurseOfThePiercedHeartEffect extends OneShotEffect { filter.add(new ControllerIdPredicate(opponent.getId())); TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { return permanent.damage(1, source.getSourceId(), source, game, false, true) > 0; diff --git a/Mage.Sets/src/mage/cards/c/CurseboundWitch.java b/Mage.Sets/src/mage/cards/c/CurseboundWitch.java new file mode 100644 index 00000000000..f907e99b2f4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CurseboundWitch.java @@ -0,0 +1,59 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.effects.common.DraftFromSpellbookEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CurseboundWitch extends CardImpl { + + private static final List spellbook = Collections.unmodifiableList(Arrays.asList( + "Black Cat", + "Bloodhunter Bat", + "Cauldron Familiar", + "Cruel Reality", + "Curse of Leeches", + "Expanded Anatomy", + "Sorcerer's Broom", + "Torment of Scarabs", + "Trespasser's Curse", + "Unwilling Ingredient", + "Witch's Cauldron", + "Witch's Cottage", + "Witch's Familiar", + "Witch's Oven", + "Witch's Vengeance" + )); + + public CurseboundWitch(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARLOCK); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // When Cursebound Witch dies, draft a card from Cursebound Witch's spellbook. + this.addAbility(new DiesSourceTriggeredAbility(new DraftFromSpellbookEffect(spellbook))); + } + + private CurseboundWitch(final CurseboundWitch card) { + super(card); + } + + @Override + public CurseboundWitch copy() { + return new CurseboundWitch(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CursedScroll.java b/Mage.Sets/src/mage/cards/c/CursedScroll.java index 2c73f1c341d..07347ac7d4c 100644 --- a/Mage.Sets/src/mage/cards/c/CursedScroll.java +++ b/Mage.Sets/src/mage/cards/c/CursedScroll.java @@ -59,7 +59,7 @@ class CursedScrollEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); if (sourceObject != null && controller != null && cardName != null && !cardName.isEmpty()) { if (!controller.getHand().isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/c/CustodiSquire.java b/Mage.Sets/src/mage/cards/c/CustodiSquire.java index 6783d217b5f..7482f8be3d4 100644 --- a/Mage.Sets/src/mage/cards/c/CustodiSquire.java +++ b/Mage.Sets/src/mage/cards/c/CustodiSquire.java @@ -9,10 +9,7 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.choices.VoteHandler; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.game.Game; @@ -41,7 +38,7 @@ public final class CustodiSquire extends CardImpl { // Will of the council - When Custodi Squire enters the battlefield, starting with you, each player votes for an artifact, creature, or enchantment card in your graveyard. Return each card with the most votes or tied for most votes to your hand. this.addAbility(new EntersBattlefieldTriggeredAbility( new CustodiSquireVoteEffect(), false) - .withFlavorWord("Will of the council") + .setAbilityWord(AbilityWord.WILL_OF_THE_COUNCIL) ); } @@ -107,7 +104,7 @@ class CustodiSquireVote extends VoteHandler { public Card playerChoose(String voteInfo, Player player, Player decidingPlayer, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); if (controller == null || controller.getGraveyard().count( - filter, source.getSourceId(), source.getControllerId(), game + filter, source.getControllerId(), source, game ) < 1) { return null; } diff --git a/Mage.Sets/src/mage/cards/c/CutOfTheProfits.java b/Mage.Sets/src/mage/cards/c/CutOfTheProfits.java new file mode 100644 index 00000000000..7d8eba2b48d --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CutOfTheProfits.java @@ -0,0 +1,37 @@ +package mage.cards.c; + +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.keyword.CasualtyAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CutOfTheProfits extends CardImpl { + + public CutOfTheProfits(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{B}{B}"); + + // Casualty 3 + this.addAbility(new CasualtyAbility(this, 3)); + + // You draw X cards and you lose X life. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(ManacostVariableValue.REGULAR, "you")); + this.getSpellAbility().addEffect(new LoseLifeSourceControllerEffect(ManacostVariableValue.REGULAR).concatBy("and")); + } + + private CutOfTheProfits(final CutOfTheProfits card) { + super(card); + } + + @Override + public CutOfTheProfits copy() { + return new CutOfTheProfits(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CutTheTethers.java b/Mage.Sets/src/mage/cards/c/CutTheTethers.java index ff6c7f510c4..d63bf76705b 100644 --- a/Mage.Sets/src/mage/cards/c/CutTheTethers.java +++ b/Mage.Sets/src/mage/cards/c/CutTheTethers.java @@ -67,7 +67,7 @@ class CutTheTethersEffect extends OneShotEffect { } Cards toHand = new CardsImpl(); for (Permanent permanent : game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game )) { Player player = game.getPlayer(permanent.getOwnerId()); if (player == null) { diff --git a/Mage.Sets/src/mage/cards/c/CutYourLosses.java b/Mage.Sets/src/mage/cards/c/CutYourLosses.java new file mode 100644 index 00000000000..544366fd4e1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CutYourLosses.java @@ -0,0 +1,36 @@ +package mage.cards.c; + +import mage.abilities.effects.common.MillHalfLibraryTargetEffect; +import mage.abilities.keyword.CasualtyAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.TargetPlayer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CutYourLosses extends CardImpl { + + public CutYourLosses(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{U}{U}"); + + // Casualty 2 + this.addAbility(new CasualtyAbility(this, 2)); + + // Target player mills half their library, rounded down. + this.getSpellAbility().addEffect(new MillHalfLibraryTargetEffect(false)); + this.getSpellAbility().addTarget(new TargetPlayer()); + } + + private CutYourLosses(final CutYourLosses card) { + super(card); + } + + @Override + public CutYourLosses copy() { + return new CutYourLosses(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CutthroatContender.java b/Mage.Sets/src/mage/cards/c/CutthroatContender.java new file mode 100644 index 00000000000..79c346ec763 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CutthroatContender.java @@ -0,0 +1,45 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CutthroatContender extends CardImpl { + + public CutthroatContender(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Pay 1 life: Cutthroat Contender gets +1/+0 until end of turn. Activate only once each turn. + this.addAbility(new LimitedTimesPerTurnActivatedAbility( + Zone.BATTLEFIELD, + new BoostSourceEffect(1, 0, Duration.EndOfTurn), + new PayLifeCost(1) + )); + } + + private CutthroatContender(final CutthroatContender card) { + super(card); + } + + @Override + public CutthroatContender copy() { + return new CutthroatContender(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CyberdriveAwakener.java b/Mage.Sets/src/mage/cards/c/CyberdriveAwakener.java new file mode 100644 index 00000000000..4418ffff38d --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CyberdriveAwakener.java @@ -0,0 +1,131 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class CyberdriveAwakener extends CardImpl { + + public CyberdriveAwakener(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{5}{U}"); + + this.subtype.add(SubType.CONSTRUCT); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Other artifact creatures you control have flying. + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + FlyingAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENTS_ARTIFACT_CREATURE, true + ))); + + // When Cyberdrive Awakener enters the battlefield, until end of turn, each noncreature artifact you control becomes an artifact creature with base power and toughness 4/4. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CyberdriveAwakenerEffect())); + } + + private CyberdriveAwakener(final CyberdriveAwakener card) { + super(card); + } + + @Override + public CyberdriveAwakener copy() { + return new CyberdriveAwakener(this); + } +} + +class CyberdriveAwakenerEffect extends ContinuousEffectImpl { + + private static final FilterPermanent filter = new FilterControlledArtifactPermanent(); + + static { + filter.add(Predicates.not(CardType.CREATURE.getPredicate())); + } + + CyberdriveAwakenerEffect() { + super(Duration.EndOfTurn, Outcome.BecomeCreature); + staticText = "until end of turn, each noncreature artifact you control " + + "becomes an artifact creature with base power and toughness 4/4"; + } + + private CyberdriveAwakenerEffect(final CyberdriveAwakenerEffect effect) { + super(effect); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + game.getBattlefield() + .getActivePermanents(filter, source.getControllerId(), source, game) + .stream() + .filter(Objects::nonNull) + .map(permanent -> new MageObjectReference(permanent, game)) + .forEach(affectedObjectList::add); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + List permanents = affectedObjectList + .stream() + .map(mor -> mor.getPermanent(game)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (permanents.isEmpty()) { + discard(); + return false; + } + for (Permanent permanent : permanents) { + switch (layer) { + case TypeChangingEffects_4: + permanent.addCardType(game, CardType.ARTIFACT, CardType.CREATURE); + break; + case PTChangingEffects_7: + if (sublayer == SubLayer.SetPT_7b) { + permanent.getPower().setValue(4); + permanent.getToughness().setValue(4); + } + } + } + return true; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.TypeChangingEffects_4 + || layer == Layer.PTChangingEffects_7; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public CyberdriveAwakenerEffect copy() { + return new CyberdriveAwakenerEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CyclicalEvolution.java b/Mage.Sets/src/mage/cards/c/CyclicalEvolution.java index b6d3c453d1e..daf7599d142 100644 --- a/Mage.Sets/src/mage/cards/c/CyclicalEvolution.java +++ b/Mage.Sets/src/mage/cards/c/CyclicalEvolution.java @@ -30,7 +30,7 @@ public final class CyclicalEvolution extends CardImpl { getSpellAbility().addTarget(new TargetCreaturePermanent()); getSpellAbility().addEffect(new ExileSpellEffect()); Effect effect = new AddCountersSourceEffect(CounterType.TIME.createInstance(), StaticValue.get(3), true, true); - effect.setText("with 3 time counters on it"); + effect.setText("with three time counters on it"); getSpellAbility().addEffect(effect); // Suspend 3-{2}{G} diff --git a/Mage.Sets/src/mage/cards/c/CyclopsGladiator.java b/Mage.Sets/src/mage/cards/c/CyclopsGladiator.java index 88cdd41de4f..85d7b3a4ab0 100644 --- a/Mage.Sets/src/mage/cards/c/CyclopsGladiator.java +++ b/Mage.Sets/src/mage/cards/c/CyclopsGladiator.java @@ -69,7 +69,7 @@ class CyclopsGladiatorEffect extends OneShotEffect { filter.add(new ControllerIdPredicate(defenderId)); TargetCreaturePermanent target = new TargetCreaturePermanent(filter); Player player = game.getPlayer(source.getControllerId()); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (target.canChoose(source.getControllerId(), source, game)) { if (player != null && player.chooseTarget(Outcome.Detriment, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); Permanent cyclops = game.getPermanent(source.getSourceId()); diff --git a/Mage.Sets/src/mage/cards/c/CylianSunsinger.java b/Mage.Sets/src/mage/cards/c/CylianSunsinger.java index fce586b35ff..b540cca2d42 100644 --- a/Mage.Sets/src/mage/cards/c/CylianSunsinger.java +++ b/Mage.Sets/src/mage/cards/c/CylianSunsinger.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -9,26 +7,31 @@ import mage.abilities.effects.common.continuous.BoostAllEffect; 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.constants.SubType; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class CylianSunsinger extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Cylian Sunsinger and each other creature with the same name"); - + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("{this} and each other creature with the same name as it"); + static { - filter.add(new NamePredicate("Cylian Sunsinger")); + filter.add(CylianSunsingerPredicate.instance); } public CylianSunsinger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.SHAMAN); @@ -36,8 +39,9 @@ public final class CylianSunsinger extends CardImpl { this.toughness = new MageInt(2); // {R}{G}{W}: Cylian Sunsinger and each other creature with the same name as it get +3/+3 until end of turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostAllEffect(3, 3, Duration.EndOfTurn, filter, false), new ManaCostsImpl("{R}{G}{W}"))); - + this.addAbility(new SimpleActivatedAbility(new BoostAllEffect( + 3, 3, Duration.EndOfTurn, filter, false + ), new ManaCostsImpl<>("{R}{G}{W}"))); } private CylianSunsinger(final CylianSunsinger card) { @@ -49,3 +53,14 @@ public final class CylianSunsinger extends CardImpl { return new CylianSunsinger(this); } } + +enum CylianSunsingerPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return input.getObject().getId().equals(input.getSourceId()) || CardUtil.haveSameNames( + input.getObject(), game.getPermanentOrLKIBattlefield(input.getSourceId()) + ); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DAvenantHealer.java b/Mage.Sets/src/mage/cards/d/DAvenantHealer.java index 01193c4a882..9c9fa46236e 100644 --- a/Mage.Sets/src/mage/cards/d/DAvenantHealer.java +++ b/Mage.Sets/src/mage/cards/d/DAvenantHealer.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -11,14 +9,14 @@ import mage.abilities.effects.common.PreventDamageToTargetEffect; 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.constants.SubType; +import mage.target.common.TargetAnyTarget; import mage.target.common.TargetAttackingOrBlockingCreature; -import mage.target.common.TargetCreatureOrPlayer; + +import java.util.UUID; /** - * * @author LoneFox */ public final class DAvenantHealer extends CardImpl { @@ -32,12 +30,15 @@ public final class DAvenantHealer extends CardImpl { this.toughness = new MageInt(2); // {T}: D'Avenant Healer deals 1 damage to target attacking or blocking creature. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new TapSourceCost()); ability.addTarget(new TargetAttackingOrBlockingCreature()); this.addAbility(ability); + // {T}: Prevent the next 1 damage that would be dealt to any target this turn. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventDamageToTargetEffect(Duration.EndOfTurn, 1), new TapSourceCost()); - ability.addTarget(new TargetCreatureOrPlayer()); + ability = new SimpleActivatedAbility( + new PreventDamageToTargetEffect(Duration.EndOfTurn, 1), new TapSourceCost() + ); + ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DackFayden.java b/Mage.Sets/src/mage/cards/d/DackFayden.java index 6262699e044..bec6d58041f 100644 --- a/Mage.Sets/src/mage/cards/d/DackFayden.java +++ b/Mage.Sets/src/mage/cards/d/DackFayden.java @@ -3,7 +3,6 @@ package mage.cards.d; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardTargetEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -27,7 +26,7 @@ public final class DackFayden extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.DACK); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Target player draws two cards, then discards two cards. LoyaltyAbility ability = new LoyaltyAbility(new DrawCardTargetEffect(2), 1); diff --git a/Mage.Sets/src/mage/cards/d/DaghatarTheAdamant.java b/Mage.Sets/src/mage/cards/d/DaghatarTheAdamant.java index 28b49ec0c78..88312e02a36 100644 --- a/Mage.Sets/src/mage/cards/d/DaghatarTheAdamant.java +++ b/Mage.Sets/src/mage/cards/d/DaghatarTheAdamant.java @@ -83,7 +83,7 @@ class MoveCounterFromTargetToTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && controller != null) { Permanent fromPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (fromPermanent != null && fromPermanent.getCounters(game).getCount(CounterType.P1P1) > 0) { diff --git a/Mage.Sets/src/mage/cards/d/DakkonShadowSlayer.java b/Mage.Sets/src/mage/cards/d/DakkonShadowSlayer.java index 16e694976c5..0d398ef26c5 100644 --- a/Mage.Sets/src/mage/cards/d/DakkonShadowSlayer.java +++ b/Mage.Sets/src/mage/cards/d/DakkonShadowSlayer.java @@ -3,7 +3,6 @@ package mage.cards.d; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.LandsYouControlCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetEffect; @@ -35,7 +34,7 @@ public final class DakkonShadowSlayer extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.DAKKON); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(0)); + this.setStartingLoyalty(0); // Dakkon, Shadow Slayer enters the battlefield with a number of loyalty counters on him equal to the number of lands you control. this.addAbility(new EntersBattlefieldAbility( diff --git a/Mage.Sets/src/mage/cards/d/DalakosCrafterOfWonders.java b/Mage.Sets/src/mage/cards/d/DalakosCrafterOfWonders.java index 0e7fc4685c1..e925f4042c8 100644 --- a/Mage.Sets/src/mage/cards/d/DalakosCrafterOfWonders.java +++ b/Mage.Sets/src/mage/cards/d/DalakosCrafterOfWonders.java @@ -97,7 +97,7 @@ enum DalakosCrafterOfWondersCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && object.isArtifact(game); } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/d/Damn.java b/Mage.Sets/src/mage/cards/d/Damn.java index 6e43afc5fb8..896049062cb 100644 --- a/Mage.Sets/src/mage/cards/d/Damn.java +++ b/Mage.Sets/src/mage/cards/d/Damn.java @@ -31,7 +31,7 @@ public final class Damn extends CardImpl { this.addAbility(new OverloadAbility( this, new DestroyAllEffect(FILTER_PERMANENT_CREATURES, true), - new ManaCostsImpl<>("{2}{W}{W") + new ManaCostsImpl<>("{2}{W}{W}") )); } diff --git a/Mage.Sets/src/mage/cards/d/DamningVerdict.java b/Mage.Sets/src/mage/cards/d/DamningVerdict.java new file mode 100644 index 00000000000..c379f733dfb --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DamningVerdict.java @@ -0,0 +1,41 @@ +package mage.cards.d; + +import mage.abilities.effects.common.DestroyAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.CounterAnyPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DamningVerdict extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creatures with no counters on them"); + + static { + filter.add(Predicates.not(CounterAnyPredicate.instance)); + } + + public DamningVerdict(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{W}{W}"); + + // Destroy all creatures with no counters on them. + this.getSpellAbility().addEffect(new DestroyAllEffect(filter)); + } + + private DamningVerdict(final DamningVerdict card) { + super(card); + } + + @Override + public DamningVerdict copy() { + return new DamningVerdict(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DampeningPulse.java b/Mage.Sets/src/mage/cards/d/DampeningPulse.java index 9e14405c9bf..341f7d61602 100644 --- a/Mage.Sets/src/mage/cards/d/DampeningPulse.java +++ b/Mage.Sets/src/mage/cards/d/DampeningPulse.java @@ -1,4 +1,3 @@ - package mage.cards.d; import java.util.UUID; @@ -8,9 +7,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; /** * @@ -18,18 +15,11 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class DampeningPulse extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public DampeningPulse(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{U}"); // Creatures your opponents control get -1/-0. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(-1, -0, Duration.WhileOnBattlefield, filter, false))); - + this.addAbility(new SimpleStaticAbility(new BoostAllEffect(-1, -0, Duration.WhileOnBattlefield, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, false))); } private DampeningPulse(final DampeningPulse card) { diff --git a/Mage.Sets/src/mage/cards/d/DanceOfTheDead.java b/Mage.Sets/src/mage/cards/d/DanceOfTheDead.java index 5891d52b4be..7b7e0567351 100644 --- a/Mage.Sets/src/mage/cards/d/DanceOfTheDead.java +++ b/Mage.Sets/src/mage/cards/d/DanceOfTheDead.java @@ -34,6 +34,7 @@ import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; /** * @@ -277,6 +278,6 @@ class DanceOfTheDeadDoIfCostPaidEffect extends DoIfCostPaid { @Override public String getText(Mode mode) { - return "that player may " + getCostText() + ". If they do, " + executingEffects.getText(mode); + return "that player may " + CardUtil.addCostVerb(cost.getText()) + ". If they do, " + executingEffects.getText(mode); } } diff --git a/Mage.Sets/src/mage/cards/d/DanseMacabre.java b/Mage.Sets/src/mage/cards/d/DanseMacabre.java index 1b767ccae65..04e3c7ffab6 100644 --- a/Mage.Sets/src/mage/cards/d/DanseMacabre.java +++ b/Mage.Sets/src/mage/cards/d/DanseMacabre.java @@ -87,13 +87,13 @@ class DanseMacabreEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player == null || game.getBattlefield().count( - filter, source.getSourceId(), source.getControllerId(), game + filter, source.getControllerId(), source, game ) < 1) { continue; } TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + player.choose(Outcome.Sacrifice, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent == null) { continue; @@ -124,7 +124,7 @@ class DanseMacabreEffect extends OneShotEffect { return true; } target.setNotTarget(true); - controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game); + controller.choose(Outcome.PutCreatureInPlay, target, source, game); controller.moveCards(new CardsImpl(target.getTargets()), Zone.BATTLEFIELD, source, game); return true; } diff --git a/Mage.Sets/src/mage/cards/d/DapperShieldmate.java b/Mage.Sets/src/mage/cards/d/DapperShieldmate.java new file mode 100644 index 00000000000..259a8365775 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DapperShieldmate.java @@ -0,0 +1,54 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DapperShieldmate extends CardImpl { + + public DapperShieldmate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Dapper Shieldmate enters the battlefield with a shield counter on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.SHIELD.createInstance(1)), + "with a shield counter on it. (If it would be dealt damage " + + "or destroyed, remove a shield counter from it instead.)" + )); + + // As long as it's your turn, Dapper Shieldmate gets +2/+0. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(2, 0, Duration.WhileOnBattlefield), + MyTurnCondition.instance, "as long as it's your turn, {this} gets +2/+0" + ))); + } + + private DapperShieldmate(final DapperShieldmate card) { + super(card); + } + + @Override + public DapperShieldmate copy() { + return new DapperShieldmate(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DarettiIngeniousIconoclast.java b/Mage.Sets/src/mage/cards/d/DarettiIngeniousIconoclast.java index 21f49b83963..57677a18173 100644 --- a/Mage.Sets/src/mage/cards/d/DarettiIngeniousIconoclast.java +++ b/Mage.Sets/src/mage/cards/d/DarettiIngeniousIconoclast.java @@ -2,7 +2,6 @@ package mage.cards.d; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.effects.common.CreateTokenEffect; @@ -18,7 +17,7 @@ import mage.filter.StaticFilters; import mage.filter.predicate.Predicates; import mage.game.permanent.token.DarettiConstructToken; import mage.target.TargetPermanent; -import mage.target.common.TargetCardInGraveyardOrBattlefield; +import mage.target.common.TargetCardInGraveyardBattlefieldOrStack; import mage.target.common.TargetControlledPermanent; import java.util.UUID; @@ -43,7 +42,7 @@ public final class DarettiIngeniousIconoclast extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.DARETTI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Create a 1/1 colorless Construct artifact creature token with defender. this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new DarettiConstructToken()), 1)); @@ -66,7 +65,7 @@ public final class DarettiIngeniousIconoclast extends CardImpl { .setText("Choose target artifact card in a graveyard or artifact on the battlefield. " + "Create three tokens that are copies of it"), -6 ); - ability.addTarget(new TargetCardInGraveyardOrBattlefield(1, 1, + ability.addTarget(new TargetCardInGraveyardBattlefieldOrStack(1, 1, StaticFilters.FILTER_CARD_ARTIFACT, StaticFilters.FILTER_PERMANENT_ARTIFACT)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DarettiScrapSavant.java b/Mage.Sets/src/mage/cards/d/DarettiScrapSavant.java index 0a3f91aa63b..ccd5f04e61c 100644 --- a/Mage.Sets/src/mage/cards/d/DarettiScrapSavant.java +++ b/Mage.Sets/src/mage/cards/d/DarettiScrapSavant.java @@ -3,7 +3,6 @@ package mage.cards.d; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.discard.DiscardAndDrawThatManyEffect; @@ -11,7 +10,7 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledArtifactPermanent; import mage.game.Game; import mage.game.command.emblems.DarettiScrapSavantEmblem; @@ -33,14 +32,14 @@ public final class DarettiScrapSavant extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.DARETTI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +2: Discard up to two cards, then draw that many cards. this.addAbility(new LoyaltyAbility(new DiscardAndDrawThatManyEffect(2), 2)); // -2: Sacrifice an artifact. If you do, return target artifact card from your graveyard to the battlefield. LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new DarettiSacrificeEffect(), -2); - loyaltyAbility.addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + loyaltyAbility.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); this.addAbility(loyaltyAbility); // -10: You get an emblem with "Whenever an artifact is put into your graveyard from the battlefield, return that card to the battlefield at the beginning of the next end step." @@ -83,7 +82,7 @@ class DarettiSacrificeEffect extends OneShotEffect { return false; } Target target = new TargetControlledPermanent(1, 1, new FilterControlledArtifactPermanent(), true); - if (!target.canChoose(source.getSourceId(), controller.getId(), game) + if (!target.canChoose(controller.getId(), source, game) || !controller.chooseTarget(outcome, target, source, game)) { return true; } diff --git a/Mage.Sets/src/mage/cards/d/DarigaazTheIgniter.java b/Mage.Sets/src/mage/cards/d/DarigaazTheIgniter.java index 2ffdcc63812..72f7d565315 100644 --- a/Mage.Sets/src/mage/cards/d/DarigaazTheIgniter.java +++ b/Mage.Sets/src/mage/cards/d/DarigaazTheIgniter.java @@ -79,7 +79,7 @@ class DarigaazTheIgniterEffect extends OneShotEffect { damagedPlayer.revealCards("hand of " + damagedPlayer.getName(), damagedPlayer.getHand(), game); FilterCard filter = new FilterCard(); filter.add(new ColorPredicate(choice.getColor())); - int damage = damagedPlayer.getHand().count(filter, source.getSourceId(), source.getControllerId(), game); + int damage = damagedPlayer.getHand().count(filter, source.getControllerId(), source, game); if (damage > 0) { damagedPlayer.damage(damage, source.getSourceId(), source, game); } diff --git a/Mage.Sets/src/mage/cards/d/DarigaazsCharm.java b/Mage.Sets/src/mage/cards/d/DarigaazsCharm.java index a1a444ea12c..ba92d621c06 100644 --- a/Mage.Sets/src/mage/cards/d/DarigaazsCharm.java +++ b/Mage.Sets/src/mage/cards/d/DarigaazsCharm.java @@ -31,14 +31,12 @@ public final class DarigaazsCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE)); // or Darigaaz's Charm deals 3 damage to any target; - Mode mode = new Mode(); - mode.addEffect(new DamageTargetEffect(3)); + Mode mode = new Mode(new DamageTargetEffect(3)); mode.addTarget(new TargetAnyTarget()); this.getSpellAbility().addMode(mode); // or target creature gets +3/+3 until end of turn. - mode = new Mode(); - mode.addEffect(new BoostTargetEffect(3, 3, Duration.EndOfTurn)); + mode = new Mode(new BoostTargetEffect(3, 3, Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/d/DaringArchaeologist.java b/Mage.Sets/src/mage/cards/d/DaringArchaeologist.java index a7d7aa52af3..709d5ab9a94 100644 --- a/Mage.Sets/src/mage/cards/d/DaringArchaeologist.java +++ b/Mage.Sets/src/mage/cards/d/DaringArchaeologist.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -14,12 +12,13 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.FilterSpell; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.filter.predicate.mageobject.HistoricPredicate; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class DaringArchaeologist extends CardImpl { @@ -41,7 +40,7 @@ public final class DaringArchaeologist extends CardImpl { // When Daring Archaeologist enters the battlefield, you may return target artifact card from your graveyard to your hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect() .setText("you may return target artifact card from your graveyard to your hand"), true); - ability.addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); // Whenever you cast a historic spell, put a +1/+1 counter on Daring Archaeologist. diff --git a/Mage.Sets/src/mage/cards/d/DaringBuccaneer.java b/Mage.Sets/src/mage/cards/d/DaringBuccaneer.java index ce392e959b6..6672cfe4959 100644 --- a/Mage.Sets/src/mage/cards/d/DaringBuccaneer.java +++ b/Mage.Sets/src/mage/cards/d/DaringBuccaneer.java @@ -34,9 +34,9 @@ public final class DaringBuccaneer extends CardImpl { // As an additional cost to cast Daring Buccaneer, reveal a Pirate card from your hand or pay {2}. this.getSpellAbility().addCost(new OrCost( - new RevealTargetFromHandCost(new TargetCardInHand(filter)), - new GenericManaCost(2), - "reveal a Pirate card from your hand or pay {2}")); + "reveal a Pirate card from your hand or pay {2}", new RevealTargetFromHandCost(new TargetCardInHand(filter)), + new GenericManaCost(2) + )); } diff --git a/Mage.Sets/src/mage/cards/d/DaringEscape.java b/Mage.Sets/src/mage/cards/d/DaringEscape.java new file mode 100644 index 00000000000..335dbe77546 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DaringEscape.java @@ -0,0 +1,38 @@ +package mage.cards.d; + +import java.util.UUID; + +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author weirddan455 + */ +public final class DaringEscape extends CardImpl { + + public DaringEscape(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); + + // Target creature gets +1/+0 and gains first strike until end of turn. Scry 1. + this.getSpellAbility().addEffect(new BoostTargetEffect(1, 0).setText("target creature gets +1/+0")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance()).setText("and gains first strike until end of turn")); + this.getSpellAbility().addEffect(new ScryEffect(1, false)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private DaringEscape(final DaringEscape card) { + super(card); + } + + @Override + public DaringEscape copy() { + return new DaringEscape(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DaringThief.java b/Mage.Sets/src/mage/cards/d/DaringThief.java index 6638c65078f..8ca8d4fef4d 100644 --- a/Mage.Sets/src/mage/cards/d/DaringThief.java +++ b/Mage.Sets/src/mage/cards/d/DaringThief.java @@ -72,7 +72,7 @@ class TargetControlledPermanentSharingOpponentPermanentCardType extends TargetCo @Override public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { if (super.canTarget(controllerId, id, source, game)) { - Set cardTypes = getOpponentPermanentCardTypes(source.getSourceId(), controllerId, game); + Set cardTypes = getOpponentPermanentCardTypes(controllerId, game); Permanent permanent = game.getPermanent(id); for (CardType type : permanent.getCardType(game)) { if (cardTypes.contains(type)) { @@ -84,13 +84,13 @@ class TargetControlledPermanentSharingOpponentPermanentCardType extends TargetCo } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { // get all cardtypes from opponents permanents - Set cardTypes = getOpponentPermanentCardTypes(sourceId, sourceControllerId, game); + Set cardTypes = getOpponentPermanentCardTypes(sourceControllerId, game); Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); if (targetSource != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { for (CardType type : permanent.getCardType(game)) { if (cardTypes.contains(type)) { @@ -109,7 +109,7 @@ class TargetControlledPermanentSharingOpponentPermanentCardType extends TargetCo return new TargetControlledPermanentSharingOpponentPermanentCardType(this); } - private EnumSet getOpponentPermanentCardTypes(UUID sourceId, UUID sourceControllerId, Game game) { + private EnumSet getOpponentPermanentCardTypes(UUID sourceControllerId, Game game) { Player controller = game.getPlayer(sourceControllerId); EnumSet cardTypes = EnumSet.noneOf(CardType.class); if (controller != null) { @@ -154,12 +154,12 @@ class DaringThiefSecondTarget extends TargetPermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); if (firstTarget != null) { - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); if (targetSource != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { if (permanent.shareTypes(firstTarget, game)) { possibleTargets.add(permanent.getId()); diff --git a/Mage.Sets/src/mage/cards/d/DarkBargain.java b/Mage.Sets/src/mage/cards/d/DarkBargain.java index ba6656edc02..64746094866 100644 --- a/Mage.Sets/src/mage/cards/d/DarkBargain.java +++ b/Mage.Sets/src/mage/cards/d/DarkBargain.java @@ -1,32 +1,25 @@ - package mage.cards.d; import java.util.UUID; -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageControllerEffect; -import mage.cards.*; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; /** * - * @author Quercitron + * @author awjackson */ public final class DarkBargain extends CardImpl { public DarkBargain(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}"); - // Look at the top three cards of your library. Put two of them into your hand and the rest into your graveyard. + // Look at the top three cards of your library. Put two of them into your hand and the other into your graveyard. // Dark Bargain deals 2 damage to you. - this.getSpellAbility().addEffect(new DarkBargainEffect()); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(3, 2, PutCards.HAND, PutCards.GRAVEYARD)); this.getSpellAbility().addEffect(new DamageControllerEffect(2)); } @@ -39,47 +32,3 @@ public final class DarkBargain extends CardImpl { return new DarkBargain(this); } } - -class DarkBargainEffect extends OneShotEffect { - - public DarkBargainEffect() { - super(Outcome.Benefit); - this.staticText = "Look at the top three cards of your library. Put two of them into your hand and the other into your graveyard"; - } - - public DarkBargainEffect(final DarkBargainEffect effect) { - super(effect); - } - - @Override - public DarkBargainEffect copy() { - return new DarkBargainEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - MageObject sourceOject = source.getSourceObject(game); - if (player != null && sourceOject != null) { - Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 3)); - if (!cards.isEmpty()) { - Cards cardsToHand = new CardsImpl(); - player.lookAtCards(sourceOject.getIdName(), cards, game); - TargetCard target = new TargetCard(Math.min(2, cards.size()), Zone.LIBRARY, new FilterCard("two cards to put in your hand")); - if (player.choose(Outcome.DrawCard, cards, target, game)) { - for (UUID targetId : target.getTargets()) { - Card card = cards.get(targetId, game); - if (card != null) { - cardsToHand.add(card); - cards.remove(card); - } - } - } - player.moveCards(cardsToHand, Zone.HAND, source, game); - player.moveCards(cards, Zone.GRAVEYARD, source, game); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DarkIntimations.java b/Mage.Sets/src/mage/cards/d/DarkIntimations.java index 2397f33cafa..bdc801ede14 100644 --- a/Mage.Sets/src/mage/cards/d/DarkIntimations.java +++ b/Mage.Sets/src/mage/cards/d/DarkIntimations.java @@ -48,7 +48,7 @@ public final class DarkIntimations extends CardImpl { this.getSpellAbility().addEffect(new DarkIntimationsEffect()); // When you cast a Bolas planeswalker spell, exile Dark Intimations from your graveyard. That planeswalker enters the battlefield with an additional loyalty counter on it. - this.addAbility(new SpellCastControllerTriggeredAbility(Zone.GRAVEYARD, new DarkIntimationsGraveyardEffect(), filter, false, true)); + this.addAbility(new SpellCastControllerTriggeredAbility(Zone.GRAVEYARD, new DarkIntimationsGraveyardEffect(), filter, false, true).setTriggerPhrase("When you cast a Bolas planeswalker spell, ")); } private DarkIntimations(final DarkIntimations card) { @@ -101,7 +101,7 @@ class DarkIntimationsEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null) { TargetPermanent target = new TargetPermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Sacrifice, target, source, game); perms.addAll(target.getTargets()); } @@ -120,8 +120,8 @@ class DarkIntimationsEffect extends OneShotEffect { } } TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(filterCard); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) - && controller.choose(Outcome.ReturnToHand, target, source.getSourceId(), game)) { + if (target.canChoose(source.getControllerId(), source, game) + && controller.choose(Outcome.ReturnToHand, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card == null) { return false; diff --git a/Mage.Sets/src/mage/cards/d/DarkSphere.java b/Mage.Sets/src/mage/cards/d/DarkSphere.java index 7a170798509..dd33b03f9bd 100644 --- a/Mage.Sets/src/mage/cards/d/DarkSphere.java +++ b/Mage.Sets/src/mage/cards/d/DarkSphere.java @@ -70,13 +70,13 @@ class DarkSpherePreventionEffect extends ReplacementEffectImpl { @Override public void init(Ability source, Game game) { - this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); } @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); DamageEvent damageEvent = (DamageEvent) event; if (controller != null) { controller.damage((int) Math.ceil(damageEvent.getAmount() / 2.0), damageEvent.getSourceId(), source, game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), damageEvent.getAppliedEffects()); diff --git a/Mage.Sets/src/mage/cards/d/DarkWithering.java b/Mage.Sets/src/mage/cards/d/DarkWithering.java index 73ccc5e66fd..be1052fd643 100644 --- a/Mage.Sets/src/mage/cards/d/DarkWithering.java +++ b/Mage.Sets/src/mage/cards/d/DarkWithering.java @@ -24,7 +24,7 @@ public final class DarkWithering extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); // Madness {B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{B}"))); } private DarkWithering(final DarkWithering card) { diff --git a/Mage.Sets/src/mage/cards/d/DarkestHour.java b/Mage.Sets/src/mage/cards/d/DarkestHour.java index d8609cd4ea9..fcc3dabac5d 100644 --- a/Mage.Sets/src/mage/cards/d/DarkestHour.java +++ b/Mage.Sets/src/mage/cards/d/DarkestHour.java @@ -49,7 +49,7 @@ class DarkestHourEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { permanent.getColor(game).setColor(ObjectColor.BLACK); } return true; diff --git a/Mage.Sets/src/mage/cards/d/DarkheartSliver.java b/Mage.Sets/src/mage/cards/d/DarkheartSliver.java index a3d2f57da18..bb7d549cb99 100644 --- a/Mage.Sets/src/mage/cards/d/DarkheartSliver.java +++ b/Mage.Sets/src/mage/cards/d/DarkheartSliver.java @@ -34,7 +34,7 @@ public final class DarkheartSliver extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(3), new SacrificeSourceCost()); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(ability, - Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, + Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS, "All Slivers have \"Sacrifice this permanent: You gain 3 life.\""))); } diff --git a/Mage.Sets/src/mage/cards/d/DarlingOfTheMasses.java b/Mage.Sets/src/mage/cards/d/DarlingOfTheMasses.java new file mode 100644 index 00000000000..ab3e80ddcae --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DarlingOfTheMasses.java @@ -0,0 +1,50 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.permanent.token.CitizenGreenWhiteToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DarlingOfTheMasses extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.CITIZEN, "Citizens"); + + public DarlingOfTheMasses(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{W}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Other Citizens you control get +1/+0. + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 0, Duration.WhileOnBattlefield, filter, true + ))); + + // Whenever Darling of the Masses attacks, create a 1/1 green and white Citizen creature token. + this.addAbility(new AttacksTriggeredAbility(new CreateTokenEffect(new CitizenGreenWhiteToken()))); + } + + private DarlingOfTheMasses(final DarlingOfTheMasses card) { + super(card); + } + + @Override + public DarlingOfTheMasses copy() { + return new DarlingOfTheMasses(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DarthSidiousSithLord.java b/Mage.Sets/src/mage/cards/d/DarthSidiousSithLord.java index a8d859d1284..b06238c860e 100644 --- a/Mage.Sets/src/mage/cards/d/DarthSidiousSithLord.java +++ b/Mage.Sets/src/mage/cards/d/DarthSidiousSithLord.java @@ -4,7 +4,6 @@ package mage.cards.d; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.SacrificeEffect; @@ -39,7 +38,7 @@ public final class DarthSidiousSithLord extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SIDIOUS); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +3: Destroy target noncreature permanent. Ability ability = new LoyaltyAbility(new DestroyTargetEffect(), +3); diff --git a/Mage.Sets/src/mage/cards/d/DarthTyranusCountOfSerenno.java b/Mage.Sets/src/mage/cards/d/DarthTyranusCountOfSerenno.java index 5207ab9898a..cfa20e3ece1 100644 --- a/Mage.Sets/src/mage/cards/d/DarthTyranusCountOfSerenno.java +++ b/Mage.Sets/src/mage/cards/d/DarthTyranusCountOfSerenno.java @@ -4,7 +4,6 @@ package mage.cards.d; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.SearchEffect; @@ -39,7 +38,7 @@ public final class DarthTyranusCountOfSerenno extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.DOOKU); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Up to one target creature gets -6/-0 until your next turn. Effect effect = new BoostTargetEffect(-6, 0, Duration.UntilYourNextTurn); diff --git a/Mage.Sets/src/mage/cards/d/DaruHealer.java b/Mage.Sets/src/mage/cards/d/DaruHealer.java index 4ed657242b7..644e2a33b7a 100644 --- a/Mage.Sets/src/mage/cards/d/DaruHealer.java +++ b/Mage.Sets/src/mage/cards/d/DaruHealer.java @@ -37,7 +37,7 @@ public final class DaruHealer extends CardImpl { this.addAbility(ability); // Morph {W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{W}"))); } diff --git a/Mage.Sets/src/mage/cards/d/DaruLancer.java b/Mage.Sets/src/mage/cards/d/DaruLancer.java index bf91992cd6f..05c43badeff 100644 --- a/Mage.Sets/src/mage/cards/d/DaruLancer.java +++ b/Mage.Sets/src/mage/cards/d/DaruLancer.java @@ -27,7 +27,7 @@ public final class DaruLancer extends CardImpl { // First strike this.addAbility(FirstStrikeAbility.getInstance()); // Morph {2}{W}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{W}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{W}{W}"))); } private DaruLancer(final DaruLancer card) { diff --git a/Mage.Sets/src/mage/cards/d/DaruMender.java b/Mage.Sets/src/mage/cards/d/DaruMender.java index 1af1b051ab0..fd6c180f3dc 100644 --- a/Mage.Sets/src/mage/cards/d/DaruMender.java +++ b/Mage.Sets/src/mage/cards/d/DaruMender.java @@ -28,7 +28,7 @@ public final class DaruMender extends CardImpl { this.toughness = new MageInt(1); // Morph {W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{W}"))); // When Daru Mender is turned face up, regenerate target creature. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new RegenerateTargetEffect()); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/d/DaruSanctifier.java b/Mage.Sets/src/mage/cards/d/DaruSanctifier.java index 8fef06d341b..eb8323dbfba 100644 --- a/Mage.Sets/src/mage/cards/d/DaruSanctifier.java +++ b/Mage.Sets/src/mage/cards/d/DaruSanctifier.java @@ -28,7 +28,7 @@ public final class DaruSanctifier extends CardImpl { this.toughness = new MageInt(4); // Morph {1}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{W}"))); // When Daru Sanctifier is turned face up, destroy target enchantment. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new DestroyTargetEffect()); ability.addTarget(new TargetEnchantmentPermanent()); diff --git a/Mage.Sets/src/mage/cards/d/DaughterOfAutumn.java b/Mage.Sets/src/mage/cards/d/DaughterOfAutumn.java index 8bfcd985ede..5fe6e3339b0 100644 --- a/Mage.Sets/src/mage/cards/d/DaughterOfAutumn.java +++ b/Mage.Sets/src/mage/cards/d/DaughterOfAutumn.java @@ -81,7 +81,7 @@ class DaughterOfAutumnPreventDamageTargetEffect extends RedirectionEffect { 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 (filter.match(permanent, permanent.getControllerId(), source, game)) { if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) { if (event.getTargetId() != null) { TargetPermanent target = new TargetPermanent(); diff --git a/Mage.Sets/src/mage/cards/d/DauntlessBodyguard.java b/Mage.Sets/src/mage/cards/d/DauntlessBodyguard.java index 535c7ab7ac0..7e2757a2c52 100644 --- a/Mage.Sets/src/mage/cards/d/DauntlessBodyguard.java +++ b/Mage.Sets/src/mage/cards/d/DauntlessBodyguard.java @@ -87,7 +87,7 @@ class DauntlessBodyguardChooseCreatureEffect extends OneShotEffect { Permanent mageObject = game.getPermanentEntering(source.getSourceId()); if (controller != null && mageObject != null) { TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(1, 1, filter, true); - if (controller.choose(this.outcome, target, source.getSourceId(), game)) { + if (controller.choose(this.outcome, target, source, game)) { Permanent chosenCreature = game.getPermanent(target.getFirstTarget()); if (chosenCreature != null) { game.getState().setValue(mageObject.getId() + "_chosenCreature", new MageObjectReference(chosenCreature, game)); diff --git a/Mage.Sets/src/mage/cards/d/DauntlessEscort.java b/Mage.Sets/src/mage/cards/d/DauntlessEscort.java index 4157804ce9c..5c322790a35 100644 --- a/Mage.Sets/src/mage/cards/d/DauntlessEscort.java +++ b/Mage.Sets/src/mage/cards/d/DauntlessEscort.java @@ -1,41 +1,36 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.keyword.IndestructibleAbility; 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.constants.SubType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author North */ public final class DauntlessEscort extends CardImpl { public DauntlessEscort(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.RHINO); this.subtype.add(SubType.SOLDIER); - - - this.power = new MageInt(3); this.toughness = new MageInt(3); // Sacrifice Dauntless Escort: Creatures you control are indestructible this turn. - Effect effect = new GainAbilityAllEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES, false); - effect.setText("Creatures you control are indestructible this turn"); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new SacrificeSourceCost())); + this.addAbility(new SimpleActivatedAbility(new GainAbilityAllEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURES, false + ), new SacrificeSourceCost())); } private DauntlessEscort(final DauntlessEscort card) { diff --git a/Mage.Sets/src/mage/cards/d/DauthiVoidwalker.java b/Mage.Sets/src/mage/cards/d/DauthiVoidwalker.java index 9ab5d97c7af..f68400a3137 100644 --- a/Mage.Sets/src/mage/cards/d/DauthiVoidwalker.java +++ b/Mage.Sets/src/mage/cards/d/DauthiVoidwalker.java @@ -19,6 +19,7 @@ import mage.filter.FilterCard; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.PermanentToken; import mage.players.Player; import mage.target.common.TargetCardInExile; import mage.target.targetpointer.FixedTarget; @@ -101,6 +102,7 @@ class DauthiVoidwalkerReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { return ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD + && !(((ZoneChangeEvent) event).getTarget() instanceof PermanentToken) && game.getOpponents(source.getControllerId()).contains(game.getOwnerId(event.getTargetId())); } } @@ -139,7 +141,7 @@ class DauthiVoidwalkerPlayEffect extends OneShotEffect { TargetCardInExile target = new TargetCardInExile( 0, 1, filter, null, true ); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card == null) { return false; diff --git a/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java b/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java index 7209a035552..efbca10c547 100644 --- a/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java +++ b/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java @@ -3,7 +3,6 @@ package mage.cards.d; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; @@ -27,7 +26,7 @@ public final class DavrielRogueShadowmage extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.DAVRIEL); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // At the beginning of each opponent's upkeep, if that player has one or fewer cards in hand, Davriel, Rogue Shadowmage deals 2 damage to them. this.addAbility(new ConditionalInterveningIfTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/d/DawnCharm.java b/Mage.Sets/src/mage/cards/d/DawnCharm.java index 76e15531189..fcdc9a9f657 100644 --- a/Mage.Sets/src/mage/cards/d/DawnCharm.java +++ b/Mage.Sets/src/mage/cards/d/DawnCharm.java @@ -38,13 +38,11 @@ public final class DawnCharm extends CardImpl { // Choose one - Prevent all combat damage that would be dealt this turn this.getSpellAbility().addEffect(new PreventAllDamageByAllPermanentsEffect(Duration.EndOfTurn, true)); // or regenerate target creature; - Mode mode = new Mode(); - mode.addEffect(new RegenerateTargetEffect()); + Mode mode = new Mode(new RegenerateTargetEffect()); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or counter target spell that targets you. - mode = new Mode(); - mode.addEffect(new CounterTargetEffect()); + mode = new Mode(new CounterTargetEffect()); mode.addTarget(new TargetSpell(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/d/DawnToDusk.java b/Mage.Sets/src/mage/cards/d/DawnToDusk.java index c1c074f5d14..68861251fd8 100644 --- a/Mage.Sets/src/mage/cards/d/DawnToDusk.java +++ b/Mage.Sets/src/mage/cards/d/DawnToDusk.java @@ -34,8 +34,7 @@ public final class DawnToDusk extends CardImpl { this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filterCard).withChooseHint("return from graveyard to hand")); // and/or destroy target enchantment. - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetEnchantmentPermanent().withChooseHint("destroy")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/d/DawnbreakReclaimer.java b/Mage.Sets/src/mage/cards/d/DawnbreakReclaimer.java index cb95219643b..e637f81d39f 100644 --- a/Mage.Sets/src/mage/cards/d/DawnbreakReclaimer.java +++ b/Mage.Sets/src/mage/cards/d/DawnbreakReclaimer.java @@ -94,8 +94,8 @@ class DawnbreakReclaimerEffect extends OneShotEffect { Player opponent = null; Card cardOpponentGraveyard = null; chosenCreatureOpponentGraveyard.setNotTarget(true); - if (chosenCreatureOpponentGraveyard.canChoose(source.getSourceId(), source.getControllerId(), game)) { - controller.choose(Outcome.Detriment, chosenCreatureOpponentGraveyard, source.getSourceId(), game); + if (chosenCreatureOpponentGraveyard.canChoose(source.getControllerId(), source, game)) { + controller.choose(Outcome.Detriment, chosenCreatureOpponentGraveyard, source, game); cardOpponentGraveyard = game.getCard(chosenCreatureOpponentGraveyard.getFirstTarget()); if (cardOpponentGraveyard != null) { opponent = game.getPlayer(cardOpponentGraveyard.getOwnerId()); @@ -109,7 +109,7 @@ class DawnbreakReclaimerEffect extends OneShotEffect { if (opponent == null) { // if no card from opponent was available controller has to chose an opponent to select a creature card in controllers graveyard TargetOpponent targetOpponent = new TargetOpponent(true); - controller.choose(outcome, targetOpponent, source.getSourceId(), game); + controller.choose(outcome, targetOpponent, source, game); opponent = game.getPlayer(targetOpponent.getFirstTarget()); if (opponent != null) { game.informPlayers(sourceObject.getLogName() @@ -126,8 +126,8 @@ class DawnbreakReclaimerEffect extends OneShotEffect { TargetCardInGraveyard targetControllerGaveyard = new TargetCardInGraveyard(filterCreatureCard); targetControllerGaveyard.setNotTarget(true); Card controllerCreatureCard = null; - if (targetControllerGaveyard.canChoose(source.getSourceId(), opponent.getId(), game) - && opponent.choose(outcome, targetControllerGaveyard, source.getSourceId(), game)) { + if (targetControllerGaveyard.canChoose(opponent.getId(), source, game) + && opponent.choose(outcome, targetControllerGaveyard, source, game)) { controllerCreatureCard = game.getCard(targetControllerGaveyard.getFirstTarget()); if (controllerCreatureCard != null) { game.informPlayers(sourceObject.getLogName() diff --git a/Mage.Sets/src/mage/cards/d/DawnglowInfusion.java b/Mage.Sets/src/mage/cards/d/DawnglowInfusion.java index bea66dae04e..fc5a75c0421 100644 --- a/Mage.Sets/src/mage/cards/d/DawnglowInfusion.java +++ b/Mage.Sets/src/mage/cards/d/DawnglowInfusion.java @@ -30,7 +30,7 @@ public final class DawnglowInfusion extends CardImpl { new ManaWasSpentCondition(ColoredManaSymbol.G), "You gain X life if {G} was spent to cast this spell")); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new GainLifeEffect(xValue), - new ManaWasSpentCondition(ColoredManaSymbol.W), " And X life if {W} was spent to cast it")); + new ManaWasSpentCondition(ColoredManaSymbol.W), "and X life if {W} was spent to cast this spell")); this.getSpellAbility().addEffect(new InfoEffect("(Do both if {G}{W} was spent.)")); diff --git a/Mage.Sets/src/mage/cards/d/DawningPurist.java b/Mage.Sets/src/mage/cards/d/DawningPurist.java index b26b71ec1eb..26f96bafd34 100644 --- a/Mage.Sets/src/mage/cards/d/DawningPurist.java +++ b/Mage.Sets/src/mage/cards/d/DawningPurist.java @@ -37,7 +37,7 @@ public final class DawningPurist extends CardImpl { this.addAbility(new DawningPuristTriggeredAbility()); // Morph {1}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{W}"))); } private DawningPurist(final DawningPurist card) { diff --git a/Mage.Sets/src/mage/cards/d/DaxosOfMeletis.java b/Mage.Sets/src/mage/cards/d/DaxosOfMeletis.java index 21cb9ee126a..4c28d21acba 100644 --- a/Mage.Sets/src/mage/cards/d/DaxosOfMeletis.java +++ b/Mage.Sets/src/mage/cards/d/DaxosOfMeletis.java @@ -60,7 +60,7 @@ class DaxosOfMeletisEffect extends OneShotEffect { public DaxosOfMeletisEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "exile the top card of that player's library. You gain life equal to that card's mana value. Until end of turn, you may cast that card and you may spend mana as though it were mana of any color to cast it"; + this.staticText = "exile the top card of that player's library. You gain life equal to that card's mana value. Until end of turn, you may cast that card and you may spend mana as though it were mana of any color to cast that spell"; } public DaxosOfMeletisEffect(final DaxosOfMeletisEffect effect) { @@ -78,7 +78,7 @@ class DaxosOfMeletisEffect extends OneShotEffect { if (controller != null) { Player damagedPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); if (damagedPlayer != null) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); UUID exileId = CardUtil.getCardExileZoneId(game, source); Card card = damagedPlayer.getLibrary().getFromTop(game); if (card != null && sourceObject != null) { diff --git a/Mage.Sets/src/mage/cards/d/DayOfTheDragons.java b/Mage.Sets/src/mage/cards/d/DayOfTheDragons.java index e05dbda3c96..33d3c585840 100644 --- a/Mage.Sets/src/mage/cards/d/DayOfTheDragons.java +++ b/Mage.Sets/src/mage/cards/d/DayOfTheDragons.java @@ -69,7 +69,7 @@ class DayOfTheDragonsEntersEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { Set toExile = new HashSet<>(); toExile.addAll(game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)); diff --git a/Mage.Sets/src/mage/cards/d/DaybreakCoronet.java b/Mage.Sets/src/mage/cards/d/DaybreakCoronet.java index 2d0b71ed7ce..3e7d04984ab 100644 --- a/Mage.Sets/src/mage/cards/d/DaybreakCoronet.java +++ b/Mage.Sets/src/mage/cards/d/DaybreakCoronet.java @@ -1,12 +1,7 @@ - package mage.cards.d; -import java.util.LinkedList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; @@ -17,44 +12,54 @@ import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicate; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; + +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class DaybreakCoronet extends CardImpl { - + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature with another Aura attached to it"); + + static { + filter.add(AuraAttachedPredicate.instance); + } + public DaybreakCoronet(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}{W}"); this.subtype.add(SubType.AURA); - // Enchant creature with another Aura attached to it - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with another Aura attached to it."); - filter.add(new AuraAttachedPredicate(this.getId())); - TargetPermanent auraTarget = new TargetCreaturePermanent(filter); + TargetPermanent auraTarget = new TargetPermanent(filter); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); - + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // Enchanted creature gets +3/+3 and has first strike, vigilance, and lifelink. - ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(3, 3, Duration.WhileOnBattlefield)); - Effect effect = new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.AURA); - effect.setText("and has first strike"); - ability.addEffect(effect); - effect = new GainAbilityAttachedEffect(VigilanceAbility.getInstance(), AttachmentType.AURA); - effect.setText(", vigilance"); - ability.addEffect(effect); - effect = new GainAbilityAttachedEffect(LifelinkAbility.getInstance(), AttachmentType.AURA); - effect.setText(", and lifelink"); - ability.addEffect(effect); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect( + 3, 3, Duration.WhileOnBattlefield + )); + ability.addEffect(new GainAbilityAttachedEffect( + FirstStrikeAbility.getInstance(), AttachmentType.AURA + ).setText("and has first strike")); + ability.addEffect(new GainAbilityAttachedEffect( + VigilanceAbility.getInstance(), AttachmentType.AURA + ).setText(", vigilance")); + ability.addEffect(new GainAbilityAttachedEffect( + LifelinkAbility.getInstance(), AttachmentType.AURA + ).setText(", and lifelink")); this.addAbility(ability); } @@ -68,28 +73,21 @@ public final class DaybreakCoronet extends CardImpl { } } -class AuraAttachedPredicate implements Predicate { - - private final UUID ownId; - - public AuraAttachedPredicate(UUID ownId) { - this.ownId = ownId; - } +enum AuraAttachedPredicate implements ObjectSourcePlayerPredicate { + instance; @Override - public boolean apply(Permanent input, Game game) { - List attachments = new LinkedList(); - attachments.addAll(input.getAttachments()); - for (UUID uuid : attachments) { - if (!uuid.equals(ownId)) { - Permanent attachment = game.getPermanent(uuid); - if (attachment != null - && attachment.hasSubtype(SubType.AURA, game)) { - return true; - } - } - } - return false; + public boolean apply(ObjectSourcePlayer input, Game game) { + List attachments = new LinkedList<>(); + attachments.addAll(input.getObject().getAttachments()); + return input + .getObject() + .getAttachments() + .stream() + .filter(uuid -> !uuid.equals(input.getSourceId())) + .map(game::getPermanent) + .filter(Objects::nonNull) + .anyMatch(permanent -> permanent.hasSubtype(SubType.AURA, game)); } @Override diff --git a/Mage.Sets/src/mage/cards/d/DazzlingSphinx.java b/Mage.Sets/src/mage/cards/d/DazzlingSphinx.java index 172a3f0a1f8..50f72e6b55e 100644 --- a/Mage.Sets/src/mage/cards/d/DazzlingSphinx.java +++ b/Mage.Sets/src/mage/cards/d/DazzlingSphinx.java @@ -1,6 +1,5 @@ package mage.cards.d; -import mage.ApprovingObject; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; @@ -13,6 +12,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import mage.util.CardUtil; import java.util.UUID; @@ -73,24 +73,14 @@ class DazzlingSphinxEffect extends OneShotEffect { return false; } Cards cards = new CardsImpl(); - Card toCast = null; for (Card card : opponent.getLibrary().getCards(game)) { cards.add(card); + opponent.moveCards(card, Zone.EXILED, source, game); if (card.isInstantOrSorcery(game)) { - toCast = card; + CardUtil.castSpellWithAttributesForFree(controller, source, game, card); + break; } } - opponent.moveCards(cards, Zone.EXILED, source, game); - if (toCast != null && controller.chooseUse( - outcome, "Cast " + toCast.getName() + " without paying its mana cost?", source, game - )) { - game.getState().setValue("PlayFromNotOwnHandZone" + toCast.getId(), Boolean.TRUE); - controller.cast( - controller.chooseAbilityForCast(toCast, game, true), - game, true, new ApprovingObject(source, game) - ); - game.getState().setValue("PlayFromNotOwnHandZone" + toCast.getId(), null); - } cards.retainZone(Zone.EXILED, game); opponent.putCardsOnBottomOfLibrary(cards, game, source, false); return true; diff --git a/Mage.Sets/src/mage/cards/d/DeadReckoning.java b/Mage.Sets/src/mage/cards/d/DeadReckoning.java index 5909fb861a1..a412639041f 100644 --- a/Mage.Sets/src/mage/cards/d/DeadReckoning.java +++ b/Mage.Sets/src/mage/cards/d/DeadReckoning.java @@ -63,10 +63,10 @@ class DeadReckoningEffect extends OneShotEffect { TargetCreaturePermanent target2 = new TargetCreaturePermanent(); if (controller != null) { - if (target1.canChoose(source.getSourceId(), source.getControllerId(), game) - && controller.choose(Outcome.Benefit, target1, source.getSourceId(), game) - && target2.canChoose(source.getSourceId(), source.getControllerId(), game) - && controller.choose(Outcome.Damage, target2, source.getSourceId(), game)) { + if (target1.canChoose(source.getControllerId(), source, game) + && controller.choose(Outcome.Benefit, target1, source, game) + && target2.canChoose(source.getControllerId(), source, game) + && controller.choose(Outcome.Damage, target2, source, game)) { Card creatureInGraveyard = game.getCard(target1.getFirstTarget()); if (creatureInGraveyard != null) { if (controller.putCardsOnTopOfLibrary(creatureInGraveyard, game, source, true)) { diff --git a/Mage.Sets/src/mage/cards/d/DeadRingers.java b/Mage.Sets/src/mage/cards/d/DeadRingers.java index e7948b8839d..c49c070e635 100644 --- a/Mage.Sets/src/mage/cards/d/DeadRingers.java +++ b/Mage.Sets/src/mage/cards/d/DeadRingers.java @@ -6,7 +6,7 @@ import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters;; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.Target; diff --git a/Mage.Sets/src/mage/cards/d/DeadeyeHarpooner.java b/Mage.Sets/src/mage/cards/d/DeadeyeHarpooner.java index 05ea3661bb7..f6912f11f9d 100644 --- a/Mage.Sets/src/mage/cards/d/DeadeyeHarpooner.java +++ b/Mage.Sets/src/mage/cards/d/DeadeyeHarpooner.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -13,18 +11,21 @@ import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterOpponentsCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; -import mage.target.common.TargetOpponentsCreaturePermanent; +import mage.target.TargetPermanent; import mage.watchers.common.RevoltWatcher; +import java.util.UUID; + /** - * * @author Styxo */ public final class DeadeyeHarpooner extends CardImpl { - private static final FilterOpponentsCreaturePermanent filter = new FilterOpponentsCreaturePermanent("tapped creature an opponent controls"); + private static final FilterPermanent filter + = new FilterOpponentsCreaturePermanent("tapped creature an opponent controls"); static { filter.add(TappedPredicate.TAPPED); @@ -39,15 +40,14 @@ public final class DeadeyeHarpooner extends CardImpl { this.toughness = new MageInt(2); // Revolt — When Deadeye Harpooner enters the battlefield, if a permanent you controlled left the battlefield this turn, destroy target tapped creature an opponent controls. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( - new DestroyTargetEffect(), false), RevoltCondition.instance, - "Revolt — When {this} enters the battlefield, if a permanent you controlled left" - + " the battlefield this turn, destroy target tapped creature an opponent controls." + Ability ability = new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), false), + RevoltCondition.instance, "When {this} enters the battlefield, if a permanent you controlled " + + "left the battlefield this turn, destroy target tapped creature an opponent controls." ); ability.setAbilityWord(AbilityWord.REVOLT); - ability.addTarget(new TargetOpponentsCreaturePermanent(filter)); - ability.addWatcher(new RevoltWatcher()); - this.addAbility(ability); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability, new RevoltWatcher()); } private DeadeyeHarpooner(final DeadeyeHarpooner card) { diff --git a/Mage.Sets/src/mage/cards/d/DeadeyeRigHauler.java b/Mage.Sets/src/mage/cards/d/DeadeyeRigHauler.java index 36291ae34cd..a1ec8903b68 100644 --- a/Mage.Sets/src/mage/cards/d/DeadeyeRigHauler.java +++ b/Mage.Sets/src/mage/cards/d/DeadeyeRigHauler.java @@ -32,7 +32,7 @@ public final class DeadeyeRigHauler extends CardImpl { // Raid— When Deadeye Rig-Hauler enters the battlefield, if you attacked this turn, you may return target creature to its owner's hand. Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true), RaidCondition.instance, - "Raid — When {this} enters the battlefield, if you attacked this turn, you may return target creature to its owner's hand."); + "When {this} enters the battlefield, if you attacked this turn, you may return target creature to its owner's hand."); ability.addTarget(new TargetCreaturePermanent()); ability.setAbilityWord(AbilityWord.RAID); ability.addHint(RaidHint.instance); diff --git a/Mage.Sets/src/mage/cards/d/DeadeyeTormentor.java b/Mage.Sets/src/mage/cards/d/DeadeyeTormentor.java index 51f62a39688..306fcdcc41b 100644 --- a/Mage.Sets/src/mage/cards/d/DeadeyeTormentor.java +++ b/Mage.Sets/src/mage/cards/d/DeadeyeTormentor.java @@ -32,7 +32,7 @@ public final class DeadeyeTormentor extends CardImpl { // Raid — When Deadeye Tormentor enters the battlefield, if you attacked this turn, target opponent discards a card. Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(1)), RaidCondition.instance, - "Raid — When {this} enters the battlefield, if you attacked this turn, target opponent discards a card."); + "When {this} enters the battlefield, if you attacked this turn, target opponent discards a card."); ability.addTarget(new TargetOpponent()); ability.setAbilityWord(AbilityWord.RAID); ability.addHint(RaidHint.instance); diff --git a/Mage.Sets/src/mage/cards/d/DeadlyBrew.java b/Mage.Sets/src/mage/cards/d/DeadlyBrew.java index 35c6fcf026f..0f9db1d9a64 100644 --- a/Mage.Sets/src/mage/cards/d/DeadlyBrew.java +++ b/Mage.Sets/src/mage/cards/d/DeadlyBrew.java @@ -81,10 +81,10 @@ class DeadlyBrewEffect extends OneShotEffect { } TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), playerId, game)) { + if (!target.canChoose(playerId, source, game)) { continue; } - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent == null) { continue; diff --git a/Mage.Sets/src/mage/cards/d/DeadlyTempest.java b/Mage.Sets/src/mage/cards/d/DeadlyTempest.java index a924d104efc..90a33631b49 100644 --- a/Mage.Sets/src/mage/cards/d/DeadlyTempest.java +++ b/Mage.Sets/src/mage/cards/d/DeadlyTempest.java @@ -60,7 +60,7 @@ class DeadlyTempestEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Map destroyedCreatures = new HashMap<>(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { if (permanent.destroy(source, game, false)) { int count = destroyedCreatures.getOrDefault(permanent.getControllerId(), 0); destroyedCreatures.put(permanent.getControllerId(), count + 1); diff --git a/Mage.Sets/src/mage/cards/d/DeadwoodTreefolk.java b/Mage.Sets/src/mage/cards/d/DeadwoodTreefolk.java index 09c22523d4c..6f643a69575 100644 --- a/Mage.Sets/src/mage/cards/d/DeadwoodTreefolk.java +++ b/Mage.Sets/src/mage/cards/d/DeadwoodTreefolk.java @@ -16,7 +16,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; @@ -26,9 +26,9 @@ import mage.target.common.TargetCardInYourGraveyard; */ public final class DeadwoodTreefolk extends CardImpl { - private static final FilterCreatureCard filter = new FilterCreatureCard("another creature card from your graveyard"); + private static final FilterCreatureCard filter = new FilterCreatureCard("another target creature card from your graveyard"); static { - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); } public DeadwoodTreefolk(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DeafeningClarion.java b/Mage.Sets/src/mage/cards/d/DeafeningClarion.java index 98cd7ceca63..1339695905e 100644 --- a/Mage.Sets/src/mage/cards/d/DeafeningClarion.java +++ b/Mage.Sets/src/mage/cards/d/DeafeningClarion.java @@ -30,8 +30,7 @@ public final class DeafeningClarion extends CardImpl { )); // • Creatures you control gain lifelink until end of turn. - Mode mode = new Mode(); - mode.addEffect(new GainAbilityControlledEffect( + Mode mode = new Mode(new GainAbilityControlledEffect( LifelinkAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES diff --git a/Mage.Sets/src/mage/cards/d/DealGoneBad.java b/Mage.Sets/src/mage/cards/d/DealGoneBad.java new file mode 100644 index 00000000000..e80bc047ed6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DealGoneBad.java @@ -0,0 +1,39 @@ +package mage.cards.d; + +import mage.abilities.effects.common.MillCardsTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.TargetPlayer; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DealGoneBad extends CardImpl { + + public DealGoneBad(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}"); + + // Target creature gets -3/-3 until end of turn. Target player mills three cards. + this.getSpellAbility().addEffect(new BoostTargetEffect(-3, -3)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new MillCardsTargetEffect(3) + .setText("Target player mills three cards") + .setTargetPointer(new SecondTargetPointer())); + this.getSpellAbility().addTarget(new TargetPlayer()); + } + + private DealGoneBad(final DealGoneBad card) { + super(card); + } + + @Override + public DealGoneBad copy() { + return new DealGoneBad(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DeathBaron.java b/Mage.Sets/src/mage/cards/d/DeathBaron.java index 49fd9011ed7..7cc4b753369 100644 --- a/Mage.Sets/src/mage/cards/d/DeathBaron.java +++ b/Mage.Sets/src/mage/cards/d/DeathBaron.java @@ -44,7 +44,7 @@ public final class DeathBaron extends CardImpl { 1, 1, Duration.WhileOnBattlefield, filter, false )); ability.addEffect(new GainAbilityControlledEffect( - DeathtouchAbility.getInstance(), Duration.WhileOnBattlefield, filter, true + DeathtouchAbility.getInstance(), Duration.WhileOnBattlefield, filter ).setText("and have deathtouch")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DeathCultist.java b/Mage.Sets/src/mage/cards/d/DeathCultist.java index 3b5be9709b2..e0ff79c3dd6 100644 --- a/Mage.Sets/src/mage/cards/d/DeathCultist.java +++ b/Mage.Sets/src/mage/cards/d/DeathCultist.java @@ -31,7 +31,7 @@ public final class DeathCultist extends CardImpl { SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseLifeTargetEffect(1), new SacrificeSourceCost()); - ability.addEffect(new GainLifeEffect(1)); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DeathFrenzy.java b/Mage.Sets/src/mage/cards/d/DeathFrenzy.java index d7b35c8d05d..17b9ffcb172 100644 --- a/Mage.Sets/src/mage/cards/d/DeathFrenzy.java +++ b/Mage.Sets/src/mage/cards/d/DeathFrenzy.java @@ -57,7 +57,7 @@ class DeathFrenzyDelayedTriggeredAbility extends DelayedTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.isDiesEvent() && zEvent.getTarget() != null && StaticFilters.FILTER_PERMANENT_CREATURES.match(zEvent.getTarget(), sourceId, controllerId, game)) { + if (zEvent.isDiesEvent() && zEvent.getTarget() != null && StaticFilters.FILTER_PERMANENT_CREATURES.match(zEvent.getTarget(), controllerId, this, game)) { return true; } return false; diff --git a/Mage.Sets/src/mage/cards/d/DeathMaskDuplicant.java b/Mage.Sets/src/mage/cards/d/DeathMaskDuplicant.java index bbe060867f5..50a21ea5903 100644 --- a/Mage.Sets/src/mage/cards/d/DeathMaskDuplicant.java +++ b/Mage.Sets/src/mage/cards/d/DeathMaskDuplicant.java @@ -1,4 +1,3 @@ - package mage.cards.d; import java.util.UUID; @@ -93,7 +92,9 @@ public final class DeathMaskDuplicant extends CardImpl { Player player = game.getPlayer(playerId); if (player != null) { UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), sourceObject.getZoneChangeCounter(game)); - if (exileId != null) { + if (exileId != null + && game.getState().getExile().getExileZone(exileId) != null + && !game.getState().getExile().getExileZone(exileId).isEmpty()) { for (UUID cardId : game.getState().getExile().getExileZone(exileId)) { Card card = game.getCard(cardId); if (card != null && card.isCreature(game)) { diff --git a/Mage.Sets/src/mage/cards/d/DeathTyrant.java b/Mage.Sets/src/mage/cards/d/DeathTyrant.java index c41d2a17c76..87cf6a9c356 100644 --- a/Mage.Sets/src/mage/cards/d/DeathTyrant.java +++ b/Mage.Sets/src/mage/cards/d/DeathTyrant.java @@ -42,7 +42,7 @@ public final class DeathTyrant extends CardImpl { // {5}{B}: Return Death Tyrant from your graveyard to the battlefield tapped. this.addAbility(new SimpleActivatedAbility( - Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(true), + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(true, false), new ManaCostsImpl<>("{5}{B}") )); } diff --git a/Mage.Sets/src/mage/cards/d/DeathbellowWarCry.java b/Mage.Sets/src/mage/cards/d/DeathbellowWarCry.java index 1655ec9108d..f6e4e18dc0b 100644 --- a/Mage.Sets/src/mage/cards/d/DeathbellowWarCry.java +++ b/Mage.Sets/src/mage/cards/d/DeathbellowWarCry.java @@ -1,20 +1,14 @@ package mage.cards.d; -import mage.abilities.Ability; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; -import mage.game.Game; -import mage.target.common.TargetCardInLibrary; -import mage.util.CardUtil; +import mage.target.common.TargetCardWithDifferentNameInLibrary; -import java.util.Objects; import java.util.UUID; /** @@ -22,11 +16,20 @@ import java.util.UUID; */ public final class DeathbellowWarCry extends CardImpl { + private static final FilterCard minotaurFilter + = new FilterCreatureCard("Minotaur creature cards with different names"); + + static { + minotaurFilter.add(SubType.MINOTAUR.getPredicate()); + } + public DeathbellowWarCry(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{5}{R}{R}{R}"); // Search your library for up to four Minotaur creature cards with different names, put them onto the battlefield, then shuffle your library. - this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect(new DeathbellowWarCryTarget())); + this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect( + new TargetCardWithDifferentNameInLibrary(0, 4, minotaurFilter) + )); } private DeathbellowWarCry(final DeathbellowWarCry card) { @@ -38,40 +41,3 @@ public final class DeathbellowWarCry extends CardImpl { return new DeathbellowWarCry(this); } } - -class DeathbellowWarCryTarget extends TargetCardInLibrary { - - private static final FilterCard minotaurFilter - = new FilterCreatureCard("Minotaur creature cards with different names"); - - static { - minotaurFilter.add(SubType.MINOTAUR.getPredicate()); - } - - DeathbellowWarCryTarget() { - super(0, 4, minotaurFilter); - } - - private DeathbellowWarCryTarget(final DeathbellowWarCryTarget target) { - super(target); - } - - @Override - public DeathbellowWarCryTarget copy() { - return new DeathbellowWarCryTarget(this); - } - - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Cards cards, Game game) { - Card card = cards.get(id, game); - return card != null - && filter.match(card, playerId, game) - && this - .getTargets() - .stream() - .map(game::getCard) - .filter(Objects::nonNull) - .map(Card::getName) - .noneMatch(n -> CardUtil.haveSameNames(card, n, game)); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DeathbonnetHulk.java b/Mage.Sets/src/mage/cards/d/DeathbonnetHulk.java index 7d39869b0f5..dfe959fbd40 100644 --- a/Mage.Sets/src/mage/cards/d/DeathbonnetHulk.java +++ b/Mage.Sets/src/mage/cards/d/DeathbonnetHulk.java @@ -73,7 +73,7 @@ class DeathbonnetHulkEffect extends OneShotEffect { } TargetCard target = new TargetCardInGraveyard(0, 1); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card == null) { return false; diff --git a/Mage.Sets/src/mage/cards/d/DeathbringerThoctar.java b/Mage.Sets/src/mage/cards/d/DeathbringerThoctar.java index f9a55cfcae8..759b8a60dd0 100644 --- a/Mage.Sets/src/mage/cards/d/DeathbringerThoctar.java +++ b/Mage.Sets/src/mage/cards/d/DeathbringerThoctar.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesCreatureTriggeredAbility; @@ -13,31 +11,33 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class DeathbringerThoctar extends CardImpl { public DeathbringerThoctar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{R}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.BEAST); - - - this.power = new MageInt(3); this.toughness = new MageInt(3); // Whenever another creature dies, you may put a +1/+1 counter on Deathbringer Thoctar. - this.addAbility(new DiesCreatureTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true, true)); + this.addAbility(new DiesCreatureTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true, true + )); // Remove a +1/+1 counter from Deathbringer Thoctar: Deathbringer Thoctar deals 1 damage to any target. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new RemoveCountersSourceCost(CounterType.P1P1.createInstance())); + Ability ability = new SimpleActivatedAbility( + new DamageTargetEffect(1, "it"), + new RemoveCountersSourceCost(CounterType.P1P1.createInstance()) + ); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DeathlessAngel.java b/Mage.Sets/src/mage/cards/d/DeathlessAngel.java index 5565a995682..e4c85490ed6 100644 --- a/Mage.Sets/src/mage/cards/d/DeathlessAngel.java +++ b/Mage.Sets/src/mage/cards/d/DeathlessAngel.java @@ -35,7 +35,7 @@ public final class DeathlessAngel extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // {W}{W}: Target creature is indestructible this turn. - Effect effect = new GainAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn, "Target creature is indestructible this turn"); + Effect effect = new GainAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{W}{W}")); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/d/DeathmistRaptor.java b/Mage.Sets/src/mage/cards/d/DeathmistRaptor.java index 18716f58ee4..30673de8658 100644 --- a/Mage.Sets/src/mage/cards/d/DeathmistRaptor.java +++ b/Mage.Sets/src/mage/cards/d/DeathmistRaptor.java @@ -41,7 +41,7 @@ public final class DeathmistRaptor extends CardImpl { this.addAbility(new TurnedFaceUpAllTriggeredAbility(Zone.GRAVEYARD, new DeathmistRaptorEffect(), new FilterControlledPermanent("a permanent you control"), false, true)); // Megamorph {4}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{G}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{G}"), true)); } private DeathmistRaptor(final DeathmistRaptor card) { diff --git a/Mage.Sets/src/mage/cards/d/Deathrender.java b/Mage.Sets/src/mage/cards/d/Deathrender.java index 83ad67b46ae..3ccafa0c1a5 100644 --- a/Mage.Sets/src/mage/cards/d/Deathrender.java +++ b/Mage.Sets/src/mage/cards/d/Deathrender.java @@ -71,7 +71,7 @@ class DeathrenderEffect extends OneShotEffect { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (controller != null && sourcePermanent != null) { TargetCardInHand target = new TargetCardInHand(0, 1, StaticFilters.FILTER_CARD_CREATURE); - if (controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCardInPlay, target, source, game)) { Card creatureInHand = game.getCard(target.getFirstTarget()); if (creatureInHand != null) { if (controller.moveCards(creatureInHand, Zone.BATTLEFIELD, source, game)) { diff --git a/Mage.Sets/src/mage/cards/d/DebtToTheKami.java b/Mage.Sets/src/mage/cards/d/DebtToTheKami.java index 45782470c23..8942d39ff60 100644 --- a/Mage.Sets/src/mage/cards/d/DebtToTheKami.java +++ b/Mage.Sets/src/mage/cards/d/DebtToTheKami.java @@ -73,7 +73,7 @@ class DebtToTheKamiExileCreatureEffect extends OneShotEffect { } Target target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent == null) { return false; @@ -112,7 +112,7 @@ class DebtToTheKamiExileEnchantmentEffect extends OneShotEffect { } Target target = new TargetControlledPermanent(filter); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent == null) { return false; diff --git a/Mage.Sets/src/mage/cards/d/DeceiverExarch.java b/Mage.Sets/src/mage/cards/d/DeceiverExarch.java index 17746f20aa9..0b23152db08 100644 --- a/Mage.Sets/src/mage/cards/d/DeceiverExarch.java +++ b/Mage.Sets/src/mage/cards/d/DeceiverExarch.java @@ -42,8 +42,7 @@ public final class DeceiverExarch extends CardImpl { // When Deceiver Exarch enters the battlefield, choose one - Untap target permanent you control; or tap target permanent an opponent controls. Ability ability = new EntersBattlefieldTriggeredAbility(new UntapTargetEffect()); ability.addTarget(new TargetControlledPermanent()); - Mode mode = new Mode(); - mode.addEffect(new TapTargetEffect()); + Mode mode = new Mode(new TapTargetEffect()); mode.addTarget(new TargetPermanent(filter)); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/d/DeceiverOfForm.java b/Mage.Sets/src/mage/cards/d/DeceiverOfForm.java index 4d375c6bf09..e94700afdf4 100644 --- a/Mage.Sets/src/mage/cards/d/DeceiverOfForm.java +++ b/Mage.Sets/src/mage/cards/d/DeceiverOfForm.java @@ -1,4 +1,3 @@ - package mage.cards.d; import java.util.UUID; @@ -63,18 +62,25 @@ class DeceiverOfFormEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + Card copyFromCard = null; MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { - Card copyFromCard = controller.getLibrary().getFromTop(game); - if (copyFromCard != null) { - Cards cards = new CardsImpl(copyFromCard); + Card cardFromTop = controller.getLibrary().getFromTop(game); + if (cardFromTop != null) { + Cards cards = new CardsImpl(cardFromTop); controller.revealCards(sourceObject.getIdName(), cards, game); - if (copyFromCard.isCreature(game)) { + if (cardFromTop.isCreature(game)) { if (controller.chooseUse(outcome, "Let creatures you control other than " - + sourceObject.getLogName() + " becomes copies of " + copyFromCard.getLogName() + " until end of turn?", source, game)) { + + sourceObject.getLogName() + " becomes copies of " + cardFromTop.getLogName() + " until end of turn?", source, game)) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), game)) { if (!permanent.getId().equals(sourceObject.getId())) { + copyFromCard = cardFromTop; + // handle MDFC + if (cardFromTop instanceof ModalDoubleFacesCard + && ((ModalDoubleFacesCard) cardFromTop).getLeftHalfCard().isCreature(game)) { + copyFromCard = ((ModalDoubleFacesCard) cardFromTop).getLeftHalfCard(); + } Permanent newBluePrint = null; newBluePrint = new PermanentCard(copyFromCard, source.getControllerId(), game); newBluePrint.assignNewId(); diff --git a/Mage.Sets/src/mage/cards/d/DeclarationInStone.java b/Mage.Sets/src/mage/cards/d/DeclarationInStone.java index 17785f873e8..c0a7c294bcb 100644 --- a/Mage.Sets/src/mage/cards/d/DeclarationInStone.java +++ b/Mage.Sets/src/mage/cards/d/DeclarationInStone.java @@ -60,7 +60,7 @@ class DeclarationInStoneEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && controller != null) { Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (targetPermanent != null) { diff --git a/Mage.Sets/src/mage/cards/d/DecreeOfAnnihilation.java b/Mage.Sets/src/mage/cards/d/DecreeOfAnnihilation.java index a52cc656a0d..025cbae0efd 100644 --- a/Mage.Sets/src/mage/cards/d/DecreeOfAnnihilation.java +++ b/Mage.Sets/src/mage/cards/d/DecreeOfAnnihilation.java @@ -85,7 +85,7 @@ class DecreeOfAnnihilationEffect extends OneShotEffect { } Cards cards = new CardsImpl(); for (Permanent permanent : game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game )) { cards.add(permanent); } diff --git a/Mage.Sets/src/mage/cards/d/DeepSlumberTitan.java b/Mage.Sets/src/mage/cards/d/DeepSlumberTitan.java index 974c122c81e..c45342bc9bf 100644 --- a/Mage.Sets/src/mage/cards/d/DeepSlumberTitan.java +++ b/Mage.Sets/src/mage/cards/d/DeepSlumberTitan.java @@ -36,7 +36,7 @@ public final class DeepSlumberTitan extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DontUntapInControllersUntapStepSourceEffect())); // Whenever Deep-Slumber Titan is dealt damage, untap it. - this.addAbility(new DealtDamageToSourceTriggeredAbility(new UntapSourceEffect(), false)); + this.addAbility(new DealtDamageToSourceTriggeredAbility(new UntapSourceEffect().setText("untap it"), false)); } diff --git a/Mage.Sets/src/mage/cards/d/DefenderOfTheOrder.java b/Mage.Sets/src/mage/cards/d/DefenderOfTheOrder.java index 271fdc0ef8a..84da3f6e2d0 100644 --- a/Mage.Sets/src/mage/cards/d/DefenderOfTheOrder.java +++ b/Mage.Sets/src/mage/cards/d/DefenderOfTheOrder.java @@ -27,7 +27,7 @@ public final class DefenderOfTheOrder extends CardImpl { this.toughness = new MageInt(4); // Morph {W}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{W}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{W}{W}"))); // When Defender of the Order is turned face up, creatures you control get +0/+2 until end of turn. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new BoostControlledEffect(0, 2, Duration.EndOfTurn))); } diff --git a/Mage.Sets/src/mage/cards/d/DefiantOgre.java b/Mage.Sets/src/mage/cards/d/DefiantOgre.java index 29ac2c52971..bf2ebfb345d 100644 --- a/Mage.Sets/src/mage/cards/d/DefiantOgre.java +++ b/Mage.Sets/src/mage/cards/d/DefiantOgre.java @@ -32,8 +32,7 @@ public final class DefiantOgre extends CardImpl { // * Put a +1/+1 counter on Defiant Ogre. Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false); // * Destroy target artifact. - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetArtifactPermanent()); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/d/DefilerOfSouls.java b/Mage.Sets/src/mage/cards/d/DefilerOfSouls.java index a7889898e01..4e10c0a36a2 100644 --- a/Mage.Sets/src/mage/cards/d/DefilerOfSouls.java +++ b/Mage.Sets/src/mage/cards/d/DefilerOfSouls.java @@ -83,10 +83,10 @@ class DefilerOfSoulsEffect extends OneShotEffect { //A spell or ability could have removed the only legal target this player //had, if thats the case this ability should fizzle. - if (amount > 0 && target.canChoose(source.getSourceId(), player.getId(), game)) { + if (amount > 0 && target.canChoose(player.getId(), source, game)) { boolean abilityApplied = false; - while (player.canRespond() && !target.isChosen() && target.canChoose(source.getSourceId(), player.getId(), game)) { - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + while (player.canRespond() && !target.isChosen() && target.canChoose(player.getId(), source, game)) { + player.choose(Outcome.Sacrifice, target, source, game); } for ( int idx = 0; idx < target.getTargets().size(); idx++) { diff --git a/Mage.Sets/src/mage/cards/d/DeflectingPalm.java b/Mage.Sets/src/mage/cards/d/DeflectingPalm.java index de70d22d084..9f6562ace07 100644 --- a/Mage.Sets/src/mage/cards/d/DeflectingPalm.java +++ b/Mage.Sets/src/mage/cards/d/DeflectingPalm.java @@ -62,7 +62,7 @@ class DeflectingPalmEffect extends PreventionEffectImpl { @Override public void init(Ability source, Game game) { - this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); super.init(source, game); } diff --git a/Mage.Sets/src/mage/cards/d/Deicide.java b/Mage.Sets/src/mage/cards/d/Deicide.java index 9effd337a8d..3a104ea0271 100644 --- a/Mage.Sets/src/mage/cards/d/Deicide.java +++ b/Mage.Sets/src/mage/cards/d/Deicide.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect; @@ -16,17 +14,15 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetEnchantmentPermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Deicide extends CardImpl { - - public Deicide(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); // Exile target enchantment. If the exiled card is a God card, search its controller's graveyard, hand, and library for any number of cards with the same name as that card and exile them, then that player shuffles their library. this.getSpellAbility().addEffect(new DeicideExileEffect()); @@ -45,32 +41,34 @@ public final class Deicide extends CardImpl { class DeicideExileEffect extends SearchTargetGraveyardHandLibraryForCardNameAndExileEffect { - public DeicideExileEffect() { - super(true, "its controller's","any number of cards with the same name as that card"); + DeicideExileEffect() { + super(true, "its controller's", "any number of cards with the same name as that card"); } - public DeicideExileEffect(final DeicideExileEffect effect) { + private DeicideExileEffect(final DeicideExileEffect effect) { super(effect); } @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); Card sourceCard = game.getCard(source.getSourceId()); - if (controller != null && sourceCard != null) { - Permanent targetEnchantment = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (targetEnchantment != null) { - controller.moveCardToExileWithInfo(targetEnchantment, null, "", source, game, Zone.BATTLEFIELD, true); - // 4/26/2014 - // Deicide looks at the card in exile, not the permanent that was exiled, to determine - // if it is a God. For each of the Gods in the Theros block, it won't matter what your - // devotion to its color(s) was. The card is a God card when not on the battlefield. - Card cardInExile = game.getExile().getCard(targetEnchantment.getId(), game); - if (cardInExile != null && cardInExile.hasSubtype(SubType.GOD, game)) { - Player enchantmentController = game.getPlayer(targetEnchantment.getControllerId()); - return enchantmentController != null && super.applySearchAndExile(game, source, cardInExile.getName(), enchantmentController.getId()); - } - } + if (controller == null || sourceCard == null) { + return false; + } + Permanent targetEnchantment = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (targetEnchantment == null) { + return false; + } + controller.moveCards(targetEnchantment, Zone.EXILED, source, game); + // 4/26/2014 + // Deicide looks at the card in exile, not the permanent that was exiled, to determine + // if it is a God. For each of the Gods in the Theros block, it won't matter what your + // devotion to its color(s) was. The card is a God card when not on the battlefield. + Card cardInExile = game.getExile().getCard(targetEnchantment.getId(), game); + if (cardInExile != null && cardInExile.hasSubtype(SubType.GOD, game)) { + Player enchantmentController = game.getPlayer(targetEnchantment.getControllerId()); + return enchantmentController != null && super.applySearchAndExile(game, source, cardInExile.getName(), enchantmentController.getId()); } return false; } @@ -82,10 +80,6 @@ class DeicideExileEffect extends SearchTargetGraveyardHandLibraryForCardNameAndE @Override public String getText(Mode mode) { - StringBuilder sb = new StringBuilder(); - sb.append("Exile target enchantment. If the exiled card is a God card, "); - sb.append(super.getText(mode)); - return sb.toString(); + return "Exile target enchantment. If the exiled card is a God card, " + super.getText(mode); } - -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/d/DelayTactic.java b/Mage.Sets/src/mage/cards/d/DelayTactic.java index 56cdf1b869f..6a7e6d13514 100644 --- a/Mage.Sets/src/mage/cards/d/DelayTactic.java +++ b/Mage.Sets/src/mage/cards/d/DelayTactic.java @@ -38,8 +38,7 @@ public final class DelayTactic extends CardImpl { .setText("Creatures you control gain hexproof until end of turn")); // Creatures target opponent controls don't untap during their next untap step. - Mode mode = new Mode(); - mode.addEffect(new DelayTacticEffect()); + Mode mode = new Mode(new DelayTacticEffect()); mode.addTarget(new TargetOpponent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/d/DeliverUntoEvil.java b/Mage.Sets/src/mage/cards/d/DeliverUntoEvil.java index 5f1a212885b..4a3deaba67c 100644 --- a/Mage.Sets/src/mage/cards/d/DeliverUntoEvil.java +++ b/Mage.Sets/src/mage/cards/d/DeliverUntoEvil.java @@ -85,7 +85,7 @@ class DeliverUntoEvilEffect extends OneShotEffect { } TargetOpponent targetOpponent = new TargetOpponent(); targetOpponent.setNotTarget(true); - if (!player.choose(outcome, targetOpponent, source.getSourceId(), game)) { + if (!player.choose(outcome, targetOpponent, source, game)) { return false; } Player opponent = game.getPlayer(targetOpponent.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/d/DementiaSliver.java b/Mage.Sets/src/mage/cards/d/DementiaSliver.java index 85284e15036..9ecacbe183e 100644 --- a/Mage.Sets/src/mage/cards/d/DementiaSliver.java +++ b/Mage.Sets/src/mage/cards/d/DementiaSliver.java @@ -77,7 +77,7 @@ class DementiaSliverEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player opponent = game.getPlayer(targetPointer.getFirst(game, source)); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); if (opponent != null && sourceObject != null && cardName != null && !cardName.isEmpty()) { if (!opponent.getHand().isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/d/DemonicHordes.java b/Mage.Sets/src/mage/cards/d/DemonicHordes.java index 28e10d0fcf3..671d3e4cbea 100644 --- a/Mage.Sets/src/mage/cards/d/DemonicHordes.java +++ b/Mage.Sets/src/mage/cards/d/DemonicHordes.java @@ -95,7 +95,7 @@ class DemonicHordesEffect extends OneShotEffect { choiceOpponent.setNotTarget(true); FilterLandPermanent filterLand = new FilterLandPermanent(); filterLand.add(new ControllerIdPredicate(source.getControllerId())); - if (controller.choose(Outcome.Neutral, choiceOpponent, source.getSourceId(), game)) { + if (controller.choose(Outcome.Neutral, choiceOpponent, source, game)) { Player opponent = game.getPlayer(choiceOpponent.getFirstTarget()); if (opponent != null) { Target chosenLand = new TargetLandPermanent(filterLand); diff --git a/Mage.Sets/src/mage/cards/d/DemonicPact.java b/Mage.Sets/src/mage/cards/d/DemonicPact.java index f13e5ab7a0f..c4028787a5c 100644 --- a/Mage.Sets/src/mage/cards/d/DemonicPact.java +++ b/Mage.Sets/src/mage/cards/d/DemonicPact.java @@ -37,19 +37,16 @@ public final class DemonicPact extends CardImpl { ability.addEffect(effect); // - Target opponent discards two cards - Mode mode = new Mode(); + Mode mode = new Mode(new DiscardTargetEffect(2)); mode.addTarget(new TargetOpponent()); - mode.addEffect(new DiscardTargetEffect(2)); ability.addMode(mode); // - Draw two cards - mode = new Mode(); - mode.addEffect(new DrawCardSourceControllerEffect(2)); + mode = new Mode(new DrawCardSourceControllerEffect(2)); ability.addMode(mode); // - You lose the game. - mode = new Mode(); - mode.addEffect(new LoseGameSourceControllerEffect()); + mode = new Mode(new LoseGameSourceControllerEffect()); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/d/DemonsDue.java b/Mage.Sets/src/mage/cards/d/DemonsDue.java new file mode 100644 index 00000000000..7cbb2ba9f29 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DemonsDue.java @@ -0,0 +1,35 @@ +package mage.cards.d; + +import java.util.UUID; + +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author weirddan455 + */ +public final class DemonsDue extends CardImpl { + + public DemonsDue(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}"); + + // Scry 2, then draw 2 cards. You lose 2 life. + this.getSpellAbility().addEffect(new ScryEffect(2, false)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2).concatBy(", then")); + this.getSpellAbility().addEffect(new LoseLifeSourceControllerEffect(2)); + } + + private DemonsDue(final DemonsDue card) { + super(card); + } + + @Override + public DemonsDue copy() { + return new DemonsDue(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DenProtector.java b/Mage.Sets/src/mage/cards/d/DenProtector.java index b4ed3f67c31..2992d44ee38 100644 --- a/Mage.Sets/src/mage/cards/d/DenProtector.java +++ b/Mage.Sets/src/mage/cards/d/DenProtector.java @@ -34,7 +34,7 @@ public final class DenProtector extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeBlockedByCreaturesWithLessPowerEffect())); // Megamorph {1}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{G}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{G}"), true)); // When Den Protector is turned face up, return target card from your graveyard to your hand. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/d/DenseCanopy.java b/Mage.Sets/src/mage/cards/d/DenseCanopy.java index 7edf71bf51c..727959aef73 100644 --- a/Mage.Sets/src/mage/cards/d/DenseCanopy.java +++ b/Mage.Sets/src/mage/cards/d/DenseCanopy.java @@ -58,7 +58,7 @@ class DenseCanopyCantBlockEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filter.match(permanent, source.getControllerId(), source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/d/DenyingWind.java b/Mage.Sets/src/mage/cards/d/DenyingWind.java index aa69afb4acd..778c83dc83d 100644 --- a/Mage.Sets/src/mage/cards/d/DenyingWind.java +++ b/Mage.Sets/src/mage/cards/d/DenyingWind.java @@ -1,33 +1,23 @@ - package mage.cards.d; -import java.util.List; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.search.SearchLibraryAndExileTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.game.Game; -import mage.players.Player; import mage.target.TargetPlayer; -import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; /** - * * @author fireshoes */ public final class DenyingWind extends CardImpl { public DenyingWind(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{7}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{7}{U}{U}"); // Search target player's library for up to seven cards and exile them. Then that player shuffles their library. - getSpellAbility().addEffect(new DenyingWindEffect()); + getSpellAbility().addEffect(new SearchLibraryAndExileTargetEffect(7, true)); getSpellAbility().addTarget(new TargetPlayer()); } @@ -40,41 +30,3 @@ public final class DenyingWind extends CardImpl { return new DenyingWind(this); } } - -class DenyingWindEffect extends OneShotEffect { - - public DenyingWindEffect() { - super(Outcome.Neutral); - staticText = "search target player's library for up to seven cards and exile them. Then that player shuffles"; - } - - public DenyingWindEffect(final DenyingWindEffect effect) { - super(effect); - } - - @Override - public DenyingWindEffect copy() { - return new DenyingWindEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getFirstTarget()); - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null && player != null) { - TargetCardInLibrary target = new TargetCardInLibrary(0, 7, new FilterCard("cards from player's library to exile")); - if (controller.searchLibrary(target, source, game, player.getId())) { - List targets = target.getTargets(); - for (UUID targetId : targets) { - Card card = player.getLibrary().remove(targetId, game); - if (card != null) { - controller.moveCardToExileWithInfo(card, null, null, source, game, Zone.LIBRARY, true); - } - } - } - player.shuffleLibrary(source, game); - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DeployTheGatewatch.java b/Mage.Sets/src/mage/cards/d/DeployTheGatewatch.java index 0b4b5919c00..9bd9d851b9b 100644 --- a/Mage.Sets/src/mage/cards/d/DeployTheGatewatch.java +++ b/Mage.Sets/src/mage/cards/d/DeployTheGatewatch.java @@ -2,29 +2,29 @@ package mage.cards.d; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.filter.FilterCard; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; +import mage.filter.common.FilterPlaneswalkerCard; /** * - * @author fireshoes + * @author awjackson */ public final class DeployTheGatewatch extends CardImpl { + private static final FilterCard filter = new FilterPlaneswalkerCard("planeswalker cards"); + public DeployTheGatewatch(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}{W}"); // Look at the top seven cards of your library. Put up to two planeswalker cards from among them onto the battlefield. // Put the rest on the bottom of your library in a random order. - this.getSpellAbility().addEffect(new DeployTheGatewatchEffect()); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + 7, 2, filter, PutCards.BATTLEFIELD, PutCards.BOTTOM_RANDOM, false)); } private DeployTheGatewatch(final DeployTheGatewatch card) { @@ -36,50 +36,3 @@ public final class DeployTheGatewatch extends CardImpl { return new DeployTheGatewatch(this); } } - -class DeployTheGatewatchEffect extends OneShotEffect { - - private static final FilterCard filter = new FilterCard("up to two planeswalker cards"); - - static { - filter.add(CardType.PLANESWALKER.getPredicate()); - } - - public DeployTheGatewatchEffect() { - super(Outcome.DrawCard); - this.staticText = "Look at the top seven cards of your library. Put up to two planeswalker cards from among them onto the battlefield. " - + "Put the rest on the bottom of your library in a random order"; - } - - public DeployTheGatewatchEffect(final DeployTheGatewatchEffect effect) { - super(effect); - } - - @Override - public DeployTheGatewatchEffect copy() { - return new DeployTheGatewatchEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - // Look at the top seven cards of your library. - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 7)); - controller.lookAtCards(source, null, cards, game); - // Put up to two planeswalker cards from among them onto the battlefield. - if (cards.count(filter, game) > 0) { - TargetCard target = new TargetCard(0, 2, Zone.LIBRARY, filter); - if (controller.choose(Outcome.DrawCard, cards, target, game)) { - Cards pickedCards = new CardsImpl(target.getTargets()); - cards.removeAll(pickedCards); - controller.moveCards(pickedCards.getCards(game), Zone.BATTLEFIELD, source, game); - } - } - // Put the rest on the bottom of your library in a random order - controller.putCardsOnBottomOfLibrary(cards, game, source, false); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/d/Depopulate.java b/Mage.Sets/src/mage/cards/d/Depopulate.java new file mode 100644 index 00000000000..0e9d9187a7d --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/Depopulate.java @@ -0,0 +1,88 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.MulticoloredPredicate; +import mage.game.Controllable; +import mage.game.Game; +import mage.players.Player; + +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class Depopulate extends CardImpl { + + public Depopulate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}{W}"); + + // Each player who controls a multicolored creature draws a card. Then destroy all creatures. + this.getSpellAbility().addEffect(new DepopulateEffect()); + this.getSpellAbility().addEffect(new DestroyAllEffect( + StaticFilters.FILTER_PERMANENT_CREATURES + ).concatBy("Then")); + } + + private Depopulate(final Depopulate card) { + super(card); + } + + @Override + public Depopulate copy() { + return new Depopulate(this); + } +} + +class DepopulateEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(MulticoloredPredicate.instance); + } + + DepopulateEffect() { + super(Outcome.Benefit); + staticText = "each player who controls a multicolored creature draws a card"; + } + + private DepopulateEffect(final DepopulateEffect effect) { + super(effect); + } + + @Override + public DepopulateEffect copy() { + return new DepopulateEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Set players = game + .getBattlefield() + .getActivePermanents(filter, source.getControllerId(), game) + .stream() + .map(Controllable::getControllerId) + .collect(Collectors.toSet()); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + if (!players.contains(playerId)) { + continue; + } + Player player = game.getPlayer(playerId); + if (player != null) { + player.drawCards(1, source, game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/d/Dermoplasm.java b/Mage.Sets/src/mage/cards/d/Dermoplasm.java index 465970fec0c..43a4dc73f50 100644 --- a/Mage.Sets/src/mage/cards/d/Dermoplasm.java +++ b/Mage.Sets/src/mage/cards/d/Dermoplasm.java @@ -39,7 +39,7 @@ public final class Dermoplasm extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Morph {2}{U}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{U}{U}"))); // When Dermoplasm is turned face up, you may put a creature card with a morph ability from your hand onto the battlefield face up. If you do, return Dermoplasm to its owner's hand. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new DermoplasmEffect())); diff --git a/Mage.Sets/src/mage/cards/d/Dermotaxi.java b/Mage.Sets/src/mage/cards/d/Dermotaxi.java index dc1940d6325..675717c2dbf 100644 --- a/Mage.Sets/src/mage/cards/d/Dermotaxi.java +++ b/Mage.Sets/src/mage/cards/d/Dermotaxi.java @@ -88,7 +88,7 @@ class DermotaxiImprintEffect extends OneShotEffect { if (!target.canChoose(source.getControllerId(), game)) { return false; } - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card == null) { return false; diff --git a/Mage.Sets/src/mage/cards/d/DescendantsPath.java b/Mage.Sets/src/mage/cards/d/DescendantsPath.java index 60ea0e591d7..15a5132abcc 100644 --- a/Mage.Sets/src/mage/cards/d/DescendantsPath.java +++ b/Mage.Sets/src/mage/cards/d/DescendantsPath.java @@ -1,8 +1,5 @@ package mage.cards.d; -import java.util.UUID; -import mage.ApprovingObject; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -13,15 +10,16 @@ import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.TargetController; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author noxx - * */ public final class DescendantsPath extends CardImpl { @@ -31,8 +29,7 @@ public final class DescendantsPath extends CardImpl { // At the beginning of your upkeep, reveal the top card of your library. // If it's a creature card that shares a creature type with a creature you control, // you may cast that card without paying its mana cost. Otherwise, put that card on the bottom of your library. - Ability ability = new BeginningOfUpkeepTriggeredAbility(new DescendantsPathEffect(), TargetController.YOU, false); - this.addAbility(ability); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DescendantsPathEffect(), TargetController.YOU, false)); } private DescendantsPath(final DescendantsPath card) { @@ -67,46 +64,27 @@ class DescendantsPathEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { - if (controller.getLibrary().hasCards()) { - Card card = controller.getLibrary().getFromTop(game); - if (card == null) { - return false; - } - controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game); - if (card.isCreature(game)) { - FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - boolean found = false; - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controller.getId(), game)) { - if (card.shareCreatureTypes(game, permanent)) { - found = true; - break; - } - } - if (found) { - game.informPlayers(sourceObject.getLogName() + ": Found a creature that shares a creature type with the revealed card."); - if (controller.chooseUse(Outcome.Benefit, "Cast the card?", source, game)) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - } else { - game.informPlayers(sourceObject.getLogName() + ": " + controller.getLogName() + " canceled casting the card."); - controller.getLibrary().putOnBottom(card, game); - } - } else { - game.informPlayers(sourceObject.getLogName() + ": No creature that shares a creature type with the revealed card."); - controller.getLibrary().putOnBottom(card, game); - } - } else { - game.informPlayers(sourceObject.getLogName() + ": Put " + card.getLogName() + " on the bottom."); - controller.getLibrary().putOnBottom(card, game); - } - - return true; - } + if (controller == null) { + return false; } - return false; + Card card = controller.getLibrary().getFromTop(game); + if (card == null) { + return false; + } + controller.revealCards(source, new CardsImpl(card), game); + if (card.isCreature(game) + && game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, + source.getControllerId(), source, game + ).stream() + .anyMatch(permanent -> permanent.shareCreatureTypes(game, card))) { + CardUtil.castSpellWithAttributesForFree(controller, source, game, card); + } + if (game.getState().getZone(card.getId()) == Zone.LIBRARY) { + controller.putCardsOnBottomOfLibrary(card, game, source, false); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/d/DescentIntoMadness.java b/Mage.Sets/src/mage/cards/d/DescentIntoMadness.java index 56369a1da37..3bbcf50039d 100644 --- a/Mage.Sets/src/mage/cards/d/DescentIntoMadness.java +++ b/Mage.Sets/src/mage/cards/d/DescentIntoMadness.java @@ -149,8 +149,8 @@ class DescentIntoMadnessEffect extends OneShotEffect { filter.add(Predicates.not(Predicates.or(uuidPredicates))); target = new TargetControlledPermanent(0, 1, filter, true); - if (target.canChoose(source.getSourceId(), player.getId(), game) - && player.choose(Outcome.Exile, target, source.getSourceId(), game)) { + if (target.canChoose(player.getId(), source, game) + && player.choose(Outcome.Exile, target, source, game)) { for (UUID targetId : target.getTargets()) { if (!selectedObjects.contains(targetId)) { Permanent chosen = game.getPermanent(targetId); @@ -174,7 +174,7 @@ class DescentIntoMadnessEffect extends OneShotEffect { uuidPredicates.add(new CardIdPredicate(uuid)); } filterInHand.add(Predicates.not(Predicates.or(uuidPredicates))); - if (targetInHand.canChoose(source.getSourceId(), player.getId(), game) && + if (targetInHand.canChoose(player.getId(), source, game) && player.choose(Outcome.Exile, player.getHand(), targetInHand, game)) { Card card = player.getHand().get(targetInHand.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/cards/d/DesecrationDemon.java b/Mage.Sets/src/mage/cards/d/DesecrationDemon.java index 1991ae3a46a..90bd9124845 100644 --- a/Mage.Sets/src/mage/cards/d/DesecrationDemon.java +++ b/Mage.Sets/src/mage/cards/d/DesecrationDemon.java @@ -73,10 +73,10 @@ class DesecrationDemonEffect extends OneShotEffect { filter.add(CardType.CREATURE.getPredicate()); filter.add(TargetController.YOU.getControllerPredicate()); TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, false); - if (target.canChoose(source.getSourceId(), opponent.getId(), game)) { + if (target.canChoose(opponent.getId(), source, game)) { if (opponent.chooseUse(Outcome.AIDontUseIt, "Sacrifice a creature to tap " + descrationDemon.getLogName() + "and put a +1/+1 counter on it?", source, game)) { - opponent.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + opponent.choose(Outcome.Sacrifice, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.sacrifice(source, game); diff --git a/Mage.Sets/src/mage/cards/d/DesertsHold.java b/Mage.Sets/src/mage/cards/d/DesertsHold.java index e5991d4ed3d..6a2a3883f1c 100644 --- a/Mage.Sets/src/mage/cards/d/DesertsHold.java +++ b/Mage.Sets/src/mage/cards/d/DesertsHold.java @@ -1,13 +1,8 @@ - package mage.cards.d; -import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.OrCondition; -import mage.abilities.condition.common.CardsInControllerGraveyardCondition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.condition.common.DesertControlledOrGraveyardCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.GainLifeEffect; @@ -18,25 +13,16 @@ 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.common.FilterControlledPermanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author emerald000 */ public final class DesertsHold extends CardImpl { - private static final FilterControlledPermanent filterDesertPermanent = new FilterControlledPermanent("Desert"); - private static final FilterCard filterDesertCard = new FilterCard("Desert card"); - static { - filterDesertPermanent.add(SubType.DESERT.getPredicate()); - filterDesertCard.add(SubType.DESERT.getPredicate()); - } - public DesertsHold(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); @@ -46,19 +32,17 @@ public final class DesertsHold extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Removal)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // When Desert's Hold enters the battlefield, if you control a Desert or there is a Desert card in your graveyard, you gain 3 life. this.addAbility(new ConditionalInterveningIfTriggeredAbility( new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3)), - new OrCondition( - new PermanentsOnTheBattlefieldCondition(new FilterControlledPermanent(filterDesertPermanent)), - new CardsInControllerGraveyardCondition(1, filterDesertCard)), - "When {this} enters the battlefield, if you control a Desert or there is a Desert card in your graveyard, you gain 3 life.")); + DesertControlledOrGraveyardCondition.instance, "When {this} enters the battlefield, " + + "if you control a Desert or there is a Desert card in your graveyard, you gain 3 life." + ).addHint(DesertControlledOrGraveyardCondition.getHint())); // Enchanted creature can't attack or block, and its activated abilities can't be activated. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBlockAttackActivateAttachedEffect())); + this.addAbility(new SimpleStaticAbility(new CantBlockAttackActivateAttachedEffect())); } private DesertsHold(final DesertsHold card) { diff --git a/Mage.Sets/src/mage/cards/d/Desolation.java b/Mage.Sets/src/mage/cards/d/Desolation.java index ab24fda9780..e71475caaf7 100644 --- a/Mage.Sets/src/mage/cards/d/Desolation.java +++ b/Mage.Sets/src/mage/cards/d/Desolation.java @@ -69,10 +69,10 @@ class DesolationEffect extends OneShotEffect { } TargetPermanent target = new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), player.getId(), game)) { + if (!target.canChoose(player.getId(), source, game)) { continue; } - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + player.choose(Outcome.Sacrifice, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanents.add(permanent); diff --git a/Mage.Sets/src/mage/cards/d/DesperateGambit.java b/Mage.Sets/src/mage/cards/d/DesperateGambit.java index 2e9d4d1ce22..d516d09dfd6 100644 --- a/Mage.Sets/src/mage/cards/d/DesperateGambit.java +++ b/Mage.Sets/src/mage/cards/d/DesperateGambit.java @@ -65,7 +65,7 @@ class DesperateGambitEffect extends PreventionEffectImpl { @Override public void init(Ability source, Game game) { - this.target.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), game); + this.target.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), source, game); Player you = game.getPlayer(source.getControllerId()); if(you != null) { wonFlip = you.flipCoin(source, game, true); diff --git a/Mage.Sets/src/mage/cards/d/DespoilerOfSouls.java b/Mage.Sets/src/mage/cards/d/DespoilerOfSouls.java index 523cf9ba436..4e2067a33df 100644 --- a/Mage.Sets/src/mage/cards/d/DespoilerOfSouls.java +++ b/Mage.Sets/src/mage/cards/d/DespoilerOfSouls.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.CantBlockAbility; @@ -16,29 +14,37 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class DespoilerOfSouls extends CardImpl { - + + private static final FilterCard filter = new FilterCreatureCard("two other creature cards from your graveyard"); + + static { + filter.add(AnotherPredicate.instance); + } + public DespoilerOfSouls(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{B}"); this.subtype.add(SubType.HORROR); this.power = new MageInt(3); this.toughness = new MageInt(1); // Despoiler of Souls can't block. this.addAbility(new CantBlockAbility()); - + // {B}{B}, Exile two other creature cards from your graveyard: Return Despoiler of Souls from your graveyard to the battlefield. - FilterCard filter = new FilterCreatureCard("two other creature cards from your graveyard"); - filter.add(Predicates.not(new CardIdPredicate(this.getId()))); - Ability ability = new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(false), new ManaCostsImpl("{B}{B}")); + Ability ability = new SimpleActivatedAbility( + Zone.GRAVEYARD, + new ReturnSourceFromGraveyardToBattlefieldEffect(false), + new ManaCostsImpl<>("{B}{B}") + ); ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(2, filter))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DestructiveTampering.java b/Mage.Sets/src/mage/cards/d/DestructiveTampering.java index 03cea1bd220..7716d0b5719 100644 --- a/Mage.Sets/src/mage/cards/d/DestructiveTampering.java +++ b/Mage.Sets/src/mage/cards/d/DestructiveTampering.java @@ -36,8 +36,7 @@ public final class DestructiveTampering extends CardImpl { this.getSpellAbility().addTarget(new TargetArtifactPermanent()); // * Creatures without flying can't block this turn. - Mode mode = new Mode(); - mode.addEffect(new CantBlockAllEffect(filter, Duration.EndOfTurn)); + Mode mode = new Mode(new CantBlockAllEffect(filter, Duration.EndOfTurn)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/d/DetentionSphere.java b/Mage.Sets/src/mage/cards/d/DetentionSphere.java index eb162004602..2737ad3267c 100644 --- a/Mage.Sets/src/mage/cards/d/DetentionSphere.java +++ b/Mage.Sets/src/mage/cards/d/DetentionSphere.java @@ -77,7 +77,7 @@ class DetentionSphereEntersEffect extends OneShotEffect { UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && exileId != null && targetPermanent != null && controller != null) { if (CardUtil.haveEmptyName(targetPermanent)) { // face down creature diff --git a/Mage.Sets/src/mage/cards/d/DeterminedIteration.java b/Mage.Sets/src/mage/cards/d/DeterminedIteration.java new file mode 100644 index 00000000000..f6ecda1604c --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DeterminedIteration.java @@ -0,0 +1,79 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PopulateEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HasteAbility; +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.game.Game; +import mage.target.targetpointer.FixedTargets; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DeterminedIteration extends CardImpl { + + public DeterminedIteration(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + + // At the beginning of combat on your turn, populate. The token created this way gains haste. Sacrifice it at the beginning of the next end step. + this.addAbility(new BeginningOfCombatTriggeredAbility( + new DeterminedIterationEffect(), TargetController.YOU, false + )); + } + + private DeterminedIteration(final DeterminedIteration card) { + super(card); + } + + @Override + public DeterminedIteration copy() { + return new DeterminedIteration(this); + } +} + +class DeterminedIterationEffect extends OneShotEffect { + + DeterminedIterationEffect() { + super(Outcome.Benefit); + staticText = "populate. The token created this way gains haste. Sacrifice it at the beginning of the " + + "next end step. (To populate, create a token that's a copy of a creature token you control.)"; + } + + private DeterminedIterationEffect(final DeterminedIterationEffect effect) { + super(effect); + } + + @Override + public DeterminedIterationEffect copy() { + return new DeterminedIterationEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + PopulateEffect effect = new PopulateEffect(); + effect.apply(game, source); + if (effect.getAddedPermanents().isEmpty()) { + return false; + } + game.addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.Custom + ).setTargetPointer(new FixedTargets(effect.getAddedPermanents(), game)), source); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new SacrificeTargetEffect("sacrifice the token") + .setTargetPointer(new FixedTargets(effect.getAddedPermanents(), game)) + ), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/d/Detritivore.java b/Mage.Sets/src/mage/cards/d/Detritivore.java index c0f8ef457d5..ed04f93a184 100644 --- a/Mage.Sets/src/mage/cards/d/Detritivore.java +++ b/Mage.Sets/src/mage/cards/d/Detritivore.java @@ -24,7 +24,6 @@ import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.players.Player; import mage.target.common.TargetNonBasicLandPermanent; @@ -113,7 +112,7 @@ class NonBasicLandsInOpponentsGraveyards implements DynamicValue { if (controller.hasOpponent(playerUUID, game)) { Player player = game.getPlayer(playerUUID); if (player != null) { - amount += player.getGraveyard().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + amount += player.getGraveyard().count(filter, sourceAbility.getControllerId(), sourceAbility, game); } } } diff --git a/Mage.Sets/src/mage/cards/d/DevastatingMastery.java b/Mage.Sets/src/mage/cards/d/DevastatingMastery.java index 204e2298e46..01e48fcba33 100644 --- a/Mage.Sets/src/mage/cards/d/DevastatingMastery.java +++ b/Mage.Sets/src/mage/cards/d/DevastatingMastery.java @@ -89,7 +89,7 @@ class DevastatingMasteryAlternativeCostEffect extends OneShotEffect { TargetPermanent target = new TargetPermanent( 0, 2, StaticFilters.FILTER_PERMANENTS_NON_LAND, true ); - opponent.choose(Outcome.ReturnToHand, target, source.getSourceId(), game); + opponent.choose(Outcome.ReturnToHand, target, source, game); return opponent.moveCards(new CardsImpl(target.getTargets()), Zone.HAND, source, game); } } diff --git a/Mage.Sets/src/mage/cards/d/DevilishValet.java b/Mage.Sets/src/mage/cards/d/DevilishValet.java new file mode 100644 index 00000000000..3933fd941d7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DevilishValet.java @@ -0,0 +1,81 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AllianceAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; +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.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DevilishValet extends CardImpl { + + public DevilishValet(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.DEVIL); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Alliance — Whenever another creature enters the battlefield under your control, double Devilish Valet's power until end of turn. + this.addAbility(new AllianceAbility(new DevilishValetEffect())); + } + + private DevilishValet(final DevilishValet card) { + super(card); + } + + @Override + public DevilishValet copy() { + return new DevilishValet(this); + } +} + +class DevilishValetEffect extends OneShotEffect { + + DevilishValetEffect() { + super(Outcome.Benefit); + staticText = "double {this}'s power until end of turn"; + } + + private DevilishValetEffect(final DevilishValetEffect effect) { + super(effect); + } + + @Override + public DevilishValetEffect copy() { + return new DevilishValetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + return false; + } + game.addEffect(new BoostSourceEffect( + permanent.getPower().getValue(), 0, Duration.EndOfTurn + ), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DevourFlesh.java b/Mage.Sets/src/mage/cards/d/DevourFlesh.java index 2526ef94c78..7a129dde457 100644 --- a/Mage.Sets/src/mage/cards/d/DevourFlesh.java +++ b/Mage.Sets/src/mage/cards/d/DevourFlesh.java @@ -66,7 +66,7 @@ class DevourFleshSacrificeEffect extends OneShotEffect { int realCount = game.getBattlefield().countAll(filter, player.getId(), game); if (realCount > 0) { Target target = new TargetControlledPermanent(1, 1, filter, true); - while (player.canRespond() && !target.isChosen() && target.canChoose(source.getSourceId(), player.getId(), game)) { + while (player.canRespond() && !target.isChosen() && target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Sacrifice, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/d/DevouringHellion.java b/Mage.Sets/src/mage/cards/d/DevouringHellion.java index fe3be168fad..5a547c90b37 100644 --- a/Mage.Sets/src/mage/cards/d/DevouringHellion.java +++ b/Mage.Sets/src/mage/cards/d/DevouringHellion.java @@ -81,7 +81,7 @@ class DevouringHellionEffect extends OneShotEffect { return false; } Target target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); - if (!player.choose(outcome, target, source.getSourceId(), game)) { + if (!player.choose(outcome, target, source, game)) { return false; } int xValue = 0; diff --git a/Mage.Sets/src/mage/cards/d/DevoutInvocation.java b/Mage.Sets/src/mage/cards/d/DevoutInvocation.java index 567c3b194e6..fb8681984cf 100644 --- a/Mage.Sets/src/mage/cards/d/DevoutInvocation.java +++ b/Mage.Sets/src/mage/cards/d/DevoutInvocation.java @@ -67,7 +67,7 @@ class DevoutInvocationEffect extends OneShotEffect { } TargetPermanent target = new TargetControlledPermanent(0, Integer.MAX_VALUE, DevoutInvocation.filter, true); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); if (target.getTargets().isEmpty()) { return false; } diff --git a/Mage.Sets/src/mage/cards/d/DhalsimPliablePacifist.java b/Mage.Sets/src/mage/cards/d/DhalsimPliablePacifist.java new file mode 100644 index 00000000000..dd864834dda --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DhalsimPliablePacifist.java @@ -0,0 +1,198 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.AttacksCreatureYouControlTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.SourceAttackingCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.game.Game; +import mage.game.events.DamagedPlayerEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DhalsimPliablePacifist extends CardImpl { + + private static final Condition condition = new InvertCondition(SourceAttackingCondition.instance); + private static final FilterControlledCreaturePermanent filter + = new FilterControlledCreaturePermanent("a creature you control with reach"); + + static { + filter.add(new AbilityPredicate(ReachAbility.class)); + } + + public DhalsimPliablePacifist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MONK); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Teleport—Dhalsim, Pliable Pacifist has hexproof unless he's attacking. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(HexproofAbility.getInstance()), + condition, "{this} has hexproof unless he's attacking" + )).withFlavorWord("Teleport")); + + // Whenever a creature you control with reach attacks, untap it and it can't be blocked by creatures with greater power this combat. + this.addAbility(new AttacksCreatureYouControlTriggeredAbility( + new DhalsimPliablePacifistEffect(), false, filter, true + )); + + // Fierce Punch—Whenever one or more creatures you control deal combat damage to a player, draw a card. + this.addAbility(new DhalsimPliablePacifistTriggeredAbility()); + } + + private DhalsimPliablePacifist(final DhalsimPliablePacifist card) { + super(card); + } + + @Override + public DhalsimPliablePacifist copy() { + return new DhalsimPliablePacifist(this); + } +} + +class DhalsimPliablePacifistEffect extends OneShotEffect { + + DhalsimPliablePacifistEffect() { + super(Outcome.Benefit); + staticText = "untap it and it can't be blocked by creatures with greater power this combat"; + } + + private DhalsimPliablePacifistEffect(final DhalsimPliablePacifistEffect effect) { + super(effect); + } + + @Override + public DhalsimPliablePacifistEffect copy() { + return new DhalsimPliablePacifistEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + return false; + } + permanent.untap(game); + game.addEffect(new DhalsimPliablePacifistBlockEffect(permanent, game), source); + return true; + } +} + +class DhalsimPliablePacifistBlockEffect extends RestrictionEffect { + + private final MageObjectReference mor; + + DhalsimPliablePacifistBlockEffect(Permanent permanent, Game game) { + super(Duration.EndOfTurn); + this.mor = new MageObjectReference(permanent, game); + } + + private DhalsimPliablePacifistBlockEffect(final DhalsimPliablePacifistBlockEffect effect) { + super(effect); + this.mor = effect.mor; + } + + @Override + public DhalsimPliablePacifistBlockEffect copy() { + return new DhalsimPliablePacifistBlockEffect(this); + } + + @Override + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + return false; + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + Permanent attacker = mor.getPermanent(game); + if (attacker == null) { + discard(); + return false; + } + return permanent.getPower().getValue() > attacker.getPower().getValue(); + } +} + +class DhalsimPliablePacifistTriggeredAbility extends TriggeredAbilityImpl { + + private final Set damagedPlayerIds = new HashSet<>(); + + DhalsimPliablePacifistTriggeredAbility() { + super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), false); + this.withFlavorWord("Fierce Punch"); + } + + private DhalsimPliablePacifistTriggeredAbility(final DhalsimPliablePacifistTriggeredAbility ability) { + super(ability); + } + + @Override + public DhalsimPliablePacifistTriggeredAbility copy() { + return new DhalsimPliablePacifistTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER + || event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_PRIORITY + || event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_PRIORITY || + (event.getType() == GameEvent.EventType.ZONE_CHANGE && event.getTargetId().equals(getSourceId()))) { + damagedPlayerIds.clear(); + return false; + } + if (event.getType() != GameEvent.EventType.DAMAGED_PLAYER) { + return false; + } + DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; + Permanent permanent = game.getPermanent(event.getSourceId()); + if (!damageEvent.isCombatDamage() + || permanent == null + || !permanent.isControlledBy(this.getControllerId()) + || !permanent.isCreature(game) || + damagedPlayerIds.contains(event.getPlayerId())) { + return false; + } + damagedPlayerIds.add(event.getPlayerId()); + return true; + } + + @Override + public String getTriggerPhrase() { + return "Whenever one or more creatures you control deal combat damage to a player, "; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DiabolicRevelation.java b/Mage.Sets/src/mage/cards/d/DiabolicRevelation.java index b2a0598d11a..42bd43284fc 100644 --- a/Mage.Sets/src/mage/cards/d/DiabolicRevelation.java +++ b/Mage.Sets/src/mage/cards/d/DiabolicRevelation.java @@ -57,8 +57,13 @@ class DiabolicRevelationEffect extends OneShotEffect { if (player == null) { return false; } + int xValue = source.getManaCostsToPay().getX(); + if (xValue < 1) { + player.shuffleLibrary(source, game); + return true; + } TargetCardInLibrary target = new TargetCardInLibrary( - 0, source.getManaCostsToPay().getX(), StaticFilters.FILTER_CARD + 0, xValue, StaticFilters.FILTER_CARD ); player.searchLibrary(target, source, game); Cards cards = new CardsImpl(); diff --git a/Mage.Sets/src/mage/cards/d/DiabolicVision.java b/Mage.Sets/src/mage/cards/d/DiabolicVision.java index dc05352ce62..8a422cfc068 100644 --- a/Mage.Sets/src/mage/cards/d/DiabolicVision.java +++ b/Mage.Sets/src/mage/cards/d/DiabolicVision.java @@ -1,13 +1,11 @@ - package mage.cards.d; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterCard; /** * @@ -19,7 +17,7 @@ public final class DiabolicVision extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}{B}"); // Look at the top five cards of your library. Put one of them into your hand and the rest on top of your library in any order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(5), false, StaticValue.get(1), new FilterCard(), true, false)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(5, 1, PutCards.HAND, PutCards.TOP_ANY)); } private DiabolicVision(final DiabolicVision card) { diff --git a/Mage.Sets/src/mage/cards/d/DiffusionSliver.java b/Mage.Sets/src/mage/cards/d/DiffusionSliver.java index 80fced50b9f..6ea1e05da49 100644 --- a/Mage.Sets/src/mage/cards/d/DiffusionSliver.java +++ b/Mage.Sets/src/mage/cards/d/DiffusionSliver.java @@ -14,7 +14,6 @@ import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; @@ -74,7 +73,7 @@ class DiffusionSliverTriggeredAbility extends TriggeredAbilityImpl { return false; } Permanent creature = game.getPermanent(event.getTargetId()); - if (creature == null || !filter.match(creature, getSourceId(), getControllerId(), game)) { + if (creature == null || !filter.match(creature, getControllerId(), this, game)) { return false; } this.getEffects().clear(); diff --git a/Mage.Sets/src/mage/cards/d/DigThroughTime.java b/Mage.Sets/src/mage/cards/d/DigThroughTime.java index 743560efe5a..b9a8c554ca1 100644 --- a/Mage.Sets/src/mage/cards/d/DigThroughTime.java +++ b/Mage.Sets/src/mage/cards/d/DigThroughTime.java @@ -1,13 +1,11 @@ package mage.cards.d; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.DelveAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.FilterCard; import java.util.UUID; @@ -23,7 +21,7 @@ public final class DigThroughTime extends CardImpl { this.addAbility(new DelveAbility()); // Look at the top seven cards of your library. Put two of them into your hand and the rest on the bottom of your library in any order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(7), false, StaticValue.get(2), new FilterCard(), Zone.LIBRARY, false, false)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(7, 2, PutCards.HAND, PutCards.BOTTOM_ANY)); } private DigThroughTime(final DigThroughTime card) { diff --git a/Mage.Sets/src/mage/cards/d/DigUpTheBody.java b/Mage.Sets/src/mage/cards/d/DigUpTheBody.java new file mode 100644 index 00000000000..28dbdad5e65 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DigUpTheBody.java @@ -0,0 +1,80 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.CasualtyAbility; +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.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DigUpTheBody extends CardImpl { + + public DigUpTheBody(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); + + // Casualty 1 + this.addAbility(new CasualtyAbility(this, 1)); + + // Mill two cards, then return a creature card from your graveyard to your hand. + this.getSpellAbility().addEffect(new DigUpTheBodyEffect()); + } + + private DigUpTheBody(final DigUpTheBody card) { + super(card); + } + + @Override + public DigUpTheBody copy() { + return new DigUpTheBody(this); + } +} + +class DigUpTheBodyEffect extends OneShotEffect { + + DigUpTheBodyEffect() { + super(Outcome.Benefit); + staticText = "mill two cards, then you may return a creature card from your graveyard to your hand"; + } + + private DigUpTheBodyEffect(final DigUpTheBodyEffect effect) { + super(effect); + } + + @Override + public DigUpTheBodyEffect copy() { + return new DigUpTheBodyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + player.millCards(2, source, game); + TargetCard target = new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); + target.setNotTarget(true); + if (!target.canChoose(source.getControllerId(), source, game)) { + return true; + } + player.choose(outcome, target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + player.moveCards(card, Zone.HAND, source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DimirCharm.java b/Mage.Sets/src/mage/cards/d/DimirCharm.java index 8a557c1a931..353f09eeed2 100644 --- a/Mage.Sets/src/mage/cards/d/DimirCharm.java +++ b/Mage.Sets/src/mage/cards/d/DimirCharm.java @@ -45,14 +45,12 @@ public final class DimirCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetSpell(filterSorcery)); //or destroy target creature with power 2 or less - Mode mode1 = new Mode(); - mode1.addEffect(new DestroyTargetEffect()); + Mode mode1 = new Mode(new DestroyTargetEffect()); mode1.addTarget(new TargetCreaturePermanent(filterCreature)); this.getSpellAbility().addMode(mode1); //or look at the top three cards of target player's library, then put one back and the rest into that player's graveyard - Mode mode2 = new Mode(); - mode2.addEffect(new DimirCharmEffect()); + Mode mode2 = new Mode(new DimirCharmEffect()); mode2.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode2); } diff --git a/Mage.Sets/src/mage/cards/d/DirgurNemesis.java b/Mage.Sets/src/mage/cards/d/DirgurNemesis.java index 65e8bbc68d9..5d4abc3ec8b 100644 --- a/Mage.Sets/src/mage/cards/d/DirgurNemesis.java +++ b/Mage.Sets/src/mage/cards/d/DirgurNemesis.java @@ -26,7 +26,7 @@ public final class DirgurNemesis extends CardImpl { // Defender this.addAbility(DefenderAbility.getInstance()); // Megamorph {6}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{6}{U}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{6}{U}"), true)); } private DirgurNemesis(final DirgurNemesis card) { diff --git a/Mage.Sets/src/mage/cards/d/DiscerningTaste.java b/Mage.Sets/src/mage/cards/d/DiscerningTaste.java index 7a1bf6eb6f9..af77e13612f 100644 --- a/Mage.Sets/src/mage/cards/d/DiscerningTaste.java +++ b/Mage.Sets/src/mage/cards/d/DiscerningTaste.java @@ -4,14 +4,13 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; @@ -41,10 +40,8 @@ public final class DiscerningTaste extends CardImpl { class DiscerningTasteEffect extends LookLibraryAndPickControllerEffect { - public DiscerningTasteEffect() { - super(StaticValue.get(4), false, StaticValue.get(1), StaticFilters.FILTER_CARD, Zone.GRAVEYARD, - false, false, false, Zone.HAND, false, false, false - ); + DiscerningTasteEffect() { + super(4, 1, PutCards.HAND, PutCards.GRAVEYARD); } private DiscerningTasteEffect(final DiscerningTasteEffect effect) { @@ -57,16 +54,17 @@ class DiscerningTasteEffect extends LookLibraryAndPickControllerEffect { } @Override - protected void putCardsBack(Ability source, Player player, Cards cards, Game game) { + protected boolean actionWithPickedCards(Game game, Ability source, Player player, Cards pickedCards, Cards otherCards) { + super.actionWithPickedCards(game, source, player, pickedCards, otherCards); int life = 0; - for (Card card : cards.getCards(StaticFilters.FILTER_CARD_CREATURE, game)) { + for (Card card : otherCards.getCards(StaticFilters.FILTER_CARD_CREATURE, game)) { int power = card.getPower().getValue(); if (power > life) { life = power; } } - player.moveCards(cards, Zone.GRAVEYARD, source, game); player.gainLife(life, game, source); + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/d/DiscipleOfBolas.java b/Mage.Sets/src/mage/cards/d/DiscipleOfBolas.java index 0cea7a7c65f..eaf4605b92a 100644 --- a/Mage.Sets/src/mage/cards/d/DiscipleOfBolas.java +++ b/Mage.Sets/src/mage/cards/d/DiscipleOfBolas.java @@ -68,7 +68,7 @@ class DiscipleOfBolasEffect extends OneShotEffect { if (controller != null) { Target target = new TargetControlledCreaturePermanent(1, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, true); target.setRequired(true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (target.canChoose(source.getControllerId(), source, game)) { controller.chooseTarget(outcome, target, source, game); Permanent sacrificed = game.getPermanent(target.getFirstTarget()); if (sacrificed != null) { diff --git a/Mage.Sets/src/mage/cards/d/DiscipleOfDeceit.java b/Mage.Sets/src/mage/cards/d/DiscipleOfDeceit.java index e93917805ea..1834f1c9d86 100644 --- a/Mage.Sets/src/mage/cards/d/DiscipleOfDeceit.java +++ b/Mage.Sets/src/mage/cards/d/DiscipleOfDeceit.java @@ -73,7 +73,7 @@ class DiscipleOfDeceitEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (player != null && mageObject != null) { Cost cost = new DiscardTargetCost(new TargetCardInHand(new FilterNonlandCard())); String message = "Discard a nonland card to search your library?"; diff --git a/Mage.Sets/src/mage/cards/d/DiscipleOfTheRing.java b/Mage.Sets/src/mage/cards/d/DiscipleOfTheRing.java index 62dbb1a2c40..5fe2032a404 100644 --- a/Mage.Sets/src/mage/cards/d/DiscipleOfTheRing.java +++ b/Mage.Sets/src/mage/cards/d/DiscipleOfTheRing.java @@ -44,19 +44,16 @@ public final class DiscipleOfTheRing extends CardImpl { ability.addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_NON_CREATURE)); // or Disciple of the Ring gets +1/+1 until end of turn; - Mode mode = new Mode(); - mode.addEffect(new BoostSourceEffect(1, 1, Duration.EndOfTurn)); + Mode mode = new Mode(new BoostSourceEffect(1, 1, Duration.EndOfTurn)); ability.addMode(mode); // or Tap target creature; - mode = new Mode(); - mode.addEffect(new TapTargetEffect()); + mode = new Mode(new TapTargetEffect()); mode.addTarget(new TargetCreaturePermanent()); ability.addMode(mode); // or Untap target creature. - mode = new Mode(); - mode.addEffect(new UntapTargetEffect()); + mode = new Mode(new UntapTargetEffect()); mode.addTarget(new TargetCreaturePermanent()); ability.addMode(mode); diff --git a/Mage.Sets/src/mage/cards/d/DisciplinedDuelist.java b/Mage.Sets/src/mage/cards/d/DisciplinedDuelist.java new file mode 100644 index 00000000000..46cdc772121 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DisciplinedDuelist.java @@ -0,0 +1,47 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DisciplinedDuelist extends CardImpl { + + public DisciplinedDuelist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Double strike + this.addAbility(DoubleStrikeAbility.getInstance()); + + // Disciplined Duelist enters the battlefield with a shield counter on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.SHIELD.createInstance(1)), + "with a shield counter on it. (If it would be dealt damage " + + "or destroyed, remove a shield counter from it instead.)" + )); + } + + private DisciplinedDuelist(final DisciplinedDuelist card) { + super(card); + } + + @Override + public DisciplinedDuelist copy() { + return new DisciplinedDuelist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DiscoverTheImpossible.java b/Mage.Sets/src/mage/cards/d/DiscoverTheImpossible.java new file mode 100644 index 00000000000..b4c8cb159a2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DiscoverTheImpossible.java @@ -0,0 +1,92 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DiscoverTheImpossible extends CardImpl { + + public DiscoverTheImpossible(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}"); + + // Look at the top five cards of your library. Exile one of them face down and put the rest on the bottom of your library in a random order. You may cast the exiled card without paying its mana cost if it's an instant spell with mana value 2 or less. If you don't, put that card into your hand. + this.getSpellAbility().addEffect(new DiscoverTheImpossibleEffect()); + } + + private DiscoverTheImpossible(final DiscoverTheImpossible card) { + super(card); + } + + @Override + public DiscoverTheImpossible copy() { + return new DiscoverTheImpossible(this); + } +} + +class DiscoverTheImpossibleEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard(); + + static { + filter.add(CardType.INSTANT.getPredicate()); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 3)); + } + + DiscoverTheImpossibleEffect() { + super(Outcome.PlayForFree); + staticText = "look at the top five cards of your library. Exile one of them face down " + + "and put the rest on the bottom of your library in a random order. " + + "You may cast the exiled card without paying its mana cost if it's an instant spell " + + "with mana value 2 or less. If you don't, put that card into your hand"; + } + + private DiscoverTheImpossibleEffect(final DiscoverTheImpossibleEffect effect) { + super(effect); + } + + @Override + public DiscoverTheImpossibleEffect copy() { + return new DiscoverTheImpossibleEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 5)); + if (cards.isEmpty()) { + return false; + } + TargetCard target = new TargetCardInLibrary(); + player.choose(outcome, cards, target, game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + player.putCardsOnBottomOfLibrary(card, game, source, false); + return true; + } + player.moveCards(card, Zone.EXILED, source, game); + card.setFaceDown(true, game); + cards.retainZone(Zone.LIBRARY, game); + player.putCardsOnBottomOfLibrary(cards, game, source, false); + return CardUtil.castSpellWithAttributesForFree(player, source, game, new CardsImpl(card), filter) + || player.moveCards(card, Zone.HAND, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DiscoveryDispersal.java b/Mage.Sets/src/mage/cards/d/DiscoveryDispersal.java index 08cbf7a1024..83c78119a1c 100644 --- a/Mage.Sets/src/mage/cards/d/DiscoveryDispersal.java +++ b/Mage.Sets/src/mage/cards/d/DiscoveryDispersal.java @@ -104,7 +104,7 @@ class DispersalEffect extends OneShotEffect { filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, highestCMC)); filter.add(new ControllerIdPredicate(opponentId)); Target target = new TargetPermanent(1, 1, filter, true); - if (opponent.choose(outcome, target, source.getSourceId(), game)) { + if (opponent.choose(outcome, target, source, game)) { if (target.getFirstTarget() == null) { continue; } diff --git a/Mage.Sets/src/mage/cards/d/DiseasedVermin.java b/Mage.Sets/src/mage/cards/d/DiseasedVermin.java index ad0957bafaf..7b1c68458f1 100644 --- a/Mage.Sets/src/mage/cards/d/DiseasedVermin.java +++ b/Mage.Sets/src/mage/cards/d/DiseasedVermin.java @@ -23,7 +23,6 @@ import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPlayer; @@ -98,8 +97,8 @@ class DiseasedVerminEffect extends OneShotEffect { if (sourcePermanent != null && controller != null) { TargetPlayer targetOpponent = new TargetPlayer(1, 1, false, filter); - if (targetOpponent.canChoose(source.getSourceId(), controller.getId(), game) - && controller.choose(Outcome.Damage, targetOpponent, source.getSourceId(), game)) { + if (targetOpponent.canChoose(controller.getId(), source, game) + && controller.choose(Outcome.Damage, targetOpponent, source, game)) { Player opponent = game.getPlayer(targetOpponent.getFirstTarget()); if (opponent != null && sourcePermanent.getCounters(game).getCount(CounterType.INFECTION) > 0) { diff --git a/Mage.Sets/src/mage/cards/d/Disentomb.java b/Mage.Sets/src/mage/cards/d/Disentomb.java index 11de039761d..074d8d43233 100644 --- a/Mage.Sets/src/mage/cards/d/Disentomb.java +++ b/Mage.Sets/src/mage/cards/d/Disentomb.java @@ -1,16 +1,15 @@ - package mage.cards.d; -import java.util.UUID; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public final class Disentomb extends CardImpl { @@ -18,8 +17,8 @@ public final class Disentomb extends CardImpl { public Disentomb(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); } private Disentomb(final Disentomb card) { @@ -30,5 +29,4 @@ public final class Disentomb extends CardImpl { public Disentomb copy() { return new Disentomb(this); } - } diff --git a/Mage.Sets/src/mage/cards/d/Dismantle.java b/Mage.Sets/src/mage/cards/d/Dismantle.java index 023f24e1121..d18c739c372 100644 --- a/Mage.Sets/src/mage/cards/d/Dismantle.java +++ b/Mage.Sets/src/mage/cards/d/Dismantle.java @@ -72,7 +72,7 @@ class DismantleEffect extends OneShotEffect { permanent.destroy(source, game, false); if (counterCount > 0) { Target target = new TargetControlledPermanent(1, 1, new FilterControlledArtifactPermanent("an artifact you control"), true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { + if (target.canChoose(controller.getId(), source, game)) { controller.chooseTarget(Outcome.Benefit, target, source, game); Permanent artifact = game.getPermanent(target.getFirstTarget()); Counter counter; diff --git a/Mage.Sets/src/mage/cards/d/Dismiss.java b/Mage.Sets/src/mage/cards/d/Dismiss.java index d44576ef540..250610c941c 100644 --- a/Mage.Sets/src/mage/cards/d/Dismiss.java +++ b/Mage.Sets/src/mage/cards/d/Dismiss.java @@ -20,7 +20,7 @@ public final class Dismiss extends CardImpl { this.getSpellAbility().addEffect(new CounterTargetEffect()); this.getSpellAbility().addTarget(new TargetSpell()); - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private Dismiss(final Dismiss card) { diff --git a/Mage.Sets/src/mage/cards/d/Disorder.java b/Mage.Sets/src/mage/cards/d/Disorder.java index 3c6182bb79e..1a0fdd93b65 100644 --- a/Mage.Sets/src/mage/cards/d/Disorder.java +++ b/Mage.Sets/src/mage/cards/d/Disorder.java @@ -74,7 +74,7 @@ class DisorderEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { for (Player player : game .getBattlefield() - .getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game) + .getActivePermanents(filter, source.getControllerId(), source, game) .stream() .filter(Objects::nonNull) .map(Controllable::getControllerId) diff --git a/Mage.Sets/src/mage/cards/d/DisplayOfDominance.java b/Mage.Sets/src/mage/cards/d/DisplayOfDominance.java index 80deb4690ec..6bb8b129ab1 100644 --- a/Mage.Sets/src/mage/cards/d/DisplayOfDominance.java +++ b/Mage.Sets/src/mage/cards/d/DisplayOfDominance.java @@ -50,8 +50,7 @@ public final class DisplayOfDominance extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent(filter)); // or Permanents you control can't be the targets of blue or black spells your opponents control this turn - Mode mode = new Mode(); - mode.addEffect(new DisplayOfDominanceEffect()); + Mode mode = new Mode(new DisplayOfDominanceEffect()); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/d/DisruptingShoal.java b/Mage.Sets/src/mage/cards/d/DisruptingShoal.java index b0c7d91c62d..fc6d2df5859 100644 --- a/Mage.Sets/src/mage/cards/d/DisruptingShoal.java +++ b/Mage.Sets/src/mage/cards/d/DisruptingShoal.java @@ -14,8 +14,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.common.FilterOwnedCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.stack.Spell; @@ -29,15 +27,21 @@ import java.util.UUID; */ public final class DisruptingShoal extends CardImpl { + private static final FilterOwnedCard filter + = new FilterOwnedCard("a blue card with mana value X from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLUE)); + } + public DisruptingShoal(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{U}{U}"); this.subtype.add(SubType.ARCANE); // You may exile a blue card with converted mana cost X from your hand rather than pay Disrupting Shoal's mana cost. - FilterOwnedCard filter = new FilterOwnedCard("a blue card with mana value X from your hand"); - filter.add(new ColorPredicate(ObjectColor.BLUE)); - filter.add(Predicates.not(new CardIdPredicate(this.getId()))); // the exile cost can never be paid with the card itself - this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter), true))); + this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost( + new TargetCardInHand(filter), true + ))); // 2/1/2005: Disrupting Shoal can target any spell, but does nothing unless that spell's converted mana cost is X. // Counter target spell if its converted mana cost is X. @@ -96,5 +100,4 @@ class DisruptingShoalCounterTargetEffect extends OneShotEffect { public String getText(Mode mode) { return "Counter target spell if its mana value is X"; } - } diff --git a/Mage.Sets/src/mage/cards/d/DisruptionProtocol.java b/Mage.Sets/src/mage/cards/d/DisruptionProtocol.java index 017af341b2c..2dffb4ef3cd 100644 --- a/Mage.Sets/src/mage/cards/d/DisruptionProtocol.java +++ b/Mage.Sets/src/mage/cards/d/DisruptionProtocol.java @@ -32,8 +32,8 @@ public final class DisruptionProtocol extends CardImpl { // As an additional cost to cast this spell, tap an untapped artifact you control or pay {1}. this.getSpellAbility().addCost(new OrCost( - new TapTargetCost(new TargetControlledPermanent(filter)), - new GenericManaCost(1), "tap an untapped artifact you control or pay {1}" + "tap an untapped artifact you control or pay {1}", new TapTargetCost(new TargetControlledPermanent(filter)), + new GenericManaCost(1) )); // Counter target spell. diff --git a/Mage.Sets/src/mage/cards/d/DisruptivePitmage.java b/Mage.Sets/src/mage/cards/d/DisruptivePitmage.java index 3933fff5e46..3f08e35f643 100644 --- a/Mage.Sets/src/mage/cards/d/DisruptivePitmage.java +++ b/Mage.Sets/src/mage/cards/d/DisruptivePitmage.java @@ -36,7 +36,7 @@ public final class DisruptivePitmage extends CardImpl { this.addAbility(ability); // Morph {U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{U}"))); } private DisruptivePitmage(final DisruptivePitmage card) { diff --git a/Mage.Sets/src/mage/cards/d/DistantMelody.java b/Mage.Sets/src/mage/cards/d/DistantMelody.java index f36597a4b9e..9c9787df4ad 100644 --- a/Mage.Sets/src/mage/cards/d/DistantMelody.java +++ b/Mage.Sets/src/mage/cards/d/DistantMelody.java @@ -59,7 +59,7 @@ class DistantMelodyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Choice typeChoice = new ChoiceCreatureType(game.getObject(source.getSourceId())); + Choice typeChoice = new ChoiceCreatureType(game.getObject(source)); if (controller != null && controller.choose(Outcome.BoostCreature, typeChoice, game)) { FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); filter.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); diff --git a/Mage.Sets/src/mage/cards/d/DistantMemories.java b/Mage.Sets/src/mage/cards/d/DistantMemories.java index 715ef508ca8..9ae05462efa 100644 --- a/Mage.Sets/src/mage/cards/d/DistantMemories.java +++ b/Mage.Sets/src/mage/cards/d/DistantMemories.java @@ -63,7 +63,7 @@ class DistantMemoriesEffect extends OneShotEffect { TargetCardInLibrary target = new TargetCardInLibrary(); if (controller.searchLibrary(target, source, game)) { - Card card = controller.getLibrary().remove(target.getFirstTarget(), game); + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { controller.moveCards(card, Zone.EXILED, source, game); controller.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/d/DistemperOfTheBlood.java b/Mage.Sets/src/mage/cards/d/DistemperOfTheBlood.java index d8176c89aff..170a724cdd3 100644 --- a/Mage.Sets/src/mage/cards/d/DistemperOfTheBlood.java +++ b/Mage.Sets/src/mage/cards/d/DistemperOfTheBlood.java @@ -33,7 +33,7 @@ public final class DistemperOfTheBlood extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Madness {R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{R}"))); } private DistemperOfTheBlood(final DistemperOfTheBlood card) { diff --git a/Mage.Sets/src/mage/cards/d/DisturbedBurial.java b/Mage.Sets/src/mage/cards/d/DisturbedBurial.java index 7889dbbf8ad..cec61e917f9 100644 --- a/Mage.Sets/src/mage/cards/d/DisturbedBurial.java +++ b/Mage.Sets/src/mage/cards/d/DisturbedBurial.java @@ -1,8 +1,6 @@ - package mage.cards.d; -import java.util.UUID; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.BuybackAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -10,8 +8,9 @@ import mage.constants.CardType; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class DisturbedBurial extends CardImpl { @@ -23,7 +22,7 @@ public final class DisturbedBurial extends CardImpl { this.addAbility(new BuybackAbility("{3}")); // 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()); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); } private DisturbedBurial(final DisturbedBurial card) { diff --git a/Mage.Sets/src/mage/cards/d/DisturbingPlot.java b/Mage.Sets/src/mage/cards/d/DisturbingPlot.java index e9ced3a80ce..d2a8cf2c636 100644 --- a/Mage.Sets/src/mage/cards/d/DisturbingPlot.java +++ b/Mage.Sets/src/mage/cards/d/DisturbingPlot.java @@ -1,31 +1,32 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.ConspireAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.target.common.TargetCardInGraveyard; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class DisturbingPlot extends CardImpl { + private static final FilterCard filter = new FilterCreatureCard("creature card from a graveyard"); + public DisturbingPlot(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 a graveyard to its owner's hand. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card in a graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInGraveyard(filter)); // Conspire - this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE)); - + this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.ONE)); } private DisturbingPlot(final DisturbingPlot card) { diff --git a/Mage.Sets/src/mage/cards/d/DiverSkaab.java b/Mage.Sets/src/mage/cards/d/DiverSkaab.java index 5a4897b1767..9995fe173fe 100644 --- a/Mage.Sets/src/mage/cards/d/DiverSkaab.java +++ b/Mage.Sets/src/mage/cards/d/DiverSkaab.java @@ -3,16 +3,12 @@ package mage.cards.d; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ExploitCreatureTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; import mage.abilities.keyword.ExploitAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -33,7 +29,9 @@ public final class DiverSkaab extends CardImpl { this.addAbility(new ExploitAbility()); // When Diver Skaab exploits a creature, target creature's owner puts it on the top or bottom of their library. - Ability ability = new ExploitCreatureTriggeredAbility(new DiverSkaabEffect()); + Ability ability = new ExploitCreatureTriggeredAbility(new PutOnTopOrBottomLibraryTargetEffect( + "target creature's owner puts it on the top or bottom of their library" + )); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } @@ -47,33 +45,3 @@ public final class DiverSkaab extends CardImpl { return new DiverSkaab(this); } } - -class DiverSkaabEffect extends OneShotEffect { - - DiverSkaabEffect() { - super(Outcome.Removal); - staticText = "target creature's owner puts it on the top or bottom of their library"; - } - - private DiverSkaabEffect(final DiverSkaabEffect effect) { - super(effect); - } - - @Override - public DiverSkaabEffect copy() { - return new DiverSkaabEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget())); - if (player == null) { - return false; - } - if (player.chooseUse(Outcome.Detriment, "Put the targeted object on the top or bottom of your library?", - "", "Top", "Bottom", source, game)) { - return new PutOnLibraryTargetEffect(true).apply(game, source); - } - return new PutOnLibraryTargetEffect(false).apply(game, source); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DivineReckoning.java b/Mage.Sets/src/mage/cards/d/DivineReckoning.java index 946a25e9803..5155dac6d92 100644 --- a/Mage.Sets/src/mage/cards/d/DivineReckoning.java +++ b/Mage.Sets/src/mage/cards/d/DivineReckoning.java @@ -14,7 +14,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.TimingRule; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; @@ -68,8 +67,8 @@ class DivineReckoningEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null) { Target target = new TargetControlledPermanent(1, 1, new FilterControlledCreaturePermanent(), true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { - while (player.canRespond() && !target.isChosen() && target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { + while (player.canRespond() && !target.isChosen() && target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Benefit, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); @@ -80,7 +79,7 @@ class DivineReckoningEffect extends OneShotEffect { } } - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURES, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURES, source.getControllerId(), source, game)) { if (!chosen.contains(permanent)) { permanent.destroy(source, game, false); } diff --git a/Mage.Sets/src/mage/cards/d/DivinersWand.java b/Mage.Sets/src/mage/cards/d/DivinersWand.java index a72f5ea6fd0..109ca960617 100644 --- a/Mage.Sets/src/mage/cards/d/DivinersWand.java +++ b/Mage.Sets/src/mage/cards/d/DivinersWand.java @@ -27,25 +27,13 @@ import java.util.UUID; */ public final class DivinersWand extends CardImpl { - private static final FilterPermanent filter = new FilterCreaturePermanent("a Wizard creature"); - - static { - filter.add(SubType.WIZARD.getPredicate()); - } + private static final FilterPermanent filter = new FilterCreaturePermanent(SubType.WIZARD, "a Wizard creature"); public DivinersWand(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.TRIBAL, CardType.ARTIFACT}, "{3}"); this.subtype.add(SubType.WIZARD); this.subtype.add(SubType.EQUIPMENT); - // Whenever a Wizard creature enters the battlefield, you may attach Diviner's Wand to it. - this.addAbility(new EntersBattlefieldAllTriggeredAbility( - Zone.BATTLEFIELD, new AttachEffect(Outcome.Detriment, "attach {this} to it"), - filter, true, SetTargetPointer.PERMANENT, null)); - - // Equip {3} - this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(3), false)); - // Equipped creature has "Whenever you draw a card, this creature gets +1/+1 and gains flying until end of turn" and "{4}: Draw a card." // new abilities Ability newBoost = new DrawCardControllerTriggeredAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn), false); @@ -60,6 +48,14 @@ public final class DivinersWand extends CardImpl { Ability totalAbility = new SimpleStaticAbility(Zone.BATTLEFIELD, effectBoost); totalAbility.addEffect(effectDraw.concatBy("and")); this.addAbility(totalAbility); + + // Whenever a Wizard creature enters the battlefield, you may attach Diviner's Wand to it. + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + Zone.BATTLEFIELD, new AttachEffect(Outcome.Detriment, "attach {this} to it"), + filter, true, SetTargetPointer.PERMANENT, null)); + + // Equip {3} + this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(3), false)); } private DivinersWand(final DivinersWand card) { diff --git a/Mage.Sets/src/mage/cards/d/DiviningWitch.java b/Mage.Sets/src/mage/cards/d/DiviningWitch.java index af7cab017d1..2d2e6ceb1c9 100644 --- a/Mage.Sets/src/mage/cards/d/DiviningWitch.java +++ b/Mage.Sets/src/mage/cards/d/DiviningWitch.java @@ -71,7 +71,7 @@ public final class DiviningWitch extends CardImpl { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/d/DjinnIlluminatus.java b/Mage.Sets/src/mage/cards/d/DjinnIlluminatus.java index 8ea8ea86d9c..703e9ed2209 100644 --- a/Mage.Sets/src/mage/cards/d/DjinnIlluminatus.java +++ b/Mage.Sets/src/mage/cards/d/DjinnIlluminatus.java @@ -86,7 +86,7 @@ class DjinnIlluminatusGainReplicateEffect extends ContinuousEffectImpl { && !stackObject.getManaCost().isEmpty()) { //handle cases like Ancestral Vision Spell spell = (Spell) stackObject; if (filter.match(stackObject, game)) { - ReplicateAbility replicateAbility = replicateAbilities.computeIfAbsent(spell.getId(), k -> new ReplicateAbility(spell.getCard(), spell.getSpellAbility().getManaCosts().getText())); + ReplicateAbility replicateAbility = replicateAbilities.computeIfAbsent(spell.getId(), k -> new ReplicateAbility(spell.getSpellAbility().getManaCosts().getText())); game.getState().addOtherAbility(spell.getCard(), replicateAbility, false); // Do not copy because paid and # of activations state is handled in the baility } } diff --git a/Mage.Sets/src/mage/cards/d/DjinnOfWishes.java b/Mage.Sets/src/mage/cards/d/DjinnOfWishes.java index 3269631dec2..18ca6122497 100644 --- a/Mage.Sets/src/mage/cards/d/DjinnOfWishes.java +++ b/Mage.Sets/src/mage/cards/d/DjinnOfWishes.java @@ -1,7 +1,6 @@ package mage.cards.d; -import java.util.UUID; import mage.ApprovingObject; import mage.MageInt; import mage.MageObject; @@ -22,14 +21,13 @@ import mage.counters.CounterType; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author nantuko */ public final class DjinnOfWishes extends CardImpl { - private static final String ruleText = "{this} enters the battlefield with three wish counters on it"; - public DjinnOfWishes(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); this.subtype.add(SubType.DJINN); @@ -40,7 +38,7 @@ public final class DjinnOfWishes extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Djinn of Wishes enters the battlefield with three wish counters on it. - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.WISH.createInstance(3)), ruleText)); + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.WISH.createInstance(3)), "with three wish counters on it")); // {2}{U}{U}, Remove a wish counter from Djinn of Wishes: Reveal the top card of your library. You may play that card without paying its mana cost. If you don't, exile it. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DjinnOfWishesEffect(), new ManaCostsImpl("{2}{U}{U}")); @@ -72,7 +70,7 @@ class DjinnOfWishesEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null && controller.getLibrary().hasCards()) { Card card = controller.getLibrary().getFromTop(game); Cards cards = new CardsImpl(card); diff --git a/Mage.Sets/src/mage/cards/d/DoOrDie.java b/Mage.Sets/src/mage/cards/d/DoOrDie.java index b6e700a8998..509d5b85666 100644 --- a/Mage.Sets/src/mage/cards/d/DoOrDie.java +++ b/Mage.Sets/src/mage/cards/d/DoOrDie.java @@ -67,7 +67,7 @@ class DoOrDieEffect extends OneShotEffect { TargetCreaturePermanent creatures = new TargetCreaturePermanent(0, count, new FilterCreaturePermanent("creatures to put in the first pile"), true); List pile1 = new ArrayList<>(); creatures.setRequired(false); - if (player.choose(Outcome.Neutral, creatures, source.getSourceId(), game)) { + if (player.choose(Outcome.Neutral, creatures, source, game)) { List targets = creatures.getTargets(); for (UUID targetId : targets) { Permanent p = game.getPermanent(targetId); diff --git a/Mage.Sets/src/mage/cards/d/DocentOfPerfection.java b/Mage.Sets/src/mage/cards/d/DocentOfPerfection.java index eff5ca4030d..d2e8d111aa0 100644 --- a/Mage.Sets/src/mage/cards/d/DocentOfPerfection.java +++ b/Mage.Sets/src/mage/cards/d/DocentOfPerfection.java @@ -96,7 +96,7 @@ class DocentOfPerfectionEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) >= 3) { + if (game.getBattlefield().count(filter, source.getControllerId(), source, game) >= 3) { return new TransformSourceEffect().apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/d/DodgyJalopy.java b/Mage.Sets/src/mage/cards/d/DodgyJalopy.java new file mode 100644 index 00000000000..f7e4d7292f0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DodgyJalopy.java @@ -0,0 +1,87 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.SetPowerSourceEffect; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.ScavengeAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DodgyJalopy extends CardImpl { + + public DodgyJalopy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{G}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(0); + this.toughness = new MageInt(5); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Dodgy Jalopy's power is equal to the highest mana value among creatures you control. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SetPowerSourceEffect(DodgyJalopyValue.instance, Duration.EndOfGame) + )); + + // Crew 3 + this.addAbility(new CrewAbility(3)); + + // Scavenge {2}{G} + this.addAbility(new ScavengeAbility(new ManaCostsImpl<>("{2}{G}"))); + } + + private DodgyJalopy(final DodgyJalopy card) { + super(card); + } + + @Override + public DodgyJalopy copy() { + return new DodgyJalopy(this); + } +} + +enum DodgyJalopyValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, + sourceAbility.getControllerId(), sourceAbility, game + ).stream() + .mapToInt(MageObject::getManaValue) + .max() + .orElse(0); + } + + @Override + public DodgyJalopyValue copy() { + return this; + } + + @Override + public String getMessage() { + return "the highest mana value among creatures you control"; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DokuchiSilencer.java b/Mage.Sets/src/mage/cards/d/DokuchiSilencer.java index 88a256091b5..665dc888daa 100644 --- a/Mage.Sets/src/mage/cards/d/DokuchiSilencer.java +++ b/Mage.Sets/src/mage/cards/d/DokuchiSilencer.java @@ -20,6 +20,7 @@ import mage.game.Game; import mage.game.events.DamagedEvent; import mage.game.events.GameEvent; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInHand; import java.util.UUID; @@ -90,6 +91,7 @@ class BlindZealotTriggeredAbility extends TriggeredAbilityImpl { new DestroyTargetEffect(), false, "destroy target creature or planeswalker that player controls" ); + ability.addTarget(new TargetPermanent(filter)); this.getEffects().clear(); this.addEffect(new DoWhenCostPaid( ability, diff --git a/Mage.Sets/src/mage/cards/d/DollhouseOfHorrors.java b/Mage.Sets/src/mage/cards/d/DollhouseOfHorrors.java index 01d92282866..2c5d5da70d5 100644 --- a/Mage.Sets/src/mage/cards/d/DollhouseOfHorrors.java +++ b/Mage.Sets/src/mage/cards/d/DollhouseOfHorrors.java @@ -6,7 +6,8 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.ExileFromGraveCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.dynamicvalue.common.ArtifactYouControlCount; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; @@ -20,6 +21,7 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.game.permanent.PermanentCard; import mage.target.common.TargetCardInYourGraveyard; @@ -58,6 +60,8 @@ public final class DollhouseOfHorrors extends CardImpl { class DollhouseOfHorrorsEffect extends OneShotEffect { + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.CONSTRUCT)); + DollhouseOfHorrorsEffect() { super(Outcome.Benefit); staticText = "create a token that's a copy of the exiled card, except it's a 0/0 Construct artifact in " + @@ -87,10 +91,12 @@ class DollhouseOfHorrorsEffect extends OneShotEffect { effect.setSavedPermanent(new PermanentCard(card, source.getControllerId(), game)); effect.setAdditionalSubType(SubType.CONSTRUCT); effect.addAdditionalAbilities(new SimpleStaticAbility(new BoostSourceEffect( - ArtifactYouControlCount.instance, - ArtifactYouControlCount.instance, - Duration.WhileOnBattlefield - ).setText("This creature gets +1/+1 for each artifact you control"))); + xValue, + xValue, + Duration.WhileOnBattlefield, + false, + "this creature" + ))); effect.apply(game, source); game.addEffect(new GainAbilityTargetEffect( HasteAbility.getInstance(), Duration.EndOfTurn diff --git a/Mage.Sets/src/mage/cards/d/DomriAnarchOfBolas.java b/Mage.Sets/src/mage/cards/d/DomriAnarchOfBolas.java index ef161e24f03..9dbe48f6fbc 100644 --- a/Mage.Sets/src/mage/cards/d/DomriAnarchOfBolas.java +++ b/Mage.Sets/src/mage/cards/d/DomriAnarchOfBolas.java @@ -3,7 +3,6 @@ package mage.cards.d; import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CantBeCounteredControlledEffect; @@ -30,7 +29,7 @@ public final class DomriAnarchOfBolas extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.DOMRI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // Creatures you control get +1/+0. this.addAbility(new SimpleStaticAbility( diff --git a/Mage.Sets/src/mage/cards/d/DomriChaosBringer.java b/Mage.Sets/src/mage/cards/d/DomriChaosBringer.java index 17e1e627510..7d4814aa1ec 100644 --- a/Mage.Sets/src/mage/cards/d/DomriChaosBringer.java +++ b/Mage.Sets/src/mage/cards/d/DomriChaosBringer.java @@ -5,11 +5,10 @@ import mage.Mana; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.mana.ManaEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledSpellsEffect; import mage.abilities.effects.mana.BasicManaEffect; @@ -38,7 +37,7 @@ public final class DomriChaosBringer extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.DOMRI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Add {R} or {G}. If that mana is spent on a creature spell, it gains riot. this.addAbility(new LoyaltyAbility(new DomriChaosBringerEffect(), 1)); @@ -47,15 +46,7 @@ public final class DomriChaosBringer extends CardImpl { // creature cards from among them and put them into your hand. Put the rest // on the bottom of your library in a random order. this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(2), - StaticFilters.FILTER_CARD_CREATURE, Zone.LIBRARY, false, - true, true, Zone.HAND, false, false, false - ).setText( - "Look at the top four cards of your library. " - + "You may reveal up to two creature cards from among them " - + "and put them into your hand. Put the rest on the bottom of your library " - + "in a random order." - ), -3)); + 4, 2, StaticFilters.FILTER_CARD_CREATURES, PutCards.HAND, PutCards.BOTTOM_RANDOM), -3)); // −8: You get an emblem with "At the beginning of each end step, create a 4/4 red // and green Beast creature token with trample." diff --git a/Mage.Sets/src/mage/cards/d/DomriCitySmasher.java b/Mage.Sets/src/mage/cards/d/DomriCitySmasher.java index 2475c5f7d1c..b719cb3d4c0 100644 --- a/Mage.Sets/src/mage/cards/d/DomriCitySmasher.java +++ b/Mage.Sets/src/mage/cards/d/DomriCitySmasher.java @@ -2,7 +2,6 @@ package mage.cards.d; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -31,7 +30,7 @@ public final class DomriCitySmasher extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.DOMRI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +2: Creatures you control get +1/+1 and gain haste until end of turn. Ability ability = new LoyaltyAbility(new BoostControlledEffect( diff --git a/Mage.Sets/src/mage/cards/d/DomriRade.java b/Mage.Sets/src/mage/cards/d/DomriRade.java index 137e79e0330..631d3251ea4 100644 --- a/Mage.Sets/src/mage/cards/d/DomriRade.java +++ b/Mage.Sets/src/mage/cards/d/DomriRade.java @@ -3,7 +3,6 @@ package mage.cards.d; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.FightTargetsEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -31,7 +30,7 @@ public final class DomriRade extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.DOMRI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Look at the top card of your library. If it's a creature card, you may reveal it and put it into your hand. this.addAbility(new LoyaltyAbility(new DomriRadeEffect1(), 1)); diff --git a/Mage.Sets/src/mage/cards/d/DonalHeraldOfWings.java b/Mage.Sets/src/mage/cards/d/DonalHeraldOfWings.java index 2df6161f99f..f015995e447 100644 --- a/Mage.Sets/src/mage/cards/d/DonalHeraldOfWings.java +++ b/Mage.Sets/src/mage/cards/d/DonalHeraldOfWings.java @@ -5,19 +5,22 @@ import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.FilterSpell; import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; import mage.filter.predicate.mageobject.MageObjectReferencePredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.game.stack.StackObject; import mage.players.Player; import mage.target.targetpointer.FixedTarget; -import mage.util.CardUtil; import mage.util.functions.StackObjectCopyApplier; import java.util.UUID; @@ -27,6 +30,14 @@ import java.util.UUID; */ public class DonalHeraldOfWings extends CardImpl { + private static final FilterSpell filterSpell = new FilterSpell("a nonlegendary creature spell with flying"); + + static { + filterSpell.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); + filterSpell.add(CardType.CREATURE.getPredicate()); + filterSpell.add(new AbilityPredicate(FlyingAbility.class)); + } + public DonalHeraldOfWings(UUID ownderId, CardSetInfo setInfo) { super(ownderId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); @@ -40,57 +51,18 @@ public class DonalHeraldOfWings extends CardImpl { // Whenever you cast a nonlegendary creature spell with flying, you may copy it, // except the copy is a 1/1 Spirit in addition to its other types. // Do this only once each turn. (The copy becomes a token.) - // TODO: This still triggers and asks if you wanna use it, even if you've used it once this turn. - this.addAbility(new DonalHeraldOfWingsTriggeredAbility()); + this.addAbility(new SpellCastControllerTriggeredAbility( + new DonalHeraldOfWingsEffect(), filterSpell, true, true + ).setDoOnlyOnce(true)); } - private DonalHeraldOfWings(final DonalHeraldOfWings card) { super(card); } - - @Override - public DonalHeraldOfWings copy() { return new DonalHeraldOfWings(this); } -} - -class DonalHeraldOfWingsTriggeredAbility extends SpellCastControllerTriggeredAbility { - - private static final FilterSpell filterSpell = new FilterSpell("a nonlegendary creature spell with flying"); - static { - filterSpell.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); - filterSpell.add(CardType.CREATURE.getPredicate()); - } - - DonalHeraldOfWingsTriggeredAbility() { - super(new DonalHeraldOfWingsEffect(), filterSpell, true, true); - } - - private DonalHeraldOfWingsTriggeredAbility(final DonalHeraldOfWingsTriggeredAbility ability) { super(ability); } - - @Override - public DonalHeraldOfWingsTriggeredAbility copy() { - return new DonalHeraldOfWingsTriggeredAbility(this); + private DonalHeraldOfWings(final DonalHeraldOfWings card) { + super(card); } @Override - public boolean checkTrigger(GameEvent event, Game game) { - return abilityAvailableThisTurn(game) && super.checkTrigger(event, game); - } - - @Override - public boolean resolve(Game game) { - if (!(abilityAvailableThisTurn(game) && super.resolve(game))) { return false; } - game.getState().setValue( - CardUtil.getCardZoneString("lastTurnResolved" + originalId, sourceId, game), - game.getTurnNum() - ); - - return true; - } - - private boolean abilityAvailableThisTurn(Game game) { - Integer lastTurnResolved = (Integer) game.getState().getValue( - CardUtil.getCardZoneString("lastTurnResolved" + originalId, sourceId, game) - ); - // A null result is assumed to mean the this ability has not been used yet. - return lastTurnResolved == null || lastTurnResolved != game.getTurnNum(); + public DonalHeraldOfWings copy() { + return new DonalHeraldOfWings(this); } } @@ -98,19 +70,24 @@ class DonalHeraldOfWingsEffect extends OneShotEffect { DonalHeraldOfWingsEffect() { super(Outcome.Copy); - staticText = "you may copy it, except the copy is a 1/1 Spirit in addition to its other types. " + - "Do this only once each turn. (The copy becomes a token.)"; + staticText = "copy it, except the copy is a 1/1 Spirit in addition to its other types"; } - private DonalHeraldOfWingsEffect(final DonalHeraldOfWingsEffect effect) { super(effect); } + private DonalHeraldOfWingsEffect(final DonalHeraldOfWingsEffect effect) { + super(effect); + } @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { return false; } + if (controller == null) { + return false; + } // Get the card that was cast - if (this.getTargetPointer() == null) { return false; } + if (this.getTargetPointer() == null) { + return false; + } Spell originalSpell = game.getStack().getSpell(((FixedTarget) this.getTargetPointer()).getTarget()); // Create a token copy @@ -120,7 +97,9 @@ class DonalHeraldOfWingsEffect extends OneShotEffect { } @Override - public Effect copy() { return new DonalHeraldOfWingsEffect(this); } + public Effect copy() { + return new DonalHeraldOfWingsEffect(this); + } } enum DonalHeraldOfWingsApplier implements StackObjectCopyApplier { @@ -134,5 +113,7 @@ enum DonalHeraldOfWingsApplier implements StackObjectCopyApplier { } @Override - public MageObjectReferencePredicate getNextNewTargetType(int copyNumber) { return null; } + public MageObjectReferencePredicate getNextNewTargetType(int copyNumber) { + return null; + } } diff --git a/Mage.Sets/src/mage/cards/d/DoomCannon.java b/Mage.Sets/src/mage/cards/d/DoomCannon.java index b081a673447..f04d62fd208 100644 --- a/Mage.Sets/src/mage/cards/d/DoomCannon.java +++ b/Mage.Sets/src/mage/cards/d/DoomCannon.java @@ -68,9 +68,9 @@ class DoomCannonFilter extends FilterControlledCreaturePermanent { } @Override - public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { - if (super.match(permanent, sourceId, playerId, game)) { - SubType subType = ChooseCreatureTypeEffect.getChosenCreatureType(sourceId, game); + public boolean match(Permanent permanent, UUID playerId, Ability source, Game game) { + if (super.match(permanent, playerId, source, game)) { + SubType subType = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game); if (subType != null && permanent.hasSubtype(subType, game)) { return true; } diff --git a/Mage.Sets/src/mage/cards/d/DoomForetold.java b/Mage.Sets/src/mage/cards/d/DoomForetold.java index 5ae9c226bbd..6a59095a0da 100644 --- a/Mage.Sets/src/mage/cards/d/DoomForetold.java +++ b/Mage.Sets/src/mage/cards/d/DoomForetold.java @@ -86,7 +86,7 @@ class DoomForetoldEffect extends OneShotEffect { if (game.getBattlefield().contains(filter2, source, game, 1)) { TargetPermanent target = new TargetPermanent(filter2); target.setNotTarget(true); - if (player.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) { + if (player.choose(Outcome.Sacrifice, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null && permanent.sacrifice(source, game)) { return true; diff --git a/Mage.Sets/src/mage/cards/d/Doomfall.java b/Mage.Sets/src/mage/cards/d/Doomfall.java index d44ef4f6582..030c2aff728 100644 --- a/Mage.Sets/src/mage/cards/d/Doomfall.java +++ b/Mage.Sets/src/mage/cards/d/Doomfall.java @@ -36,8 +36,7 @@ public final class Doomfall extends CardImpl { this.getSpellAbility().addTarget(new TargetOpponent()); // • Target opponent reveals their hand. You choose a nonland card from it. Exile that card. - Mode mode = new Mode(); - mode.addEffect(new ExileCardYouChooseTargetOpponentEffect(StaticFilters.FILTER_CARD_A_NON_LAND) + Mode mode = new Mode(new ExileCardYouChooseTargetOpponentEffect(StaticFilters.FILTER_CARD_A_NON_LAND) .setText("Target opponent reveals their hand. You choose a nonland card from it. Exile that card")); mode.addTarget(new TargetOpponent()); this.getSpellAbility().addMode(mode); @@ -75,7 +74,7 @@ class DoomfallEffect extends OneShotEffect { if (targetPlayer != null) { Target target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (targetPlayer.choose(outcome, target, source.getSourceId(), game)) { + if (targetPlayer.choose(outcome, target, source, game)) { targetPlayer.moveCards(game.getPermanent(target.getFirstTarget()), Zone.EXILED, source, game); } return true; diff --git a/Mage.Sets/src/mage/cards/d/Doomgape.java b/Mage.Sets/src/mage/cards/d/Doomgape.java index d114db688b8..db4cc41cd93 100644 --- a/Mage.Sets/src/mage/cards/d/Doomgape.java +++ b/Mage.Sets/src/mage/cards/d/Doomgape.java @@ -74,7 +74,7 @@ class DoomgapeEffect extends OneShotEffect { if (controller != null) { Target target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (controller.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.Sacrifice, target, source, game)) { Permanent creature = game.getPermanent(target.getFirstTarget()); if (creature != null) { if (creature.sacrifice(source, game)) { diff --git a/Mage.Sets/src/mage/cards/d/DoomwakeGiant.java b/Mage.Sets/src/mage/cards/d/DoomwakeGiant.java index f44de289fce..7dba89fe0c2 100644 --- a/Mage.Sets/src/mage/cards/d/DoomwakeGiant.java +++ b/Mage.Sets/src/mage/cards/d/DoomwakeGiant.java @@ -10,8 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; /** * @@ -19,12 +18,6 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class DoomwakeGiant extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public DoomwakeGiant(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT,CardType.CREATURE},"{4}{B}"); this.subtype.add(SubType.GIANT); @@ -33,7 +26,7 @@ public final class DoomwakeGiant extends CardImpl { this.toughness = new MageInt(6); // Constellation - When Doomwake Giant or another enchantment enters the battlefield under your control, creatures your opponents control get -1/-1 until end of turn. - this.addAbility(new ConstellationAbility(new BoostAllEffect(-1,-1, Duration.EndOfTurn, filter, false))); + this.addAbility(new ConstellationAbility(new BoostAllEffect(-1, -1, Duration.EndOfTurn, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, false))); } private DoomwakeGiant(final DoomwakeGiant card) { diff --git a/Mage.Sets/src/mage/cards/d/DoorOfDestinies.java b/Mage.Sets/src/mage/cards/d/DoorOfDestinies.java index acbece3d2f7..67a4940ef13 100644 --- a/Mage.Sets/src/mage/cards/d/DoorOfDestinies.java +++ b/Mage.Sets/src/mage/cards/d/DoorOfDestinies.java @@ -85,7 +85,7 @@ class AddCounterAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever you cast a spell of the chosen type, put a charge counter on {this}"; + return "Whenever you cast a spell of the chosen type, put a charge counter on {this}."; } } diff --git a/Mage.Sets/src/mage/cards/d/DormantGomazoa.java b/Mage.Sets/src/mage/cards/d/DormantGomazoa.java index b5b09287d7c..a1e3732b1c1 100644 --- a/Mage.Sets/src/mage/cards/d/DormantGomazoa.java +++ b/Mage.Sets/src/mage/cards/d/DormantGomazoa.java @@ -37,7 +37,7 @@ public final class DormantGomazoa extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DontUntapInControllersUntapStepSourceEffect())); // Whenever you become the target of a spell, you may untap Dormant Gomazoa. - this.addAbility(new BecomesTargetControllerSpellTriggeredAbility(new UntapSourceEffect(), true)); + this.addAbility(new BecomesTargetControllerSpellTriggeredAbility(new UntapSourceEffect(), true).setTriggerPhrase("Whenever you become the target of a spell, ")); } private DormantGomazoa(final DormantGomazoa card) { diff --git a/Mage.Sets/src/mage/cards/d/DoublingChant.java b/Mage.Sets/src/mage/cards/d/DoublingChant.java index 9607085e063..c917c1c62b4 100644 --- a/Mage.Sets/src/mage/cards/d/DoublingChant.java +++ b/Mage.Sets/src/mage/cards/d/DoublingChant.java @@ -69,7 +69,7 @@ class DoublingChantEffect extends OneShotEffect { } Set names = game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game ) .stream() .filter(Objects::nonNull) diff --git a/Mage.Sets/src/mage/cards/d/Dovescape.java b/Mage.Sets/src/mage/cards/d/Dovescape.java index 31370e44374..f783bc045ff 100644 --- a/Mage.Sets/src/mage/cards/d/Dovescape.java +++ b/Mage.Sets/src/mage/cards/d/Dovescape.java @@ -1,4 +1,3 @@ - package mage.cards.d; import java.util.UUID; @@ -10,11 +9,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SetTargetPointer; -import mage.filter.FilterSpell; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.permanent.token.DovescapeToken; -import mage.game.permanent.token.Token; +import mage.game.permanent.token.WhiteBlueBirdToken; import mage.game.stack.Spell; /** @@ -23,17 +20,11 @@ import mage.game.stack.Spell; */ public final class Dovescape extends CardImpl { - private static final FilterSpell filter = new FilterSpell("a noncreature spell"); - - static { - filter.add(Predicates.not(CardType.CREATURE.getPredicate())); - } - public Dovescape(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W/U}{W/U}{W/U}"); // Whenever a player casts a noncreature spell, counter that spell. That player creates X 1/1 white and blue Bird creature tokens with flying, where X is the spell's converted mana cost. - this.addAbility(new SpellCastAllTriggeredAbility(new DovescapeEffect(), filter, false, SetTargetPointer.SPELL)); + this.addAbility(new SpellCastAllTriggeredAbility(new DovescapeEffect(), StaticFilters.FILTER_SPELL_A_NON_CREATURE, false, SetTargetPointer.SPELL)); } private Dovescape(final Dovescape card) { @@ -72,8 +63,7 @@ class DovescapeEffect extends OneShotEffect { spellControllerID = spell.getControllerId(); game.getStack().counter(spell.getId(), source, game); } - Token token = new DovescapeToken(); - token.putOntoBattlefield(spellCMC, game, source, spellControllerID); + new WhiteBlueBirdToken().putOntoBattlefield(spellCMC, game, source, spellControllerID); return true; } } diff --git a/Mage.Sets/src/mage/cards/d/DovinArchitectOfLaw.java b/Mage.Sets/src/mage/cards/d/DovinArchitectOfLaw.java index 997df68c943..ee86a72467e 100644 --- a/Mage.Sets/src/mage/cards/d/DovinArchitectOfLaw.java +++ b/Mage.Sets/src/mage/cards/d/DovinArchitectOfLaw.java @@ -2,7 +2,6 @@ package mage.cards.d; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -25,7 +24,7 @@ public final class DovinArchitectOfLaw extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.DOVIN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: You gain 2 life and draw a card. Ability ability = new LoyaltyAbility(new GainLifeEffect(2), 1); diff --git a/Mage.Sets/src/mage/cards/d/DovinBaan.java b/Mage.Sets/src/mage/cards/d/DovinBaan.java index e2c59790d5b..dd266aa886b 100644 --- a/Mage.Sets/src/mage/cards/d/DovinBaan.java +++ b/Mage.Sets/src/mage/cards/d/DovinBaan.java @@ -4,7 +4,6 @@ package mage.cards.d; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -21,7 +20,6 @@ import mage.constants.SuperType; import mage.game.Game; import mage.game.command.emblems.DovinBaanEmblem; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.target.common.TargetCreaturePermanent; /** @@ -35,7 +33,7 @@ public final class DovinBaan extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.DOVIN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Until your next turn, up to one target creature gets -3/-0 and its activated abilities can't be activated. Effect effect = new BoostTargetEffect(-3, 0, Duration.UntilYourNextTurn); diff --git a/Mage.Sets/src/mage/cards/d/DovinGrandArbiter.java b/Mage.Sets/src/mage/cards/d/DovinGrandArbiter.java index 4d7d713cfce..55c899a46b5 100644 --- a/Mage.Sets/src/mage/cards/d/DovinGrandArbiter.java +++ b/Mage.Sets/src/mage/cards/d/DovinGrandArbiter.java @@ -3,18 +3,16 @@ package mage.cards.d; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.counters.CounterType; -import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; @@ -33,7 +31,7 @@ public final class DovinGrandArbiter extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.DOVIN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Until end of turn, whenever a creature you control deals combat damage to a player, put a loyalty counter on Dovin, Grand Arbiter. this.addAbility(new LoyaltyAbility(new CreateDelayedTriggeredAbilityEffect( @@ -42,19 +40,13 @@ public final class DovinGrandArbiter extends CardImpl { // -1: Create a 1/1 colorless Thopter artifact creature token with flying. You gain 1 life. Ability ability = new LoyaltyAbility(new CreateTokenEffect(new ThopterColorlessToken()), -1); - ability.addEffect(new GainLifeEffect(1).setText("You gain 1 life.")); + ability.addEffect(new GainLifeEffect(1)); this.addAbility(ability); - // -7: Look at the top ten cards of your library. Put three of them into your hand and the rest on the bottom of your library in a random order. + // -7: Look at the top ten cards of your library. Put three of them into your hand + // and the rest on the bottom of your library in a random order. this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(10), false, - StaticValue.get(3), StaticFilters.FILTER_CARD, - Zone.LIBRARY, false, false, false, - Zone.HAND, false, false, false - ).setBackInRandomOrder(true).setText("Look at the top ten cards of your library. " + - "Put three of them into your hand and the rest " + - "on the bottom of your library in a random order." - ), -7)); + 10, 3, PutCards.HAND, PutCards.BOTTOM_RANDOM), -7)); } private DovinGrandArbiter(final DovinGrandArbiter card) { diff --git a/Mage.Sets/src/mage/cards/d/DovinHandOfControl.java b/Mage.Sets/src/mage/cards/d/DovinHandOfControl.java index dc14c627a52..796e70c88f7 100644 --- a/Mage.Sets/src/mage/cards/d/DovinHandOfControl.java +++ b/Mage.Sets/src/mage/cards/d/DovinHandOfControl.java @@ -2,7 +2,6 @@ package mage.cards.d; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.PreventDamageByTargetEffect; import mage.abilities.effects.common.PreventDamageToTargetEffect; @@ -36,7 +35,7 @@ public final class DovinHandOfControl extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.DOVIN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Artifact, instant, and sorcery spells your opponents cast cost {1} more to cast. this.addAbility(new SimpleStaticAbility(new SpellsCostIncreasingAllEffect(1, filter, TargetController.OPPONENT))); diff --git a/Mage.Sets/src/mage/cards/d/DowsingShaman.java b/Mage.Sets/src/mage/cards/d/DowsingShaman.java index 6306f47b088..dc5338f913b 100644 --- a/Mage.Sets/src/mage/cards/d/DowsingShaman.java +++ b/Mage.Sets/src/mage/cards/d/DowsingShaman.java @@ -1,23 +1,21 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Loki */ public final class DowsingShaman extends CardImpl { @@ -29,7 +27,7 @@ public final class DowsingShaman extends CardImpl { } public DowsingShaman(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.CENTAUR); this.subtype.add(SubType.SHAMAN); @@ -37,7 +35,7 @@ public final class DowsingShaman extends CardImpl { this.toughness = new MageInt(4); // {2}{G}, {tap}: Return target enchantment card from your graveyard to your hand. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{2}{G}")); + Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl<>("{2}{G}")); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/d/Draco.java b/Mage.Sets/src/mage/cards/d/Draco.java index ee193475007..8c91d4e1c94 100644 --- a/Mage.Sets/src/mage/cards/d/Draco.java +++ b/Mage.Sets/src/mage/cards/d/Draco.java @@ -65,7 +65,7 @@ class DracoCostReductionEffect extends CostModificationEffectImpl { @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { - CardUtil.reduceCost(abilityToModify, new DomainValue(2).calculate(game, source, this)); + CardUtil.reduceCost(abilityToModify, 2 * DomainValue.REGULAR.calculate(game, source, this)); return true; } @@ -98,7 +98,7 @@ class DracoSacrificeUnlessPaysEffect extends OneShotEffect { Permanent permanent = game.getPermanent(source.getSourceId()); if (player != null && permanent != null) { // The cost is reduced by {2} for each basic land type. - int domainValueReduction = new DomainValue(2).calculate(game, source, this); + int domainValueReduction = 2 * DomainValue.REGULAR.calculate(game, source, this); int count = Math.max(0, MAX_DOMAIN_VALUE - domainValueReduction); if (player.chooseUse(Outcome.Benefit, "Pay {" + count + "}? Or " + permanent.getName() + " will be sacrificed.", source, game)) { Cost cost = ManaUtil.createManaCost(count, false); diff --git a/Mage.Sets/src/mage/cards/d/Dracoplasm.java b/Mage.Sets/src/mage/cards/d/Dracoplasm.java index 80b1a77d3c7..03dd066c61b 100644 --- a/Mage.Sets/src/mage/cards/d/Dracoplasm.java +++ b/Mage.Sets/src/mage/cards/d/Dracoplasm.java @@ -96,7 +96,7 @@ class DracoplasmEffect extends ReplacementEffectImpl { Player controller = game.getPlayer(source.getControllerId()); if (creature != null && controller != null) { Target target = new TargetControlledPermanent(0, Integer.MAX_VALUE, filter, true); - if (!target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (!target.canChoose(source.getControllerId(), source, game)) { return false; } controller.chooseTarget(Outcome.Detriment, target, source, game); diff --git a/Mage.Sets/src/mage/cards/d/DrafnasRestoration.java b/Mage.Sets/src/mage/cards/d/DrafnasRestoration.java index 8d0fbc575ce..d6b080002e3 100644 --- a/Mage.Sets/src/mage/cards/d/DrafnasRestoration.java +++ b/Mage.Sets/src/mage/cards/d/DrafnasRestoration.java @@ -12,7 +12,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.filter.common.FilterArtifactCard; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.events.TargetEvent; import mage.game.stack.StackObject; import mage.players.Player; @@ -61,14 +60,14 @@ class DrafnasRestorationTarget extends TargetCardInGraveyard { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); - MageObject object = game.getObject(sourceId); + MageObject object = game.getObject(source); if (object instanceof StackObject) { Player targetPlayer = game.getPlayer(((StackObject) object).getStackAbility().getFirstTarget()); if (targetPlayer != null) { - for (Card card : targetPlayer.getGraveyard().getCards(filter, sourceId, sourceControllerId, game)) { - if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) { + for (Card card : targetPlayer.getGraveyard().getCards(filter, sourceControllerId, source, game)) { + if (source == null || source.getSourceId() == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, source.getSourceId(), sourceControllerId))) { possibleTargets.add(card.getId()); } } diff --git a/Mage.Sets/src/mage/cards/d/DragDown.java b/Mage.Sets/src/mage/cards/d/DragDown.java index b06002ca0be..2a17a475aec 100644 --- a/Mage.Sets/src/mage/cards/d/DragDown.java +++ b/Mage.Sets/src/mage/cards/d/DragDown.java @@ -1,30 +1,35 @@ - package mage.cards.d; -import java.util.UUID; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.MultipliedValue; import mage.abilities.dynamicvalue.common.DomainValue; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.hint.common.DomainHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class DragDown extends CardImpl { - public DragDown(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{B}"); + private static final DynamicValue xValue = new MultipliedValue(DomainValue.REGULAR, -1); + public DragDown(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); // Domain - Target creature gets -1/-1 until end of turn for each basic land type among lands you control. - this.getSpellAbility().addEffect(new BoostTargetEffect(new DomainValue(-1), new DomainValue(-1), Duration.EndOfTurn, true)); + this.getSpellAbility().addEffect(new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn, true) + .setText("target creature gets -1/-1 until end of turn for each basic land type among lands you control")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addHint(DomainHint.instance); + this.getSpellAbility().setAbilityWord(AbilityWord.DOMAIN); } private DragDown(final DragDown card) { diff --git a/Mage.Sets/src/mage/cards/d/DragonBroodmother.java b/Mage.Sets/src/mage/cards/d/DragonBroodmother.java index d3b11680f96..490af7b814b 100644 --- a/Mage.Sets/src/mage/cards/d/DragonBroodmother.java +++ b/Mage.Sets/src/mage/cards/d/DragonBroodmother.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; @@ -13,8 +11,9 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.game.permanent.token.DragonBroodmotherDragonToken; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class DragonBroodmother extends CardImpl { @@ -30,7 +29,10 @@ public final class DragonBroodmother extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // At the beginning of each upkeep, create a 1/1 red and green Dragon creature token with flying and devour 2. (As the token enters the battlefield, you may sacrifice any number of creatures. It enters the battlefield with twice that many +1/+1 counters on it.) - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new DragonBroodmotherDragonToken()), TargetController.ANY, false)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new CreateTokenEffect(new DragonBroodmotherDragonToken()), + TargetController.EACH_PLAYER, false + )); } private DragonBroodmother(final DragonBroodmother card) { @@ -41,5 +43,4 @@ public final class DragonBroodmother extends CardImpl { public DragonBroodmother copy() { return new DragonBroodmother(this); } - } diff --git a/Mage.Sets/src/mage/cards/d/DragonKamisEgg.java b/Mage.Sets/src/mage/cards/d/DragonKamisEgg.java new file mode 100644 index 00000000000..ec980a36827 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DragonKamisEgg.java @@ -0,0 +1,91 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesThisOrAnotherCreatureTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPermanent; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DragonKamisEgg extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.DRAGON); + + public DragonKamisEgg(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); + + this.subtype.add(SubType.EGG); + this.power = new MageInt(0); + this.toughness = new MageInt(1); + this.color.setGreen(true); + this.nightCard = true; + + // Whenever Dragon-Kami's Egg or a Dragon you control dies, you may cast a creature spell from among cards you own in exile with hatching counters on them without paying its mana cost. + this.addAbility(new DiesThisOrAnotherCreatureTriggeredAbility( + new DragonKamisEggEffect(), false, filter + ).setTriggerPhrase("Whenever {this} or a Dragon you control dies, ")); + } + + private DragonKamisEgg(final DragonKamisEgg card) { + super(card); + } + + @Override + public DragonKamisEgg copy() { + return new DragonKamisEgg(this); + } +} + +class DragonKamisEggEffect extends OneShotEffect { + + DragonKamisEggEffect() { + super(Outcome.Benefit); + staticText = "you may cast a creature spell from among cards you own in exile " + + "with hatching counters on them without paying its mana cost"; + } + + private DragonKamisEggEffect(final DragonKamisEggEffect effect) { + super(effect); + } + + @Override + public DragonKamisEggEffect copy() { + return new DragonKamisEggEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(); + game.getExile() + .getAllCards(game, player.getId()) + .stream() + .filter(Objects::nonNull) + .filter(card -> card.getCounters(game).containsKey(CounterType.HATCHLING)) + .forEach(cards::add); + return !cards.isEmpty() && CardUtil.castSpellWithAttributesForFree( + player, source, game, cards, StaticFilters.FILTER_CARD_CREATURE + ); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DragonkinBerserker.java b/Mage.Sets/src/mage/cards/d/DragonkinBerserker.java index 58b0065c766..fd7162fa5a0 100644 --- a/Mage.Sets/src/mage/cards/d/DragonkinBerserker.java +++ b/Mage.Sets/src/mage/cards/d/DragonkinBerserker.java @@ -72,7 +72,7 @@ class DragonkinBerserkerEffect extends CostModificationEffectImpl { @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { CardUtil.reduceCost(abilityToModify, game.getBattlefield().count( - filter, source.getSourceId(), source.getControllerId(), game + filter, source.getControllerId(), source, game )); return true; } diff --git a/Mage.Sets/src/mage/cards/d/DragonlordOjutai.java b/Mage.Sets/src/mage/cards/d/DragonlordOjutai.java index 8d9c750fe63..d2faf5617bb 100644 --- a/Mage.Sets/src/mage/cards/d/DragonlordOjutai.java +++ b/Mage.Sets/src/mage/cards/d/DragonlordOjutai.java @@ -1,26 +1,22 @@ - package mage.cards.d; import java.util.UUID; import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.SourceTappedCondition; import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HexproofAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; -import mage.filter.FilterCard; /** * @@ -40,14 +36,15 @@ public final class DragonlordOjutai extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Dragonlord Ojutai has hexproof as long as it's untapped. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( new GainAbilitySourceEffect(HexproofAbility.getInstance(), Duration.WhileOnBattlefield), SourceTappedCondition.UNTAPPED, "{this} has hexproof as long as it's untapped"))); // Whenever Dragonlord Ojutai deals combat damage to a player, look at the top three cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new LookLibraryAndPickControllerEffect - (StaticValue.get(3), false, StaticValue.get(1), new FilterCard(), Zone.LIBRARY, false, false), false)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.BOTTOM_ANY), + false)); } private DragonlordOjutai(final DragonlordOjutai card) { diff --git a/Mage.Sets/src/mage/cards/d/DragonsDisciple.java b/Mage.Sets/src/mage/cards/d/DragonsDisciple.java index ea6fc91d699..30afb797215 100644 --- a/Mage.Sets/src/mage/cards/d/DragonsDisciple.java +++ b/Mage.Sets/src/mage/cards/d/DragonsDisciple.java @@ -85,7 +85,7 @@ class DragonsDiscipleEffect extends OneShotEffect { Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId()); if (controller != null && sourcePermanent != null) { TargetCardInHand target = new TargetCardInHand(filter); - if (!target.possibleTargets(source.getSourceId(), source.getControllerId(), game).isEmpty() + if (!target.possibleTargets(source.getControllerId(), source, game).isEmpty() && controller.chooseUse(outcome, "Reveal a Dragon card from your hand?", source, game) && controller.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/d/DragonsEyeSavants.java b/Mage.Sets/src/mage/cards/d/DragonsEyeSavants.java index c853373c86a..dfbb6bcaca8 100644 --- a/Mage.Sets/src/mage/cards/d/DragonsEyeSavants.java +++ b/Mage.Sets/src/mage/cards/d/DragonsEyeSavants.java @@ -39,7 +39,7 @@ public final class DragonsEyeSavants extends CardImpl { this.toughness = new MageInt(6); // Morph - Reveal a blue card in your hand. - this.addAbility(new MorphAbility(this, new RevealTargetFromHandCost(new TargetCardInHand(filter)))); + this.addAbility(new MorphAbility(new RevealTargetFromHandCost(new TargetCardInHand(filter)))); // When Dragon's Eye Savants is turned face up, look at target opponent's hand. Effect effect = new LookAtTargetPlayerHandEffect(); diff --git a/Mage.Sets/src/mage/cards/d/DragonsFire.java b/Mage.Sets/src/mage/cards/d/DragonsFire.java index acf4da3a752..af5f6e0d073 100644 --- a/Mage.Sets/src/mage/cards/d/DragonsFire.java +++ b/Mage.Sets/src/mage/cards/d/DragonsFire.java @@ -133,7 +133,7 @@ class DragonsFireCost extends CostImpl { switch (chosenZone) { case HAND: targets.add(new TargetCardInHand(handFilter)); - if (targets.choose(Outcome.Benefit, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.Benefit, controllerId, source.getSourceId(), source, game)) { Card card = game.getCard(targets.getFirstTarget()); if (card != null) { dragonZone = DragonZone.HAND; @@ -144,7 +144,7 @@ class DragonsFireCost extends CostImpl { break; case BATTLEFIELD: targets.add(new TargetControlledPermanent(battlefieldFilter)); - if (targets.choose(Outcome.Benefit, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.Benefit, controllerId, source.getSourceId(), source, game)) { Permanent permanent = game.getPermanent(targets.getFirstTarget()); if (permanent != null) { dragonZone = DragonZone.BATTLEFIELD; diff --git a/Mage.Sets/src/mage/cards/d/DragonsparkReactor.java b/Mage.Sets/src/mage/cards/d/DragonsparkReactor.java index 177e921035d..38c01c29f8e 100644 --- a/Mage.Sets/src/mage/cards/d/DragonsparkReactor.java +++ b/Mage.Sets/src/mage/cards/d/DragonsparkReactor.java @@ -31,13 +31,16 @@ public final class DragonsparkReactor extends CardImpl { // Whenever Dragonspark Reactor or another artifact enters the battlefield under your control, put a charge counter on Dragonspark Reactor. this.addAbility(new EntersBattlefieldThisOrAnotherTriggeredAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), StaticFilters.FILTER_PERMANENT_ARTIFACT, false, true )); // {4}, Sacrifice Dragonspark Reactor: It deals damage equal to the number of charge counters on it to target player and that much damage to up to one target creature. Ability ability = new SimpleActivatedAbility( - new DamageTargetEffect(xValue, "it"), new GenericManaCost(4) + new DamageTargetEffect(xValue).setText( + "it deals damage equal to the number of charge counters on it to target player " + + "and that much damage to up to one target creature" + ), new GenericManaCost(4) ); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetPlayer()); diff --git a/Mage.Sets/src/mage/cards/d/DrainPower.java b/Mage.Sets/src/mage/cards/d/DrainPower.java index fbe0f63f208..73d90162a52 100644 --- a/Mage.Sets/src/mage/cards/d/DrainPower.java +++ b/Mage.Sets/src/mage/cards/d/DrainPower.java @@ -114,7 +114,7 @@ class DrainPowerEffect extends OneShotEffect { FilterLandPermanent filter2 = new FilterLandPermanent("land you control to tap for mana (remaining: " + permList.size() + ')'); filter2.add(new PermanentInListPredicate(permList)); target = new TargetPermanent(1, 1, filter2, true); - while (!target.isChosen() && target.canChoose(source.getSourceId(), targetPlayer.getId(), game) && targetPlayer.canRespond()) { + while (!target.isChosen() && target.canChoose(targetPlayer.getId(), source, game) && targetPlayer.canRespond()) { targetPlayer.chooseTarget(Outcome.Neutral, target, source, game); } permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/d/DrakeFamiliar.java b/Mage.Sets/src/mage/cards/d/DrakeFamiliar.java index dd81c36763c..a0a58e5b397 100644 --- a/Mage.Sets/src/mage/cards/d/DrakeFamiliar.java +++ b/Mage.Sets/src/mage/cards/d/DrakeFamiliar.java @@ -66,7 +66,7 @@ class DrakeFamiliarEffect extends OneShotEffect { } TargetPermanent target = new TargetPermanent(StaticFilters.FILTER_PERMANENT_ENCHANTMENT); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), controller.getId(), game) + if (target.canChoose(controller.getId(), source, game) && controller.chooseUse(outcome, "Return an enchantment to its owner's hand?", source, game)) { controller.chooseTarget(Outcome.ReturnToHand, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/d/DrakeUmbra.java b/Mage.Sets/src/mage/cards/d/DrakeUmbra.java index 3e2dc1835e7..4b55be6cdd3 100644 --- a/Mage.Sets/src/mage/cards/d/DrakeUmbra.java +++ b/Mage.Sets/src/mage/cards/d/DrakeUmbra.java @@ -1,8 +1,5 @@ - package mage.cards.d; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; @@ -17,6 +14,8 @@ import mage.constants.*; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * @author Loki */ @@ -31,12 +30,16 @@ public final class DrakeUmbra extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Enchanted creature gets +3/+3 and has flying. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(3, 3, Duration.WhileOnBattlefield))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA))); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect( + 3, 3, Duration.WhileOnBattlefield + )); + ability.addEffect(new GainAbilityAttachedEffect( + FlyingAbility.getInstance(), AttachmentType.AURA + ).setText("and has flying")); + this.addAbility(ability); // Totem armor this.addAbility(new TotemArmorAbility()); diff --git a/Mage.Sets/src/mage/cards/d/DralnusCrusade.java b/Mage.Sets/src/mage/cards/d/DralnusCrusade.java index 3a868b93052..63786171698 100755 --- a/Mage.Sets/src/mage/cards/d/DralnusCrusade.java +++ b/Mage.Sets/src/mage/cards/d/DralnusCrusade.java @@ -49,7 +49,7 @@ class DralnusCrusadeEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - for (Permanent permanent : game.getState().getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE_GOBLINS, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getState().getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE_GOBLINS, source.getControllerId(), source, game)) { switch (layer) { case TypeChangingEffects_4: permanent.addSubType(game, SubType.ZOMBIE); diff --git a/Mage.Sets/src/mage/cards/d/DranaKalastriaBloodchief.java b/Mage.Sets/src/mage/cards/d/DranaKalastriaBloodchief.java index 72334b9d248..1b42a541415 100644 --- a/Mage.Sets/src/mage/cards/d/DranaKalastriaBloodchief.java +++ b/Mage.Sets/src/mage/cards/d/DranaKalastriaBloodchief.java @@ -38,7 +38,7 @@ public final class DranaKalastriaBloodchief extends CardImpl { this.addAbility(FlyingAbility.getInstance()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(StaticValue.get(0), new SignInversionDynamicValue(ManacostVariableValue.REGULAR), Duration.EndOfTurn), new ManaCostsImpl("{X}{B}{B}")); - ability.addEffect(new BoostSourceEffect(ManacostVariableValue.REGULAR, StaticValue.get(0), Duration.EndOfTurn)); + ability.addEffect(new BoostSourceEffect(ManacostVariableValue.REGULAR, StaticValue.get(0), Duration.EndOfTurn).concatBy("and")); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DrawnFromDreams.java b/Mage.Sets/src/mage/cards/d/DrawnFromDreams.java index a9777c29890..c55cc5520d2 100644 --- a/Mage.Sets/src/mage/cards/d/DrawnFromDreams.java +++ b/Mage.Sets/src/mage/cards/d/DrawnFromDreams.java @@ -1,12 +1,10 @@ package mage.cards.d; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import java.util.UUID; @@ -19,10 +17,7 @@ public final class DrawnFromDreams extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}{U}"); // Look at the top seven cards of your library. Put two of them into your hand and the rest on the bottom of your library in a random order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(7), false, StaticValue.get(2), - StaticFilters.FILTER_CARD, Zone.LIBRARY, false, false - ).setBackInRandomOrder(true)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(7, 2, PutCards.HAND, PutCards.BOTTOM_RANDOM)); } private DrawnFromDreams(final DrawnFromDreams card) { diff --git a/Mage.Sets/src/mage/cards/d/DreadCacodemon.java b/Mage.Sets/src/mage/cards/d/DreadCacodemon.java index fc396178375..c1a3bdf24e3 100644 --- a/Mage.Sets/src/mage/cards/d/DreadCacodemon.java +++ b/Mage.Sets/src/mage/cards/d/DreadCacodemon.java @@ -1,4 +1,3 @@ - package mage.cards.d; import java.util.UUID; @@ -14,6 +13,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.watchers.common.CastFromHandWatcher; @@ -22,12 +22,7 @@ import mage.watchers.common.CastFromHandWatcher; * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class DreadCacodemon extends CardImpl { - - private static final FilterCreaturePermanent opponentsCreatures = new FilterCreaturePermanent("creatures your opponents control"); - static { - opponentsCreatures.add(TargetController.OPPONENT.getControllerPredicate()); - } - + private static final FilterCreaturePermanent otherCreaturesYouControl = new FilterCreaturePermanent("other creatures you control"); static { otherCreaturesYouControl.add(TargetController.YOU.getControllerPredicate()); @@ -39,10 +34,10 @@ public final class DreadCacodemon extends CardImpl { this.subtype.add(SubType.DEMON); this.power = new MageInt(8); this.toughness = new MageInt(8); - + // When Dread Cacodemon enters the battlefield, // if you cast it from your hand, destroy all creatures your opponents control, then tap all other creatures you control. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(opponentsCreatures, false)); + TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new DestroyAllEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES)); ability.addEffect(new TapAllEffect(otherCreaturesYouControl)); this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, CastFromHandSourcePermanentCondition.instance, "When {this} enters the battlefield, if you cast it from your hand, destroy all creatures your opponents control, then tap all other creatures you control."), new CastFromHandWatcher()); @@ -56,4 +51,4 @@ public final class DreadCacodemon extends CardImpl { public DreadCacodemon copy() { return new DreadCacodemon(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/d/DreadbringerLampads.java b/Mage.Sets/src/mage/cards/d/DreadbringerLampads.java index c2680f32efb..1c9e5972336 100644 --- a/Mage.Sets/src/mage/cards/d/DreadbringerLampads.java +++ b/Mage.Sets/src/mage/cards/d/DreadbringerLampads.java @@ -1,10 +1,10 @@ - package mage.cards.d; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.abilityword.ConstellationAbility; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.IntimidateAbility; import mage.cards.CardImpl; @@ -28,7 +28,9 @@ public final class DreadbringerLampads extends CardImpl { this.toughness = new MageInt(2); // Constellation - Whenever Dreadbringer Lampads or another enchantment enters the battlefield under your control, target creature gains intimidate until end of turn. - Ability ability = new ConstellationAbility(new GainAbilityTargetEffect(IntimidateAbility.getInstance(), Duration.EndOfTurn), false); + Effect effect = new GainAbilityTargetEffect(IntimidateAbility.getInstance(), Duration.EndOfTurn); + effect.setText("target creature gains intimidate until end of turn. (It can't be blocked except by artifact creatures and/or creatures that share a color with it.)"); + Ability ability = new ConstellationAbility(effect); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DreadhordeArcanist.java b/Mage.Sets/src/mage/cards/d/DreadhordeArcanist.java index 58c6deb298f..68ba166c204 100644 --- a/Mage.Sets/src/mage/cards/d/DreadhordeArcanist.java +++ b/Mage.Sets/src/mage/cards/d/DreadhordeArcanist.java @@ -74,7 +74,7 @@ enum DreadhordeArcanistPredicate implements ObjectSourcePlayerPredicate { @Override public boolean apply(ObjectSourcePlayer input, Game game) { - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(input.getSourceId()); + Permanent sourcePermanent = input.getSource().getSourcePermanentOrLKI(game); return sourcePermanent != null && input.getObject().getManaValue() <= sourcePermanent.getPower().getValue(); } diff --git a/Mage.Sets/src/mage/cards/d/DreamFracture.java b/Mage.Sets/src/mage/cards/d/DreamFracture.java index 5d477198036..5dfce396648 100644 --- a/Mage.Sets/src/mage/cards/d/DreamFracture.java +++ b/Mage.Sets/src/mage/cards/d/DreamFracture.java @@ -27,7 +27,7 @@ public final class DreamFracture extends CardImpl { this.getSpellAbility().addTarget(new TargetSpell()); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } diff --git a/Mage.Sets/src/mage/cards/d/DreamHalls.java b/Mage.Sets/src/mage/cards/d/DreamHalls.java index 19928b062e8..c2177337cae 100644 --- a/Mage.Sets/src/mage/cards/d/DreamHalls.java +++ b/Mage.Sets/src/mage/cards/d/DreamHalls.java @@ -12,7 +12,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.SharesColorWithSourcePredicate; import mage.game.Game; import mage.players.Player; @@ -45,8 +45,8 @@ class DreamHallsEffect extends ContinuousEffectImpl { private static final FilterCard filter = new FilterCard("a card that shares a color with that spell"); static { - filter.add(new AnotherCardPredicate()); - filter.add(new SharesColorWithSourcePredicate()); + filter.add(AnotherPredicate.instance); + filter.add(SharesColorWithSourcePredicate.instance); } private final AlternativeCostSourceAbility alternativeCastingCostAbility = new AlternativeCostSourceAbility(new DiscardCardCost(filter), SourceIsSpellCondition.instance); diff --git a/Mage.Sets/src/mage/cards/d/DreamPillager.java b/Mage.Sets/src/mage/cards/d/DreamPillager.java index 45e5f290a3d..228c9fd15c6 100644 --- a/Mage.Sets/src/mage/cards/d/DreamPillager.java +++ b/Mage.Sets/src/mage/cards/d/DreamPillager.java @@ -5,9 +5,8 @@ import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; import mage.abilities.keyword.FlyingAbility; @@ -18,8 +17,6 @@ import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.*; import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; -import mage.game.events.GameEvent; import mage.players.Player; import mage.target.targetpointer.FixedTargets; @@ -38,7 +35,9 @@ public final class DreamPillager extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Whenever Dream Pillager deals combat damage to a player, exile that many cards from the top of your library. Until end of turn, you may cast nonland cards from among those exiled cards. - this.addAbility(new DreamPillagerTriggeredAbility()); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DreamPillagerEffect(), + false, true)); } private DreamPillager(final DreamPillager card) { @@ -51,48 +50,11 @@ public final class DreamPillager extends CardImpl { } } -class DreamPillagerTriggeredAbility extends TriggeredAbilityImpl { - - public DreamPillagerTriggeredAbility() { - super(Zone.BATTLEFIELD, new DreamPillagerEffect(), false); - } - - public DreamPillagerTriggeredAbility(final DreamPillagerTriggeredAbility ability) { - super(ability); - } - - @Override - public DreamPillagerTriggeredAbility copy() { - return new DreamPillagerTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getSourceId().equals(this.sourceId) && ((DamagedPlayerEvent) event).isCombatDamage()) { - for (Effect effect : getEffects()) { - effect.setValue("damage", event.getAmount()); - } - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever {this} deals combat damage to a player, exile that many cards from the top of your library. Until end of turn, you may cast spells from among those exiled cards."; - } -} - class DreamPillagerEffect extends OneShotEffect { public DreamPillagerEffect() { super(Outcome.Benefit); - this.staticText = "exile that many cards from the top of your library. Until end of turn, you may cast nonland cards from among those exiled cards"; + this.staticText = "exile that many cards from the top of your library. Until end of turn, you may cast spells from among those exiled cards"; } public DreamPillagerEffect(final DreamPillagerEffect effect) { diff --git a/Mage.Sets/src/mage/cards/d/DreamTides.java b/Mage.Sets/src/mage/cards/d/DreamTides.java index 9a0dab7cfa0..5cb1b723072 100644 --- a/Mage.Sets/src/mage/cards/d/DreamTides.java +++ b/Mage.Sets/src/mage/cards/d/DreamTides.java @@ -81,7 +81,7 @@ class DreamTidesEffect extends OneShotEffect { int countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size(); while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.AIDontUseIt, "Pay {2} and untap a tapped nongreen creature under your control?", source, game)) { Target tappedCreatureTarget = new TargetControlledCreaturePermanent(1, 1, filter, true); - if (player.choose(Outcome.Detriment, tappedCreatureTarget, source.getSourceId(), game)) { + if (player.choose(Outcome.Detriment, tappedCreatureTarget, source, game)) { Cost cost = ManaUtil.createManaCost(2, false); Permanent tappedCreature = game.getPermanent(tappedCreatureTarget.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/d/DreamsGrip.java b/Mage.Sets/src/mage/cards/d/DreamsGrip.java index 6eb3d1a9b41..dab457c387f 100644 --- a/Mage.Sets/src/mage/cards/d/DreamsGrip.java +++ b/Mage.Sets/src/mage/cards/d/DreamsGrip.java @@ -31,11 +31,9 @@ public final class DreamsGrip extends CardImpl { this.getSpellAbility().addTarget(target1); this.getSpellAbility().addEffect(tapEffect); //or untap target permanent. - Mode mode = new Mode(); + Mode mode = new Mode(new UntapTargetEffect()); TargetPermanent target2 = new TargetPermanent(new FilterPermanent("Permanent to untap")); mode.addTarget(target2); - Effect untapEffect = new UntapTargetEffect(); - mode.addEffect(untapEffect); this.getSpellAbility().addMode(mode); // Entwine {1} diff --git a/Mage.Sets/src/mage/cards/d/Dreamstealer.java b/Mage.Sets/src/mage/cards/d/Dreamstealer.java index 7fea7af4f36..858a16f2379 100644 --- a/Mage.Sets/src/mage/cards/d/Dreamstealer.java +++ b/Mage.Sets/src/mage/cards/d/Dreamstealer.java @@ -1,21 +1,17 @@ - package mage.cards.d; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.keyword.EternalizeAbility; import mage.abilities.keyword.MenaceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Outcome; -import mage.game.Game; -import mage.players.Player; /** * @@ -34,12 +30,13 @@ public final class Dreamstealer extends CardImpl { // Menace this.addAbility(new MenaceAbility(false)); - // When Dreamstealer deals combat damage to a player, that player discards that many cards. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DreamstealerDiscardEffect(), false, true)); + // Whenever Dreamstealer deals combat damage to a player, that player discards that many cards. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DiscardTargetEffect(SavedDamageValue.MANY), + false, true)); // Eternalize {4}{B}{B} this.addAbility(new EternalizeAbility(new ManaCostsImpl("{4}{B}{B}"), this)); - } private Dreamstealer(final Dreamstealer card) { @@ -51,33 +48,3 @@ public final class Dreamstealer extends CardImpl { return new Dreamstealer(this); } } - -class DreamstealerDiscardEffect extends OneShotEffect { - - public DreamstealerDiscardEffect() { - super(Outcome.Discard); - this.staticText = "that player discards that many cards"; - } - - public DreamstealerDiscardEffect(final DreamstealerDiscardEffect effect) { - super(effect); - } - - @Override - public DreamstealerDiscardEffect copy() { - return new DreamstealerDiscardEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); - if (targetPlayer != null) { - int damage = (Integer) getValue("damage"); - targetPlayer.discard(damage, false, false, source, game); - game.informPlayers(targetPlayer.getLogName() + "discards " + damage + " card(s)"); - return true; - } - return false; - } - -} diff --git a/Mage.Sets/src/mage/cards/d/DromarsCharm.java b/Mage.Sets/src/mage/cards/d/DromarsCharm.java index 827b711df45..631042d3a3e 100644 --- a/Mage.Sets/src/mage/cards/d/DromarsCharm.java +++ b/Mage.Sets/src/mage/cards/d/DromarsCharm.java @@ -25,12 +25,10 @@ public final class DromarsCharm extends CardImpl { // Choose one - You gain 5 life; or counter target spell; or target creature gets -2/-2 until end of turn. this.getSpellAbility().addEffect(new GainLifeEffect(5)); - Mode mode = new Mode(); - mode.addEffect(new CounterTargetEffect()); + Mode mode = new Mode(new CounterTargetEffect()); mode.addTarget(new TargetSpell()); this.getSpellAbility().addMode(mode); - mode = new Mode(); - mode.addEffect(new BoostTargetEffect(-2, -2, Duration.EndOfTurn)); + mode = new Mode(new BoostTargetEffect(-2, -2, Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/d/DromokasCommand.java b/Mage.Sets/src/mage/cards/d/DromokasCommand.java index 6d8b427d447..20790ca01db 100644 --- a/Mage.Sets/src/mage/cards/d/DromokasCommand.java +++ b/Mage.Sets/src/mage/cards/d/DromokasCommand.java @@ -42,26 +42,23 @@ public final class DromokasCommand extends CardImpl { this.getSpellAbility().getTargets().add(new TargetSpell(new FilterInstantOrSorcerySpell())); // or Target player sacrifices an enchantment; - Mode mode = new Mode(); Effect effect = new SacrificeEffect(filterEnchantment, 1, "target player"); effect.setText("Target player sacrifices an enchantment"); - mode.addEffect(effect); + Mode mode = new Mode(effect); mode.addTarget(new TargetPlayer()); this.getSpellAbility().getModes().addMode(mode); // Put a +1/+1 counter on target creature; - mode = new Mode(); effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); effect.setText("Put a +1/+1 counter on target creature"); - mode.addEffect(effect); + mode = new Mode(effect); mode.addTarget(new TargetCreaturePermanent(filterCreature)); this.getSpellAbility().getModes().addMode(mode); // or Target creature you control fights target creature you don't control. - mode = new Mode(); effect = new FightTargetsEffect(); effect.setText("Target creature you control fights target creature you don't control"); - mode.addEffect(effect); + mode = new Mode(effect); mode.addTarget(new TargetControlledCreaturePermanent()); mode.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); this.getSpellAbility().getModes().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/d/DropOfHoney.java b/Mage.Sets/src/mage/cards/d/DropOfHoney.java index f51ef99936e..860af8120f7 100644 --- a/Mage.Sets/src/mage/cards/d/DropOfHoney.java +++ b/Mage.Sets/src/mage/cards/d/DropOfHoney.java @@ -89,8 +89,8 @@ class DropOfHoneyEffect extends OneShotEffect { filter.add(new PowerPredicate(ComparisonType.EQUAL_TO, leastPower)); Target target = new TargetPermanent(filter); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { - if (controller.choose(outcome, target, source.getSourceId(), game)) { + if (target.canChoose(source.getControllerId(), source, game)) { + if (controller.choose(outcome, target, source, game)) { permanentToDestroy = game.getPermanent(target.getFirstTarget()); } } @@ -123,7 +123,7 @@ class DropOfHoneyStateTriggeredAbility extends StateTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - return game.getBattlefield().count(StaticFilters.FILTER_PERMANENT_CREATURES, this.getSourceId(), this.getControllerId(), game) == 0; + return game.getBattlefield().count(StaticFilters.FILTER_PERMANENT_CREATURES, this.getControllerId(), this, game) == 0; } @Override diff --git a/Mage.Sets/src/mage/cards/d/DrownedCatacomb.java b/Mage.Sets/src/mage/cards/d/DrownedCatacomb.java index b56bfb446fc..0557adf0aea 100644 --- a/Mage.Sets/src/mage/cards/d/DrownedCatacomb.java +++ b/Mage.Sets/src/mage/cards/d/DrownedCatacomb.java @@ -1,41 +1,45 @@ - package mage.cards.d; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.Condition; -import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.mana.BlackManaAbility; import mage.abilities.mana.BlueManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.filter.common.FilterLandPermanent; +import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public final class DrownedCatacomb extends CardImpl { - private static final FilterLandPermanent filter = new FilterLandPermanent(); + private static final FilterPermanent filter = new FilterPermanent(); static { - filter.add(Predicates.or(SubType.SWAMP.getPredicate(), SubType.ISLAND.getPredicate())); + filter.add(Predicates.or( + SubType.SWAMP.getPredicate(), + SubType.ISLAND.getPredicate() + )); } + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0); + public DrownedCatacomb(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, null); - Condition controls = new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)); - String abilityText = " tapped unless you control a Island or a Swamp"; - this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect(new TapSourceEffect(), controls, abilityText), abilityText)); + this.addAbility(new EntersBattlefieldAbility( + new TapSourceEffect(), condition, null, + "tapped unless you control an Island or a Swamp" + )); this.addAbility(new BlackManaAbility()); this.addAbility(new BlueManaAbility()); } diff --git a/Mage.Sets/src/mage/cards/d/DruidOfPurification.java b/Mage.Sets/src/mage/cards/d/DruidOfPurification.java index 37ec1c0e3ca..7839dcefe59 100644 --- a/Mage.Sets/src/mage/cards/d/DruidOfPurification.java +++ b/Mage.Sets/src/mage/cards/d/DruidOfPurification.java @@ -76,7 +76,7 @@ class DruidOfPurificationEffect extends OneShotEffect { "artifact or enchantment not controlled by " + controller.getName() ); filter.add(Predicates.not(new ControllerIdPredicate(controller.getId()))); - if (game.getBattlefield().count(filter, source.getControllerId(), source.getControllerId(), game) < 1) { + if (game.getBattlefield().count(filter, source.getControllerId(), source, game) < 1) { return false; } TargetPermanent target = new TargetPermanent(0, 1, filter); @@ -88,7 +88,7 @@ class DruidOfPurificationEffect extends OneShotEffect { continue; } target.clearChosen(); - player.choose(Outcome.DestroyPermanent, target, source.getSourceId(), game); + player.choose(Outcome.DestroyPermanent, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent == null) { game.informPlayers(player.getLogName() + " has not chosen a permanent"); diff --git a/Mage.Sets/src/mage/cards/d/DruidsCall.java b/Mage.Sets/src/mage/cards/d/DruidsCall.java index f067b70a1b4..77072372e04 100644 --- a/Mage.Sets/src/mage/cards/d/DruidsCall.java +++ b/Mage.Sets/src/mage/cards/d/DruidsCall.java @@ -1,10 +1,8 @@ - package mage.cards.d; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.common.DealtDamageAttachedTriggeredAbility; -import mage.abilities.dynamicvalue.common.NumericSetToEffectValues; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.CreateTokenTargetEffect; @@ -30,16 +28,14 @@ public final class DruidsCall extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{G}"); this.subtype.add(SubType.AURA); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Whenever enchanted creature is dealt damage, its controller creates that many 1/1 green Squirrel creature tokens. - Effect effect = new CreateTokenTargetEffect(new SquirrelToken(), new NumericSetToEffectValues("that much", "damage")); + Effect effect = new CreateTokenTargetEffect(new SquirrelToken(), SavedDamageValue.MANY); effect.setText("its controller creates that many 1/1 green Squirrel creature tokens"); this.addAbility(new DealtDamageAttachedTriggeredAbility(Zone.BATTLEFIELD, effect, false, SetTargetPointer.PLAYER)); } diff --git a/Mage.Sets/src/mage/cards/d/Drumbellower.java b/Mage.Sets/src/mage/cards/d/Drumbellower.java new file mode 100644 index 00000000000..4a401682379 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/Drumbellower.java @@ -0,0 +1,42 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.UntapAllDuringEachOtherPlayersUntapStepEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Drumbellower extends CardImpl { + + public Drumbellower(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Untap all creatures you control during each other player's untap step. + this.addAbility(new SimpleStaticAbility(new UntapAllDuringEachOtherPlayersUntapStepEffect(StaticFilters.FILTER_CONTROLLED_CREATURES))); + } + + private Drumbellower(final Drumbellower card) { + super(card); + } + + @Override + public Drumbellower copy() { + return new Drumbellower(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DuergarAssailant.java b/Mage.Sets/src/mage/cards/d/DuergarAssailant.java index a962587347b..bf5f25b5aeb 100644 --- a/Mage.Sets/src/mage/cards/d/DuergarAssailant.java +++ b/Mage.Sets/src/mage/cards/d/DuergarAssailant.java @@ -30,7 +30,7 @@ public final class DuergarAssailant extends CardImpl { this.toughness = new MageInt(1); // Sacrifice Duergar Assailant: Duergar Assailant deals 1 damage to target attacking or blocking creature. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new SacrificeSourceCost()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1, "it"), new SacrificeSourceCost()); ability.addTarget(new TargetAttackingOrBlockingCreature()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/d/DulcetSirens.java b/Mage.Sets/src/mage/cards/d/DulcetSirens.java index c31b7d17b66..5f2d7dbb689 100644 --- a/Mage.Sets/src/mage/cards/d/DulcetSirens.java +++ b/Mage.Sets/src/mage/cards/d/DulcetSirens.java @@ -43,7 +43,7 @@ public final class DulcetSirens extends CardImpl { // Morph {U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{U}"))); } private DulcetSirens(final DulcetSirens card) { diff --git a/Mage.Sets/src/mage/cards/d/Duneblast.java b/Mage.Sets/src/mage/cards/d/Duneblast.java index d306f8f68d0..6a46f88bd33 100644 --- a/Mage.Sets/src/mage/cards/d/Duneblast.java +++ b/Mage.Sets/src/mage/cards/d/Duneblast.java @@ -65,10 +65,10 @@ class DuneblastEffect extends OneShotEffect { Target target = new TargetCreaturePermanent(0,1,new FilterCreaturePermanent("creature to keep"), true); target.setRequired(true); Permanent creatureToKeep = null; - if (controller.choose(outcome, target, source.getSourceId(), game)) { + if (controller.choose(outcome, target, source, game)) { creatureToKeep = game.getPermanent(target.getFirstTarget()); } - for(Permanent creature: game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURES, source.getControllerId(), source.getSourceId(), game)) { + for(Permanent creature: game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURES, source.getControllerId(), source, game)) { if (!Objects.equals(creature, creatureToKeep)) { creature.destroy(source, game, false); } diff --git a/Mage.Sets/src/mage/cards/d/DungeonShade.java b/Mage.Sets/src/mage/cards/d/DungeonShade.java index 67f455cbecf..aa77d49b589 100644 --- a/Mage.Sets/src/mage/cards/d/DungeonShade.java +++ b/Mage.Sets/src/mage/cards/d/DungeonShade.java @@ -31,7 +31,7 @@ public final class DungeonShade extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // {B}: Dungeon Shade gets +1/+1 until end of turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 1, Duration.EndOfTurn), new ManaCostsImpl("B"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 1, Duration.EndOfTurn), new ManaCostsImpl<>("{B}"))); } private DungeonShade(final DungeonShade card) { diff --git a/Mage.Sets/src/mage/cards/d/Duplicant.java b/Mage.Sets/src/mage/cards/d/Duplicant.java index 2467806469b..5bc27b30129 100644 --- a/Mage.Sets/src/mage/cards/d/Duplicant.java +++ b/Mage.Sets/src/mage/cards/d/Duplicant.java @@ -42,7 +42,7 @@ public final class Duplicant extends CardImpl { // Imprint - When Duplicant enters the battlefield, you may exile target nontoken creature. Ability ability = new EntersBattlefieldTriggeredAbility(new DuplicantExileTargetEffect(), true); ability.addTarget(new TargetCreaturePermanent(filter)); - ability.withFlavorWord("Imprint"); + ability.setAbilityWord(AbilityWord.IMPRINT); this.addAbility(ability); // As long as the exiled card is a creature card, Duplicant has that card's power, toughness, and creature types. It's still a Shapeshifter. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DuplicantContinuousEffect())); diff --git a/Mage.Sets/src/mage/cards/d/Duplicity.java b/Mage.Sets/src/mage/cards/d/Duplicity.java index 2867b40dd88..18b2e57e938 100644 --- a/Mage.Sets/src/mage/cards/d/Duplicity.java +++ b/Mage.Sets/src/mage/cards/d/Duplicity.java @@ -75,7 +75,7 @@ class DuplicityEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { if (controller.getLibrary().hasCards()) { @@ -111,7 +111,7 @@ class DuplicityExileHandEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { if (!controller.getHand().isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/d/DurableHandicraft.java b/Mage.Sets/src/mage/cards/d/DurableHandicraft.java index 16b8d2e76b4..1ea08e05aff 100644 --- a/Mage.Sets/src/mage/cards/d/DurableHandicraft.java +++ b/Mage.Sets/src/mage/cards/d/DurableHandicraft.java @@ -1,14 +1,11 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.counter.AddCountersAllEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; @@ -18,27 +15,33 @@ import mage.constants.CardType; import mage.constants.SetTargetPointer; import mage.constants.Zone; import mage.counters.CounterType; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author spjspj */ public final class DurableHandicraft extends CardImpl { public DurableHandicraft(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); // Whenever a creature enters the battlefield under your control, you may pay {1}. If you do, put a +1/+1 counter on that creature. - Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); - effect.setText("put a +1/+1 counter on that creature"); - DoIfCostPaid doIfCostPaid = new DoIfCostPaid(effect, new GenericManaCost(1)); - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, doIfCostPaid, new FilterControlledCreaturePermanent(), false, SetTargetPointer.PERMANENT, null)); + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, + new DoIfCostPaid( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on that creature"), + new GenericManaCost(1) + ), StaticFilters.FILTER_PERMANENT_A_CREATURE, + false, SetTargetPointer.PERMANENT, null + )); // {5}{G}, Sacrifice Durable Handicraft: Put a +1/+1 counter on each creature you control. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new AddCountersAllEffect(CounterType.P1P1.createInstance(), new FilterControlledCreaturePermanent()), - new ManaCostsImpl("{5}{G}")); + Ability ability = new SimpleActivatedAbility(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE + ), new ManaCostsImpl<>("{5}{G}")); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } @@ -52,4 +55,3 @@ public final class DurableHandicraft extends CardImpl { return new DurableHandicraft(this); } } - diff --git a/Mage.Sets/src/mage/cards/d/DurkwoodBaloth.java b/Mage.Sets/src/mage/cards/d/DurkwoodBaloth.java index 89670c2e323..487ad3f2bda 100644 --- a/Mage.Sets/src/mage/cards/d/DurkwoodBaloth.java +++ b/Mage.Sets/src/mage/cards/d/DurkwoodBaloth.java @@ -24,7 +24,7 @@ public final class DurkwoodBaloth extends CardImpl { this.toughness = new MageInt(5); // Suspend 5-{G} - this.addAbility(new SuspendAbility(5, new ManaCostsImpl("{G"), this)); + this.addAbility(new SuspendAbility(5, new ManaCostsImpl("{G}"), this)); } private DurkwoodBaloth(final DurkwoodBaloth card) { diff --git a/Mage.Sets/src/mage/cards/d/DuskDawn.java b/Mage.Sets/src/mage/cards/d/DuskDawn.java index c0929318c0f..9726f1103c9 100644 --- a/Mage.Sets/src/mage/cards/d/DuskDawn.java +++ b/Mage.Sets/src/mage/cards/d/DuskDawn.java @@ -1,21 +1,14 @@ package mage.cards.d; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.keyword.AftermathAbility; import mage.cards.Card; import mage.cards.CardSetInfo; import mage.cards.SplitCard; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.Outcome; -import mage.constants.SpellAbilityType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreaturePermanent; @@ -23,9 +16,12 @@ import mage.filter.predicate.mageobject.PowerPredicate; import mage.game.Game; import mage.players.Player; +import java.util.Set; +import java.util.UUID; + public final class DuskDawn extends SplitCard { - private static final FilterCreaturePermanent filterCreatures3orGreater = new FilterCreaturePermanent("creatures with power greater than or equal to 3"); + private static final FilterCreaturePermanent filterCreatures3orGreater = new FilterCreaturePermanent("creatures with power 3 or greater"); static { filterCreatures3orGreater.add(new PowerPredicate(ComparisonType.MORE_THAN, 2)); @@ -36,15 +32,12 @@ public final class DuskDawn extends SplitCard { // Dusk // Destroy all creatures with power 3 or greater. - Effect destroy = new DestroyAllEffect(filterCreatures3orGreater); - destroy.setText("Destroy all creatures with power greater than or equal to 3."); - getLeftHalfCard().getSpellAbility().addEffect(destroy); + getLeftHalfCard().getSpellAbility().addEffect(new DestroyAllEffect(filterCreatures3orGreater)); // Dawn // Return all creature cards with power less than or equal to 2 from your graveyard to your hand. getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); getRightHalfCard().getSpellAbility().addEffect(new DawnEffect()); - } private DuskDawn(final DuskDawn card) { diff --git a/Mage.Sets/src/mage/cards/d/DuskMangler.java b/Mage.Sets/src/mage/cards/d/DuskMangler.java new file mode 100644 index 00000000000..8a81b9efbcf --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DuskMangler.java @@ -0,0 +1,58 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.OrCost; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.abilities.effects.common.SacrificeOpponentsEffect; +import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DuskMangler extends CardImpl { + + public DuskMangler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}"); + + this.subtype.add(SubType.HORROR); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // As an additional cost to cast this spell, sacrifice a creature, discard a card, or pay 4 life. + this.getSpellAbility().addCost(new OrCost( + "sacrifice a creature, discard a card, or pay 4 life", + new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT), + new DiscardCardCost(), new PayLifeCost(4) + )); + + // When Dusk Mangler enters the battlefield, each opponent sacrifices a creature, discards a card, and loses 4 life. + Ability ability = new EntersBattlefieldTriggeredAbility( + new SacrificeOpponentsEffect(StaticFilters.FILTER_PERMANENT_A_CREATURE) + ); + ability.addEffect(new DiscardEachPlayerEffect(TargetController.OPPONENT).setText(", discards a card")); + ability.addEffect(new LoseLifeOpponentsEffect(4).setText(", and loses 4 life")); + this.addAbility(ability); + } + + private DuskMangler(final DuskMangler card) { + super(card); + } + + @Override + public DuskMangler copy() { + return new DuskMangler(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DuskUrchins.java b/Mage.Sets/src/mage/cards/d/DuskUrchins.java index fa3a758d405..bc614bf1bc6 100644 --- a/Mage.Sets/src/mage/cards/d/DuskUrchins.java +++ b/Mage.Sets/src/mage/cards/d/DuskUrchins.java @@ -28,10 +28,10 @@ public final class DuskUrchins extends CardImpl { this.toughness = new MageInt(3); // Whenever Dusk Urchins attacks or blocks, put a -1/-1 counter on it. - this.addAbility(new AttacksOrBlocksTriggeredAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance()), false)); + this.addAbility(new AttacksOrBlocksTriggeredAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance()).setText("put a -1/-1 counter on it"), false)); // When Dusk Urchins dies, draw a card for each -1/-1 counter on it. - this.addAbility(new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(new CountersSourceCount(CounterType.M1M1)))); + this.addAbility(new DiesSourceTriggeredAbility(new DrawCardSourceControllerEffect(new CountersSourceCount(CounterType.M1M1)).setText("draw a card for each -1/-1 counter on it"))); } diff --git a/Mage.Sets/src/mage/cards/d/DuskwatchRecruiter.java b/Mage.Sets/src/mage/cards/d/DuskwatchRecruiter.java index b7ea9403b6a..7844b2006e5 100644 --- a/Mage.Sets/src/mage/cards/d/DuskwatchRecruiter.java +++ b/Mage.Sets/src/mage/cards/d/DuskwatchRecruiter.java @@ -7,21 +7,19 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.TransformAbility; import mage.cards.CardImpl; 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; /** * @author fireshoes */ public final class DuskwatchRecruiter extends CardImpl { - private static final FilterCreatureCard filter = new FilterCreatureCard("a creature card"); - public DuskwatchRecruiter(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.HUMAN); @@ -35,8 +33,8 @@ public final class DuskwatchRecruiter extends CardImpl { // {2}{G}: Look at the top three cards of your library. You may reveal a creature card from among them and put it into your hand. // Put the rest on the bottom of your library in any order. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new LookLibraryAndPickControllerEffect(3, 1, filter, true, false, Zone.HAND, true), + this.addAbility(new SimpleActivatedAbility( + new LookLibraryAndPickControllerEffect(3, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_ANY), new ManaCostsImpl("{2}{G}"))); // At the beginning of each upkeep, if no spells were cast last turn, transform Duskwatch Recruiter. @@ -52,5 +50,4 @@ public final class DuskwatchRecruiter extends CardImpl { public DuskwatchRecruiter copy() { return new DuskwatchRecruiter(this); } - -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/d/DustElemental.java b/Mage.Sets/src/mage/cards/d/DustElemental.java index 7b401cb6e40..cd61f01c9dc 100644 --- a/Mage.Sets/src/mage/cards/d/DustElemental.java +++ b/Mage.Sets/src/mage/cards/d/DustElemental.java @@ -20,7 +20,7 @@ import mage.filter.common.FilterControlledCreaturePermanent; */ public final class DustElemental extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(" creatures you control"); + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creatures you control"); public DustElemental(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}{W}"); diff --git a/Mage.Sets/src/mage/cards/d/DustOfMoments.java b/Mage.Sets/src/mage/cards/d/DustOfMoments.java index f69b07ec895..bae8372b21e 100644 --- a/Mage.Sets/src/mage/cards/d/DustOfMoments.java +++ b/Mage.Sets/src/mage/cards/d/DustOfMoments.java @@ -1,32 +1,23 @@ - package mage.cards.d; -import java.util.List; -import java.util.Locale; -import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.counters.Counter; import mage.counters.CounterType; -import mage.filter.Filter; -import mage.filter.FilterCard; -import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterPermanentOrSuspendedCard; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; + +import java.util.UUID; /** - * - * @author Gal Lerman - * + * @author TheElk801 */ public final class DustOfMoments extends CardImpl { @@ -34,12 +25,10 @@ public final class DustOfMoments extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); // Choose one - Remove two time counters from each permanent and each suspended card - this.getSpellAbility().addEffect(new RemoveCountersEffect()); + this.getSpellAbility().addEffect(new DustOfMomentsEffect(true)); // Or put two time counters on each permanent with a time counter on it and each suspended card - Mode mode = new Mode(); - mode.addEffect(new AddCountersEffect()); - this.getSpellAbility().addMode(mode); + this.getSpellAbility().addMode(new Mode(new DustOfMomentsEffect(false))); } private DustOfMoments(final DustOfMoments card) { @@ -50,173 +39,60 @@ public final class DustOfMoments extends CardImpl { public DustOfMoments copy() { return new DustOfMoments(this); } +} - //TODO: PermanentImpl.getCounters() and CardImpl.getCounters(game) don't return the same value for the same Card - //TODO: This means I can't use a Card generic for Permanents and Exiled cards and use Card.getCounters(game) - //TODO: This is the reason i've copy pasted some logic in DustOfMomentsEffect - //TODO: After this issue is fixed/explained i'll refactor the code - public abstract static class DustOfMomentsEffect extends OneShotEffect { +class DustOfMomentsEffect extends OneShotEffect { - private final Counter counter; - private final Filter permFilter; - private final Filter exiledFilter; + private static final FilterPermanentOrSuspendedCard filter = new FilterPermanentOrSuspendedCard(); + private final boolean remove; - public DustOfMomentsEffect() { - super(Outcome.Benefit); - this.counter = new Counter(CounterType.TIME.getName(), 2); - this.permFilter = new FilterPermanent("permanent and each suspended card"); - permFilter.add(CounterType.TIME.getPredicate()); + DustOfMomentsEffect(boolean remove) { + super(Outcome.Benefit); + this.remove = remove; + } - this.exiledFilter = new FilterCard("permanent and each suspended card"); - exiledFilter.add(CounterType.TIME.getPredicate()); - setText(); - } + private DustOfMomentsEffect(final DustOfMomentsEffect effect) { + super(effect); + this.remove = effect.remove; + } - public DustOfMomentsEffect(final DustOfMomentsEffect effect) { - super(effect); - this.counter = effect.counter.copy(); - this.permFilter = effect.permFilter.copy(); - this.exiledFilter = effect.exiledFilter.copy(); - } + @Override + public DustOfMomentsEffect copy() { + return new DustOfMomentsEffect(this); + } - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller != null && sourceObject != null) { - updatePermanents(source, game, controller, sourceObject); - updateSuspended(source, game, controller, sourceObject); - return true; - } - return false; - } - - private void updateSuspended(final Ability source, final Game game, final Player controller, final MageObject sourceObject) { - final List exiledCards = game.getExile().getAllCards(game); - execute(source, game, controller, sourceObject, exiledCards); - } - - private void updatePermanents(final Ability source, final Game game, final Player controller, final MageObject sourceObject) { - List permanents = game.getBattlefield().getAllActivePermanents(); - executeP(source, game, controller, sourceObject, permanents); - } - - private void executeP(final Ability source, final Game game, final Player controller, final MageObject sourceObject, final List cards) { - if (cards == null || cards.isEmpty()) { - return; - } - for (Permanent card : cards) { - if (permFilter.match(card, game)) { - final String counterName = counter.getName(); - if (shouldRemoveCounters()) { - final Counter existingCounterOfSameType = card.getCounters(game).get(counterName); - final int countersToRemove = Math.min(existingCounterOfSameType.getCount(), counter.getCount()); - final Counter modifiedCounter = new Counter(counterName, countersToRemove); - card.removeCounters(modifiedCounter, source, game); - } else { - card.addCounters(counter, source.getControllerId(), source, game); - } - if (!game.isSimulation()) { - game.informPlayers(sourceObject.getName() + ": " + - controller.getLogName() + getActionStr() + 's' + - counter.getCount() + ' ' + counterName.toLowerCase(Locale.ENGLISH) + - " counter on " + card.getName()); - } - } - } - } - - private void execute(final Ability source, final Game game, final Player controller, final MageObject sourceObject, final List cards) { - if (cards == null || cards.isEmpty()) { - return; - } - for (Card card : cards) { - if (exiledFilter.match(card, game)) { - final String counterName = counter.getName(); - if (shouldRemoveCounters()) { - final Counter existingCounterOfSameType = card.getCounters(game).get(counterName); - final int countersToRemove = Math.min(existingCounterOfSameType.getCount(), counter.getCount()); - final Counter modifiedCounter = new Counter(counterName, countersToRemove); - card.removeCounters(modifiedCounter, source, game); - } else { - card.addCounters(counter, source.getControllerId(), source, game); - } - if (!game.isSimulation()) { - game.informPlayers(sourceObject.getName() + ": " + - controller.getLogName() + getActionStr() + "s " + - counter.getCount() + ' ' + counterName.toLowerCase(Locale.ENGLISH) + - " counter on " + card.getName()); - } - } - } - } - - protected abstract boolean shouldRemoveCounters(); - - protected abstract String getActionStr(); - - private void setText() { - StringBuilder sb = new StringBuilder(); - sb.append(getActionStr()); - if (counter.getCount() > 1) { - sb.append(Integer.toString(counter.getCount())).append(' ').append(counter.getName().toLowerCase(Locale.ENGLISH)).append(" counters on each "); + @Override + public boolean apply(Game game, Ability source) { + for (Permanent permanent : game.getBattlefield().getActivePermanents( + remove ? StaticFilters.FILTER_PERMANENT : filter.getPermanentFilter(), + source.getControllerId(), source, game + )) { + if (remove) { + permanent.removeCounters(CounterType.TIME.createInstance(2), source, game); } else { - sb.append("a ").append(counter.getName().toLowerCase(Locale.ENGLISH)).append(" counter on each "); + permanent.addCounters(CounterType.TIME.createInstance(2), source, game); } - sb.append(permFilter.getMessage()); - staticText = sb.toString(); } + for (Card card : game.getExile().getCards(filter.getCardFilter(), game)) { + if (remove) { + card.removeCounters(CounterType.TIME.createInstance(2), source, game); + } else { + card.addCounters(CounterType.TIME.createInstance(2), source, game); + } + } + return true; } - public static class AddCountersEffect extends DustOfMomentsEffect { - - public AddCountersEffect() { - super(); - } - - public AddCountersEffect(final DustOfMomentsEffect effect) { - super(effect); - } - - @Override - protected boolean shouldRemoveCounters() { - return false; - } - - @Override - protected String getActionStr() { - return "add"; - } - - @Override - public Effect copy() { - return new AddCountersEffect(this); - } - } - - public static class RemoveCountersEffect extends DustOfMomentsEffect { - - public RemoveCountersEffect() { - super(); - } - - public RemoveCountersEffect(final DustOfMomentsEffect effect) { - super(effect); - } - - @Override - protected boolean shouldRemoveCounters() { - return true; - } - - @Override - protected String getActionStr() { - return "remove"; - } - - @Override - public Effect copy() { - return new RemoveCountersEffect(this); + @Override + public String getText(Mode mode) { + StringBuilder sb = new StringBuilder(remove ? "remove" : "put"); + sb.append(" two time counters "); + sb.append(remove ? "from" : "on"); + sb.append(" each permanent"); + if (!remove) { + sb.append("with a time counter on it"); } + sb.append(" and each suspended card"); + return sb.toString(); } } diff --git a/Mage.Sets/src/mage/cards/d/DutifulAttendant.java b/Mage.Sets/src/mage/cards/d/DutifulAttendant.java index 5c2f7f560f3..e50a9136818 100644 --- a/Mage.Sets/src/mage/cards/d/DutifulAttendant.java +++ b/Mage.Sets/src/mage/cards/d/DutifulAttendant.java @@ -11,7 +11,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.common.TargetCardInYourGraveyard; /** @@ -23,7 +23,7 @@ public final class DutifulAttendant extends CardImpl { private static final FilterCreatureCard filter = new FilterCreatureCard("another target creature card from your graveyard"); static { - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); } public DutifulAttendant(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DwarvenBlastminer.java b/Mage.Sets/src/mage/cards/d/DwarvenBlastminer.java index 92f695b10b9..28905a56166 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenBlastminer.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenBlastminer.java @@ -34,7 +34,7 @@ public final class DwarvenBlastminer extends CardImpl { this.addAbility(ability); // Morph {R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{R}"))); } private DwarvenBlastminer(final DwarvenBlastminer card) { diff --git a/Mage.Sets/src/mage/cards/d/DwarvenSeaClan.java b/Mage.Sets/src/mage/cards/d/DwarvenSeaClan.java index c5eed289139..d831766e919 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenSeaClan.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenSeaClan.java @@ -30,7 +30,7 @@ public final class DwarvenSeaClan extends CardImpl { private static final FilterAttackingOrBlockingCreature filter = new FilterAttackingOrBlockingCreature(); static { - filter.add(new ControllerControlsIslandPredicate()); + filter.add(ControllerControlsIslandPredicate.instance); } public DwarvenSeaClan(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DwarvenShrine.java b/Mage.Sets/src/mage/cards/d/DwarvenShrine.java index 16e76e0790c..c09a4a42cfd 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenShrine.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenShrine.java @@ -88,7 +88,7 @@ class DwarvenShrineEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int count = 0; - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { Spell spell = (Spell) game.getState().getValue("dwarvenShrine" + mageObject); if (spell != null) { diff --git a/Mage.Sets/src/mage/cards/d/DwynenGiltLeafDaen.java b/Mage.Sets/src/mage/cards/d/DwynenGiltLeafDaen.java index 58cf085cc49..0e81a67b938 100644 --- a/Mage.Sets/src/mage/cards/d/DwynenGiltLeafDaen.java +++ b/Mage.Sets/src/mage/cards/d/DwynenGiltLeafDaen.java @@ -42,7 +42,7 @@ public final class DwynenGiltLeafDaen extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, new FilterCreaturePermanent(SubType.ELF, "Elf creatures"), true))); // Whenever Dwynen, Gilt-Leaf Daen attacks, you gain 1 life for each attacking Elf you control. - this.addAbility(new AttacksTriggeredAbility(new GainLifeEffect(new PermanentsOnBattlefieldCount(filter)), false)); + this.addAbility(new AttacksTriggeredAbility(new GainLifeEffect(new PermanentsOnBattlefieldCount(filter)).setText("you gain 1 life for each attacking Elf you control"), false)); } private DwynenGiltLeafDaen(final DwynenGiltLeafDaen card) { diff --git a/Mage.Sets/src/mage/cards/d/DynavoltTower.java b/Mage.Sets/src/mage/cards/d/DynavoltTower.java index b0ef2837dad..33bec510004 100644 --- a/Mage.Sets/src/mage/cards/d/DynavoltTower.java +++ b/Mage.Sets/src/mage/cards/d/DynavoltTower.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; @@ -12,24 +10,27 @@ import mage.abilities.effects.common.counter.GetEnergyCountersControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.common.FilterInstantOrSorcerySpell; +import mage.filter.StaticFilters; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author emerald000 */ public final class DynavoltTower extends CardImpl { public DynavoltTower(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // Whenever you cast an instant or sorcery spell, you get {E}{E}. - this.addAbility(new SpellCastControllerTriggeredAbility(new GetEnergyCountersControllerEffect(2), new FilterInstantOrSorcerySpell(), false)); + this.addAbility(new SpellCastControllerTriggeredAbility( + new GetEnergyCountersControllerEffect(2), + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false + )); // {T}, Pay {E}{E}{E}{E}{E}: Dynavolt Tower deals 3 damage to any target. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(3), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(3), new TapSourceCost()); ability.addCost(new PayEnergyCost(5)); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/e/EHondaSumoChampion.java b/Mage.Sets/src/mage/cards/e/EHondaSumoChampion.java new file mode 100644 index 00000000000..711cabfee2e --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EHondaSumoChampion.java @@ -0,0 +1,60 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.ruleModifying.CombatDamageByToughnessEffect; +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.filter.StaticFilters; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EHondaSumoChampion extends CardImpl { + + public EHondaSumoChampion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(0); + this.toughness = new MageInt(7); + + // Sumo Spirit—As long as it's your turn, each creature assigns combat damage equal to its toughness rather than its power. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new CombatDamageByToughnessEffect(StaticFilters.FILTER_PERMANENT_CREATURE, false), + MyTurnCondition.instance, "as long as it's your turn, each creature " + + "assigns combat damage equal to its toughness rather than its power" + )).withFlavorWord("Sumo Spirit")); + + // Hundred Hand Slap—Whenever E. Honda, Sumo Champion attacks, up to one hundred target creatures each get +0/+X until end of turn, where X is the number of cards in your hand. + Ability ability = new AttacksTriggeredAbility(new BoostTargetEffect( + StaticValue.get(0), CardsInTargetPlayerHandCount.instance, Duration.EndOfTurn + ).setText("up to one hundred target creatures each get +0/+X until end of turn, where X is the number of cards in your hand")); + ability.addTarget(new TargetCreaturePermanent(0, 100)); + this.addAbility(ability.withFlavorWord("Hundred Hand Slap")); + } + + private EHondaSumoChampion(final EHondaSumoChampion card) { + super(card); + } + + @Override + public EHondaSumoChampion copy() { + return new EHondaSumoChampion(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EMPBlast.java b/Mage.Sets/src/mage/cards/e/EMPBlast.java index 8a7bf01487a..e5775833dd7 100644 --- a/Mage.Sets/src/mage/cards/e/EMPBlast.java +++ b/Mage.Sets/src/mage/cards/e/EMPBlast.java @@ -59,7 +59,7 @@ class EMPBlastEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent artifact : game.getBattlefield().getActivePermanents(new FilterArtifactPermanent(), source.getControllerId(), source.getSourceId(), game)) { + for (Permanent artifact : game.getBattlefield().getActivePermanents(new FilterArtifactPermanent(), source.getControllerId(), source, game)) { artifact.tap(source, game); } return true; diff --git a/Mage.Sets/src/mage/cards/e/EarthenGoo.java b/Mage.Sets/src/mage/cards/e/EarthenGoo.java index 68b38ce2c5f..2a2d98144af 100644 --- a/Mage.Sets/src/mage/cards/e/EarthenGoo.java +++ b/Mage.Sets/src/mage/cards/e/EarthenGoo.java @@ -37,9 +37,8 @@ public final class EarthenGoo extends CardImpl { // Cumulative upkeep {R} or {G} this.addAbility(new CumulativeUpkeepAbility(new OrCost( - new ManaCostsImpl("{R}"), - new ManaCostsImpl("{G}"), - "{R} or {G}" + "{R} or {G}", new ManaCostsImpl("{R}"), + new ManaCostsImpl("{G}") ))); // Earthen Goo gets +1/+1 for each age counter on it. diff --git a/Mage.Sets/src/mage/cards/e/EarthshakerKhenra.java b/Mage.Sets/src/mage/cards/e/EarthshakerKhenra.java index 41343176fdb..529169415ec 100644 --- a/Mage.Sets/src/mage/cards/e/EarthshakerKhenra.java +++ b/Mage.Sets/src/mage/cards/e/EarthshakerKhenra.java @@ -73,7 +73,7 @@ enum EarthshakerKhenraPredicate implements ObjectSourcePlayerPredicate { @Override public boolean apply(ObjectSourcePlayer input, Game game) { - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(input.getSourceId()); + Permanent sourcePermanent = input.getSource().getSourcePermanentOrLKI(game); return sourcePermanent != null && input.getObject().getPower().getValue() <= sourcePermanent.getPower().getValue(); } } diff --git a/Mage.Sets/src/mage/cards/e/EarwigSquad.java b/Mage.Sets/src/mage/cards/e/EarwigSquad.java index 516afaaaddc..8af66926dc1 100644 --- a/Mage.Sets/src/mage/cards/e/EarwigSquad.java +++ b/Mage.Sets/src/mage/cards/e/EarwigSquad.java @@ -5,23 +5,15 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.ProwlCostWasPaidCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.search.SearchLibraryAndExileTargetEffect; import mage.abilities.hint.common.ProwlCostWasPaidHint; import mage.abilities.keyword.ProwlAbility; -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.game.Game; -import mage.players.Player; -import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetOpponent; -import java.util.List; import java.util.UUID; /** @@ -41,11 +33,15 @@ public final class EarwigSquad extends CardImpl { this.addAbility(new ProwlAbility(this, "{2}{B}")); // When Earwig Squad enters the battlefield, if its prowl cost was paid, search target opponent's library for three cards and exile them. Then that player shuffles their library. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new EarwigSquadEffect(), false); + Ability ability = new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility( + new SearchLibraryAndExileTargetEffect(3, true), false + ), ProwlCostWasPaidCondition.instance, "When {this} enters the battlefield, " + + "if its prowl cost was paid, search target opponent's library for three cards " + + "and exile them. Then that player shuffles." + ); ability.addTarget(new TargetOpponent()); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, ProwlCostWasPaidCondition.instance, - "When {this} enters the battlefield, if its prowl cost was paid, search target opponent's library for three cards and exile them. Then that player shuffles.") - .addHint(ProwlCostWasPaidHint.instance)); + this.addAbility(ability.addHint(ProwlCostWasPaidHint.instance)); } @@ -58,41 +54,3 @@ public final class EarwigSquad extends CardImpl { return new EarwigSquad(this); } } - -class EarwigSquadEffect extends OneShotEffect { - - public EarwigSquadEffect() { - super(Outcome.Benefit); - staticText = "search target opponent's library for three cards and exile them. Then that player shuffles"; - } - - public EarwigSquadEffect(final EarwigSquadEffect effect) { - super(effect); - } - - @Override - public EarwigSquadEffect copy() { - return new EarwigSquadEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player opponent = game.getPlayer(source.getFirstTarget()); - Player player = game.getPlayer(source.getControllerId()); - if (player != null && opponent != null) { - TargetCardInLibrary target = new TargetCardInLibrary(0, 3, new FilterCard("cards from opponents library to exile")); - if (player.searchLibrary(target, source, game, opponent.getId())) { - List targets = target.getTargets(); - for (UUID targetId : targets) { - Card card = opponent.getLibrary().remove(targetId, game); - if (card != null) { - player.moveCardToExileWithInfo(card, null, null, source, game, Zone.LIBRARY, true); - } - } - } - opponent.shuffleLibrary(source, game); - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/e/EatenAlive.java b/Mage.Sets/src/mage/cards/e/EatenAlive.java index 27b3da87ebd..36b0cee0670 100644 --- a/Mage.Sets/src/mage/cards/e/EatenAlive.java +++ b/Mage.Sets/src/mage/cards/e/EatenAlive.java @@ -22,8 +22,8 @@ public final class EatenAlive extends CardImpl { // As an additional cost to cast this spell, sacrifice a creature or pay {3}{B}. this.getSpellAbility().addCost(new OrCost( - new SacrificeTargetCost(new TargetControlledCreaturePermanent()), - new ManaCostsImpl<>("{3}{B}"), "sacrifice a creature or pay {3}{B}" + "sacrifice a creature or pay {3}{B}", new SacrificeTargetCost(new TargetControlledCreaturePermanent()), + new ManaCostsImpl<>("{3}{B}") )); // Exile target creature or planeswalker. diff --git a/Mage.Sets/src/mage/cards/e/EaterOfVirtue.java b/Mage.Sets/src/mage/cards/e/EaterOfVirtue.java new file mode 100644 index 00000000000..8af937ff619 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EaterOfVirtue.java @@ -0,0 +1,193 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.cards.e; + +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.DiesAttachedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.MenaceAbility; +import mage.abilities.keyword.ProtectionAbility; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.SetTargetPointer; +import mage.constants.SubLayer; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * @author jeffwadsworth + */ +public final class EaterOfVirtue extends CardImpl { + + public EaterOfVirtue(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + + addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.EQUIPMENT); + + // Whenever equipped creature dies, exile it. + this.addAbility(new DiesAttachedTriggeredAbility(new EaterOfVirtueExileEffect(), "equipped creature", false, true, SetTargetPointer.CARD)); + + // Equipped creature gets +2/+0. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(2, 0, Duration.WhileOnBattlefield))); + + // As long as a card exiled with Eater of Virtue has flying, equipped creature has flying. The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, protection, reach, trample, and vigilance. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new EaterOfVirtueGainAbilityAttachedEffect())); + + // Equip {1} + this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(1))); + + } + + private EaterOfVirtue(final EaterOfVirtue card) { + super(card); + } + + @Override + public EaterOfVirtue copy() { + return new EaterOfVirtue(this); + } +} + +class EaterOfVirtueExileEffect extends OneShotEffect { + + EaterOfVirtueExileEffect() { + super(Outcome.Neutral); + this.staticText = "exile it"; + } + + EaterOfVirtueExileEffect(final EaterOfVirtueExileEffect effect) { + super(effect); + } + + @Override + public EaterOfVirtueExileEffect copy() { + return new EaterOfVirtueExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent eaterOfVirtue = game.getPermanent(source.getSourceId()); + Card exiledCard = game.getCard(targetPointer.getFirst(game, source)); + if (controller != null + && eaterOfVirtue != null + && exiledCard != null) { + UUID exileId = CardUtil.getExileZoneId(source.getSourceId().toString() + "cards exiled by Eater of Virtue", game); + controller.moveCardsToExile(exiledCard, source, game, true, exileId, eaterOfVirtue.getIdName()); + return true; + } + return false; + } +} + +class EaterOfVirtueGainAbilityAttachedEffect extends ContinuousEffectImpl { + + public EaterOfVirtueGainAbilityAttachedEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "As long as a card exiled with Eater of Virtue has flying, equipped creature has flying. The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, protection, reach, trample, and vigilance"; + } + + public EaterOfVirtueGainAbilityAttachedEffect(final EaterOfVirtueGainAbilityAttachedEffect effect) { + super(effect); + } + + @Override + public EaterOfVirtueGainAbilityAttachedEffect copy() { + return new EaterOfVirtueGainAbilityAttachedEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent eaterOfVirtue = game.getPermanent(source.getSourceId()); + if (eaterOfVirtue != null + && eaterOfVirtue.getAttachedTo() != null) { + Permanent permanent = game.getPermanent(eaterOfVirtue.getAttachedTo()); + if (permanent != null) { + UUID exileId = CardUtil.getExileZoneId(source.getSourceId().toString() + "cards exiled by Eater of Virtue", game); + if (game.getState().getExile().getExileZone(exileId) != null + && game.getState().getExile().getExileZone(exileId).size() > 0) { + Set cardsInExile = game.getState().getExile().getExileZone(exileId).getCards(game); + for (Card card : cardsInExile) { + for (Ability a : card.getAbilities()) { + if (a instanceof FlyingAbility) { + permanent.addAbility(a, source.getSourceId(), game); + } + if (a instanceof FirstStrikeAbility) { + permanent.addAbility(a, source.getSourceId(), game); + } + if (a instanceof DoubleStrikeAbility) { + permanent.addAbility(a, source.getSourceId(), game); + } + if (a instanceof DeathtouchAbility) { + permanent.addAbility(a, source.getSourceId(), game); + } + if (a instanceof HasteAbility) { + permanent.addAbility(a, source.getSourceId(), game); + } + if (a instanceof HexproofAbility) { + permanent.addAbility(a, source.getSourceId(), game); + } + if (a instanceof IndestructibleAbility) { + permanent.addAbility(a, source.getSourceId(), game); + } + if (a instanceof LifelinkAbility) { + permanent.addAbility(a, source.getSourceId(), game); + } + if (a instanceof MenaceAbility) { + permanent.addAbility(a, source.getSourceId(), game); + } + if (a instanceof ProtectionAbility) { + permanent.addAbility(a, source.getSourceId(), game); + } + if (a instanceof IndestructibleAbility) { + permanent.addAbility(a, source.getSourceId(), game); + } + if (a instanceof ReachAbility) { + permanent.addAbility(a, source.getSourceId(), game); + } + if (a instanceof TrampleAbility) { + permanent.addAbility(a, source.getSourceId(), game); + } + if (a instanceof VigilanceAbility) { + permanent.addAbility(a, source.getSourceId(), game); + } + } + } + } + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EbonbladeReaper.java b/Mage.Sets/src/mage/cards/e/EbonbladeReaper.java index 6abcd54f01e..e8c4c179396 100644 --- a/Mage.Sets/src/mage/cards/e/EbonbladeReaper.java +++ b/Mage.Sets/src/mage/cards/e/EbonbladeReaper.java @@ -36,7 +36,7 @@ public final class EbonbladeReaper extends CardImpl { this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new LoseHalfLifeTargetEffect(), false, true)); //Morph {3}{B}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{3}{B}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl<>("{3}{B}{B}"))); } private EbonbladeReaper(final EbonbladeReaper card) { diff --git a/Mage.Sets/src/mage/cards/e/EbonyCharm.java b/Mage.Sets/src/mage/cards/e/EbonyCharm.java index 73bef406273..72087d73a51 100644 --- a/Mage.Sets/src/mage/cards/e/EbonyCharm.java +++ b/Mage.Sets/src/mage/cards/e/EbonyCharm.java @@ -31,15 +31,13 @@ public final class EbonyCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetOpponent()); // or exile up to three target cards from a single graveyard; - Mode mode = new Mode(); - mode.addEffect(new ExileTargetEffect()); + Mode mode = new Mode(new ExileTargetEffect()); mode.addTarget((new TargetCardInASingleGraveyard(0, 3, StaticFilters.FILTER_CARD_CARDS))); this.getSpellAbility().addMode(mode); // or target creature gains fear until end of turn. - mode = new Mode(); + mode = new Mode(new GainAbilityTargetEffect(FearAbility.getInstance(), Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); - mode.addEffect(new GainAbilityTargetEffect(FearAbility.getInstance(), Duration.EndOfTurn)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/e/EccentricFarmer.java b/Mage.Sets/src/mage/cards/e/EccentricFarmer.java index 018ce65be2b..86dbdc7cc0b 100644 --- a/Mage.Sets/src/mage/cards/e/EccentricFarmer.java +++ b/Mage.Sets/src/mage/cards/e/EccentricFarmer.java @@ -74,7 +74,7 @@ class EccentricFarmerEffect extends OneShotEffect { TargetCard target = new TargetCardInYourGraveyard( 0, 1, StaticFilters.FILTER_CARD_LAND, true ); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); player.moveCards(game.getCard(target.getFirstTarget()), Zone.HAND, source, game); return true; } diff --git a/Mage.Sets/src/mage/cards/e/EchoBaseCommando.java b/Mage.Sets/src/mage/cards/e/EchoBaseCommando.java index 7812cab8b0b..aee603a7e70 100644 --- a/Mage.Sets/src/mage/cards/e/EchoBaseCommando.java +++ b/Mage.Sets/src/mage/cards/e/EchoBaseCommando.java @@ -86,7 +86,7 @@ class EchoBaseCommandoEffect extends CostModificationEffectImpl { public boolean applies(Ability abilityToModify, Ability source, Game game) { if (abilityToModify.getAbilityType() == AbilityType.ACTIVATED || (abilityToModify.getAbilityType() == AbilityType.MANA && (abilityToModify instanceof ActivatedAbility))) { Permanent permanent = game.getPermanent(abilityToModify.getSourceId()); - if (filter.match(permanent, source.getSourceId(), source.getControllerId(), game)) { + if (filter.match(permanent, source.getControllerId(), source, game)) { return true; } } diff --git a/Mage.Sets/src/mage/cards/e/EchoInspector.java b/Mage.Sets/src/mage/cards/e/EchoInspector.java new file mode 100644 index 00000000000..964a4eddfba --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EchoInspector.java @@ -0,0 +1,42 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EchoInspector extends CardImpl { + + public EchoInspector(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Echo Inspector enters the battlefield, it connives. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ConniveSourceEffect())); + } + + private EchoInspector(final EchoInspector card) { + super(card); + } + + @Override + public EchoInspector copy() { + return new EchoInspector(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EchoTracer.java b/Mage.Sets/src/mage/cards/e/EchoTracer.java index 25f291bbb0d..a4cf5c241db 100644 --- a/Mage.Sets/src/mage/cards/e/EchoTracer.java +++ b/Mage.Sets/src/mage/cards/e/EchoTracer.java @@ -28,7 +28,7 @@ public final class EchoTracer extends CardImpl { this.toughness = new MageInt(2); // Morph {2}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{U}"))); // When Echo Tracer is turned face up, return target creature to its owner's hand. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new ReturnToHandTargetEffect()); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/e/EcologicalAppreciation.java b/Mage.Sets/src/mage/cards/e/EcologicalAppreciation.java index 422f92a1d28..2af61be2533 100644 --- a/Mage.Sets/src/mage/cards/e/EcologicalAppreciation.java +++ b/Mage.Sets/src/mage/cards/e/EcologicalAppreciation.java @@ -1,6 +1,5 @@ package mage.cards.e; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileSpellEffect; @@ -18,6 +17,7 @@ import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetCardWithDifferentNameInLibrary; import mage.target.common.TargetOpponent; import mage.util.CardUtil; @@ -28,7 +28,6 @@ import java.util.UUID; import java.util.stream.Collectors; /** - * * @author htrajan */ public final class EcologicalAppreciation extends CardImpl { @@ -55,7 +54,9 @@ class EcologicalAppreciationEffect extends OneShotEffect { EcologicalAppreciationEffect() { super(Outcome.Benefit); - staticText = "search your library and graveyard for up to four creature cards with different names that each have mana value X or less and reveal them. An opponent chooses two of those cards. Shuffle the chosen cards into your library and put the rest onto the battlefield"; + staticText = "search your library and graveyard for up to four creature cards with different names " + + "that each have mana value X or less and reveal them. An opponent chooses two of those cards. " + + "Shuffle the chosen cards into your library and put the rest onto the battlefield"; } private EcologicalAppreciationEffect(final EcologicalAppreciationEffect effect) { @@ -76,85 +77,69 @@ class EcologicalAppreciationEffect extends OneShotEffect { int xValue = source.getManaCostsToPay().getX(); FilterCard filter = new FilterCreatureCard(); filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, xValue + 1)); - TargetCard targetCardsInLibrary = new TargetCardInLibrary(0, 4, filter) { - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { - if (!super.canTarget(playerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - Set disallowedCards = this.getTargets().stream() - .map(game::getCard) - .collect(Collectors.toSet()); - return isValidTarget(card, disallowedCards); - } - }; + TargetCardInLibrary targetCardsInLibrary = new TargetCardWithDifferentNameInLibrary(0, 4, filter); targetCardsInLibrary.setNotTarget(true); targetCardsInLibrary.withChooseHint("Step 1 of 2: Search library"); - player.choose(Outcome.PutCreatureInPlay, new CardsImpl(player.getLibrary().getCards(game)), targetCardsInLibrary, game); + player.searchLibrary(targetCardsInLibrary, source, game); Cards cards = new CardsImpl(targetCardsInLibrary.getTargets()); + cards.retainZone(Zone.LIBRARY, game); - boolean status = !cards.isEmpty(); - - if (status) { - int remainingCards = 4 - cards.size(); - if (remainingCards > 0) { - TargetCard targetCardsInGY = new TargetCardInYourGraveyard(0, remainingCards, filter) { - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { - if (!super.canTarget(playerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - Set disallowedCards = this.getTargets().stream() + int remainingCards = 4 - cards.size(); + if (remainingCards > 0) { + TargetCard targetCardsInGY = new TargetCardInYourGraveyard(0, remainingCards, filter) { + @Override + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + if (!super.canTarget(playerId, id, source, game)) { + return false; + } + Card card = game.getCard(id); + Set disallowedCards = this.getTargets().stream() .map(game::getCard) .collect(Collectors.toSet()); - Set checkList = new HashSet<>(); - checkList.addAll(disallowedCards); - checkList.addAll(cards.getCards(game)); - return isValidTarget(card, checkList); - } - }; - targetCardsInGY.setNotTarget(true); - targetCardsInGY.withChooseHint("Step 2 of 2: Search graveyard"); - player.choose(Outcome.PutCreatureInPlay, new CardsImpl(player.getGraveyard().getCards(game)), targetCardsInGY, game); - cards.addAll(targetCardsInGY.getTargets()); - } + Set checkList = new HashSet<>(); + checkList.addAll(disallowedCards); + checkList.addAll(cards.getCards(game)); + return isValidTarget(card, checkList); + } + }; + targetCardsInGY.setNotTarget(true); + targetCardsInGY.withChooseHint("Step 2 of 2: Search graveyard"); + player.choose(Outcome.PutCreatureInPlay, player.getGraveyard(), targetCardsInGY, game); + cards.addAll(targetCardsInGY.getTargets()); + cards.removeIf(uuid -> { + Zone zone = game.getState().getZone(uuid); + return zone != Zone.GRAVEYARD && zone != Zone.LIBRARY; + }); + } - TargetOpponent targetOpponent = new TargetOpponent(); - targetOpponent.setNotTarget(true); - player.choose(outcome, targetOpponent, source.getSourceId(), game); - Player opponent = game.getPlayer(targetOpponent.getFirstTarget()); + TargetOpponent targetOpponent = new TargetOpponent(); + targetOpponent.setNotTarget(true); + player.choose(outcome, targetOpponent, source, game); + Player opponent = game.getPlayer(targetOpponent.getFirstTarget()); - if (opponent == null) { - status = false; - } - - if (status) { - TargetCard chosenCards = new TargetCard(2, Zone.ALL, StaticFilters.FILTER_CARD); - chosenCards.setNotTarget(true); - opponent.choose(outcome, cards, chosenCards, game); - Cards toShuffle = new CardsImpl(chosenCards.getTargets().stream() + if (opponent != null) { + TargetCard chosenCards = new TargetCard(2, Zone.ALL, StaticFilters.FILTER_CARD); + chosenCards.setNotTarget(true); + opponent.choose(outcome, cards, chosenCards, game); + Cards toShuffle = new CardsImpl(chosenCards.getTargets().stream() .map(game::getCard) .collect(Collectors.toList())); - player.putCardsOnTopOfLibrary(toShuffle, game, source, false); - cards.removeAll(toShuffle); + player.putCardsOnTopOfLibrary(toShuffle, game, source, false); + cards.removeAll(toShuffle); - player.moveCards(cards, Zone.BATTLEFIELD, source, game); - } + player.moveCards(cards, Zone.BATTLEFIELD, source, game); } player.shuffleLibrary(source, game); - return status; + return true; } private boolean isValidTarget(Card target, Set disallowedCards) { - return target != null && - disallowedCards.stream() + return target != null + && disallowedCards.stream() .filter(Objects::nonNull) - .map(MageObject::getName) - .noneMatch(name -> CardUtil.haveSameNames(name, target.getName())); + .noneMatch(card -> CardUtil.haveSameNames(card, target)); } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/e/EdgarMarkov.java b/Mage.Sets/src/mage/cards/e/EdgarMarkov.java index 6dfd5ad28d5..53158da3c0e 100644 --- a/Mage.Sets/src/mage/cards/e/EdgarMarkov.java +++ b/Mage.Sets/src/mage/cards/e/EdgarMarkov.java @@ -51,7 +51,7 @@ public final class EdgarMarkov extends CardImpl { Ability ability = new ConditionalInterveningIfTriggeredAbility( new SpellCastControllerTriggeredAbility(Zone.ALL, new CreateTokenEffect(new EdgarMarkovToken()), filter2, false, false), SourceOnBattlefieldOrCommandZoneCondition.instance, - "Eminence — Whenever you cast another Vampire spell, if {this} is in the command zone or on the battlefield, create a 1/1 black Vampire creature token."); + " possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set possibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); Set names = this.getTargets() .stream() .map(game::getCard) diff --git a/Mage.Sets/src/mage/cards/e/EfreetWeaponmaster.java b/Mage.Sets/src/mage/cards/e/EfreetWeaponmaster.java index 5747ba0848b..853d1be254c 100644 --- a/Mage.Sets/src/mage/cards/e/EfreetWeaponmaster.java +++ b/Mage.Sets/src/mage/cards/e/EfreetWeaponmaster.java @@ -42,7 +42,7 @@ public final class EfreetWeaponmaster extends CardImpl { this.addAbility(new EfreetWeaponmasterAbility()); // Morph {2}{U}{R}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}{R}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{U}{R}{W}"))); } private EfreetWeaponmaster(final EfreetWeaponmaster card) { diff --git a/Mage.Sets/src/mage/cards/e/EgoErasure.java b/Mage.Sets/src/mage/cards/e/EgoErasure.java index 15f98b62d6f..5e04a97b332 100644 --- a/Mage.Sets/src/mage/cards/e/EgoErasure.java +++ b/Mage.Sets/src/mage/cards/e/EgoErasure.java @@ -13,7 +13,6 @@ import mage.game.permanent.Permanent; import mage.target.TargetPlayer; import java.util.Iterator; -import java.util.List; import java.util.UUID; /** @@ -28,9 +27,8 @@ public final class EgoErasure extends CardImpl { // Changeling this.addAbility(new ChangelingAbility()); - //Creatures target player controls get -2/+0 and lose all creature types until end of turn. - this.getSpellAbility().addEffect(new EgoErasureBoostEffect()); - this.getSpellAbility().addEffect(new EgoErasureLoseEffect()); + // Creatures target player controls get -2/+0 and lose all creature types until end of turn. + this.getSpellAbility().addEffect(new EgoErasureEffect()); this.getSpellAbility().addTarget(new TargetPlayer()); } @@ -44,84 +42,67 @@ public final class EgoErasure extends CardImpl { } } -class EgoErasureLoseEffect extends ContinuousEffectImpl { +class EgoErasureEffect extends ContinuousEffectImpl { - public EgoErasureLoseEffect() { - super(Duration.EndOfTurn, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Neutral); - staticText = "and lose all creature types until end of turn"; + public EgoErasureEffect() { + super(Duration.EndOfTurn, Outcome.Neutral); + staticText = "creatures target player controls get -2/-0 and lose all creature types until end of turn"; } - public EgoErasureLoseEffect(final EgoErasureLoseEffect effect) { + public EgoErasureEffect(final EgoErasureEffect effect) { super(effect); } @Override - public EgoErasureLoseEffect copy() { - return new EgoErasureLoseEffect(this); + public EgoErasureEffect copy() { + return new EgoErasureEffect(this); } @Override public void init(Ability source, Game game) { super.init(source, game); - if (this.affectedObjectsSet) { - List creatures = game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getFirstTarget(), game); - for (Permanent creature : creatures) { - affectedObjectList.add(new MageObjectReference(creature, game)); + game.getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, + source.getFirstTarget(), source, game + ).stream() + .map(permanent -> new MageObjectReference(permanent, game)) + .forEach(affectedObjectList::add); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + for (Iterator it = affectedObjectList.iterator(); it.hasNext(); ) { + Permanent permanent = it.next().getPermanent(game); + if (permanent == null) { + it.remove(); + continue; + } + switch (layer) { + case TypeChangingEffects_4: + permanent.removeAllCreatureTypes(game); + break; + case PTChangingEffects_7: + if (sublayer == SubLayer.ModifyPT_7c) { + permanent.addPower(-2); + } + break; } } + if (affectedObjectList.isEmpty()) { + discard(); + return false; + } + return true; } @Override public boolean apply(Game game, Ability source) { - for (Iterator it = affectedObjectList.iterator(); it.hasNext(); ) { - Permanent permanent = it.next().getPermanent(game); - if (permanent != null) { - permanent.removeAllCreatureTypes(game); - } else { - it.remove(); - } - } - return true; - } -} - -class EgoErasureBoostEffect extends ContinuousEffectImpl { - - public EgoErasureBoostEffect() { - super(Duration.EndOfTurn, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.Benefit); - staticText = "Creatures target player controls get -2/+0"; - } - - public EgoErasureBoostEffect(final EgoErasureBoostEffect effect) { - super(effect); - } - - @Override - public EgoErasureBoostEffect copy() { - return new EgoErasureBoostEffect(this); - } - - @Override - public void init(Ability source, Game game) { - super.init(source, game); - if (this.affectedObjectsSet) { - List creatures = game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getFirstTarget(), game); - for (Permanent creature : creatures) { - affectedObjectList.add(new MageObjectReference(creature, game)); - } - } - } - - @Override - public boolean apply(Game game, Ability source) { - for (Iterator it = affectedObjectList.iterator(); it.hasNext(); ) { - Permanent permanent = it.next().getPermanent(game); - if (permanent != null) { - permanent.addPower(-2); - } else { - it.remove(); - } - } - return true; + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.TypeChangingEffects_4 || layer == Layer.PTChangingEffects_7; } } diff --git a/Mage.Sets/src/mage/cards/e/EiganjoSeatOfTheEmpire.java b/Mage.Sets/src/mage/cards/e/EiganjoSeatOfTheEmpire.java index a4f063bf4ce..0c7396314a3 100644 --- a/Mage.Sets/src/mage/cards/e/EiganjoSeatOfTheEmpire.java +++ b/Mage.Sets/src/mage/cards/e/EiganjoSeatOfTheEmpire.java @@ -36,7 +36,7 @@ public final class EiganjoSeatOfTheEmpire extends CardImpl { )); ability.addTarget(new TargetAttackingOrBlockingCreature()); ability.setCostAdjuster(LegendaryCreatureCostAdjuster.instance); - this.addAbility(ability); + this.addAbility(ability.addHint(LegendaryCreatureCostAdjuster.getHint())); } private EiganjoSeatOfTheEmpire(final EiganjoSeatOfTheEmpire card) { diff --git a/Mage.Sets/src/mage/cards/e/ElderBrain.java b/Mage.Sets/src/mage/cards/e/ElderBrain.java new file mode 100644 index 00000000000..2d062c76708 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ElderBrain.java @@ -0,0 +1,119 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.*; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ElderBrain extends CardImpl { + + public ElderBrain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}"); + + this.subtype.add(SubType.HORROR); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Menace + this.addAbility(new MenaceAbility(false)); + + // Whenever Elder Brain attacks a player, exile all cards from that player's hand, then they draw that many cards. You may play lands and cast spells from among the exiled cards for as long as they remain exiled. If you cast a spell this way, you may spend mana as though it were mana of any color to cast it. + this.addAbility(new ElderBrainTriggeredAbility()); + } + + private ElderBrain(final ElderBrain card) { + super(card); + } + + @Override + public ElderBrain copy() { + return new ElderBrain(this); + } +} + +class ElderBrainTriggeredAbility extends TriggeredAbilityImpl { + + ElderBrainTriggeredAbility() { + super(Zone.BATTLEFIELD, new ElderBrainEffect()); + } + + private ElderBrainTriggeredAbility(final ElderBrainTriggeredAbility ability) { + super(ability); + } + + @Override + public ElderBrainTriggeredAbility copy() { + return new ElderBrainTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Player player = game.getPlayer(game.getCombat().getDefenderId(this.getSourceId())); + if (player == null) { + return false; + } + this.getEffects().setTargetPointer(new FixedTarget(player.getId())); + return true; + } + + @Override + public String getTriggerPhrase() { + return "Whenever {this} attacks a player, "; + } +} + +class ElderBrainEffect extends OneShotEffect { + + ElderBrainEffect() { + super(Outcome.Benefit); + staticText = "exile all cards from that player's hand, then they draw that many cards. " + + "You may play lands and cast spells from among the exiled cards for as long as they remain exiled. " + + "If you cast a spell this way, you may spend mana as though it were mana of any color to cast it"; + } + + private ElderBrainEffect(final ElderBrainEffect effect) { + super(effect); + } + + @Override + public ElderBrainEffect copy() { + return new ElderBrainEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (controller == null || player == null || player.getHand().isEmpty()) { + return false; + } + Cards cards = new CardsImpl(player.getHand()); + controller.moveCards(cards, Zone.EXILED, source, game); + player.drawCards(cards.size(), source, game); + for (Card card : cards.getCards(game)) { + CardUtil.makeCardPlayable( + game, source, card, Duration.Custom, + true, controller.getId(), null + ); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/e/ElderLandWurm.java b/Mage.Sets/src/mage/cards/e/ElderLandWurm.java index fc39235c346..d4e549fab31 100644 --- a/Mage.Sets/src/mage/cards/e/ElderLandWurm.java +++ b/Mage.Sets/src/mage/cards/e/ElderLandWurm.java @@ -34,7 +34,11 @@ public final class ElderLandWurm extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // When Elder Land Wurm blocks, it loses defender. - this.addAbility(new BlocksSourceTriggeredAbility(new LoseAbilitySourceEffect(DefenderAbility.getInstance(), Duration.Custom), false, false, true)); + this.addAbility( + new BlocksSourceTriggeredAbility( + new LoseAbilitySourceEffect(DefenderAbility.getInstance(), Duration.Custom).setText("it loses defender") + ).setTriggerPhrase("When {this} blocks, ") + ); } private ElderLandWurm(final ElderLandWurm card) { diff --git a/Mage.Sets/src/mage/cards/e/ElderMastery.java b/Mage.Sets/src/mage/cards/e/ElderMastery.java index 04166291d8e..ee1065eb808 100644 --- a/Mage.Sets/src/mage/cards/e/ElderMastery.java +++ b/Mage.Sets/src/mage/cards/e/ElderMastery.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -17,29 +15,37 @@ import mage.constants.*; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class ElderMastery extends CardImpl { public ElderMastery(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{U}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{B}{R}"); this.subtype.add(SubType.AURA); // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Enchanted creature gets +3/+3 and has flying. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(3, 3, Duration.WhileOnBattlefield))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield))); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect( + 3, 3, Duration.WhileOnBattlefield + )); + ability.addEffect(new GainAbilityAttachedEffect( + FlyingAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield + ).setText("and has flying")); + this.addAbility(ability); // Whenever enchanted creature deals damage to a player, that player discards two cards. - this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility(new DiscardTargetEffect(2), "enchanted", false, true, false)); + this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility( + new DiscardTargetEffect(2), "enchanted creature", + false, true, false + )); } private ElderMastery(final ElderMastery card) { diff --git a/Mage.Sets/src/mage/cards/e/ElderfangRitualist.java b/Mage.Sets/src/mage/cards/e/ElderfangRitualist.java index 1dd64d47396..5d2cfdf3f0c 100644 --- a/Mage.Sets/src/mage/cards/e/ElderfangRitualist.java +++ b/Mage.Sets/src/mage/cards/e/ElderfangRitualist.java @@ -11,7 +11,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.FilterCard; import mage.filter.common.FilterBySubtypeCard; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.common.TargetCardInYourGraveyard; /** @@ -22,7 +22,7 @@ public final class ElderfangRitualist extends CardImpl { private static final FilterCard filter = new FilterBySubtypeCard(SubType.ELF); static { - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); filter.setMessage("another target Elf card from your graveyard"); } diff --git a/Mage.Sets/src/mage/cards/e/EldraziTemple.java b/Mage.Sets/src/mage/cards/e/EldraziTemple.java index 88eed29e1c6..4dec3aa3b47 100644 --- a/Mage.Sets/src/mage/cards/e/EldraziTemple.java +++ b/Mage.Sets/src/mage/cards/e/EldraziTemple.java @@ -68,7 +68,7 @@ class EldraziTempleCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && object.hasSubtype(SubType.ELDRAZI, game) && object.getColor(game).isColorless(); } } diff --git a/Mage.Sets/src/mage/cards/e/Electrodominance.java b/Mage.Sets/src/mage/cards/e/Electrodominance.java index ede24d12435..39a61cb31c7 100644 --- a/Mage.Sets/src/mage/cards/e/Electrodominance.java +++ b/Mage.Sets/src/mage/cards/e/Electrodominance.java @@ -1,12 +1,20 @@ package mage.cards.e; +import mage.abilities.Ability; import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; -import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.players.Player; import mage.target.common.TargetAnyTarget; +import mage.util.CardUtil; import java.util.UUID; @@ -21,7 +29,7 @@ public final class Electrodominance extends CardImpl { // Electrodominance deals X damage to any target. You may cast a card with converted mana cost X or less from your hand without paying its mana cost. this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.REGULAR)); this.getSpellAbility().addTarget(new TargetAnyTarget()); - this.getSpellAbility().addEffect(new CastWithoutPayingManaCostEffect(ManacostVariableValue.REGULAR)); + this.getSpellAbility().addEffect(new ElectrodominanceEffect()); } private Electrodominance(final Electrodominance card) { @@ -33,3 +41,34 @@ public final class Electrodominance extends CardImpl { return new Electrodominance(this); } } + +class ElectrodominanceEffect extends OneShotEffect { + + ElectrodominanceEffect() { + super(Outcome.Benefit); + staticText = "You may cast a spell with mana value X " + + "or less from your hand without paying its mana cost"; + } + + private ElectrodominanceEffect(final ElectrodominanceEffect effect) { + super(effect); + } + + @Override + public ElectrodominanceEffect copy() { + return new ElectrodominanceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + FilterCard filter = new FilterCard(); + filter.add(new ManaValuePredicate( + ComparisonType.FEWER_THAN, source.getManaCostsToPay().getX() + 1 + )); + return CardUtil.castSpellWithAttributesForFree(controller, source, game, controller.getHand(), filter); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ElectrostaticPummeler.java b/Mage.Sets/src/mage/cards/e/ElectrostaticPummeler.java index 751da4b24c4..d339d06c9ad 100644 --- a/Mage.Sets/src/mage/cards/e/ElectrostaticPummeler.java +++ b/Mage.Sets/src/mage/cards/e/ElectrostaticPummeler.java @@ -1,29 +1,31 @@ package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.PayEnergyCost; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.SourcePermanentPowerCount; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.counter.GetEnergyCountersControllerEffect; 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.constants.SubType; + +import java.util.UUID; /** - * * @author emerald000 */ public final class ElectrostaticPummeler extends CardImpl { + private static final DynamicValue xValue = new SourcePermanentPowerCount(false); + public ElectrostaticPummeler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(1); this.toughness = new MageInt(1); @@ -32,7 +34,9 @@ public final class ElectrostaticPummeler extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(3))); // Pay {E}{E}{E}: Electrostatic Pummeler gets +X/+X until end of turn, where X is its power. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(new SourcePermanentPowerCount(), new SourcePermanentPowerCount(), Duration.EndOfTurn, true), new PayEnergyCost(3))); + this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect( + xValue, xValue, Duration.EndOfTurn, true + ).setText("{this} gets +X/+X until end of turn, where X is its power"), new PayEnergyCost(3))); } private ElectrostaticPummeler(final ElectrostaticPummeler card) { diff --git a/Mage.Sets/src/mage/cards/e/Electryte.java b/Mage.Sets/src/mage/cards/e/Electryte.java index 1af4897951f..a1967a2bb5a 100644 --- a/Mage.Sets/src/mage/cards/e/Electryte.java +++ b/Mage.Sets/src/mage/cards/e/Electryte.java @@ -91,7 +91,7 @@ class ElectryteEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent thisCreature = game.getPermanent(source.getSourceId()); int amount = thisCreature.getPower().getValue(); - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); for (Permanent permanent : permanents) { permanent.damage(amount, source.getSourceId(), source, game, false, true); } diff --git a/Mage.Sets/src/mage/cards/e/ElegantEntourage.java b/Mage.Sets/src/mage/cards/e/ElegantEntourage.java new file mode 100644 index 00000000000..3d6818919c1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ElegantEntourage.java @@ -0,0 +1,57 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AllianceAbility; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ElegantEntourage extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("another permanent"); + + static { + filter.add(AnotherPredicate.instance); + } + + public ElegantEntourage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Alliance — Whenever another creature enters the battlefield under your control, target creature other than Elegant Entourage gets +1/+1 and gains trample until end of turn. + Ability ability = new AllianceAbility(new BoostTargetEffect(1, 1, Duration.EndOfTurn) + .setText("target creature other than {this} gets +1/+1")); + ability.addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance()) + .setText("and gains trample until end of turn")); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private ElegantEntourage(final ElegantEntourage card) { + super(card); + } + + @Override + public ElegantEntourage copy() { + return new ElegantEntourage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ElementalAugury.java b/Mage.Sets/src/mage/cards/e/ElementalAugury.java index 54fb9029bf5..406b8bdf36e 100644 --- a/Mage.Sets/src/mage/cards/e/ElementalAugury.java +++ b/Mage.Sets/src/mage/cards/e/ElementalAugury.java @@ -24,7 +24,7 @@ public final class ElementalAugury extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}{B}{R}"); // {3}: Look at the top three cards of target player's library, then put them back in any order. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ElementalAuguryEffect(), new ManaCostsImpl("3")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ElementalAuguryEffect(), new ManaCostsImpl<>("{3}")); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/ElephantGrass.java b/Mage.Sets/src/mage/cards/e/ElephantGrass.java index 4aeb59c4fc7..5b0af9679b2 100644 --- a/Mage.Sets/src/mage/cards/e/ElephantGrass.java +++ b/Mage.Sets/src/mage/cards/e/ElephantGrass.java @@ -41,7 +41,7 @@ public final class ElephantGrass extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackYouAllEffect(Duration.WhileOnBattlefield, filterBlack))); // Nonblack creatures can't attack you unless their controller pays {2} for each creature they control that's attacking you. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackYouUnlessPayManaAllEffect(new ManaCostsImpl<>("{2"), false, filter))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackYouUnlessPayManaAllEffect(new ManaCostsImpl<>("{2}"), false, filter))); } private ElephantGrass(final ElephantGrass card) { diff --git a/Mage.Sets/src/mage/cards/e/ElevenTheMage.java b/Mage.Sets/src/mage/cards/e/ElevenTheMage.java deleted file mode 100644 index d390c1f3217..00000000000 --- a/Mage.Sets/src/mage/cards/e/ElevenTheMage.java +++ /dev/null @@ -1,127 +0,0 @@ -package mage.cards.e; - -import mage.ApprovingObject; -import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; -import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect; -import mage.abilities.keyword.FriendsForeverAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; -import mage.target.Target; -import mage.target.common.TargetCardInHand; -import org.apache.log4j.Logger; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public final class ElevenTheMage extends CardImpl { - - public ElevenTheMage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}{R}"); - - this.addSuperType(SuperType.LEGENDARY); - this.subtype.add(SubType.HUMAN); - this.subtype.add(SubType.WIZARD); - this.power = new MageInt(3); - this.toughness = new MageInt(5); - - // Your maximum hand size is eleven. - this.addAbility(new SimpleStaticAbility(new MaximumHandSizeControllerEffect( - 11, Duration.WhileOnBattlefield, MaximumHandSizeControllerEffect.HandSizeModification.SET - ))); - - // Whenever Eleven, the Mage attacks, you draw a card and you lose 1 life. Then if you have eleven or more cards in your hand, you may cast an instant or sorcery spell from your hand without paying its mana cost. - this.addAbility(new AttacksTriggeredAbility(new ElevenTheMageEffect())); - - // Friends forever - this.addAbility(FriendsForeverAbility.getInstance()); - } - - private ElevenTheMage(final ElevenTheMage card) { - super(card); - } - - @Override - public ElevenTheMage copy() { - return new ElevenTheMage(this); - } -} - -class ElevenTheMageEffect extends OneShotEffect { - - ElevenTheMageEffect() { - super(Outcome.Benefit); - staticText = "you draw a card and you lose 1 life. Then if you have eleven or more cards in your hand, " + - "you may cast an instant or sorcery spell from your hand without paying its mana cost"; - } - - private ElevenTheMageEffect(final ElevenTheMageEffect effect) { - super(effect); - } - - @Override - public ElevenTheMageEffect copy() { - return new ElevenTheMageEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - player.drawCards(1, source, game); - player.loseLife(1, game, source, false); - if (player.getHand().size() < 11) { - return true; - } - // TODO: change this to fit with changes made in https://github.com/magefree/mage/pull/8136 when merged - Target target = new TargetCardInHand(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY); - if (!target.canChoose( - source.getSourceId(), player.getId(), game - ) || !player.chooseUse( - Outcome.PlayForFree, "Cast an instant or sorcery spell " + - "from your hand without paying its mana cost?", source, game - )) { - return true; - } - Card cardToCast = null; - boolean cancel = false; - while (player.canRespond() - && !cancel) { - if (player.chooseTarget(Outcome.PlayForFree, target, source, game)) { - cardToCast = game.getCard(target.getFirstTarget()); - if (cardToCast != null) { - if (cardToCast.getSpellAbility() == null) { - Logger.getLogger(CastWithoutPayingManaCostEffect.class).fatal("Card: " - + cardToCast.getName() + " is no land and has no spell ability!"); - cancel = true; - } - if (cardToCast.getSpellAbility().canChooseTarget(game, player.getId())) { - cancel = true; - } - } - } else { - cancel = true; - } - } - if (cardToCast != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), Boolean.TRUE); - player.cast(player.chooseAbilityForCast(cardToCast, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), null); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/e/EliteArcanist.java b/Mage.Sets/src/mage/cards/e/EliteArcanist.java index 1bc1403f022..1fc5c6999e6 100644 --- a/Mage.Sets/src/mage/cards/e/EliteArcanist.java +++ b/Mage.Sets/src/mage/cards/e/EliteArcanist.java @@ -103,7 +103,7 @@ class EliteArcanistImprintEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null && !player.getHand().isEmpty()) { TargetCard target = new TargetCard(Zone.HAND, filter); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + if (target.canChoose(source.getControllerId(), source, game) && player.choose(Outcome.Benefit, player.getHand(), target, game)) { Card card = player.getHand().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/e/EliteJavelineer.java b/Mage.Sets/src/mage/cards/e/EliteJavelineer.java index d8ebbfa8d09..ed5b99220de 100644 --- a/Mage.Sets/src/mage/cards/e/EliteJavelineer.java +++ b/Mage.Sets/src/mage/cards/e/EliteJavelineer.java @@ -1,4 +1,3 @@ - package mage.cards.e; import java.util.UUID; @@ -10,8 +9,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterAttackingCreature; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetAttackingCreature; /** * @@ -28,8 +26,8 @@ public final class EliteJavelineer extends CardImpl { this.toughness = new MageInt(2); // Whenever Elite Javelineer blocks, it deals 1 damage to target attacking creature. - Ability ability = new BlocksSourceTriggeredAbility(new DamageTargetEffect(1, "it"), false); - ability.addTarget(new TargetCreaturePermanent(new FilterAttackingCreature())); + Ability ability = new BlocksSourceTriggeredAbility(new DamageTargetEffect(1, "it")); + ability.addTarget(new TargetAttackingCreature()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/EllywickTumblestrum.java b/Mage.Sets/src/mage/cards/e/EllywickTumblestrum.java index e7634ce174d..f85be8f7636 100644 --- a/Mage.Sets/src/mage/cards/e/EllywickTumblestrum.java +++ b/Mage.Sets/src/mage/cards/e/EllywickTumblestrum.java @@ -2,7 +2,6 @@ package mage.cards.e; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect; @@ -27,7 +26,7 @@ public final class EllywickTumblestrum extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ELLYWICK); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Venture into the dungeon. this.addAbility(new LoyaltyAbility(new VentureIntoTheDungeonEffect(), 1)); diff --git a/Mage.Sets/src/mage/cards/m/MaxTheDaredevil.java b/Mage.Sets/src/mage/cards/e/ElmarUlvenwaldInformant.java similarity index 81% rename from Mage.Sets/src/mage/cards/m/MaxTheDaredevil.java rename to Mage.Sets/src/mage/cards/e/ElmarUlvenwaldInformant.java index 7ed98132cb3..30d12c2bf11 100644 --- a/Mage.Sets/src/mage/cards/m/MaxTheDaredevil.java +++ b/Mage.Sets/src/mage/cards/e/ElmarUlvenwaldInformant.java @@ -1,4 +1,4 @@ -package mage.cards.m; +package mage.cards.e; import mage.MageInt; import mage.abilities.Ability; @@ -19,9 +19,9 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class MaxTheDaredevil extends CardImpl { +public final class ElmarUlvenwaldInformant extends CardImpl { - public MaxTheDaredevil(UUID ownerId, CardSetInfo setInfo) { + public ElmarUlvenwaldInformant(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{G}"); this.addSuperType(SuperType.LEGENDARY); @@ -42,12 +42,12 @@ public final class MaxTheDaredevil extends CardImpl { this.addAbility(FriendsForeverAbility.getInstance()); } - private MaxTheDaredevil(final MaxTheDaredevil card) { + private ElmarUlvenwaldInformant(final ElmarUlvenwaldInformant card) { super(card); } @Override - public MaxTheDaredevil copy() { - return new MaxTheDaredevil(this); + public ElmarUlvenwaldInformant copy() { + return new ElmarUlvenwaldInformant(this); } } diff --git a/Mage.Sets/src/mage/cards/e/ElsewhereFlask.java b/Mage.Sets/src/mage/cards/e/ElsewhereFlask.java index e7098e13835..ba8eb40f970 100644 --- a/Mage.Sets/src/mage/cards/e/ElsewhereFlask.java +++ b/Mage.Sets/src/mage/cards/e/ElsewhereFlask.java @@ -116,7 +116,7 @@ class ElsewhereFlaskContinuousEffect extends ContinuousEffectImpl { game.getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game ).stream() .map(permanent -> new MageObjectReference(permanent, game)) .forEach(affectedObjectList::add); diff --git a/Mage.Sets/src/mage/cards/e/ElspethKnightErrant.java b/Mage.Sets/src/mage/cards/e/ElspethKnightErrant.java index 5a24864ad49..d1a7b7671c4 100644 --- a/Mage.Sets/src/mage/cards/e/ElspethKnightErrant.java +++ b/Mage.Sets/src/mage/cards/e/ElspethKnightErrant.java @@ -3,7 +3,6 @@ package mage.cards.e; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; import mage.abilities.effects.common.CreateTokenEffect; @@ -33,7 +32,7 @@ public final class ElspethKnightErrant extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ELSPETH); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Create a 1/1 white Soldier creature token. Token token = new SoldierToken(); diff --git a/Mage.Sets/src/mage/cards/e/ElspethResplendent.java b/Mage.Sets/src/mage/cards/e/ElspethResplendent.java new file mode 100644 index 00000000000..036df34d816 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ElspethResplendent.java @@ -0,0 +1,151 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.*; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.Angel33Token; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCreaturePermanent; + +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ElspethResplendent extends CardImpl { + + public ElspethResplendent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{W}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ELSPETH); + this.setStartingLoyalty(5); + + // +1: Choose up to one target creature. Put a +1/+1 counter and a counter from among flying, first strike, lifelink, or vigilance on it. + Ability ability = new LoyaltyAbility(new ElspethResplendentCounterEffect(), 1); + ability.addTarget(new TargetCreaturePermanent(0, 1)); + this.addAbility(ability); + + // −3: Look at the top seven cards of your library. You may put a permanent card with mana value 3 or less from among them onto the battlefield with a shield counter on it. Put the rest on the bottom of your library in a random order. + this.addAbility(new LoyaltyAbility(new ElspethResplendentLookEffect(), -3)); + + // −7: Create five 3/3 white Angel creature tokens with flying. + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new Angel33Token(), 5), -7)); + } + + private ElspethResplendent(final ElspethResplendent card) { + super(card); + } + + @Override + public ElspethResplendent copy() { + return new ElspethResplendent(this); + } +} + +class ElspethResplendentCounterEffect extends OneShotEffect { + + private static final Set choices = new HashSet<>(); + + static { + choices.add("Flying"); + choices.add("First strike"); + choices.add("Lifelink"); + choices.add("Vigilance"); + } + + ElspethResplendentCounterEffect() { + super(Outcome.Benefit); + staticText = "choose up to one target creature. Put a +1/+1 counter and a counter " + + "from among flying, first strike, lifelink, or vigilance on it"; + } + + private ElspethResplendentCounterEffect(final ElspethResplendentCounterEffect effect) { + super(effect); + } + + @Override + public ElspethResplendentCounterEffect copy() { + return new ElspethResplendentCounterEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (player == null || permanent == null) { + return false; + } + permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + Choice choice = new ChoiceImpl(true); + choice.setMessage("Choose an ability counter to add"); + choice.setChoices(choices); + player.choose(outcome, choice, game); + CounterType counterType = CounterType.findByName(choice.getChoice().toLowerCase(Locale.ROOT)); + permanent.addCounters(counterType.createInstance(), source, game); + return true; + } +} + +class ElspethResplendentLookEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterPermanentCard("permanent card with mana value 3 or less"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); + } + + ElspethResplendentLookEffect() { + super(Outcome.Benefit); + staticText = "look at the top seven cards of your library. You may put a permanent card " + + "with mana value 3 or less from among them onto the battlefield with a shield counter on it. " + + "Put the rest on the bottom of your library in a random order"; + } + + private ElspethResplendentLookEffect(final ElspethResplendentLookEffect effect) { + super(effect); + } + + @Override + public ElspethResplendentLookEffect copy() { + return new ElspethResplendentLookEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 7)); + TargetCard target = new TargetCardInLibrary(0, 1, filter); + player.choose(outcome, cards, target, game); + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + player.moveCards(card, Zone.BATTLEFIELD, source, game); + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) { + permanent.addCounters(CounterType.SHIELD.createInstance(), source, game); + } + } + cards.retainZone(Zone.LIBRARY, game); + player.putCardsOnBottomOfLibrary(card, game, source, false); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/e/ElspethSunsChampion.java b/Mage.Sets/src/mage/cards/e/ElspethSunsChampion.java index 5f6454a3d0b..0eedf89b8df 100644 --- a/Mage.Sets/src/mage/cards/e/ElspethSunsChampion.java +++ b/Mage.Sets/src/mage/cards/e/ElspethSunsChampion.java @@ -3,7 +3,6 @@ package mage.cards.e; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -35,7 +34,7 @@ public final class ElspethSunsChampion extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ELSPETH); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Create three 1/1 white Soldier creature tokens. this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new SoldierToken(), 3), 1)); diff --git a/Mage.Sets/src/mage/cards/e/ElspethSunsNemesis.java b/Mage.Sets/src/mage/cards/e/ElspethSunsNemesis.java index 22c8b5ef11b..6c3901a4216 100644 --- a/Mage.Sets/src/mage/cards/e/ElspethSunsNemesis.java +++ b/Mage.Sets/src/mage/cards/e/ElspethSunsNemesis.java @@ -2,7 +2,6 @@ package mage.cards.e; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -27,7 +26,7 @@ public final class ElspethSunsNemesis extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ELSPETH); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // −1: Up to two target creatures you control each get +2/+1 until end of turn. Ability ability = new LoyaltyAbility(new BoostTargetEffect(2, 1) diff --git a/Mage.Sets/src/mage/cards/e/ElspethTirel.java b/Mage.Sets/src/mage/cards/e/ElspethTirel.java index ee656aefad9..b2607851490 100644 --- a/Mage.Sets/src/mage/cards/e/ElspethTirel.java +++ b/Mage.Sets/src/mage/cards/e/ElspethTirel.java @@ -4,7 +4,6 @@ package mage.cards.e; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; @@ -31,7 +30,7 @@ public final class ElspethTirel extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ELSPETH); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); this.addAbility(new LoyaltyAbility(new ElspethTirelFirstEffect(), 2)); this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new SoldierToken(), 3), -2)); diff --git a/Mage.Sets/src/mage/cards/e/ElspethUndauntedHero.java b/Mage.Sets/src/mage/cards/e/ElspethUndauntedHero.java index d04129b3531..cb21d7facd4 100644 --- a/Mage.Sets/src/mage/cards/e/ElspethUndauntedHero.java +++ b/Mage.Sets/src/mage/cards/e/ElspethUndauntedHero.java @@ -2,7 +2,6 @@ package mage.cards.e; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.DevotionCount; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -19,7 +18,7 @@ import mage.counters.CounterType; import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.predicate.mageobject.NamePredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -39,11 +38,11 @@ public final class ElspethUndauntedHero extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ELSPETH); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +2: Put a +1/+1 counter on each of up to two target creatures. Ability ability = new LoyaltyAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), 2); - ability.addTarget(new TargetCreaturePermanent(0, 2)); + ability.addTarget(new TargetPermanent(0, 2, StaticFilters.FILTER_PERMANENT_CREATURES)); this.addAbility(ability); // −2: Search your library and/or graveyard for a card named Sunlit Hoplite and put it onto the battlefield. If you search your library this way, shuffle it. diff --git a/Mage.Sets/src/mage/cards/e/ElvishHandservant.java b/Mage.Sets/src/mage/cards/e/ElvishHandservant.java index 5c9a739143d..0534c5d3d07 100644 --- a/Mage.Sets/src/mage/cards/e/ElvishHandservant.java +++ b/Mage.Sets/src/mage/cards/e/ElvishHandservant.java @@ -18,7 +18,7 @@ import mage.filter.FilterSpell; */ public final class ElvishHandservant extends CardImpl { - private static final FilterSpell filter = new FilterSpell("Giant"); + private static final FilterSpell filter = new FilterSpell("Giant spell"); static { filter.add(SubType.GIANT.getPredicate()); diff --git a/Mage.Sets/src/mage/cards/e/ElvishRejuvenator.java b/Mage.Sets/src/mage/cards/e/ElvishRejuvenator.java index 5b15891c651..328ec0bfcc5 100644 --- a/Mage.Sets/src/mage/cards/e/ElvishRejuvenator.java +++ b/Mage.Sets/src/mage/cards/e/ElvishRejuvenator.java @@ -2,26 +2,18 @@ package mage.cards.e; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.constants.SubType; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.common.FilterLandCard; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; +import mage.constants.SubType; +import mage.filter.StaticFilters; /** * - * @author TheElk801 + * @author awjackson */ public final class ElvishRejuvenator extends CardImpl { @@ -33,8 +25,11 @@ public final class ElvishRejuvenator extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - // Whenever Elvish Rejuvenator enters the battlefield, look at the top five cards of your library. You may put a land card from among them onto the battlefield tapped. Put the rest on the bottom of your library in a random order. - this.addAbility(new EntersBattlefieldTriggeredAbility(new ElvishRejuvenatorEffect(), false)); + // When Elvish Rejuvenator enters the battlefield, look at the top five cards of your library. + // You may put a land card from among them onto the battlefield tapped. + // Put the rest on the bottom of your library in a random order. + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 5, 1, StaticFilters.FILTER_CARD_LAND_A, PutCards.BATTLEFIELD_TAPPED, PutCards.BOTTOM_RANDOM))); } private ElvishRejuvenator(final ElvishRejuvenator card) { @@ -46,49 +41,3 @@ public final class ElvishRejuvenator extends CardImpl { return new ElvishRejuvenator(this); } } - -class ElvishRejuvenatorEffect extends OneShotEffect { - - public ElvishRejuvenatorEffect() { - super(Outcome.PutCreatureInPlay); - this.staticText = "look at the top five cards of your library. " - + "You may put a land card from among them onto the battlefield tapped. " - + "Put the rest on the bottom of your library in a random order"; - } - - public ElvishRejuvenatorEffect(final ElvishRejuvenatorEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 5)); - if (!cards.isEmpty()) { - TargetCard target = new TargetCard( - 0, 1, Zone.LIBRARY, - new FilterLandCard("land card to put on the battlefield") - ); - if (controller.choose(Outcome.PutCardInPlay, cards, target, game)) { - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - controller.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, true, null); - } - } - if (!cards.isEmpty()) { - controller.putCardsOnBottomOfLibrary(cards, game, source, false); - } - } - return true; - } - - @Override - public ElvishRejuvenatorEffect copy() { - return new ElvishRejuvenatorEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/e/ElvishSoultiller.java b/Mage.Sets/src/mage/cards/e/ElvishSoultiller.java index 6f935d1921f..1a7524e7728 100644 --- a/Mage.Sets/src/mage/cards/e/ElvishSoultiller.java +++ b/Mage.Sets/src/mage/cards/e/ElvishSoultiller.java @@ -67,7 +67,7 @@ class ElvishSoultillerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (controller != null && mageObject != null) { Choice typeChoice = new ChoiceCreatureType(mageObject); if (controller.choose(outcome, typeChoice, game)) { @@ -77,7 +77,7 @@ class ElvishSoultillerEffect extends OneShotEffect { Cards cardsToLibrary = new CardsImpl(); FilterCreatureCard filter = new FilterCreatureCard(); filter.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); - cardsToLibrary.addAll(controller.getGraveyard().getCards(filter, source.getSourceId(), source.getControllerId(), game)); + cardsToLibrary.addAll(controller.getGraveyard().getCards(filter, source.getControllerId(), source, game)); controller.putCardsOnTopOfLibrary(cardsToLibrary, game, source, false); controller.shuffleLibrary(source, game); return true; diff --git a/Mage.Sets/src/mage/cards/e/EmbalmersTools.java b/Mage.Sets/src/mage/cards/e/EmbalmersTools.java index b9eed1188f6..57ea87557fb 100644 --- a/Mage.Sets/src/mage/cards/e/EmbalmersTools.java +++ b/Mage.Sets/src/mage/cards/e/EmbalmersTools.java @@ -90,7 +90,7 @@ class EmbalmersToolsEffect extends CostModificationEffectImpl { || (abilityToModify.getAbilityType() == AbilityType.MANA && (abilityToModify instanceof ActivatedAbility))) { // Activated abilities of creatures Card card = game.getCard(abilityToModify.getSourceId()); - if (filter.match(card, source.getSourceId(), source.getControllerId(), game) && game.getState().getZone(card.getId()) == Zone.GRAVEYARD) { + if (filter.match(card, source.getControllerId(), source, game) && game.getState().getZone(card.getId()) == Zone.GRAVEYARD) { return true; } } diff --git a/Mage.Sets/src/mage/cards/e/EmberWeaver.java b/Mage.Sets/src/mage/cards/e/EmberWeaver.java index a9842a79700..82f407cb7ed 100644 --- a/Mage.Sets/src/mage/cards/e/EmberWeaver.java +++ b/Mage.Sets/src/mage/cards/e/EmberWeaver.java @@ -1,10 +1,10 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; @@ -14,42 +14,44 @@ 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.Zone; +import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import java.util.UUID; + /** * @author Loki */ public final class EmberWeaver extends CardImpl { - private static final FilterPermanent redPermanentFilter = new FilterPermanent("red"); + + private static final FilterPermanent filter = new FilterPermanent(); static { - redPermanentFilter.add(new ColorPredicate(ObjectColor.RED)); + filter.add(new ColorPredicate(ObjectColor.RED)); } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + public EmberWeaver(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.SPIDER); this.power = new MageInt(2); this.toughness = new MageInt(3); this.addAbility(ReachAbility.getInstance()); - // As long as you control a red permanent, Ember Weaver gets +1/+0 and has first strike. - this.addAbility(new SimpleStaticAbility( - Zone.BATTLEFIELD, - new ConditionalContinuousEffect( - new BoostSourceEffect(1, 0, Duration.WhileOnBattlefield), - new PermanentsOnTheBattlefieldCondition(redPermanentFilter), "{this} gets +1/+0 as long as you control a red permanent"))); - this.addAbility(new SimpleStaticAbility( - Zone.BATTLEFIELD, - new ConditionalContinuousEffect( - new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield), - new PermanentsOnTheBattlefieldCondition(redPermanentFilter), "{this} has first strike as long as you control a red permanent"))); + // As long as you control a red permanent, Ember Weaver gets +1/+0 and has first strike. + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(1, 0, Duration.WhileOnBattlefield), + condition, "as long as you control a red permanent, {this} gets +1/+0" + )); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect( + FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield + ), condition, "and has first strike")); + this.addAbility(ability); } private EmberWeaver(final EmberWeaver card) { diff --git a/Mage.Sets/src/mage/cards/e/EmberwildeDjinn.java b/Mage.Sets/src/mage/cards/e/EmberwildeDjinn.java index 520ba488eb4..033ca35f546 100644 --- a/Mage.Sets/src/mage/cards/e/EmberwildeDjinn.java +++ b/Mage.Sets/src/mage/cards/e/EmberwildeDjinn.java @@ -78,7 +78,7 @@ class EmberwildeDjinnEffect extends OneShotEffect { if (player == null || sourceObject == null) { return false; } - Cost cost = new OrCost(new ManaCostsImpl("{R}{R}"), new PayLifeCost(2), "{R}{R} or 2 life"); + Cost cost = new OrCost("{R}{R} or 2 life", new ManaCostsImpl("{R}{R}"), new PayLifeCost(2)); if (player.chooseUse(Outcome.GainControl, "Gain control of " + sourceObject.getLogName() + "?", source, game)) { if (cost.pay(source, game, source, player.getId(), false)) { ContinuousEffect effect = new GainControlTargetEffect(Duration.Custom, false, player.getId()); diff --git a/Mage.Sets/src/mage/cards/e/EmeraldCharm.java b/Mage.Sets/src/mage/cards/e/EmeraldCharm.java index 2ec3528c2e7..780ca514a6c 100644 --- a/Mage.Sets/src/mage/cards/e/EmeraldCharm.java +++ b/Mage.Sets/src/mage/cards/e/EmeraldCharm.java @@ -38,14 +38,12 @@ public final class EmeraldCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent()); // or destroy target non-Aura enchantment; - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetEnchantmentPermanent(filter)); this.getSpellAbility().addMode(mode); // or target creature loses flying until end of turn. - mode = new Mode(); - mode.addEffect(new LoseAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); + mode = new Mode(new LoseAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/e/EmergentUltimatum.java b/Mage.Sets/src/mage/cards/e/EmergentUltimatum.java index 98a21bd5d90..39d140b8e3b 100644 --- a/Mage.Sets/src/mage/cards/e/EmergentUltimatum.java +++ b/Mage.Sets/src/mage/cards/e/EmergentUltimatum.java @@ -1,6 +1,5 @@ package mage.cards.e; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileSpellEffect; @@ -15,10 +14,11 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInExile; import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCardWithDifferentNameInLibrary; import mage.target.common.TargetOpponent; +import mage.util.CardUtil; import java.util.UUID; -import mage.ApprovingObject; /** * @author TheElk801 @@ -45,6 +45,13 @@ public final class EmergentUltimatum extends CardImpl { class EmergentUltimatumEffect extends OneShotEffect { + private static final FilterCard filter + = new FilterCard("monocolored cards with different names"); + + static { + filter.add(MonocoloredPredicate.instance); + } + EmergentUltimatumEffect() { super(Outcome.Benefit); staticText = "Search your library for up to three monocolored cards with different names and exile them. " + @@ -67,7 +74,7 @@ class EmergentUltimatumEffect extends OneShotEffect { if (player == null) { return false; } - TargetCardInLibrary targetCardInLibrary = new EmergentUltimatumTarget(); + TargetCardInLibrary targetCardInLibrary = new TargetCardWithDifferentNameInLibrary(0, 3, filter); targetCardInLibrary.setNotTarget(true); boolean searched = player.searchLibrary(targetCardInLibrary, source, game); Cards cards = new CardsImpl(targetCardInLibrary.getTargets()); @@ -80,7 +87,7 @@ class EmergentUltimatumEffect extends OneShotEffect { } TargetOpponent targetOpponent = new TargetOpponent(); targetOpponent.setNotTarget(true); - player.choose(outcome, targetOpponent, source.getSourceId(), game); + player.choose(outcome, targetOpponent, source, game); Player opponent = game.getPlayer(targetOpponent.getFirstTarget()); if (opponent == null) { if (searched) { @@ -97,67 +104,7 @@ class EmergentUltimatumEffect extends OneShotEffect { player.shuffleLibrary(source, game); cards.remove(toShuffle); } - while (!cards.isEmpty()) { - if (!player.chooseUse(Outcome.PlayForFree, "Cast an exiled card without paying its mana cost?", source, game)) { - break; - } - targetCardInExile.clearChosen(); - if (!player.choose(Outcome.PlayForFree, cards, targetCardInExile, game)) { - continue; - } - Card card = game.getCard(targetCardInExile.getFirstTarget()); - if (card == null) { - continue; - } - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = player.cast(player.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - cards.remove(card); // remove on non cast too (infinite freeze fix) - if (cardWasCast) { - cards.remove(card); - } else { - game.informPlayer(player, "You're not able to cast " - + card.getIdName() + " or you canceled the casting."); - } - } + CardUtil.castMultipleWithAttributeForFree(player, source, game, cards, StaticFilters.FILTER_CARD); return true; } } - -class EmergentUltimatumTarget extends TargetCardInLibrary { - - private static final FilterCard filter - = new FilterCard("monocolored cards with different names"); - - static { - filter.add(MonocoloredPredicate.instance); - } - - EmergentUltimatumTarget() { - super(0, 3, filter); - } - - private EmergentUltimatumTarget(final EmergentUltimatumTarget target) { - super(target); - } - - @Override - public EmergentUltimatumTarget copy() { - return new EmergentUltimatumTarget(this); - } - - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { - if (!super.canTarget(playerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - return card != null - && this.getTargets() - .stream() - .map(game::getCard) - .map(MageObject::getName) - .noneMatch(card.getName()::equals); - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/e/EmissaryOfDespair.java b/Mage.Sets/src/mage/cards/e/EmissaryOfDespair.java index 5fcdd686358..3310daf217e 100644 --- a/Mage.Sets/src/mage/cards/e/EmissaryOfDespair.java +++ b/Mage.Sets/src/mage/cards/e/EmissaryOfDespair.java @@ -54,7 +54,7 @@ class EmissaryOfDespairCount implements DynamicValue { } FilterArtifactPermanent filter = new FilterArtifactPermanent(); filter.add(new ControllerIdPredicate(effect.getTargetPointer().getFirst(game, sourceAbility))); - return game.getBattlefield().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + return game.getBattlefield().count(filter, sourceAbility.getControllerId(), sourceAbility, game); } @Override diff --git a/Mage.Sets/src/mage/cards/e/EmissaryOfHope.java b/Mage.Sets/src/mage/cards/e/EmissaryOfHope.java index f121794ffed..201c5541c1f 100644 --- a/Mage.Sets/src/mage/cards/e/EmissaryOfHope.java +++ b/Mage.Sets/src/mage/cards/e/EmissaryOfHope.java @@ -67,7 +67,7 @@ class EmissaryOfHopeEffect extends OneShotEffect { Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); Player sourcePlayer = game.getPlayer(source.getControllerId()); if (targetPlayer != null && sourcePlayer != null) { - int amount = game.getBattlefield().count(filter, source.getSourceId(), targetPlayer.getId(), game); + int amount = game.getBattlefield().count(filter, targetPlayer.getId(), source, game); if (amount > 0) { sourcePlayer.gainLife(amount, game, source); } diff --git a/Mage.Sets/src/mage/cards/e/EmptyTheLaboratory.java b/Mage.Sets/src/mage/cards/e/EmptyTheLaboratory.java index 74e0868a828..dd9e856e39d 100644 --- a/Mage.Sets/src/mage/cards/e/EmptyTheLaboratory.java +++ b/Mage.Sets/src/mage/cards/e/EmptyTheLaboratory.java @@ -74,7 +74,7 @@ class EmptyTheLaboratoryEffect extends OneShotEffect { int toSacrifice = Math.min( source.getManaCostsToPay().getX(), game.getBattlefield().count( - filter, source.getSourceId(), source.getControllerId(), game + filter, source.getControllerId(), source, game ) ); if (toSacrifice < 1) { @@ -82,7 +82,7 @@ class EmptyTheLaboratoryEffect extends OneShotEffect { } TargetPermanent target = new TargetPermanent(toSacrifice, filter); target.setNotTarget(true); - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + player.choose(Outcome.Sacrifice, target, source, game); int sacrificed = 0; for (UUID permanentId : target.getTargets()) { Permanent permanent = game.getPermanent(permanentId); diff --git a/Mage.Sets/src/mage/cards/e/EmpyrealVoyager.java b/Mage.Sets/src/mage/cards/e/EmpyrealVoyager.java index 9505b19c6d2..cc061ad3356 100644 --- a/Mage.Sets/src/mage/cards/e/EmpyrealVoyager.java +++ b/Mage.Sets/src/mage/cards/e/EmpyrealVoyager.java @@ -1,11 +1,9 @@ - package mage.cards.e; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.counter.GetEnergyCountersControllerEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TrampleAbility; @@ -13,9 +11,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Outcome; -import mage.game.Game; -import mage.players.Player; /** * @@ -35,7 +30,10 @@ public final class EmpyrealVoyager extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); // Whenever Empyreal Voyager deals combat damage to a player you get that many {E} - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new EmpyrealVoyagerEffect(), false, true)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new GetEnergyCountersControllerEffect(SavedDamageValue.MANY) + .setText("you get that many {E} (energy counters)."), + false, true)); } private EmpyrealVoyager(final EmpyrealVoyager card) { @@ -47,32 +45,3 @@ public final class EmpyrealVoyager extends CardImpl { return new EmpyrealVoyager(this); } } - -class EmpyrealVoyagerEffect extends OneShotEffect { - - public EmpyrealVoyagerEffect() { - super(Outcome.Benefit); - this.staticText = "get that many {E} counters"; - } - - public EmpyrealVoyagerEffect(final EmpyrealVoyagerEffect effect) { - super(effect); - } - - @Override - public EmpyrealVoyagerEffect copy() { - return new EmpyrealVoyagerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int amount = (Integer) getValue("damage"); - if (amount > 0) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - return new GetEnergyCountersControllerEffect(amount).apply(game, source); - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/e/EnchantedEvening.java b/Mage.Sets/src/mage/cards/e/EnchantedEvening.java index 7cfb26dbc41..92fceea6609 100644 --- a/Mage.Sets/src/mage/cards/e/EnchantedEvening.java +++ b/Mage.Sets/src/mage/cards/e/EnchantedEvening.java @@ -51,7 +51,7 @@ public final class EnchantedEvening extends CardImpl { public boolean apply(Game game, Ability source) { for (Permanent permanent : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_PERMANENT, source.getControllerId(), - source.getSourceId(), game + source, game )) { if (permanent != null) { permanent.addCardType(game, CardType.ENCHANTMENT); diff --git a/Mage.Sets/src/mage/cards/e/EndlessDetour.java b/Mage.Sets/src/mage/cards/e/EndlessDetour.java new file mode 100644 index 00000000000..1a06a8cc9ce --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EndlessDetour.java @@ -0,0 +1,36 @@ +package mage.cards.e; + +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInGraveyardBattlefieldOrStack; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EndlessDetour extends CardImpl { + + public EndlessDetour(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}{W}{U}"); + + // The owner of target spell, nonland permanent, or card in a graveyard puts it on the top or bottom of their library. + this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInGraveyardBattlefieldOrStack( + 1, 1, StaticFilters.FILTER_CARD, StaticFilters.FILTER_PERMANENT_NON_LAND, + StaticFilters.FILTER_SPELL, "spell, nonland permanent, or card in a graveyard" + )); + } + + private EndlessDetour(final EndlessDetour card) { + super(card); + } + + @Override + public EndlessDetour copy() { + return new EndlessDetour(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EndlessHorizons.java b/Mage.Sets/src/mage/cards/e/EndlessHorizons.java index 99eb91e8a45..e5a3899e76c 100644 --- a/Mage.Sets/src/mage/cards/e/EndlessHorizons.java +++ b/Mage.Sets/src/mage/cards/e/EndlessHorizons.java @@ -52,7 +52,7 @@ class EndlessHorizonsEffect extends OneShotEffect { EndlessHorizonsEffect() { super(Outcome.Neutral); - this.staticText = "search your library for any number of Plains cards and exile them. Then shuffle"; + this.staticText = "search your library for any number of Plains cards, exile them, then shuffle"; } private EndlessHorizonsEffect(final EndlessHorizonsEffect effect) { @@ -116,7 +116,7 @@ class EndlessHorizonsEffect2 extends OneShotEffect { 0, 1, filter, CardUtil.getExileZoneId(game, source) ); target.setNotTarget(true); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); return card != null && controller.moveCards(card, Zone.HAND, source, game); } diff --git a/Mage.Sets/src/mage/cards/e/EndlessSands.java b/Mage.Sets/src/mage/cards/e/EndlessSands.java index 24abac6087c..c66e7ef52e8 100644 --- a/Mage.Sets/src/mage/cards/e/EndlessSands.java +++ b/Mage.Sets/src/mage/cards/e/EndlessSands.java @@ -1,40 +1,45 @@ package mage.cards.e; -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.ExileTargetEffect; -import mage.abilities.effects.common.ReturnCreaturesFromExileEffect; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetForSourceEffect; import mage.abilities.mana.ColorlessManaAbility; 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.game.ExileZone; +import mage.game.Game; +import mage.players.Player; import mage.target.common.TargetControlledCreaturePermanent; +import mage.util.CardUtil; + +import java.util.UUID; public final class EndlessSands extends CardImpl { public EndlessSands(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - + this.subtype.add(SubType.DESERT); - + // {T}: Add {C}. this.addAbility(new ColorlessManaAbility()); - + // {2}, {T}: Exile target creature you control. - Ability exileAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(this.getId(), this.getIdName()), new ManaCostsImpl("{2}")); + Ability exileAbility = new SimpleActivatedAbility(new ExileTargetForSourceEffect(), new GenericManaCost(2)); exileAbility.addCost(new TapSourceCost()); exileAbility.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(exileAbility); - + // {4}, {T}, Sacrifice Endless Sands: Return each creature card exiled with Endless Sands to the battlefield under its owner's control. - ReturnCreaturesFromExileEffect returnFromExileEffect = new ReturnCreaturesFromExileEffect(this.getId(), true, "Return each creature card exiled with {this} to the battlefield under its owner's control."); - Ability returnAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, returnFromExileEffect, new ManaCostsImpl("{4}")); + Ability returnAbility = new SimpleActivatedAbility(new EndlessSandsEffect(), new GenericManaCost(4)); returnAbility.addCost(new TapSourceCost()); returnAbility.addCost(new SacrificeSourceCost()); this.addAbility(returnAbility); @@ -49,3 +54,34 @@ public final class EndlessSands extends CardImpl { return new EndlessSands(this); } } + +class EndlessSandsEffect extends OneShotEffect { + + EndlessSandsEffect() { + super(Outcome.Benefit); + staticText = "return each creature card exiled with {this} to the battlefield under its owner's control"; + } + + private EndlessSandsEffect(final EndlessSandsEffect effect) { + super(effect); + } + + @Override + public EndlessSandsEffect copy() { + return new EndlessSandsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + return player != null && exileZone != null + && player.moveCards( + exileZone.getCards(game), Zone.BATTLEFIELD, source, game, + false, false, true, null + ); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EnduringSliver.java b/Mage.Sets/src/mage/cards/e/EnduringSliver.java index 953bbfe1b58..076553ca76b 100644 --- a/Mage.Sets/src/mage/cards/e/EnduringSliver.java +++ b/Mage.Sets/src/mage/cards/e/EnduringSliver.java @@ -32,7 +32,7 @@ public final class EnduringSliver extends CardImpl { // Other sliver creatures you control have outlast {2}. this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( new OutlastAbility(new ManaCostsImpl<>("{2}")), Duration.WhileOnBattlefield, - StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, true + StaticFilters.FILTER_PERMANENT_ALL_SLIVERS, true ).setText("Other Sliver creatures you control have outlast {2}."))); } diff --git a/Mage.Sets/src/mage/cards/e/EnergyBolt.java b/Mage.Sets/src/mage/cards/e/EnergyBolt.java index 8fdd6e2db2e..cafa302b3a2 100644 --- a/Mage.Sets/src/mage/cards/e/EnergyBolt.java +++ b/Mage.Sets/src/mage/cards/e/EnergyBolt.java @@ -24,8 +24,7 @@ public final class EnergyBolt extends CardImpl { // Choose one - Energy Bolt deals X damage to target player; or target player gains X life. this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.REGULAR)); this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); - Mode mode = new Mode(); - mode.addEffect(new GainLifeTargetEffect(ManacostVariableValue.REGULAR)); + Mode mode = new Mode(new GainLifeTargetEffect(ManacostVariableValue.REGULAR)); mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/e/EnergyChamber.java b/Mage.Sets/src/mage/cards/e/EnergyChamber.java index 9485754e4cb..0bf0acd98f5 100644 --- a/Mage.Sets/src/mage/cards/e/EnergyChamber.java +++ b/Mage.Sets/src/mage/cards/e/EnergyChamber.java @@ -42,8 +42,7 @@ public final class EnergyChamber extends CardImpl { ability.addTarget(new TargetPermanent(filter)); // or put a charge counter on target noncreature artifact. - Mode mode = new Mode(); - mode.addEffect(new AddCountersTargetEffect(CounterType.CHARGE.createInstance(), Outcome.BoostCreature)); + Mode mode = new Mode(new AddCountersTargetEffect(CounterType.CHARGE.createInstance(), Outcome.BoostCreature)); mode.addTarget(new TargetPermanent(filter2)); ability.addMode(mode); diff --git a/Mage.Sets/src/mage/cards/e/EngineeredExplosives.java b/Mage.Sets/src/mage/cards/e/EngineeredExplosives.java index 1318712c0ae..16c1575cbc9 100644 --- a/Mage.Sets/src/mage/cards/e/EngineeredExplosives.java +++ b/Mage.Sets/src/mage/cards/e/EngineeredExplosives.java @@ -72,7 +72,7 @@ class EngineeredExplosivesEffect extends OneShotEffect { MageObject engineeredExplosives = game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD); if(engineeredExplosives instanceof Permanent){ int count = ((Permanent)engineeredExplosives).getCounters(game).getCount(CounterType.CHARGE); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if(permanent.getManaValue() == count){ permanent.destroy(source, game, false); } diff --git a/Mage.Sets/src/mage/cards/e/EngineeredMight.java b/Mage.Sets/src/mage/cards/e/EngineeredMight.java index f6a4c8467b9..84e318678cc 100644 --- a/Mage.Sets/src/mage/cards/e/EngineeredMight.java +++ b/Mage.Sets/src/mage/cards/e/EngineeredMight.java @@ -38,10 +38,9 @@ public final class EngineeredMight extends CardImpl { Target target = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(target); // • Creatures you control get +2/+2 and gain vigilance until end of turn. - Mode mode = new Mode(); effect = new BoostControlledEffect(2, 2, Duration.EndOfTurn); effect.setText("Creatures you control get +2/+2"); - mode.addEffect(effect); + Mode mode = new Mode(effect); effect = new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn, new FilterCreaturePermanent()); effect.setText("and gain vigilance until end of turn"); mode.addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/e/EngulfTheShore.java b/Mage.Sets/src/mage/cards/e/EngulfTheShore.java index b8d85cb541e..20489199db3 100644 --- a/Mage.Sets/src/mage/cards/e/EngulfTheShore.java +++ b/Mage.Sets/src/mage/cards/e/EngulfTheShore.java @@ -67,11 +67,11 @@ class EngulfTheShoreEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - int islands = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int islands = game.getBattlefield().count(filter, source.getControllerId(), source, game); FilterPermanent creatureFilter = new FilterCreaturePermanent(); creatureFilter.add(new ToughnessPredicate(ComparisonType.FEWER_THAN, islands + 1)); Set cardsToHand = new HashSet<>(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(creatureFilter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(creatureFilter, source.getControllerId(), source, game)) { cardsToHand.add(permanent); } controller.moveCards(cardsToHand, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/e/EnigmaticIncarnation.java b/Mage.Sets/src/mage/cards/e/EnigmaticIncarnation.java index 2c796bd0556..a572a8fb9cb 100644 --- a/Mage.Sets/src/mage/cards/e/EnigmaticIncarnation.java +++ b/Mage.Sets/src/mage/cards/e/EnigmaticIncarnation.java @@ -77,12 +77,12 @@ class EnigmaticIncarnationEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player == null - || game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) == 0 + || game.getBattlefield().count(filter, source.getControllerId(), source, game) == 0 || !player.chooseUse(outcome, "Sacrifice an enchantment?", source, game)) { return false; } TargetPermanent target = new TargetPermanent(0, 1, filter, true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent == null) { return false; diff --git a/Mage.Sets/src/mage/cards/e/EnslavedHorror.java b/Mage.Sets/src/mage/cards/e/EnslavedHorror.java index 1048f609aaf..96ccd7cf08f 100644 --- a/Mage.Sets/src/mage/cards/e/EnslavedHorror.java +++ b/Mage.Sets/src/mage/cards/e/EnslavedHorror.java @@ -78,7 +78,7 @@ class EnslavedHorrorEffect extends OneShotEffect { filterCreatureCard.add(new OwnerIdPredicate(playerId)); TargetCardInGraveyard target = new TargetCardInGraveyard(0, 1, filterCreatureCard); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), playerId, game) + if (target.canChoose(playerId, source, game) && player.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/e/EntomberExarch.java b/Mage.Sets/src/mage/cards/e/EntomberExarch.java index c616dec979e..7c87b4263da 100644 --- a/Mage.Sets/src/mage/cards/e/EntomberExarch.java +++ b/Mage.Sets/src/mage/cards/e/EntomberExarch.java @@ -4,7 +4,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.effects.common.discard.DiscardCardYouChooseTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -31,12 +31,11 @@ public final class EntomberExarch extends CardImpl { // When Entomber Exarch enters the battlefield, choose one — // • Return target creature card from your graveyard to your hand - Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), false); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); // • Target opponent reveals their hand. You choose a noncreature card from it. That player discards that card. - Mode mode = new Mode(); - mode.addEffect(new DiscardCardYouChooseTargetEffect(StaticFilters.FILTER_CARD_NON_CREATURE)); + Mode mode = new Mode(new DiscardCardYouChooseTargetEffect(StaticFilters.FILTER_CARD_NON_CREATURE)); mode.addTarget(new TargetOpponent()); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/e/EntrailsFeaster.java b/Mage.Sets/src/mage/cards/e/EntrailsFeaster.java index 7b84a0e3316..cb01061c6f6 100644 --- a/Mage.Sets/src/mage/cards/e/EntrailsFeaster.java +++ b/Mage.Sets/src/mage/cards/e/EntrailsFeaster.java @@ -70,8 +70,8 @@ class EntrailsFeasterEffect extends OneShotEffect { Permanent sourceObject = (Permanent) source.getSourceObjectIfItStillExists(game); TargetCardInGraveyard target = new TargetCardInGraveyard(filter); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), controller.getId(), game) && controller.chooseUse(outcome, "Exile a creature card from a graveyard?", source, game)) { - if (controller.choose(Outcome.Exile, target, source.getId(), game)) { + if (target.canChoose(controller.getId(), source, game) && controller.chooseUse(outcome, "Exile a creature card from a graveyard?", source, game)) { + if (controller.choose(Outcome.Exile, target, source, game)) { Card cardChosen = game.getCard(target.getFirstTarget()); if (cardChosen != null) { controller.moveCardsToExile(cardChosen, source, game, true, null, ""); diff --git a/Mage.Sets/src/mage/cards/e/EntrapmentManeuver.java b/Mage.Sets/src/mage/cards/e/EntrapmentManeuver.java index c15dba03b56..1af385b71d8 100644 --- a/Mage.Sets/src/mage/cards/e/EntrapmentManeuver.java +++ b/Mage.Sets/src/mage/cards/e/EntrapmentManeuver.java @@ -70,7 +70,7 @@ class EntrapmentManeuverSacrificeEffect extends OneShotEffect { int realCount = game.getBattlefield().countAll(filter, player.getId(), game); if (realCount > 0) { Target target = new TargetControlledPermanent(1, 1, filter, true); - while (player.canRespond() && !target.isChosen() && target.canChoose(source.getSourceId(), player.getId(), game)) { + while (player.canRespond() && !target.isChosen() && target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Sacrifice, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/e/EpicExperiment.java b/Mage.Sets/src/mage/cards/e/EpicExperiment.java index c0fe068149b..f168b0d8a92 100644 --- a/Mage.Sets/src/mage/cards/e/EpicExperiment.java +++ b/Mage.Sets/src/mage/cards/e/EpicExperiment.java @@ -3,7 +3,10 @@ package mage.cards.e; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.Outcome; @@ -11,13 +14,11 @@ import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterInstantOrSorceryCard; import mage.filter.predicate.mageobject.ManaValuePredicate; -import mage.game.ExileZone; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; +import mage.util.CardUtil; import java.util.UUID; -import mage.ApprovingObject; /** * @author LevelX2 @@ -61,59 +62,16 @@ class EpicExperimentEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { - // move cards from library to exile - controller.moveCardsToExile(controller.getLibrary().getTopCards(game, - source.getManaCostsToPay().getX()), source, game, true, - source.getSourceId(), sourceObject.getIdName()); - // cast the possible cards without paying the mana - ExileZone epicExperimentExileZone = game.getExile().getExileZone(source.getSourceId()); - FilterCard filter = new FilterInstantOrSorceryCard(); - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, - source.getManaCostsToPay().getX() + 1)); - filter.setMessage("instant and sorcery cards with mana value " - + source.getManaCostsToPay().getX() + " or less"); - Cards cardsToCast = new CardsImpl(); - if (epicExperimentExileZone == null) { - return true; - } - cardsToCast.addAll(epicExperimentExileZone.getCards(filter, source.getSourceId(), - source.getControllerId(), game)); - while (controller.canRespond() && !cardsToCast.isEmpty()) { - if (!controller.chooseUse(Outcome.PlayForFree, "Cast (another) a card exiled with " - + sourceObject.getLogName() + " without paying its mana cost?", source, game)) { - break; - } - TargetCard targetCard = new TargetCard(1, Zone.EXILED, new FilterCard( - "instant or sorcery card to cast for free")); - if (controller.choose(Outcome.PlayForFree, cardsToCast, targetCard, game)) { - Card card = game.getCard(targetCard.getFirstTarget()); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - if (!cardWasCast) { - game.informPlayer(controller, "You're not able to cast " - + card.getIdName() + " or you canceled the casting."); - } - cardsToCast.remove(card); - } else { - break; - } - } else { - break; - } - } - // move cards not cast to graveyard - ExileZone exileZone = game.getExile().getExileZone(source.getSourceId()); - if (exileZone != null) { - controller.moveCards(exileZone.getCards(game), Zone.GRAVEYARD, source, game); - } - return true; + if (controller == null || sourceObject == null) { + return false; } - - return false; + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, source.getManaCostsToPay().getX())); + controller.moveCards(cards, Zone.EXILED, source, game); + FilterCard filter = new FilterInstantOrSorceryCard(); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, source.getManaCostsToPay().getX() + 1)); + CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, filter); + controller.moveCards(cards, Zone.GRAVEYARD, source, game); + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/e/EpicProportions.java b/Mage.Sets/src/mage/cards/e/EpicProportions.java index 5a82c8ee010..737a88ffd6c 100644 --- a/Mage.Sets/src/mage/cards/e/EpicProportions.java +++ b/Mage.Sets/src/mage/cards/e/EpicProportions.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; @@ -16,24 +14,30 @@ import mage.constants.*; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class EpicProportions extends CardImpl { public EpicProportions(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}{G}"); this.subtype.add(SubType.AURA); this.addAbility(FlashAbility.getInstance()); TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect( + 5, 5, Duration.WhileOnBattlefield + )); + ability.addEffect(new GainAbilityAttachedEffect( + TrampleAbility.getInstance(), AttachmentType.AURA + ).setText("and has trample")); this.addAbility(ability); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(5, 5, Duration.WhileOnBattlefield))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(TrampleAbility.getInstance(), AttachmentType.AURA))); } private EpicProportions(final EpicProportions card) { diff --git a/Mage.Sets/src/mage/cards/e/EpiphanyAtTheDrownyard.java b/Mage.Sets/src/mage/cards/e/EpiphanyAtTheDrownyard.java index c40996a8311..ef5800585a5 100644 --- a/Mage.Sets/src/mage/cards/e/EpiphanyAtTheDrownyard.java +++ b/Mage.Sets/src/mage/cards/e/EpiphanyAtTheDrownyard.java @@ -62,7 +62,7 @@ class EpiphanyAtTheDrownyardEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/e/Epochrasite.java b/Mage.Sets/src/mage/cards/e/Epochrasite.java index 6c6b15ee5b1..f7e9dd902b8 100644 --- a/Mage.Sets/src/mage/cards/e/Epochrasite.java +++ b/Mage.Sets/src/mage/cards/e/Epochrasite.java @@ -41,7 +41,7 @@ public final class Epochrasite extends CardImpl { this.addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance(3)), new InvertCondition(CastFromHandSourcePermanentCondition.instance), - "{this} enters the battlefield with three +1/+1 counters on it if you didn't cast it from your hand", ""), + "","with three +1/+1 counters on it if you didn't cast it from your hand"), new CastFromHandWatcher()); // When Epochrasite dies, exile it with three time counters on it and it gains suspend. diff --git a/Mage.Sets/src/mage/cards/e/Equipoise.java b/Mage.Sets/src/mage/cards/e/Equipoise.java index 58f9013da3a..2528317645a 100644 --- a/Mage.Sets/src/mage/cards/e/Equipoise.java +++ b/Mage.Sets/src/mage/cards/e/Equipoise.java @@ -81,8 +81,8 @@ class EquipoiseEffect extends OneShotEffect { private void phaseOutCardType(Player controller, Player targetPlayer, CardType cardType, Ability source, Game game) { FilterPermanent filter = new FilterControlledPermanent(); filter.add(cardType.getPredicate()); - int numberController = game.getBattlefield().count(filter, source.getSourceId(), controller.getId(), game); - int numberTargetPlayer = game.getBattlefield().count(filter, source.getSourceId(), targetPlayer.getId(), game); + int numberController = game.getBattlefield().count(filter, controller.getId(), source, game); + int numberTargetPlayer = game.getBattlefield().count(filter, targetPlayer.getId(), source, game); int excess = numberTargetPlayer - numberController; if (excess > 0) { FilterPermanent filterChoose = new FilterPermanent(cardType.toString().toLowerCase(Locale.ENGLISH) + (excess > 1 ? "s" : "") + " of target player"); diff --git a/Mage.Sets/src/mage/cards/e/EraOfInnovation.java b/Mage.Sets/src/mage/cards/e/EraOfInnovation.java index fc8cf276e50..4d52e9eac1a 100644 --- a/Mage.Sets/src/mage/cards/e/EraOfInnovation.java +++ b/Mage.Sets/src/mage/cards/e/EraOfInnovation.java @@ -1,14 +1,11 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.PayEnergyCost; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.counter.GetEnergyCountersControllerEffect; @@ -16,17 +13,18 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; +import java.util.UUID; + /** - * * @author fireshoes */ public final class EraOfInnovation extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("an artifact or Artificer"); + private static final FilterPermanent filter = new FilterControlledPermanent("an artifact or Artificer"); static { filter.add(Predicates.or(CardType.ARTIFACT.getPredicate(), @@ -34,15 +32,15 @@ public final class EraOfInnovation extends CardImpl { } public EraOfInnovation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); // Whenever an artifact or Artificer enters the battlefield under you control, you may pay {1}. If you do, you get {E}{E}. - Effect effect = new DoIfCostPaid(new GetEnergyCountersControllerEffect(2), new GenericManaCost(1)); - this.addAbility(new EntersBattlefieldAllTriggeredAbility(effect, filter, - "Whenever an artifact or Artificer enters the battlefield under you control, you may pay {1}. If you do, you get {E}{E}.")); + this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new DoIfCostPaid( + new GetEnergyCountersControllerEffect(2), new GenericManaCost(1) + ), filter)); // {E}{E}{E}{E}{E}{E}, Sacrifice Era of Innovation: Draw three cards. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(3), new PayEnergyCost(6)); + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(3), new PayEnergyCost(6)); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/ErebossTitan.java b/Mage.Sets/src/mage/cards/e/ErebossTitan.java index 7b883e72048..100be729c68 100644 --- a/Mage.Sets/src/mage/cards/e/ErebossTitan.java +++ b/Mage.Sets/src/mage/cards/e/ErebossTitan.java @@ -1,4 +1,3 @@ - package mage.cards.e; import java.util.UUID; @@ -19,9 +18,8 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.ComparisonType; import mage.constants.Duration; -import mage.constants.TargetController; import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; @@ -33,25 +31,21 @@ import mage.players.Player; */ public final class ErebossTitan extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public ErebossTitan(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}{B}"); this.subtype.add(SubType.GIANT); this.power = new MageInt(5); this.toughness = new MageInt(5); - // Erebos's Titan has indestructible as long as no opponent controls a creature. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new ConditionalContinuousEffect(new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0, false), - "As long as your opponents control no creatures, {this} has indestructible"))); + // As long as your opponents control no creatures, Erebos's Titan has indestructible. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect( + IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield), + new PermanentsOnTheBattlefieldCondition( + StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, ComparisonType.EQUAL_TO, 0, false), + "As long as your opponents control no creatures, {this} has indestructible"))); - // Whenever a creature leaves an opponent's graveyard, you may discard a card. If you do, return Erebos's Titan from your graveyard to your hand. + // Whenever a creature card leaves an opponent's graveyard, you may discard a card. If you do, return Erebos's Titan from your graveyard to your hand. this.addAbility(new ErebossTitanTriggeredAbility()); } @@ -102,6 +96,6 @@ class ErebossTitanTriggeredAbility extends TriggeredAbilityImpl { @Override public String getTriggerPhrase() { - return "Whenever a creature leaves an opponent's graveyard, " ; + return "Whenever a creature card leaves an opponent's graveyard, " ; } } diff --git a/Mage.Sets/src/mage/cards/e/Erosion.java b/Mage.Sets/src/mage/cards/e/Erosion.java index d501240c0b2..a7052b3ca46 100644 --- a/Mage.Sets/src/mage/cards/e/Erosion.java +++ b/Mage.Sets/src/mage/cards/e/Erosion.java @@ -38,7 +38,7 @@ public final class Erosion extends CardImpl { this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // At the beginning of the upkeep of enchanted land's controller, destroy that land unless that player pays {1} or 1 life. - Effect effect = new DoUnlessTargetPlayerOrTargetsControllerPaysEffect(new DestroyAttachedToEffect("enchanted land"), new OrCost(new ManaCostsImpl("{1}"), new PayLifeCost(1), "{1} or 1 life")); + Effect effect = new DoUnlessTargetPlayerOrTargetsControllerPaysEffect(new DestroyAttachedToEffect("enchanted land"), new OrCost("{1} or 1 life", new ManaCostsImpl("{1}"), new PayLifeCost(1))); effect.setText("destroy that land unless that player pays {1} or 1 life"); this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, effect, TargetController.CONTROLLER_ATTACHED_TO, false, true, "At the beginning of the upkeep of enchanted land's controller, ")); } diff --git a/Mage.Sets/src/mage/cards/e/ErrantStreetArtist.java b/Mage.Sets/src/mage/cards/e/ErrantStreetArtist.java new file mode 100644 index 00000000000..f6e5af66450 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ErrantStreetArtist.java @@ -0,0 +1,80 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CopyTargetSpellEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.TargetController; +import mage.filter.FilterSpell; +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.game.stack.StackObject; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ErrantStreetArtist extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("spell you control that wasn't cast"); + + static { + filter.add(TargetController.YOU.getControllerPredicate()); + filter.add(ErrantStreetArtistPredicate.instance); + } + + public ErrantStreetArtist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // {1}{U}, {T}: Copy target spell you control that wasn't cast. You may choose new targets for the copy. + Ability ability = new SimpleActivatedAbility(new CopyTargetSpellEffect(), new ManaCostsImpl<>("{1}{U}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetSpell(filter)); + this.addAbility(ability); + } + + private ErrantStreetArtist(final ErrantStreetArtist card) { + super(card); + } + + @Override + public ErrantStreetArtist copy() { + return new ErrantStreetArtist(this); + } +} + +enum ErrantStreetArtistPredicate implements Predicate { + instance; + + @Override + public boolean apply(StackObject input, Game game) { + return input.isCopy(); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/e/ErraticMutation.java b/Mage.Sets/src/mage/cards/e/ErraticMutation.java index cade3c25a7e..49875cc0841 100644 --- a/Mage.Sets/src/mage/cards/e/ErraticMutation.java +++ b/Mage.Sets/src/mage/cards/e/ErraticMutation.java @@ -62,7 +62,7 @@ class ErraticMutationEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { CardsImpl toReveal = new CardsImpl(); Card nonLandCard = null; diff --git a/Mage.Sets/src/mage/cards/e/EscapeProtocol.java b/Mage.Sets/src/mage/cards/e/EscapeProtocol.java index 4aa3a6b6027..a67aebae611 100644 --- a/Mage.Sets/src/mage/cards/e/EscapeProtocol.java +++ b/Mage.Sets/src/mage/cards/e/EscapeProtocol.java @@ -38,7 +38,7 @@ public final class EscapeProtocol extends CardImpl { ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( new ExileTargetForSourceEffect(), false, "exile target artifact or creature you control, " + - "then return it to the battlefield under its owner's control." + "then return it to the battlefield under its owner's control" ); ability.addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false)); ability.addTarget(new TargetPermanent(filter)); diff --git a/Mage.Sets/src/mage/cards/e/EscapedNull.java b/Mage.Sets/src/mage/cards/e/EscapedNull.java index 228027ebc63..ad1ad8718dc 100644 --- a/Mage.Sets/src/mage/cards/e/EscapedNull.java +++ b/Mage.Sets/src/mage/cards/e/EscapedNull.java @@ -27,7 +27,7 @@ public final class EscapedNull extends CardImpl { this.toughness = new MageInt(2); this.addAbility(LifelinkAbility.getInstance()); - this.addAbility(new BlocksOrBecomesBlockedSourceTriggeredAbility(new BoostSourceEffect(5, 0, Duration.EndOfTurn), false)); + this.addAbility(new BlocksOrBecomesBlockedSourceTriggeredAbility(new BoostSourceEffect(5, 0, Duration.EndOfTurn).setText("it gets +5/+0 until end of turn"), false, false)); } private EscapedNull(final EscapedNull card) { diff --git a/Mage.Sets/src/mage/cards/e/EscapedShapeshifter.java b/Mage.Sets/src/mage/cards/e/EscapedShapeshifter.java index 935988818fc..e8b27784556 100644 --- a/Mage.Sets/src/mage/cards/e/EscapedShapeshifter.java +++ b/Mage.Sets/src/mage/cards/e/EscapedShapeshifter.java @@ -69,7 +69,7 @@ class EscapedShapeshifterEffect extends ContinuousEffectImpl { game.getBattlefield() .getActivePermanents( StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game ).stream() .filter(Objects::nonNull) .filter(permanent -> !permanent.getName().equals("Escaped Shapeshifter")) diff --git a/Mage.Sets/src/mage/cards/e/EsiorWardwingFamiliar.java b/Mage.Sets/src/mage/cards/e/EsiorWardwingFamiliar.java index 5e018812035..2b0978c5623 100644 --- a/Mage.Sets/src/mage/cards/e/EsiorWardwingFamiliar.java +++ b/Mage.Sets/src/mage/cards/e/EsiorWardwingFamiliar.java @@ -98,7 +98,7 @@ class EsiorWardwingFamiliarEffect extends CostModificationEffectImpl { if (allTargets.stream() .map(game::getPermanent) .filter(Objects::nonNull) - .anyMatch(permanent -> !filter.match(permanent, source.getSourceId(), source.getControllerId(), game))) { + .anyMatch(permanent -> !filter.match(permanent, source.getControllerId(), source, game))) { return false; } } @@ -106,7 +106,7 @@ class EsiorWardwingFamiliarEffect extends CostModificationEffectImpl { return allTargets.stream() .map(game::getPermanent) .filter(Objects::nonNull) - .anyMatch(permanent -> filter.match(permanent, source.getSourceId(), source.getControllerId(), game)); + .anyMatch(permanent -> filter.match(permanent, source.getControllerId(), source, game)); } @Override diff --git a/Mage.Sets/src/mage/cards/e/EsixFractalBloom.java b/Mage.Sets/src/mage/cards/e/EsixFractalBloom.java index ccfacd565e1..0a9bcf4e171 100644 --- a/Mage.Sets/src/mage/cards/e/EsixFractalBloom.java +++ b/Mage.Sets/src/mage/cards/e/EsixFractalBloom.java @@ -91,7 +91,7 @@ class EsixFractalBloomEffect extends ReplacementEffectImpl { && game.isActivePlayer(source.getControllerId()) && !EsixFractalBloomWatcher.checkPlayer(source.getControllerId(), game) && game.getBattlefield().count( - filter, source.getSourceId(), source.getControllerId(), game + filter, source.getControllerId(), source, game ) > 0; } @@ -102,7 +102,7 @@ class EsixFractalBloomEffect extends ReplacementEffectImpl { return false; } TargetPermanent target = new TargetPermanent(0, 1, filter, true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent == null) { return false; diff --git a/Mage.Sets/src/mage/cards/e/EsperCharm.java b/Mage.Sets/src/mage/cards/e/EsperCharm.java index b897dfc0504..cdb8f49de24 100644 --- a/Mage.Sets/src/mage/cards/e/EsperCharm.java +++ b/Mage.Sets/src/mage/cards/e/EsperCharm.java @@ -26,12 +26,10 @@ public final class EsperCharm extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetEnchantmentPermanent()); // or draw two cards; - Mode mode = new Mode(); - mode.addEffect(new DrawCardSourceControllerEffect(2)); + Mode mode = new Mode(new DrawCardSourceControllerEffect(2)); this.getSpellAbility().addMode(mode); // or target player discards two cards. - mode = new Mode(); - mode.addEffect(new DiscardTargetEffect(2)); + mode = new Mode(new DiscardTargetEffect(2)); mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/e/EsperSojourners.java b/Mage.Sets/src/mage/cards/e/EsperSojourners.java index 83294de53c5..86085c811d7 100644 --- a/Mage.Sets/src/mage/cards/e/EsperSojourners.java +++ b/Mage.Sets/src/mage/cards/e/EsperSojourners.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.CycleTriggeredAbility; @@ -9,39 +7,42 @@ import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.MayTapOrUntapTargetEffect; import mage.abilities.keyword.CyclingAbility; +import mage.abilities.meta.OrTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.Zone; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class EsperSojourners extends CardImpl { public EsperSojourners(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{W}{U}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{W}{U}{B}"); + this.subtype.add(SubType.VEDALKEN); this.subtype.add(SubType.WIZARD); - - - - this.power = new MageInt(2); this.toughness = new MageInt(3); // When you cycle Esper Sojourners or it dies, you may tap or untap target permanent. - Ability ability1 = new CycleTriggeredAbility(new MayTapOrUntapTargetEffect()); - Ability ability2 = new DiesSourceTriggeredAbility(new MayTapOrUntapTargetEffect()); - ability1.addTarget(new TargetPermanent()); - ability2.addTarget(new TargetPermanent()); - this.addAbility(ability1); - this.addAbility(ability2); - + Ability ability = new OrTriggeredAbility(Zone.ALL, + new MayTapOrUntapTargetEffect(), + false, + "When you cycle {this} or it dies, ", + new CycleTriggeredAbility(null, false), + new DiesSourceTriggeredAbility(null, false) + ); + ability.addTarget(new TargetPermanent()); + this.addAbility(ability); + // Cycling {2}{U} - this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}{U}"))); + this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{2}{U}"))); } private EsperSojourners(final EsperSojourners card) { diff --git a/Mage.Sets/src/mage/cards/e/EssenceFeed.java b/Mage.Sets/src/mage/cards/e/EssenceFeed.java index c37b63206a3..d51535d4c97 100644 --- a/Mage.Sets/src/mage/cards/e/EssenceFeed.java +++ b/Mage.Sets/src/mage/cards/e/EssenceFeed.java @@ -23,7 +23,7 @@ public final class EssenceFeed extends CardImpl { this.getSpellAbility().addEffect(new LoseLifeTargetEffect(3)); this.getSpellAbility().addEffect(new GainLifeEffect(3)); - this.getSpellAbility().addEffect(new CreateTokenEffect(new EldraziSpawnToken(), 3)); + this.getSpellAbility().addEffect(new CreateTokenEffect(new EldraziSpawnToken(), 3).concatBy("and")); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Sets/src/mage/cards/e/EssenceFilter.java b/Mage.Sets/src/mage/cards/e/EssenceFilter.java index 6dc8f067651..e48445b574e 100644 --- a/Mage.Sets/src/mage/cards/e/EssenceFilter.java +++ b/Mage.Sets/src/mage/cards/e/EssenceFilter.java @@ -66,11 +66,11 @@ class EssenceFilterEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { if (controller.chooseUse(outcome, "Destroy all enchantments? (otherwise all nonwhite enchantments are destroyed)", source, game)) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterEnchantmentPermanent(), controller.getId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterEnchantmentPermanent(), controller.getId(), source, game)) { permanent.destroy(source, game, false); } } else { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, controller.getId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, controller.getId(), source, game)) { permanent.destroy(source, game, false); } } diff --git a/Mage.Sets/src/mage/cards/e/EssencePulse.java b/Mage.Sets/src/mage/cards/e/EssencePulse.java index e683a2a77ff..720fe53d887 100644 --- a/Mage.Sets/src/mage/cards/e/EssencePulse.java +++ b/Mage.Sets/src/mage/cards/e/EssencePulse.java @@ -1,7 +1,5 @@ package mage.cards.e; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.MultipliedValue; import mage.abilities.dynamicvalue.common.ControllerGotLifeCount; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; @@ -11,13 +9,16 @@ import mage.constants.CardType; import mage.constants.Duration; import java.util.UUID; +import mage.abilities.dynamicvalue.LockedInDynamicValue; +import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; /** * @author TheElk801 */ public final class EssencePulse extends CardImpl { - private static final DynamicValue xValue = new MultipliedValue(ControllerGotLifeCount.instance, -1); + // rule 608.2h + private static final LockedInDynamicValue xValue = new LockedInDynamicValue(new SignInversionDynamicValue(ControllerGotLifeCount.instance)); public EssencePulse(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); diff --git a/Mage.Sets/src/mage/cards/e/EssenceSliver.java b/Mage.Sets/src/mage/cards/e/EssenceSliver.java index 058998c2874..fcf841b7983 100644 --- a/Mage.Sets/src/mage/cards/e/EssenceSliver.java +++ b/Mage.Sets/src/mage/cards/e/EssenceSliver.java @@ -1,4 +1,3 @@ - package mage.cards.e; import mage.MageInt; @@ -14,11 +13,11 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; import java.util.UUID; +import mage.target.targetpointer.FixedTarget; /** * @@ -27,14 +26,14 @@ import java.util.UUID; public final class EssenceSliver extends CardImpl { public EssenceSliver(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.subtype.add(SubType.SLIVER); this.power = new MageInt(3); this.toughness = new MageInt(3); // Whenever a Sliver deals damage, its controller gains that much life. - this.addAbility(new DealsDamageAllTriggeredAbility()); + this.addAbility(new EssenceSliverTriggeredAbility()); } @@ -48,19 +47,19 @@ public final class EssenceSliver extends CardImpl { } } -class DealsDamageAllTriggeredAbility extends TriggeredAbilityImpl { +class EssenceSliverTriggeredAbility extends TriggeredAbilityImpl { - public DealsDamageAllTriggeredAbility() { - super(Zone.BATTLEFIELD, new EssenceSliverGainThatMuchLifeEffect(), false); + public EssenceSliverTriggeredAbility() { + super(Zone.BATTLEFIELD, new EssenceSliverEffect(), false); } - public DealsDamageAllTriggeredAbility(final DealsDamageAllTriggeredAbility ability) { + public EssenceSliverTriggeredAbility(final EssenceSliverTriggeredAbility ability) { super(ability); } @Override - public DealsDamageAllTriggeredAbility copy() { - return new DealsDamageAllTriggeredAbility(this); + public EssenceSliverTriggeredAbility copy() { + return new EssenceSliverTriggeredAbility(this); } @Override @@ -71,10 +70,13 @@ class DealsDamageAllTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - Permanent creature = game.getPermanent(event.getSourceId()); - if (creature != null && creature.hasSubtype(SubType.SLIVER, game)) { + Permanent sliver = game.getPermanent(event.getSourceId()); + if (sliver != null + && sliver.hasSubtype(SubType.SLIVER, game) + && sliver.getControllerId() != null) { for (Effect effect : this.getEffects()) { effect.setValue("damage", event.getAmount()); + effect.setTargetPointer(new FixedTarget(sliver.getControllerId())); } return true; } @@ -83,34 +85,33 @@ class DealsDamageAllTriggeredAbility extends TriggeredAbilityImpl { @Override public String getTriggerPhrase() { - return "Whenever a Sliver deals damage, its controller" ; + return "Whenever a Sliver deals damage, "; } } -class EssenceSliverGainThatMuchLifeEffect extends OneShotEffect { +class EssenceSliverEffect extends OneShotEffect { - public EssenceSliverGainThatMuchLifeEffect() { + public EssenceSliverEffect() { super(Outcome.GainLife); this.staticText = "its controller gains that much life"; } - public EssenceSliverGainThatMuchLifeEffect(final EssenceSliverGainThatMuchLifeEffect effect) { + public EssenceSliverEffect(final EssenceSliverEffect effect) { super(effect); } @Override - public EssenceSliverGainThatMuchLifeEffect copy() { - return new EssenceSliverGainThatMuchLifeEffect(this); + public EssenceSliverEffect copy() { + return new EssenceSliverEffect(this); } @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { + Player controllerOfSliver = game.getPlayer(targetPointer.getFirst(game, source)); + if (controllerOfSliver != null) { int amount = (Integer) getValue("damage"); if (amount > 0) { - controller.gainLife(amount, game, source); - + controllerOfSliver.gainLife(amount, game, source); } return true; } diff --git a/Mage.Sets/src/mage/cards/e/EstridTheMasked.java b/Mage.Sets/src/mage/cards/e/EstridTheMasked.java index 06d4ff56016..77ef58cfd69 100644 --- a/Mage.Sets/src/mage/cards/e/EstridTheMasked.java +++ b/Mage.Sets/src/mage/cards/e/EstridTheMasked.java @@ -4,7 +4,6 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.MillCardsControllerEffect; @@ -46,7 +45,7 @@ public final class EstridTheMasked extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ESTRID); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +2: Untap each enchanted permanent you control. this.addAbility(new LoyaltyAbility(new UntapAllControllerEffect( @@ -150,10 +149,10 @@ class EstridTheMaskedGraveyardEffect extends OneShotEffect { return false; } controller.moveCards(controller.getGraveyard().getCards( - filter, source.getSourceId(), source.getControllerId(), game + filter, source.getControllerId(), source, game ), Zone.BATTLEFIELD, source, game); controller.moveCards(controller.getGraveyard().getCards( - filter2, source.getSourceId(), source.getControllerId(), game + filter2, source.getControllerId(), source, game ), Zone.BATTLEFIELD, source, game); return true; } diff --git a/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java b/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java index de743e3de92..b5ad1da1579 100644 --- a/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java +++ b/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java @@ -1,22 +1,20 @@ package mage.cards.e; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.*; -import mage.filter.FilterCard; import mage.filter.common.FilterNonlandCard; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; +import mage.util.CardUtil; -import java.util.HashSet; -import java.util.Set; import java.util.UUID; -import mage.ApprovingObject; /** * @author ciaccona007 & L_J @@ -34,7 +32,6 @@ public final class EtaliPrimalStorm extends CardImpl { // 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. this.addAbility(new AttacksTriggeredAbility(new EtaliPrimalStormEffect(), false)); - } private EtaliPrimalStorm(final EtaliPrimalStorm card) { @@ -69,58 +66,19 @@ class EtaliPrimalStormEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (controller != null - && sourceObject != null) { - // move cards from library to exile - Set currentExiledCards = new HashSet<>(); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - if (!player.getLibrary().getTopCards(game, 1).isEmpty()) { - Card topCard = player.getLibrary().getFromTop(game); - if (topCard != null) { - if (filter.match(topCard, source.getSourceId(), source.getControllerId(), game)) { - currentExiledCards.add(topCard); - } - controller.moveCardsToExile(topCard, source, game, true, source.getSourceId(), sourceObject.getIdName()); - } - } - } - } - - // cast the possible cards without paying the mana - Cards cardsToCast = new CardsImpl(); - cardsToCast.addAll(currentExiledCards); - boolean alreadyCast = false; - while (controller.canRespond() && !cardsToCast.isEmpty()) { - if (!controller.chooseUse(Outcome.PlayForFree, "Cast a" - + (alreadyCast ? "nother" : "") + " card exiled with " - + sourceObject.getLogName() + " without paying its mana cost?", source, game)) { - break; - } - - TargetCard targetCard = new TargetCard(1, Zone.EXILED, new FilterCard("nonland card to cast for free")); - if (!controller.choose(Outcome.PlayForFree, cardsToCast, targetCard, game)) { - break; - } - - alreadyCast = true; - Card card = game.getCard(targetCard.getFirstTarget()); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - if (!cardWasCast) { - game.informPlayer(controller, "You're not able to cast " - + card.getIdName() + " or you canceled the casting."); - } - cardsToCast.remove(card); - } - } - return true; + if (controller == null) { + return false; } - return false; + // move cards from library to exile + Cards cards = new CardsImpl(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + cards.add(player.getLibrary().getFromTop(game)); + } + } + controller.moveCards(cards, Zone.EXILED, source, game); + CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, filter); + return true; } } diff --git a/Mage.Sets/src/mage/cards/e/EtchingOfKumano.java b/Mage.Sets/src/mage/cards/e/EtchingOfKumano.java new file mode 100644 index 00000000000..55da585e7cf --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EtchingOfKumano.java @@ -0,0 +1,88 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.constants.*; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.watchers.common.DamagedByControlledWatcher; + +/** + * + * @author weirddan455 + */ +public final class EtchingOfKumano extends CardImpl { + + public EtchingOfKumano(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + this.color.setRed(true); + this.nightCard = true; + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // If a creature dealt damage this turn by a source you controlled would die, exile it instead. + this.addAbility(new SimpleStaticAbility(new EtchingOfKumanoReplacementEffect()), new DamagedByControlledWatcher()); + } + + private EtchingOfKumano(final EtchingOfKumano card) { + super(card); + } + + @Override + public EtchingOfKumano copy() { + return new EtchingOfKumano(this); + } +} + +class EtchingOfKumanoReplacementEffect extends ReplacementEffectImpl { + + public EtchingOfKumanoReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Exile); + this.staticText = "If a creature dealt damage this turn by a source you controlled would die, exile it instead"; + } + + private EtchingOfKumanoReplacementEffect(final EtchingOfKumanoReplacementEffect effect) { + super(effect); + } + + @Override + public EtchingOfKumanoReplacementEffect copy() { + return new EtchingOfKumanoReplacementEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + ((ZoneChangeEvent) event).setToZone(Zone.EXILED); + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ZoneChangeEvent zce = (ZoneChangeEvent) event; + if (zce.isDiesEvent()) { + DamagedByControlledWatcher watcher = game.getState().getWatcher(DamagedByControlledWatcher.class, source.getControllerId()); + if (watcher != null) { + return watcher.wasDamaged(zce.getTarget(), game); + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EtherealValkyrie.java b/Mage.Sets/src/mage/cards/e/EtherealValkyrie.java index 1da51c68698..e936f23f42a 100644 --- a/Mage.Sets/src/mage/cards/e/EtherealValkyrie.java +++ b/Mage.Sets/src/mage/cards/e/EtherealValkyrie.java @@ -98,7 +98,7 @@ class EtherealValkyrieTriggeredAbility extends TriggeredAbilityImpl { @Override public String getTriggerPhrase() { - return "Whenever {this} enters the battlefield or attacks, " ; + return "Whenever {this} enters the battlefield or attacks, "; } } @@ -167,6 +167,11 @@ class EtherealValkyrieEffect extends OneShotEffect { // all done pre-processing so stick the foretell cost effect onto the main card // note that the card is not foretell'd into exile, it is put into exile and made foretold if (foretellAbility != null) { + // copy source and use it for the foretold effect on the exiled card + // bug #8673 + Ability copiedSource = source.copy(); + copiedSource.newId(); + copiedSource.setSourceId(exileCard.getId()); game.getState().setValue(exileCard.getMainCard().getId().toString() + "Foretell Turn Number", game.getTurnNum()); UUID exileId = CardUtil.getExileZoneId(exileCard.getMainCard().getId().toString() + "foretellAbility", game); controller.moveCardsToExile(exileCard, source, game, true, exileId, " Foretell Turn Number: " + game.getTurnNum()); @@ -176,7 +181,7 @@ class EtherealValkyrieEffect extends OneShotEffect { game.getState().addOtherAbility(exileCard, foretellAbility); foretellAbility.activate(game, true); ContinuousEffect effect = foretellAbility.new ForetellAddCostEffect(new MageObjectReference(exileCard, game)); - game.addEffect(effect, source); + game.addEffect(effect, copiedSource); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.FORETOLD, exileCard.getId(), null, null)); return true; } diff --git a/Mage.Sets/src/mage/cards/e/EtherwroughtPage.java b/Mage.Sets/src/mage/cards/e/EtherwroughtPage.java index d30cf50f6d2..8de97f0c3b6 100644 --- a/Mage.Sets/src/mage/cards/e/EtherwroughtPage.java +++ b/Mage.Sets/src/mage/cards/e/EtherwroughtPage.java @@ -28,25 +28,18 @@ public final class EtherwroughtPage extends CardImpl { public EtherwroughtPage(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}{W}{U}{B}"); - - - - // At the beginning of your upkeep, choose one - You gain 2 life; or look at the top card of your library, then you may put that card into your graveyard; or each opponent loses 1 life. Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new GainLifeEffect(2), TargetController.YOU, false); // or look at the top card of your library, then you may put that card into your graveyard; - Mode mode = new Mode(); - mode.addEffect(new EtherwroughtPageEffect()); + Mode mode = new Mode(new EtherwroughtPageEffect()); ability.addMode(mode); // or each opponent loses 1 life - Mode mode1 = new Mode(); - mode1.addEffect(new LoseLifeOpponentsEffect(1)); + Mode mode1 = new Mode(new LoseLifeOpponentsEffect(1)); ability.addMode(mode1); this.addAbility(ability); - } private EtherwroughtPage(final EtherwroughtPage card) { @@ -63,7 +56,7 @@ class EtherwroughtPageEffect extends OneShotEffect { public EtherwroughtPageEffect() { super(Outcome.DrawCard); - this.staticText = "or look at the top card of your library, then you may put that card into your graveyard"; + this.staticText = "look at the top card of your library. You may put that card into your graveyard"; } public EtherwroughtPageEffect(final EtherwroughtPageEffect effect) { diff --git a/Mage.Sets/src/mage/cards/e/EunuchsIntrigues.java b/Mage.Sets/src/mage/cards/e/EunuchsIntrigues.java index 49f803d8361..1e4b88821b1 100644 --- a/Mage.Sets/src/mage/cards/e/EunuchsIntrigues.java +++ b/Mage.Sets/src/mage/cards/e/EunuchsIntrigues.java @@ -67,8 +67,8 @@ class EunuchsIntriguesEffect extends OneShotEffect { FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); filter.add(new ControllerIdPredicate(player.getId())); Target target = new TargetPermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { - while (!target.isChosen() && target.canChoose(source.getSourceId(), player.getId(), game) && player.canRespond()) { + if (target.canChoose(player.getId(), source, game)) { + while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) { player.chooseTarget(Outcome.DestroyPermanent, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/e/Eureka.java b/Mage.Sets/src/mage/cards/e/Eureka.java index c62b9e91acc..207f07f1b1a 100644 --- a/Mage.Sets/src/mage/cards/e/Eureka.java +++ b/Mage.Sets/src/mage/cards/e/Eureka.java @@ -75,7 +75,7 @@ class EurekaEffect extends OneShotEffect { if (currentPlayer != null && currentPlayer.canRespond() && game.getState().getPlayersInRange(controller.getId(), game).contains(currentPlayer.getId())) { target.clearChosen(); - if (target.canChoose(source.getSourceId(), currentPlayer.getId(), game) + if (target.canChoose(currentPlayer.getId(), source, game) && currentPlayer.chooseUse(outcome, "Put permanent from your hand to play?", source, game)) { if (target.chooseTarget(outcome, currentPlayer.getId(), source, game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/e/EvangelOfHeliod.java b/Mage.Sets/src/mage/cards/e/EvangelOfHeliod.java index 008265216f5..195da71958a 100644 --- a/Mage.Sets/src/mage/cards/e/EvangelOfHeliod.java +++ b/Mage.Sets/src/mage/cards/e/EvangelOfHeliod.java @@ -28,6 +28,7 @@ public final class EvangelOfHeliod extends CardImpl { // When Evangel of Heliod enters the battlefield, create a number of 1/1 white Soldier creature tokens equal to your devotion to white. this.addAbility(new EntersBattlefieldTriggeredAbility( new CreateTokenEffect(new SoldierToken(), DevotionCount.W) + .setText("create a number of 1/1 white Soldier creature tokens equal to your devotion to white") ).addHint(DevotionCount.W.getHint())); } diff --git a/Mage.Sets/src/mage/cards/e/EvasiveAction.java b/Mage.Sets/src/mage/cards/e/EvasiveAction.java index b3b81d4e1ac..6831eac3e53 100644 --- a/Mage.Sets/src/mage/cards/e/EvasiveAction.java +++ b/Mage.Sets/src/mage/cards/e/EvasiveAction.java @@ -21,7 +21,7 @@ public final class EvasiveAction extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Domain - Counter target spell unless its controller pays {1} for each basic land type among lands you control. - this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(new DomainValue())); + this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(DomainValue.REGULAR)); this.getSpellAbility().addTarget(new TargetSpell()); this.getSpellAbility().setAbilityWord(AbilityWord.DOMAIN); this.getSpellAbility().addHint(DomainHint.instance); diff --git a/Mage.Sets/src/mage/cards/e/EvelynTheCovetous.java b/Mage.Sets/src/mage/cards/e/EvelynTheCovetous.java new file mode 100644 index 00000000000..e77a8dc4ad6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EvelynTheCovetous.java @@ -0,0 +1,250 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.AsThoughManaEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlashAbility; +import mage.cards.*; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.game.CardState; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.ManaPoolItem; +import mage.players.Player; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.*; + +/** + * @author TheElk801 + */ +public final class EvelynTheCovetous extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.VAMPIRE, "Vampire"); + + public EvelynTheCovetous(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U/B}{B}{B/R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(5); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Whenever Evelyn, the Covetous or another Vampire enters the battlefield under your control, exile the top card of each player's library with a collection counter on it. + this.addAbility(new EntersBattlefieldThisOrAnotherTriggeredAbility( + new EvelynTheCovetousExileEffect(), filter, false, true + ), new EvelynTheCovetousWatcher()); + + // Once each turn, you may play a card from exile with a collection counter on it if it was exiled by an ability you controlled, and you may spend mana as though it were any color to cast it. + Ability ability = new SimpleStaticAbility(new EvelynTheCovetousCastEffect()); + ability.addEffect(new EvelynTheCovetousManaEffect()); + this.addAbility(ability); + } + + private EvelynTheCovetous(final EvelynTheCovetous card) { + super(card); + } + + @Override + public EvelynTheCovetous copy() { + return new EvelynTheCovetous(this); + } +} + +class EvelynTheCovetousExileEffect extends OneShotEffect { + + EvelynTheCovetousExileEffect() { + super(Outcome.Exile); + staticText = "exile the top card of each player's library with a collection counter on it"; + } + + private EvelynTheCovetousExileEffect(final EvelynTheCovetousExileEffect effect) { + super(effect); + } + + @Override + public EvelynTheCovetousExileEffect copy() { + return new EvelynTheCovetousExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Cards cards = new CardsImpl(); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + cards.add(player.getLibrary().getFromTop(game)); + } + } + if (cards.isEmpty()) { + return false; + } + controller.moveCards(cards, Zone.EXILED, source, game); + cards.getCards(game) + .stream() + .forEach(card -> card.addCounters(CounterType.COLLECTION.createInstance(), source, game)); + EvelynTheCovetousWatcher.addCards(source.getControllerId(), cards, game); + return true; + } +} + +class EvelynTheCovetousCastEffect extends AsThoughEffectImpl { + + EvelynTheCovetousCastEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.PlayForFree); + staticText = "once each turn, you may play a card from exile " + + "with a collection counter on it if it was exiled by an ability you controlled"; + } + + private EvelynTheCovetousCastEffect(final EvelynTheCovetousCastEffect effect) { + super(effect); + } + + @Override + public EvelynTheCovetousCastEffect copy() { + return new EvelynTheCovetousCastEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + if (!source.isControlledBy(affectedControllerId) || EvelynTheCovetousWatcher.checkUsed(source, game)) { + return false; + } + Card card = game.getCard(CardUtil.getMainCardId(game, sourceId)); + return card != null + && card.getCounters(game).getCount(CounterType.COLLECTION) > 0 + && EvelynTheCovetousWatcher.checkExile(affectedControllerId, card, game, 0); + } +} + +class EvelynTheCovetousManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { + + EvelynTheCovetousManaEffect() { + super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = ", and you may spend mana as though it were any color to cast it"; + } + + private EvelynTheCovetousManaEffect(final EvelynTheCovetousManaEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public EvelynTheCovetousManaEffect copy() { + return new EvelynTheCovetousManaEffect(this); + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + if (!source.isControlledBy(affectedControllerId) || !EvelynTheCovetousWatcher.checkUsed(source, game)) { + return false; + } + Card card = game.getCard(CardUtil.getMainCardId(game, sourceId)); + if (card == null) { + return false; + } + if (game.getState().getZone(card.getId()) == Zone.EXILED) { + return card.getCounters(game).getCount(CounterType.COLLECTION) > 0 + && EvelynTheCovetousWatcher.checkExile(affectedControllerId, card, game, 0); + } + CardState cardState; + if (card instanceof ModalDoubleFacesCard) { + cardState = game.getLastKnownInformationCard(((ModalDoubleFacesCard) card).getLeftHalfCard().getId(), Zone.EXILED); + } else { + cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED); + } + return cardState != null && cardState.getCounters().getCount(CounterType.COLLECTION) > 0 + && EvelynTheCovetousWatcher.checkExile(affectedControllerId, card, game, 1); + } + + @Override + public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + return mana.getFirstAvailable(); + } +} + +class EvelynTheCovetousWatcher extends Watcher { + + private final Map> exiledMap = new HashMap<>(); + private final Map> usedMap = new HashMap<>(); + + EvelynTheCovetousWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.SPELL_CAST + && event.getAdditionalReference() != null) { + usedMap.computeIfAbsent( + event.getAdditionalReference() + .getApprovingMageObjectReference(), + x -> new HashSet<>() + ).add(event.getPlayerId()); + } + } + + @Override + public void reset() { + super.reset(); + usedMap.clear(); + } + + static void addCards(UUID playerId, Cards cards, Game game) { + Set set = game + .getState() + .getWatcher(EvelynTheCovetousWatcher.class) + .exiledMap + .computeIfAbsent(playerId, x -> new HashSet<>()); + cards.getCards(game) + .stream() + .map(card -> new MageObjectReference(card, game)) + .forEach(set::add); + } + + static boolean checkUsed(Ability source, Game game) { + return game + .getState() + .getWatcher(EvelynTheCovetousWatcher.class) + .usedMap + .getOrDefault( + new MageObjectReference(source), + Collections.emptySet() + ).contains(source.getControllerId()); + } + + static boolean checkExile(UUID playerId, Card card, Game game, int offset) { + return game + .getState() + .getWatcher(EvelynTheCovetousWatcher.class) + .exiledMap + .getOrDefault(playerId, Collections.emptySet()) + .stream() + .anyMatch(mor -> mor.refersTo(card, game, offset)); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EvenTheScore.java b/Mage.Sets/src/mage/cards/e/EvenTheScore.java new file mode 100644 index 00000000000..b07af6fe132 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EvenTheScore.java @@ -0,0 +1,65 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; +import mage.watchers.common.CardsDrawnThisTurnWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EvenTheScore extends CardImpl { + + public EvenTheScore(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{U}{U}{U}"); + + // This spell costs {U}{U}{U} less to cast if an opponent has drawn four or more cards this turn. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, + new SpellCostReductionSourceEffect( + new ManaCostsImpl<>("{U}{U}{U}"), + EvenTheScoreCondition.instance + ) + ).setRuleAtTheTop(true), new CardsDrawnThisTurnWatcher()); + + // Draw X cards. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(ManacostVariableValue.REGULAR)); + } + + private EvenTheScore(final EvenTheScore card) { + super(card); + } + + @Override + public EvenTheScore copy() { + return new EvenTheScore(this); + } +} + +enum EvenTheScoreCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return game.getOpponents(source.getControllerId()) + .stream() + .mapToInt(game.getState().getWatcher(CardsDrawnThisTurnWatcher.class)::getCardsDrawnThisTurn) + .anyMatch(x -> x >= 4); + } + + @Override + public String toString() { + return "an opponent has drawn four or more cards this turn"; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EverbarkShaman.java b/Mage.Sets/src/mage/cards/e/EverbarkShaman.java index 8a1533f8cf5..a7630c31fee 100644 --- a/Mage.Sets/src/mage/cards/e/EverbarkShaman.java +++ b/Mage.Sets/src/mage/cards/e/EverbarkShaman.java @@ -24,7 +24,7 @@ import mage.target.common.TargetCardInYourGraveyard; */ public final class EverbarkShaman extends CardImpl { - private static final FilterCard filterForest = new FilterCard("Forest"); + private static final FilterCard filterForest = new FilterCard("Forest cards"); private static final FilterCard filterTreefolk = new FilterCard("Treefolk card from your graveyard"); static { @@ -41,7 +41,7 @@ public final class EverbarkShaman extends CardImpl { this.toughness = new MageInt(5); // {T}, Exile a Treefolk card from your graveyard: Search your library for up to two Forest cards and put them onto the battlefield tapped. Then shuffle your library. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(2, filterForest), true, Outcome.PutLandInPlay), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(0, 2, filterForest), true, Outcome.PutLandInPlay), new TapSourceCost()); ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(filterTreefolk))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/EvilTwin.java b/Mage.Sets/src/mage/cards/e/EvilTwin.java index c2f531b9f34..058ce6f2afb 100644 --- a/Mage.Sets/src/mage/cards/e/EvilTwin.java +++ b/Mage.Sets/src/mage/cards/e/EvilTwin.java @@ -80,7 +80,7 @@ class EvilTwinPredicate implements ObjectSourcePlayerPredicate { @Override public boolean apply(ObjectSourcePlayer input, Game game) { Permanent permanent = input.getObject(); - Permanent twin = game.getPermanent(input.getSourceId()); + Permanent twin = input.getSource().getSourcePermanentIfItStillExists(game); return CardUtil.haveSameNames(permanent, twin); } diff --git a/Mage.Sets/src/mage/cards/e/EvolutionCharm.java b/Mage.Sets/src/mage/cards/e/EvolutionCharm.java index b148f091c7f..cf42236dfa5 100644 --- a/Mage.Sets/src/mage/cards/e/EvolutionCharm.java +++ b/Mage.Sets/src/mage/cards/e/EvolutionCharm.java @@ -28,14 +28,12 @@ public final class EvolutionCharm extends CardImpl { this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0, 1, StaticFilters.FILTER_CARD_BASIC_LAND), true, true).setText("Search your library for a basic land card, reveal it, put it into your hand, then shuffle")); // or return target creature card from your graveyard to your hand; - Mode mode = new Mode(); - mode.addEffect(new ReturnFromGraveyardToHandTargetEffect()); + Mode mode = new Mode(new ReturnFromGraveyardToHandTargetEffect()); mode.addTarget(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.addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); + mode = new Mode(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/e/EvolvingDoor.java b/Mage.Sets/src/mage/cards/e/EvolvingDoor.java new file mode 100644 index 00000000000..5a058e68595 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EvolvingDoor.java @@ -0,0 +1,131 @@ +package mage.cards.e; + +import mage.ApprovingObject; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetControlledPermanent; +import mage.util.CardUtil; + +import java.util.*; + +/** + * @author TheElk801 + */ +public final class EvolvingDoor extends CardImpl { + + public EvolvingDoor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{G}"); + + // {1}, {T}, Sacrifice a creature: Count the colors of the sacrificed creature, then search your library for a creature card that's exactly that many colors plus one. Exile that card, then shuffle. You may cast the exiled card. Activate only as a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility(new EvolvingDoorEffect(), new GenericManaCost(1)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); + this.addAbility(ability); + } + + private EvolvingDoor(final EvolvingDoor card) { + super(card); + } + + @Override + public EvolvingDoor copy() { + return new EvolvingDoor(this); + } +} + +class EvolvingDoorEffect extends OneShotEffect { + + private static final class EvolvingDoorPredicate implements Predicate { + private final int count; + + private EvolvingDoorPredicate(int count) { + this.count = count; + } + + @Override + public boolean apply(Card input, Game game) { + return input.getColor(game).getColorCount() == count; + } + } + + private static final Map filterMap = new HashMap<>(); + + static { + for (int count = 1; count <= 6; count++) { + FilterCard filter = new FilterCard( + "creature card that's exactly " + + CardUtil.numberToText(count) + + " color" + (count > 0 ? "s" : "") + ); + filter.add(new EvolvingDoorPredicate(count)); + filterMap.put(count, filter); + } + } + + EvolvingDoorEffect() { + super(Outcome.Benefit); + staticText = "count the colors of the sacrificed creature, then search your library for a creature card " + + "that's exactly that many colors plus one. Exile that card, then shuffle. You may cast the exiled card"; + } + + private EvolvingDoorEffect(final EvolvingDoorEffect effect) { + super(effect); + } + + @Override + public EvolvingDoorEffect copy() { + return new EvolvingDoorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = CardUtil + .castStream( + source.getCosts().stream(), + SacrificeTargetCost.class + ) + .filter(Objects::nonNull) + .map(SacrificeTargetCost::getPermanents) + .flatMap(Collection::stream) + .findFirst() + .orElse(null); + if (player == null || permanent == null) { + return false; + } + TargetCardInLibrary target = new TargetCardInLibrary(filterMap.get(permanent.getColor(game).getColorCount() + 1)); + player.searchLibrary(target, source, game); + Card card = player.getLibrary().getCard(target.getFirstTarget(), game); + player.moveCards(card, Zone.EXILED, source, game); + player.shuffleLibrary(source, game); + if (card == null || !player.chooseUse( + Outcome.PlayForFree, "Cast " + card.getName() + '?', source, game + )) { + return true; + } + game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); + player.cast( + player.chooseAbilityForCast(card, game, false), + game, false, new ApprovingObject(source, game) + ); + game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/e/ExaltedAngel.java b/Mage.Sets/src/mage/cards/e/ExaltedAngel.java index 8910d101461..8c22fc6483f 100644 --- a/Mage.Sets/src/mage/cards/e/ExaltedAngel.java +++ b/Mage.Sets/src/mage/cards/e/ExaltedAngel.java @@ -30,7 +30,7 @@ public final class ExaltedAngel extends CardImpl { // Whenever Exalted Angel deals damage, you gain that much life. this.addAbility(new DealsDamageGainLifeSourceTriggeredAbility()); // Morph {2}{W}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{W}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{W}{W}"))); } private ExaltedAngel(final ExaltedAngel card) { diff --git a/Mage.Sets/src/mage/cards/e/ExcavationElephant.java b/Mage.Sets/src/mage/cards/e/ExcavationElephant.java index b39500cc314..a9189fce274 100644 --- a/Mage.Sets/src/mage/cards/e/ExcavationElephant.java +++ b/Mage.Sets/src/mage/cards/e/ExcavationElephant.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -9,15 +7,16 @@ import mage.abilities.condition.common.KickedCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.KickerAbility; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterArtifactCard; +import mage.constants.SubType; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class ExcavationElephant extends CardImpl { @@ -34,11 +33,11 @@ public final class ExcavationElephant extends CardImpl { // When Excavation Elephant enters the battlefield, if it was kicked, return target artifact card from your graveyard to your hand. TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false); - ability.addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); this.addAbility(new ConditionalInterveningIfTriggeredAbility( ability, KickedCondition.instance, "When {this} enters the battlefield, if it was kicked, " - + "return target artifact card from your graveyard to your hand." + + "return target artifact card from your graveyard to your hand." )); } diff --git a/Mage.Sets/src/mage/cards/e/ExertInfluence.java b/Mage.Sets/src/mage/cards/e/ExertInfluence.java index c56cb657859..135a09f3006 100644 --- a/Mage.Sets/src/mage/cards/e/ExertInfluence.java +++ b/Mage.Sets/src/mage/cards/e/ExertInfluence.java @@ -62,7 +62,7 @@ class ExertInfluenceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Player controller = game.getPlayer(source.getControllerId()); Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); if (controller != null && sourceObject != null) { diff --git a/Mage.Sets/src/mage/cards/e/ExhibitionMagician.java b/Mage.Sets/src/mage/cards/e/ExhibitionMagician.java new file mode 100644 index 00000000000..6622bdc00f7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ExhibitionMagician.java @@ -0,0 +1,47 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.CitizenGreenWhiteToken; +import mage.game.permanent.token.TreasureToken; + +/** + * + * @author weirddan455 + */ +public final class ExhibitionMagician extends CardImpl { + + public ExhibitionMagician(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // When Exhibition Magician enters the battlefield, choose one — + // • Create a 1/1 green and white Citizen creature token. + Ability ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new CitizenGreenWhiteToken())); + + // • Create a Treasure token. + ability.addMode(new Mode(new CreateTokenEffect(new TreasureToken()))); + this.addAbility(ability); + } + + private ExhibitionMagician(final ExhibitionMagician card) { + super(card); + } + + @Override + public ExhibitionMagician copy() { + return new ExhibitionMagician(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/Exhume.java b/Mage.Sets/src/mage/cards/e/Exhume.java index e1d5724ca38..c0de24ec1de 100644 --- a/Mage.Sets/src/mage/cards/e/Exhume.java +++ b/Mage.Sets/src/mage/cards/e/Exhume.java @@ -68,7 +68,7 @@ class ExhumeEffect extends OneShotEffect { filterCreatureCard.add(new OwnerIdPredicate(playerId)); TargetCardInGraveyard target = new TargetCardInGraveyard(filterCreatureCard); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), playerId, game) + if (target.canChoose(playerId, source, game) && player.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/e/ExhumerThrull.java b/Mage.Sets/src/mage/cards/e/ExhumerThrull.java index bbaae799fd6..ad72504e874 100644 --- a/Mage.Sets/src/mage/cards/e/ExhumerThrull.java +++ b/Mage.Sets/src/mage/cards/e/ExhumerThrull.java @@ -1,26 +1,25 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.HauntAbility; 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 */ public final class ExhumerThrull extends CardImpl { public ExhumerThrull(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}"); this.subtype.add(SubType.THRULL); this.power = new MageInt(3); @@ -28,10 +27,9 @@ public final class ExhumerThrull extends CardImpl { // Haunt // When Exhumer Thrull enters the battlefield or the creature it haunts dies, return target creature card from your graveyard to your hand. - Ability ability = new HauntAbility(this, new ReturnToHandTargetEffect()); - ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("target creature card from your graveyard"))); + Ability ability = new HauntAbility(this, new ReturnFromGraveyardToHandTargetEffect()); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); - } private ExhumerThrull(final ExhumerThrull card) { diff --git a/Mage.Sets/src/mage/cards/e/ExoticCurse.java b/Mage.Sets/src/mage/cards/e/ExoticCurse.java index dbd5f7c7203..b3c478e06bb 100644 --- a/Mage.Sets/src/mage/cards/e/ExoticCurse.java +++ b/Mage.Sets/src/mage/cards/e/ExoticCurse.java @@ -33,7 +33,7 @@ public final class ExoticCurse extends CardImpl { this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Domain - Enchanted creature gets -1/-1 for each basic land type among lands you control. - DynamicValue unboost = new SignInversionDynamicValue(new DomainValue()); + DynamicValue unboost = new SignInversionDynamicValue(DomainValue.REGULAR); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(unboost, unboost, Duration.WhileOnBattlefield)); ability.setAbilityWord(AbilityWord.DOMAIN); this.addAbility(ability.addHint(DomainHint.instance)); diff --git a/Mage.Sets/src/mage/cards/e/ExoticDisease.java b/Mage.Sets/src/mage/cards/e/ExoticDisease.java index 15b82d9d6bf..34a5523c7d4 100644 --- a/Mage.Sets/src/mage/cards/e/ExoticDisease.java +++ b/Mage.Sets/src/mage/cards/e/ExoticDisease.java @@ -1,36 +1,33 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.dynamicvalue.common.DomainValue; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.hint.common.DomainHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author LoneFox */ public final class ExoticDisease extends CardImpl { public ExoticDisease(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); // Domain - Target player loses X life and you gain X life, where X is the number of basic land types among lands you control. - DomainValue dv = new DomainValue(); - Effect effect = new LoseLifeTargetEffect(dv); - effect.setText("Domain — Target player loses X life"); - this.getSpellAbility().addEffect(effect); - effect = new GainLifeEffect(dv); - effect.setText("and you gain X life, where X is the number of basic land types among lands you control"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new LoseLifeTargetEffect(DomainValue.REGULAR) + .setText("target player loses X life")); + this.getSpellAbility().addEffect(new GainLifeEffect(DomainValue.REGULAR) + .setText("and you gain X life, where X is the number of basic land types among lands you control")); this.getSpellAbility().addTarget(new TargetPlayer()); this.getSpellAbility().addHint(DomainHint.instance); + this.getSpellAbility().setAbilityWord(AbilityWord.DOMAIN); } private ExoticDisease(final ExoticDisease card) { diff --git a/Mage.Sets/src/mage/cards/e/ExoticPets.java b/Mage.Sets/src/mage/cards/e/ExoticPets.java new file mode 100644 index 00000000000..41bf2012dfe --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ExoticPets.java @@ -0,0 +1,123 @@ +package mage.cards.e; + +import mage.MageItem; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.FishToken; +import mage.game.permanent.token.Token; +import mage.players.Player; +import mage.target.TargetPermanent; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class ExoticPets extends CardImpl { + + public ExoticPets(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}{U}"); + + // Create two 1/1 blue Fish creature tokens with "This creature can't be blocked." Then for each kind of counter among creatures you control, put a counter of that kind on either of those tokens. + this.getSpellAbility().addEffect(new ExoticPetsEffect()); + } + + private ExoticPets(final ExoticPets card) { + super(card); + } + + @Override + public ExoticPets copy() { + return new ExoticPets(this); + } +} + +class ExoticPetsEffect extends OneShotEffect { + + ExoticPetsEffect() { + super(Outcome.Benefit); + staticText = "create two 1/1 blue Fish creature tokens with \"This creature can't be blocked.\" " + + "Then for each kind of counter among creatures you control, " + + "put a counter of that kind on either of those tokens"; + } + + private ExoticPetsEffect(final ExoticPetsEffect effect) { + super(effect); + } + + @Override + public ExoticPetsEffect copy() { + return new ExoticPetsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Token token = new FishToken(); + token.putOntoBattlefield(2, game, source); + List permanents = token + .getLastAddedTokenIds() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (permanents.isEmpty()) { + return false; + } + Set counterTypes = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, + source.getControllerId(), source, game + ).stream() + .map(permanent -> permanent.getCounters(game)) + .map(HashMap::keySet) + .flatMap(Collection::stream) + .distinct() + .map(CounterType::findByName) + .collect(Collectors.toSet()); + if (counterTypes.isEmpty()) { + return true; + } + if (permanents.size() == 1) { + Permanent permanent = permanents.get(0); + for (CounterType counterType : counterTypes) { + permanent.addCounters(counterType.createInstance(), source, game); + } + return true; + } + FilterPermanent filter = new FilterPermanent("creature"); + filter.add(Predicates.or(permanents + .stream() + .map(MageItem::getId) + .map(PermanentIdPredicate::new) + .collect(Collectors.toSet()))); + TargetPermanent target = new TargetPermanent(filter); + target.setNotTarget(true); + for (CounterType counterType : counterTypes) { + target.clearChosen(); + target.withChooseHint("to add " + counterType.getArticle() + ' ' + counterType + " counter to"); + player.choose(Outcome.BoostCreature, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + permanent.addCounters(counterType.createInstance(), source, game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/e/ExpeditionSupplier.java b/Mage.Sets/src/mage/cards/e/ExpeditionSupplier.java new file mode 100644 index 00000000000..b79994cae30 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ExpeditionSupplier.java @@ -0,0 +1,44 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; +import mage.abilities.effects.common.ConjureCardEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ExpeditionSupplier extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.HUMAN, "Human"); + + public ExpeditionSupplier(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever Expedition Supplier or another Human enters the battlefield under your control, conjure a card named Utility Knife onto the battlefield. This ability triggers only once each turn. + this.addAbility(new EntersBattlefieldThisOrAnotherTriggeredAbility(new ConjureCardEffect( + "Utility Knife", Zone.BATTLEFIELD, 1 + ), filter, false, true).setTriggersOnce(true)); + } + + private ExpeditionSupplier(final ExpeditionSupplier card) { + super(card); + } + + @Override + public ExpeditionSupplier copy() { + return new ExpeditionSupplier(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ExpendableLackey.java b/Mage.Sets/src/mage/cards/e/ExpendableLackey.java new file mode 100644 index 00000000000..f5a521a22c4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ExpendableLackey.java @@ -0,0 +1,47 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.costs.common.ExileSourceFromGraveCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.permanent.token.FishToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ExpendableLackey extends CardImpl { + + public ExpendableLackey(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {1}{U}, Exile Expendable Lackey from your graveyard: Create a 1/1 blue Fish creature token with "This creature can't be blocked." Activate only as a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + Zone.GRAVEYARD, new CreateTokenEffect(new FishToken()), new ManaCostsImpl<>("{1}{U}") + ); + ability.addCost(new ExileSourceFromGraveCost()); + this.addAbility(ability); + } + + private ExpendableLackey(final ExpendableLackey card) { + super(card); + } + + @Override + public ExpendableLackey copy() { + return new ExpendableLackey(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ExperimentKraj.java b/Mage.Sets/src/mage/cards/e/ExperimentKraj.java index 9967d4ed624..0d4efac3aad 100644 --- a/Mage.Sets/src/mage/cards/e/ExperimentKraj.java +++ b/Mage.Sets/src/mage/cards/e/ExperimentKraj.java @@ -76,7 +76,7 @@ class ExperimentKrajEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { Permanent perm = game.getPermanent(source.getSourceId()); if (perm != null) { - for (Permanent creature :game.getState().getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)){ + for (Permanent creature :game.getState().getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)){ for (Ability ability: creature.getAbilities()) { if (ability instanceof ActivatedAbility) { perm.addAbility(ability, source.getSourceId(), game); diff --git a/Mage.Sets/src/mage/cards/e/ExplodingBorders.java b/Mage.Sets/src/mage/cards/e/ExplodingBorders.java index 5100de8de82..b7a82e6825a 100644 --- a/Mage.Sets/src/mage/cards/e/ExplodingBorders.java +++ b/Mage.Sets/src/mage/cards/e/ExplodingBorders.java @@ -1,4 +1,3 @@ - package mage.cards.e; import mage.abilities.dynamicvalue.common.DomainValue; @@ -7,15 +6,15 @@ import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.abilities.hint.common.DomainHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.filter.StaticFilters; import mage.target.common.TargetCardInLibrary; - -import java.util.UUID; import mage.target.common.TargetPlayerOrPlaneswalker; +import java.util.UUID; + /** - * * @author Loki */ public final class ExplodingBorders extends CardImpl { @@ -25,9 +24,10 @@ public final class ExplodingBorders extends CardImpl { // Domain - Search your library for a basic land card, put that card onto the battlefield tapped, then shuffle your library. Exploding Borders deals X damage to target player, where X is the number of basic land types among lands you control. this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true)); - this.getSpellAbility().addEffect(new DamageTargetEffect(new DomainValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(DomainValue.REGULAR)); this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); this.getSpellAbility().addHint(DomainHint.instance); + this.getSpellAbility().setAbilityWord(AbilityWord.DOMAIN); } private ExplodingBorders(final ExplodingBorders card) { diff --git a/Mage.Sets/src/mage/cards/e/ExplosionOfRiches.java b/Mage.Sets/src/mage/cards/e/ExplosionOfRiches.java index 6d3226856fc..7fbfeafeb0d 100644 --- a/Mage.Sets/src/mage/cards/e/ExplosionOfRiches.java +++ b/Mage.Sets/src/mage/cards/e/ExplosionOfRiches.java @@ -56,6 +56,7 @@ class ExplosionOfRichesEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { + int cardsDrawn = 0; for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player == null) { @@ -65,9 +66,9 @@ class ExplosionOfRichesEffect extends OneShotEffect { && !player.chooseUse(outcome, "Draw a card?", source, game)) { continue; } - if (player.drawCards(1, source, game) >= 1) { - continue; - } + cardsDrawn += player.drawCards(1, source, game); + } + for (int i = 0; i < cardsDrawn; i++) { ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( new DamageTargetEffect(5), false, "{this} deals damage to target opponent chosen at random" diff --git a/Mage.Sets/src/mage/cards/e/ExplosiveRevelation.java b/Mage.Sets/src/mage/cards/e/ExplosiveRevelation.java index 18e05135393..a6042817a77 100644 --- a/Mage.Sets/src/mage/cards/e/ExplosiveRevelation.java +++ b/Mage.Sets/src/mage/cards/e/ExplosiveRevelation.java @@ -45,7 +45,7 @@ class ExplosiveRevelationEffect extends OneShotEffect { public ExplosiveRevelationEffect() { super(Outcome.DrawCard); - this.staticText = "Choose any target. Reveal cards from the top of your library until you reveal a nonland card, {this} deals damage equal to that card's mana value to that permanent or player. Put the nonland card into your hand and the rest on the bottom of your library in any order"; + this.staticText = "Choose any target. Reveal cards from the top of your library until you reveal a nonland card. {this} deals damage equal to that card's mana value to that permanent or player. Put the nonland card into your hand and the rest on the bottom of your library in any order"; } public ExplosiveRevelationEffect(final ExplosiveRevelationEffect effect) { diff --git a/Mage.Sets/src/mage/cards/e/ExplosiveSingularity.java b/Mage.Sets/src/mage/cards/e/ExplosiveSingularity.java new file mode 100644 index 00000000000..48e52061fe2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ExplosiveSingularity.java @@ -0,0 +1,90 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetControlledPermanent; +import mage.util.CardUtil; + +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ExplosiveSingularity extends CardImpl { + + public ExplosiveSingularity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{8}{R}{R}"); + + // As an additional cost to cast this spell, you may tap any number of untapped creatures you control. This spell costs {1} less to cast for each creature tapped this way. + this.getSpellAbility().addCost(new TapTargetCost(new TargetControlledPermanent( + 0, Integer.MAX_VALUE, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES, false + )).setText("you may tap any number of untapped creatures you control. " + + "This spell costs {1} less to cast for each creature tapped this way")); + Ability ability = new SimpleStaticAbility(Zone.ALL, new ExplosiveSingularityEffect()); + ability.setRuleVisible(false); + this.addAbility(ability); + + // Explosive Singularity deals 10 damage to any target. + this.getSpellAbility().addEffect(new DamageTargetEffect(10)); + this.getSpellAbility().addTarget(new TargetAnyTarget()); + } + + private ExplosiveSingularity(final ExplosiveSingularity card) { + super(card); + } + + @Override + public ExplosiveSingularity copy() { + return new ExplosiveSingularity(this); + } +} + +class ExplosiveSingularityEffect extends CostModificationEffectImpl { + + ExplosiveSingularityEffect() { + super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST); + } + + private ExplosiveSingularityEffect(final ExplosiveSingularityEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + SpellAbility spellAbility = (SpellAbility) abilityToModify; + int reduction; + if (game.inCheckPlayableState()) { + reduction = game.getBattlefield().count( + StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES, + source.getControllerId(), source, game + ); + } else { + reduction = ((List) spellAbility.getEffects().get(0).getValue("tappedPermanents")).size(); + } + CardUtil.adjustCost(spellAbility, reduction); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + return abilityToModify instanceof SpellAbility + && abilityToModify.getSourceId().equals(source.getSourceId()); + } + + @Override + public ExplosiveSingularityEffect copy() { + return new ExplosiveSingularityEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/Expropriate.java b/Mage.Sets/src/mage/cards/e/Expropriate.java index 04aa42b4f37..8808e10acca 100644 --- a/Mage.Sets/src/mage/cards/e/Expropriate.java +++ b/Mage.Sets/src/mage/cards/e/Expropriate.java @@ -94,14 +94,14 @@ class ExpropriateEffect extends OneShotEffect { FilterPermanent filter = new FilterPermanent(); filter.add(new ControllerIdPredicate(playerId)); moneyCount = Math.min(game.getBattlefield().count( - filter, source.getSourceId(), source.getControllerId(), game + filter, source.getControllerId(), source, game ), moneyCount); if (moneyCount == 0) { continue; } TargetPermanent target = new TargetPermanent(moneyCount, filter); target.setNotTarget(true); - player.choose(Outcome.GainControl, target, source.getSourceId(), game); + player.choose(Outcome.GainControl, target, source, game); target.getTargets() .stream() .map(game::getPermanent) diff --git a/Mage.Sets/src/mage/cards/e/Extinction.java b/Mage.Sets/src/mage/cards/e/Extinction.java index 91c13915ab1..4edfef0a8fb 100644 --- a/Mage.Sets/src/mage/cards/e/Extinction.java +++ b/Mage.Sets/src/mage/cards/e/Extinction.java @@ -53,7 +53,7 @@ class ExtinctionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (player != null && sourceObject != null) { Choice typeChoice = new ChoiceCreatureType(sourceObject); diff --git a/Mage.Sets/src/mage/cards/e/ExtinctionEvent.java b/Mage.Sets/src/mage/cards/e/ExtinctionEvent.java index 875a24b820d..ea21ec077e9 100644 --- a/Mage.Sets/src/mage/cards/e/ExtinctionEvent.java +++ b/Mage.Sets/src/mage/cards/e/ExtinctionEvent.java @@ -74,7 +74,7 @@ class ExtinctionEventEffect extends OneShotEffect { ) ? oddFilter : evenFilter; return player.moveCards( game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game ).stream().collect(Collectors.toSet()), Zone.EXILED, source, game ); } diff --git a/Mage.Sets/src/mage/cards/e/Extirpate.java b/Mage.Sets/src/mage/cards/e/Extirpate.java index 511bc378496..989ce601681 100644 --- a/Mage.Sets/src/mage/cards/e/Extirpate.java +++ b/Mage.Sets/src/mage/cards/e/Extirpate.java @@ -63,7 +63,7 @@ class ExtirpateEffect extends OneShotEffect { super(Outcome.Exile); this.staticText = "Choose target card in a graveyard other than " + "a basic land card. Search its owner's graveyard, hand, " - + "and library for any number of cards with the same name " + + "and library for all cards with the same name " + "as that card and exile them. Then that player shuffles"; } @@ -79,7 +79,7 @@ class ExtirpateEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Card chosenCard = game.getCard(getTargetPointer().getFirst(game, source)); if (chosenCard != null && sourceObject != null && controller != null) { Player owner = game.getPlayer(chosenCard.getOwnerId()); diff --git a/Mage.Sets/src/mage/cards/e/Extract.java b/Mage.Sets/src/mage/cards/e/Extract.java index ee436168bb5..6d45976143e 100644 --- a/Mage.Sets/src/mage/cards/e/Extract.java +++ b/Mage.Sets/src/mage/cards/e/Extract.java @@ -1,35 +1,24 @@ - package mage.cards.e; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.search.SearchLibraryAndExileTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.game.Game; -import mage.players.Player; import mage.target.TargetPlayer; -import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; /** - * * @author cbt33, jeffwadsworth (Supreme Inquisitor) */ public final class Extract extends CardImpl { public Extract(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}"); // Search target player's library for a card and exile it. Then that player shuffles their library. - this.getSpellAbility().addEffect(new ExtractEffect()); + this.getSpellAbility().addEffect(new SearchLibraryAndExileTargetEffect(1, false)); this.getSpellAbility().addTarget(new TargetPlayer()); - } private Extract(final Extract card) { @@ -41,40 +30,3 @@ public final class Extract extends CardImpl { return new Extract(this); } } - -class ExtractEffect extends OneShotEffect { - - private static final FilterCard filter = new FilterCard(); - - public ExtractEffect() { - super(Outcome.Exile); - staticText = "Search target player's library for a card and exile it. Then that player shuffles."; - } - - public ExtractEffect(final ExtractEffect effect) { - super(effect); - } - - @Override - public ExtractEffect copy() { - return new ExtractEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player targetPlayer = game.getPlayer(source.getFirstTarget()); - Player player = game.getPlayer(source.getControllerId()); - if (player != null && targetPlayer != null) { - TargetCardInLibrary target = new TargetCardInLibrary(1, 1, filter); - if (player.searchLibrary(target, source, game, targetPlayer.getId())) { - Card card = targetPlayer.getLibrary().remove(target.getFirstTarget(), game); - if (card != null) { - player.moveCardToExileWithInfo(card, null, null, source, game, Zone.LIBRARY, true); - } - } - targetPlayer.shuffleLibrary(source, game); - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/e/ExtractBrain.java b/Mage.Sets/src/mage/cards/e/ExtractBrain.java new file mode 100644 index 00000000000..b216be93128 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ExtractBrain.java @@ -0,0 +1,77 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetOpponent; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ExtractBrain extends CardImpl { + + public ExtractBrain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{U}{B}"); + + // Target opponent chooses X cards from their hand. Look at those cards. You may cast a spell from among them without paying its mana cost. + this.getSpellAbility().addEffect(new ExtractBrainEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + private ExtractBrain(final ExtractBrain card) { + super(card); + } + + @Override + public ExtractBrain copy() { + return new ExtractBrain(this); + } +} + +class ExtractBrainEffect extends OneShotEffect { + + ExtractBrainEffect() { + super(Outcome.Benefit); + staticText = "target opponent chooses X cards from their hand. Look at those cards. " + + "You may cast a spell from among them without paying its mana cost"; + } + + private ExtractBrainEffect(final ExtractBrainEffect effect) { + super(effect); + } + + @Override + public ExtractBrainEffect copy() { + return new ExtractBrainEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(source.getFirstTarget()); + int xValue = source.getManaCostsToPay().getX(); + if (controller == null || opponent == null || opponent.getHand().isEmpty() || xValue < 1) { + return false; + } + TargetCardInHand target = new TargetCardInHand( + Math.min(opponent.getHand().size(), xValue), StaticFilters.FILTER_CARD + ); + opponent.choose(Outcome.Detriment, opponent.getHand(), target, game); + Cards cards = new CardsImpl(target.getTargets()); + controller.lookAtCards(source, null, cards, game); + CardUtil.castSpellWithAttributesForFree(controller, source, game, cards, StaticFilters.FILTER_CARD); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/e/ExtractFromDarkness.java b/Mage.Sets/src/mage/cards/e/ExtractFromDarkness.java index 6626d71ad26..49054494bd4 100644 --- a/Mage.Sets/src/mage/cards/e/ExtractFromDarkness.java +++ b/Mage.Sets/src/mage/cards/e/ExtractFromDarkness.java @@ -64,7 +64,7 @@ class ExtractFromDarknessEffect extends OneShotEffect { if (controller != null) { Target target = new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + if (target.canChoose(source.getControllerId(), source, game) && controller.chooseTarget(outcome, target, source, game)) { return controller.moveCards(game.getCard(target.getFirstTarget()), Zone.BATTLEFIELD, source, game); } diff --git a/Mage.Sets/src/mage/cards/e/ExtractTheTruth.java b/Mage.Sets/src/mage/cards/e/ExtractTheTruth.java new file mode 100644 index 00000000000..631e9731f88 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ExtractTheTruth.java @@ -0,0 +1,50 @@ +package mage.cards.e; + +import java.util.UUID; + +import mage.abilities.Mode; +import mage.abilities.effects.common.SacrificeEffect; +import mage.abilities.effects.common.discard.DiscardCardYouChooseTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicates; +import mage.target.common.TargetOpponent; + +/** + * + * @author weirddan455 + */ +public final class ExtractTheTruth extends CardImpl { + + private static final FilterCard filter = new FilterCard("creature, enchantment, or planeswalker card"); + + static { + filter.add(Predicates.or(CardType.CREATURE.getPredicate(), CardType.ENCHANTMENT.getPredicate(), CardType.PLANESWALKER.getPredicate())); + } + + public ExtractTheTruth(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); + + // Choose one— + // • Target opponent reveals their hand. You may choose a creature, enchantment, or planeswalker card from it. That player discards that card. + DiscardCardYouChooseTargetEffect effect = new DiscardCardYouChooseTargetEffect(filter); + effect.setOptional(true); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetOpponent()); + + // • Target opponent sacrifices an enchantment. + this.getSpellAbility().addMode(new Mode(new SacrificeEffect(StaticFilters.FILTER_PERMANENT_ENCHANTMENT, 1, "Target opponent")).addTarget(new TargetOpponent())); + } + + private ExtractTheTruth(final ExtractTheTruth card) { + super(card); + } + + @Override + public ExtractTheTruth copy() { + return new ExtractTheTruth(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ExtractionSpecialist.java b/Mage.Sets/src/mage/cards/e/ExtractionSpecialist.java new file mode 100644 index 00000000000..d7fba3e56eb --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ExtractionSpecialist.java @@ -0,0 +1,97 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.combat.CantAttackBlockTargetEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ExtractionSpecialist extends CardImpl { + + private static final FilterCard filter + = new FilterCreatureCard("creature card with mana value 2 or less from your graveyard"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 3)); + } + + public ExtractionSpecialist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // When Extraction Specialist enters the battlefield, return target creature card with mana value 2 or less from your graveyard to the battlefield. That creature can't attack or block for as long as you control Extraction Specialist. + Ability ability = new EntersBattlefieldTriggeredAbility(new ExtractionSpecialistEffect()); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); + } + + private ExtractionSpecialist(final ExtractionSpecialist card) { + super(card); + } + + @Override + public ExtractionSpecialist copy() { + return new ExtractionSpecialist(this); + } +} + +class ExtractionSpecialistEffect extends OneShotEffect { + + ExtractionSpecialistEffect() { + super(Outcome.Benefit); + staticText = "return target creature card with mana value 2 or less from your graveyard to the battlefield. " + + "That creature can't attack or block for as long as you control {this}"; + } + + private ExtractionSpecialistEffect(final ExtractionSpecialistEffect effect) { + super(effect); + } + + @Override + public ExtractionSpecialistEffect copy() { + return new ExtractionSpecialistEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + if (player == null || card == null) { + return false; + } + player.moveCards(card, Zone.BATTLEFIELD, source, game); + Permanent permanent = game.getPermanent(card.getId()); + if (permanent == null + && source.getSourcePermanentIfItStillExists(game) != null + && source.isControlledBy(game.getControllerId(source.getSourceId()))) { + game.addEffect(new CantAttackBlockTargetEffect(Duration.WhileControlled) + .setTargetPointer(new FixedTarget(permanent, game)), source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/e/ExtractorDemon.java b/Mage.Sets/src/mage/cards/e/ExtractorDemon.java index bf23831df86..cd90bf2f5bb 100644 --- a/Mage.Sets/src/mage/cards/e/ExtractorDemon.java +++ b/Mage.Sets/src/mage/cards/e/ExtractorDemon.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.LeavesBattlefieldAllTriggeredAbility; @@ -17,10 +15,10 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author jeffwadsworth - * */ public final class ExtractorDemon extends CardImpl { @@ -41,12 +39,16 @@ public final class ExtractorDemon extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever another creature leaves the battlefield, you may have target player put the top two cards of their library into their graveyard. - Ability ability = new LeavesBattlefieldAllTriggeredAbility(new PutLibraryIntoGraveTargetEffect(2), filter, true); + Ability ability = new LeavesBattlefieldAllTriggeredAbility( + new PutLibraryIntoGraveTargetEffect(2) + .setText("you may have target player mill two cards"), + filter, true + ); ability.addTarget(new TargetPlayer()); this.addAbility(ability); // Unearth {2}{B} - this.addAbility(new UnearthAbility(new ManaCostsImpl("{2}{B}"))); + this.addAbility(new UnearthAbility(new ManaCostsImpl<>("{2}{B}"))); } private ExtractorDemon(final ExtractorDemon card) { diff --git a/Mage.Sets/src/mage/cards/e/ExtravagantReplication.java b/Mage.Sets/src/mage/cards/e/ExtravagantReplication.java new file mode 100644 index 00000000000..3c2da465e2a --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ExtravagantReplication.java @@ -0,0 +1,48 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ExtravagantReplication extends CardImpl { + + private static final FilterPermanent filter + = new FilterNonlandPermanent("another target nonland permanent you control"); + + static { + filter.add(AnotherPredicate.instance); + } + + public ExtravagantReplication(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{U}{U}"); + + // At the beginning of your upkeep, create a token that's a copy of another target nonland permanent you control. + Ability ability = new BeginningOfUpkeepTriggeredAbility( + new CreateTokenCopyTargetEffect(), TargetController.YOU, false + ); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private ExtravagantReplication(final ExtravagantReplication card) { + super(card); + } + + @Override + public ExtravagantReplication copy() { + return new ExtravagantReplication(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ExuberantWolfbear.java b/Mage.Sets/src/mage/cards/e/ExuberantWolfbear.java index 7b2432fd808..c676b9cc540 100644 --- a/Mage.Sets/src/mage/cards/e/ExuberantWolfbear.java +++ b/Mage.Sets/src/mage/cards/e/ExuberantWolfbear.java @@ -55,7 +55,7 @@ class ExuberantWolfbearEffect extends OneShotEffect { ExuberantWolfbearEffect() { super(Outcome.Benefit); - staticText = "change the base power and toughness of target Human you control " + + staticText = "you may change the base power and toughness of target Human you control " + "to {this}'s power and toughness until end of turn"; } diff --git a/Mage.Sets/src/mage/cards/e/EyeForAnEye.java b/Mage.Sets/src/mage/cards/e/EyeForAnEye.java index cff03e1f6ad..a61532bfd86 100644 --- a/Mage.Sets/src/mage/cards/e/EyeForAnEye.java +++ b/Mage.Sets/src/mage/cards/e/EyeForAnEye.java @@ -59,7 +59,7 @@ class EyeForAnEyeEffect extends ReplacementEffectImpl { @Override public void init(Ability source, Game game) { - this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); super.init(source, game); } diff --git a/Mage.Sets/src/mage/cards/e/EyeOfSingularity.java b/Mage.Sets/src/mage/cards/e/EyeOfSingularity.java index 0f531170ec3..61f75b12e4b 100644 --- a/Mage.Sets/src/mage/cards/e/EyeOfSingularity.java +++ b/Mage.Sets/src/mage/cards/e/EyeOfSingularity.java @@ -15,7 +15,6 @@ import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; @@ -79,7 +78,7 @@ class EyeOfSingularityETBEffect extends OneShotEffect { Map cardNames = new HashMap<>(); Map toDestroy = new HashMap<>(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { String cardName = permanent.getName(); if (cardNames.get(cardName) == null) { cardNames.put(cardName, permanent.getId()); @@ -166,7 +165,7 @@ class EyeOfSingularityTriggeredEffect extends OneShotEffect { } String cn = etbPermanent.getName(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { String cardName = permanent.getName(); if (cardName.equals(cn) && !Objects.equals(permanent.getId(), etbPermanent.getId())) { toDestroy.put(permanent.getId(), 1); diff --git a/Mage.Sets/src/mage/cards/e/EzuriClawOfProgress.java b/Mage.Sets/src/mage/cards/e/EzuriClawOfProgress.java index edd8234b6f3..445c4494935 100644 --- a/Mage.Sets/src/mage/cards/e/EzuriClawOfProgress.java +++ b/Mage.Sets/src/mage/cards/e/EzuriClawOfProgress.java @@ -34,7 +34,7 @@ public final class EzuriClawOfProgress extends CardImpl { filter2.add(AnotherPredicate.instance); } - String rule = "Whenever a creature with power 2 or less enters the battlefield under your control, you get an experience counter."; + private static final String rule = "Whenever a creature with power 2 or less enters the battlefield under your control, you get an experience counter."; public EzuriClawOfProgress(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); diff --git a/Mage.Sets/src/mage/cards/e/EzurisArchers.java b/Mage.Sets/src/mage/cards/e/EzurisArchers.java index d5caf3f52da..95d98e62d44 100644 --- a/Mage.Sets/src/mage/cards/e/EzurisArchers.java +++ b/Mage.Sets/src/mage/cards/e/EzurisArchers.java @@ -3,8 +3,7 @@ package mage.cards.e; import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.ReachAbility; @@ -13,10 +12,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; /** * @@ -24,6 +22,12 @@ import mage.game.events.GameEvent.EventType; */ public final class EzurisArchers extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + public EzurisArchers(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}"); this.subtype.add(SubType.ELF); @@ -32,9 +36,11 @@ public final class EzurisArchers extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(2); + // Reach this.addAbility(ReachAbility.getInstance()); + // Whenever Ezuri's Archers blocks a creature with flying, Ezuri's Archers gets +3/+0 until end of turn. - this.addAbility(new BlocksCreatureWithFlyingTriggeredAbility(new BoostSourceEffect(3, 0, Duration.EndOfTurn), false)); + this.addAbility(new BlocksCreatureTriggeredAbility(new BoostSourceEffect(3, 0, Duration.EndOfTurn), filter, false)); } private EzurisArchers(final EzurisArchers card) { @@ -46,34 +52,3 @@ public final class EzurisArchers extends CardImpl { return new EzurisArchers(this); } } - -class BlocksCreatureWithFlyingTriggeredAbility extends TriggeredAbilityImpl { - - public BlocksCreatureWithFlyingTriggeredAbility(Effect effect, boolean optional) { - super(Zone.BATTLEFIELD, effect, optional); - } - - public BlocksCreatureWithFlyingTriggeredAbility(final BlocksCreatureWithFlyingTriggeredAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.BLOCKER_DECLARED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return event.getSourceId().equals(this.getSourceId()) && game.getPermanent(event.getTargetId()).getAbilities().containsKey(FlyingAbility.getInstance().getId()); - } - - @Override - public String getTriggerPhrase() { - return "Whenever {this} blocks a creature with flying, " ; - } - - @Override - public BlocksCreatureWithFlyingTriggeredAbility copy() { - return new BlocksCreatureWithFlyingTriggeredAbility(this); - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/e/EzurisPredation.java b/Mage.Sets/src/mage/cards/e/EzurisPredation.java index 3c2b5556728..842b0054083 100644 --- a/Mage.Sets/src/mage/cards/e/EzurisPredation.java +++ b/Mage.Sets/src/mage/cards/e/EzurisPredation.java @@ -78,7 +78,7 @@ class EzurisPredationEffect extends OneShotEffect { if (controller != null) { FilterCreaturePermanent filterCreature = new FilterCreaturePermanent(); filterCreature.add(TargetController.OPPONENT.getControllerPredicate()); - List creaturesOfOpponents = game.getBattlefield().getActivePermanents(filterCreature, source.getControllerId(), source.getSourceId(), game); + List creaturesOfOpponents = game.getBattlefield().getActivePermanents(filterCreature, source.getControllerId(), source, game); Set morSet = new HashSet<>(); if (!creaturesOfOpponents.isEmpty()) { CreateTokenEffect effect = new CreateTokenEffect(new PhyrexianBeastToken(), creaturesOfOpponents.size()); diff --git a/Mage.Sets/src/mage/cards/f/FableOfTheMirrorBreaker.java b/Mage.Sets/src/mage/cards/f/FableOfTheMirrorBreaker.java new file mode 100644 index 00000000000..d2777c8eba9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FableOfTheMirrorBreaker.java @@ -0,0 +1,53 @@ +package mage.cards.f; + +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; +import mage.abilities.effects.common.discard.DiscardAndDrawThatManyEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SagaChapter; +import mage.constants.SubType; +import mage.game.permanent.token.FableOfTheMirrorBreakerToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FableOfTheMirrorBreaker extends CardImpl { + + public FableOfTheMirrorBreaker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); + + this.subtype.add(SubType.SAGA); + this.secondSideCardClazz = mage.cards.r.ReflectionOfKikiJiki.class; + + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I — Create a 2/2 red Goblin Shaman creature token with "Whenever this creature attacks, create a Treasure token." + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new CreateTokenEffect(new FableOfTheMirrorBreakerToken())); + + // II — You may discard up to two cards. If you do, draw that many cards. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new DiscardAndDrawThatManyEffect(2) + .setText("you may discard up to two cards. If you do, draw that many cards")); + + // III — Exile this Saga, then return it to the battlefield transformed under your control. + this.addAbility(new TransformAbility()); + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + + this.addAbility(sagaAbility); + } + + private FableOfTheMirrorBreaker(final FableOfTheMirrorBreaker card) { + super(card); + } + + @Override + public FableOfTheMirrorBreaker copy() { + return new FableOfTheMirrorBreaker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FableOfWolfAndOwl.java b/Mage.Sets/src/mage/cards/f/FableOfWolfAndOwl.java index 64c1101317d..54f2890e141 100644 --- a/Mage.Sets/src/mage/cards/f/FableOfWolfAndOwl.java +++ b/Mage.Sets/src/mage/cards/f/FableOfWolfAndOwl.java @@ -10,7 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.FilterSpell; import mage.filter.predicate.mageobject.ColorPredicate; -import mage.game.permanent.token.OwlToken; +import mage.game.permanent.token.BlueBirdToken; import mage.game.permanent.token.WolfToken; /** @@ -30,7 +30,7 @@ public final class FableOfWolfAndOwl extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G/U}{G/U}{G/U}"); this.addAbility(new SpellCastControllerTriggeredAbility(new CreateTokenEffect(new WolfToken(), 1), filterGreenSpell, true)); - this.addAbility(new SpellCastControllerTriggeredAbility(new CreateTokenEffect(new OwlToken(), 1), filterBlueSpell, true)); + this.addAbility(new SpellCastControllerTriggeredAbility(new CreateTokenEffect(new BlueBirdToken(), 1), filterBlueSpell, true)); } private FableOfWolfAndOwl(final FableOfWolfAndOwl card) { diff --git a/Mage.Sets/src/mage/cards/f/FaerieImpostor.java b/Mage.Sets/src/mage/cards/f/FaerieImpostor.java index 94dc8006f78..163db673c29 100644 --- a/Mage.Sets/src/mage/cards/f/FaerieImpostor.java +++ b/Mage.Sets/src/mage/cards/f/FaerieImpostor.java @@ -75,7 +75,7 @@ class FaerieImpostorEffect extends OneShotEffect { return false; } TargetPermanent target = new TargetPermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), controller.getId(), game) + if (target.canChoose(controller.getId(), source, game) && controller.chooseUse(outcome, "Return another creature you control to its owner's hand?", source, game)) { controller.chooseTarget(Outcome.ReturnToHand, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/f/FaerieMechanist.java b/Mage.Sets/src/mage/cards/f/FaerieMechanist.java index 792d2b716b6..a5c66331411 100644 --- a/Mage.Sets/src/mage/cards/f/FaerieMechanist.java +++ b/Mage.Sets/src/mage/cards/f/FaerieMechanist.java @@ -1,18 +1,16 @@ - - package mage.cards.f; import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.FilterCard; +import mage.filter.StaticFilters; /** * @@ -20,11 +18,6 @@ import mage.filter.FilterCard; */ public final class FaerieMechanist extends CardImpl { - private static final FilterCard filter = new FilterCard("an artifact card"); - static { - filter.add(CardType.ARTIFACT.getPredicate()); - } - public FaerieMechanist(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}{U}"); @@ -36,7 +29,8 @@ public final class FaerieMechanist extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Faerie Mechanist enters the battlefield, look at the top three cards of your library. // You may reveal an artifact card from among them and put it into your hand. Put the rest on the bottom of your library in any order. - this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect(StaticValue.get(3), false, StaticValue.get(1), filter, false))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 3, 1, StaticFilters.FILTER_CARD_ARTIFACT_AN, PutCards.HAND, PutCards.BOTTOM_ANY))); } private FaerieMechanist(final FaerieMechanist card) { @@ -47,5 +41,4 @@ public final class FaerieMechanist extends CardImpl { public FaerieMechanist copy() { return new FaerieMechanist(this); } - } diff --git a/Mage.Sets/src/mage/cards/f/FaithfulDisciple.java b/Mage.Sets/src/mage/cards/f/FaithfulDisciple.java new file mode 100644 index 00000000000..fa1c59eeed2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FaithfulDisciple.java @@ -0,0 +1,63 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.effects.common.DraftFromSpellbookEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FaithfulDisciple extends CardImpl { + + private static final List spellbook = Collections.unmodifiableList(Arrays.asList( + "All That Glitters", + "Angelic Exaltation", + "Angelic Gift", + "Anointed Procession", + "Authority of the Consuls", + "Banishing Light", + "Cathars' Crusade", + "Cleric Class", + "Divine Visitation", + "Duelist's Heritage", + "Gauntlets of Light", + "Glorious Anthem", + "Sigil of the Empty Throne", + "Spectral Steel", + "Teleportation Circle" + )); + + public FaithfulDisciple(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // When Faithful Disciple dies, draft a card from Faithful Disciple's spellbook. + this.addAbility(new DiesSourceTriggeredAbility(new DraftFromSpellbookEffect(spellbook))); + } + + private FaithfulDisciple(final FaithfulDisciple card) { + super(card); + } + + @Override + public FaithfulDisciple copy() { + return new FaithfulDisciple(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FaithsReward.java b/Mage.Sets/src/mage/cards/f/FaithsReward.java index 7c643ba5a9b..1f80e9bd001 100644 --- a/Mage.Sets/src/mage/cards/f/FaithsReward.java +++ b/Mage.Sets/src/mage/cards/f/FaithsReward.java @@ -63,7 +63,7 @@ class FaithsRewardEffect extends OneShotEffect { return false; } return player.moveCards(player.getGraveyard().getCards( - filter, source.getSourceId(), source.getControllerId(), game + filter, source.getControllerId(), source, game ), Zone.BATTLEFIELD, source, game); } diff --git a/Mage.Sets/src/mage/cards/f/FaithsShield.java b/Mage.Sets/src/mage/cards/f/FaithsShield.java index 5dad4847529..6aa767c0a0f 100644 --- a/Mage.Sets/src/mage/cards/f/FaithsShield.java +++ b/Mage.Sets/src/mage/cards/f/FaithsShield.java @@ -62,7 +62,7 @@ class FaithsShieldEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (controller != null && mageObject != null) { if (FatefulHourCondition.instance.apply(game, source)) { ChoiceColor choice = new ChoiceColor(); diff --git a/Mage.Sets/src/mage/cards/f/FakeYourOwnDeath.java b/Mage.Sets/src/mage/cards/f/FakeYourOwnDeath.java new file mode 100644 index 00000000000..3a2ab64cf1b --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FakeYourOwnDeath.java @@ -0,0 +1,43 @@ +package mage.cards.f; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.TreasureToken; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author weirddan455 + */ +public final class FakeYourOwnDeath extends CardImpl { + + public FakeYourOwnDeath(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); + + // Until end of turn, target creature gets +2/+0 and gains "When this creature dies, return it to the battlefield tapped under its owner's control and you create a Treasure token." + this.getSpellAbility().addEffect(new BoostTargetEffect(2, 0).setText("Until end of turn, target creature gets +2/+0")); + Ability gainedAbility = new DiesSourceTriggeredAbility(new ReturnSourceFromGraveyardToBattlefieldEffect(true)); + gainedAbility.addEffect(new CreateTokenEffect(new TreasureToken())); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(gainedAbility) + .setText("and gains \"When this creature dies, return it to the battlefield tapped under its owner's control and you create a Treasure token.\"")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private FakeYourOwnDeath(final FakeYourOwnDeath card) { + super(card); + } + + @Override + public FakeYourOwnDeath copy() { + return new FakeYourOwnDeath(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FalcoSparaPactweaver.java b/Mage.Sets/src/mage/cards/f/FalcoSparaPactweaver.java new file mode 100644 index 00000000000..f7f11141226 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FalcoSparaPactweaver.java @@ -0,0 +1,118 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.Costs; +import mage.abilities.costs.CostsImpl; +import mage.abilities.costs.common.RemoveCounterCost; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.common.continuous.LookAtTopCardOfLibraryAnyTimeEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FalcoSparaPactweaver extends CardImpl { + + public FalcoSparaPactweaver(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.DEMON); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Falco Spara, Pactweaver enters the battlefield with a shield counter on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.SHIELD.createInstance(1)), + "with a shield counter on it. (If it would be dealt damage " + + "or destroyed, remove a shield counter from it instead.)" + )); + + // You may look at the top card of your library any time. + this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect())); + + // You may cast spells from the top of your library by removing a counter from a creature you control in addition to paying their other costs. + this.addAbility(new SimpleStaticAbility(new FalcoSparaPactweaverEffect())); + } + + private FalcoSparaPactweaver(final FalcoSparaPactweaver card) { + super(card); + } + + @Override + public FalcoSparaPactweaver copy() { + return new FalcoSparaPactweaver(this); + } +} + +class FalcoSparaPactweaverEffect extends AsThoughEffectImpl { + + FalcoSparaPactweaverEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.AIDontUseIt); + staticText = "you may cast spells from the top of your library by removing " + + "a counter from a creature you control in addition to paying their other costs"; + } + + private FalcoSparaPactweaverEffect(final FalcoSparaPactweaverEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public FalcoSparaPactweaverEffect copy() { + return new FalcoSparaPactweaverEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + Card cardToCheck = game.getCard(objectId); + if (cardToCheck == null + || !source.isControlledBy(affectedControllerId) + || !cardToCheck.isOwnedBy(affectedControllerId)) { + return false; + } + Player player = game.getPlayer(cardToCheck.getOwnerId()); + if (player == null) { + return false; + } + Card topCard = player.getLibrary().getFromTop(game); + if (topCard == null + || !topCard.getId().equals(cardToCheck.getMainCard().getId()) + || cardToCheck.isLand(game)) { + return false; + } + + Costs newCosts = new CostsImpl<>(); + newCosts.add(new RemoveCounterCost(new TargetControlledCreaturePermanent())); + newCosts.addAll(cardToCheck.getSpellAbility().getCosts()); + player.setCastSourceIdWithAlternateMana(cardToCheck.getId(), cardToCheck.getManaCost(), newCosts); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FalkenrathGorger.java b/Mage.Sets/src/mage/cards/f/FalkenrathGorger.java index d18775a0eb9..cf4b6931290 100644 --- a/Mage.Sets/src/mage/cards/f/FalkenrathGorger.java +++ b/Mage.Sets/src/mage/cards/f/FalkenrathGorger.java @@ -97,7 +97,7 @@ class FalkenrathGorgerEffect extends ContinuousEffectImpl { } // Exile for (Card card : game.getExile().getAllCards(game)) { - if (filter.match(card, source.getSourceId(), controller.getId(), game)) { + if (filter.match(card, controller.getId(), source, game)) { if (card.isOwnedBy(controller.getId())) { addMadnessToCard(game, card, usedMadnessAbilities); } @@ -114,7 +114,7 @@ class FalkenrathGorgerEffect extends ContinuousEffectImpl { private void addMadnessToCard(Game game, Card card, Map usedMadnessAbilities) { MadnessAbility ability = madnessAbilities.get(card.getId()); if (ability == null) { - ability = new MadnessAbility(card, card.getSpellAbility().getManaCosts()); + ability = new MadnessAbility(card.getSpellAbility().getManaCosts()); } game.getState().addOtherAbility(card, ability, false); usedMadnessAbilities.put(card.getId(), ability); diff --git a/Mage.Sets/src/mage/cards/f/FallOfTheThran.java b/Mage.Sets/src/mage/cards/f/FallOfTheThran.java index 133369a151b..a1c9cd03dbe 100644 --- a/Mage.Sets/src/mage/cards/f/FallOfTheThran.java +++ b/Mage.Sets/src/mage/cards/f/FallOfTheThran.java @@ -81,8 +81,8 @@ class FallOfTheThranReturnEffect extends OneShotEffect { TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(2, 2, StaticFilters.FILTER_CARD_LAND); target.setNotTarget(true); target.setTargetController(playerId); - if (target.canChoose(source.getSourceId(), playerId, game)) { - player.choose(outcome, target, source.getSourceId(), game); + if (target.canChoose(playerId, source, game)) { + player.choose(outcome, target, source, game); if (target.getTargets().size() == 2) { toBattlefield.put(playerId, new CardsImpl(target.getTargets()).getCards(game)); } diff --git a/Mage.Sets/src/mage/cards/f/FallenCleric.java b/Mage.Sets/src/mage/cards/f/FallenCleric.java index 286970848e8..dbd92a28b83 100644 --- a/Mage.Sets/src/mage/cards/f/FallenCleric.java +++ b/Mage.Sets/src/mage/cards/f/FallenCleric.java @@ -34,7 +34,7 @@ public final class FallenCleric extends CardImpl { // Protection from Clerics this.addAbility(new ProtectionAbility(filter)); // Morph {4}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{B}"))); } private FallenCleric(final FallenCleric card) { diff --git a/Mage.Sets/src/mage/cards/f/FallenIdeal.java b/Mage.Sets/src/mage/cards/f/FallenIdeal.java index 5ef67ce1538..e181745d618 100644 --- a/Mage.Sets/src/mage/cards/f/FallenIdeal.java +++ b/Mage.Sets/src/mage/cards/f/FallenIdeal.java @@ -1,13 +1,10 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.ReturnToHandSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; @@ -17,13 +14,15 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; import mage.target.TargetPermanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; + /** - * * @author fireshoes */ public final class FallenIdeal extends CardImpl { @@ -36,18 +35,19 @@ public final class FallenIdeal extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Enchanted creature has flying and "Sacrifice a creature: This creature gets +2/+1 until end of turn." - Effect effect = new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield); - Ability gainedAbility = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); - this.addAbility(gainedAbility); - gainedAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(2, 1, Duration.EndOfTurn), - new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); - effect = new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA, Duration.WhileOnBattlefield); - effect.setText("Enchanted creature has \"Sacrifice a creature: This creature gets +2/+1 until end of turn.\""); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + Ability ability = new SimpleStaticAbility(new GainAbilityAttachedEffect( + FlyingAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield + )); + ability.addEffect(new GainAbilityAttachedEffect( + new SimpleActivatedAbility( + new BoostSourceEffect(2, 1, Duration.EndOfTurn), + new SacrificeTargetCost(new TargetControlledPermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT)) + ), AttachmentType.AURA, Duration.WhileOnBattlefield + ).setText("and \"Sacrifice a creature: This creature gets +2/+1 until end of turn.\"")); + this.addAbility(ability); // When Fallen Ideal is put into a graveyard from the battlefield, return Fallen Ideal to its owner's hand. this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new ReturnToHandSourceEffect())); diff --git a/Mage.Sets/src/mage/cards/f/FalseFloor.java b/Mage.Sets/src/mage/cards/f/FalseFloor.java new file mode 100644 index 00000000000..c978f01c9a1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FalseFloor.java @@ -0,0 +1,59 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.ExileSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.ExileAllEffect; +import mage.abilities.effects.common.PermanentsEnterBattlefieldTappedEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.TappedPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FalseFloor extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("untapped creatures"); + + static { + filter.add(TappedPredicate.UNTAPPED); + } + + public FalseFloor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + + // False Floor enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // Creatures enter the battlefield tapped. + this.addAbility(new SimpleStaticAbility( + new PermanentsEnterBattlefieldTappedEffect(StaticFilters.FILTER_PERMANENT_CREATURES) + )); + + // {2}, {T}, Exile False Floor: Exile all untapped creatures. Activate only as a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility(new ExileAllEffect(filter), new GenericManaCost(2)); + ability.addCost(new TapSourceCost()); + ability.addCost(new ExileSourceCost()); + this.addAbility(ability); + } + + private FalseFloor(final FalseFloor card) { + super(card); + } + + @Override + public FalseFloor copy() { + return new FalseFloor(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FalseOrders.java b/Mage.Sets/src/mage/cards/f/FalseOrders.java index 8b4b1cf5bed..b97db6b90df 100644 --- a/Mage.Sets/src/mage/cards/f/FalseOrders.java +++ b/Mage.Sets/src/mage/cards/f/FalseOrders.java @@ -139,8 +139,8 @@ class FalseOrdersUnblockEffect extends OneShotEffect { FilterAttackingCreature filter = new FilterAttackingCreature("creature attacking " + targetsController.getLogName()); filter.add(new PermanentInListPredicate(list)); TargetAttackingCreature target = new TargetAttackingCreature(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - while (!target.isChosen() && target.canChoose(source.getSourceId(), controller.getId(), game) && controller.canRespond()) { + if (target.canChoose(controller.getId(), source, game)) { + while (!target.isChosen() && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target, source, game); } } else { diff --git a/Mage.Sets/src/mage/cards/f/Fascination.java b/Mage.Sets/src/mage/cards/f/Fascination.java index 18702f8040e..086dcac4970 100644 --- a/Mage.Sets/src/mage/cards/f/Fascination.java +++ b/Mage.Sets/src/mage/cards/f/Fascination.java @@ -25,8 +25,7 @@ public final class Fascination extends CardImpl { this.getSpellAbility().addEffect(new DrawCardAllEffect(ManacostVariableValue.REGULAR)); // * Each player puts the top X cards of their library into their graveyard. - Mode mode = new Mode(); - mode.addEffect(new MillCardsEachPlayerEffect(ManacostVariableValue.REGULAR, TargetController.ANY)); + Mode mode = new Mode(new MillCardsEachPlayerEffect(ManacostVariableValue.REGULAR, TargetController.ANY)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FatalGrudge.java b/Mage.Sets/src/mage/cards/f/FatalGrudge.java new file mode 100644 index 00000000000..e56f3b5ec0d --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FatalGrudge.java @@ -0,0 +1,113 @@ +package mage.cards.f; + +import java.util.HashSet; +import java.util.UUID; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author weirddan455 + */ +public final class FatalGrudge extends CardImpl { + + public FatalGrudge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}{R}"); + + // As an additional cost to cast this spell, sacrifice a nonland permanent. + this.getSpellAbility().addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_PERMANENT_NON_LAND)); + + // Each opponent chooses a permanent they control that shares a type with the sacrificed permanent and sacrifices it. + this.getSpellAbility().addEffect(new FatalGrudgeEffect()); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); + } + + private FatalGrudge(final FatalGrudge card) { + super(card); + } + + @Override + public FatalGrudge copy() { + return new FatalGrudge(this); + } +} + +class FatalGrudgeEffect extends OneShotEffect { + + public FatalGrudgeEffect() { + super(Outcome.Sacrifice); + this.staticText = "each opponent chooses a permanent they control that shares a type with the sacrificed permanent and sacrifices it"; + } + + private FatalGrudgeEffect(final FatalGrudgeEffect effect) { + super(effect); + } + + @Override + public FatalGrudgeEffect copy() { + return new FatalGrudgeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + HashSet types = new HashSet<>(); + for (Cost cost : source.getCosts()) { + if (cost instanceof SacrificeTargetCost) { + for (Permanent sacrificed : ((SacrificeTargetCost) cost).getPermanents()) { + types.addAll(sacrificed.getCardType(game)); + } + } + } + FilterControlledPermanent filter = new FilterControlledPermanent("permanent you control that shares a type with the sacrificed permanent"); + filter.add(new FatalGrudgePredicate(types)); + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); + opponent.chooseTarget(Outcome.Sacrifice, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + permanent.sacrifice(source, game); + } + } + } + return true; + } +} + +class FatalGrudgePredicate implements Predicate { + + private final HashSet types; + + public FatalGrudgePredicate(HashSet types) { + this.types = types; + } + + @Override + public boolean apply(MageObject input, Game game) { + for (CardType type : input.getCardType(game)) { + if (types.contains(type)) { + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FatalLore.java b/Mage.Sets/src/mage/cards/f/FatalLore.java index 9ea81f4c759..8ea2a4cb7cd 100644 --- a/Mage.Sets/src/mage/cards/f/FatalLore.java +++ b/Mage.Sets/src/mage/cards/f/FatalLore.java @@ -1,37 +1,46 @@ package mage.cards.f; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.Effect; +import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; -import mage.abilities.effects.common.DrawCardTargetEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; -import mage.target.common.TargetOpponent; -import mage.target.targetpointer.FixedTarget; +import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.Objects; +import java.util.UUID; /** - * - * @author jeffwadsworth + * @author TheElk801 */ public final class FatalLore extends CardImpl { public FatalLore(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}{B}"); - // An opponent chooses one - You draw three cards; or you destroy up to two target creatures that opponent controls and that player draws up to three cards. Those creatures can't be regenerated. - this.getSpellAbility().addEffect(new FatalLoreEffect()); - this.getSpellAbility().addTarget(new TargetOpponent(true)); + // An opponent chooses one — + this.getSpellAbility().getModes().setModeChooser(TargetController.OPPONENT); + // • You draw three cards. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).setText("you draw three cards")); + + // • You destroy up to two target creatures that player controls. They can't be regenerated. That player draws up to three cards. + this.getSpellAbility().addMode(new Mode(new DestroyTargetEffect( + "you destroy up to two target creatures that player controls. " + + "They can't be regenerated", true + )).addEffect(new FatalLoreEffect())); + this.getSpellAbility().setTargetAdjuster(FatalLoreAdjuster.instance); } private FatalLore(final FatalLore card) { @@ -44,14 +53,37 @@ public final class FatalLore extends CardImpl { } } +enum FatalLoreAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + Mode mode = ability.getModes().getMode(); + if (mode.getEffects().stream().noneMatch(DestroyTargetEffect.class::isInstance)) { + return; + } + UUID playerId = mode + .getEffects() + .stream() + .findFirst() + .filter(Objects::nonNull) + .map(effect -> (UUID) effect.getValue("choosingPlayer")) + .orElse(null); + FilterPermanent filter = new FilterCreaturePermanent("creatures controlled by " + game.getPlayer(playerId).getName()); + filter.add(new ControllerIdPredicate(playerId)); + mode.getTargets().clear(); + mode.addTarget(new TargetPermanent(0, 2, filter)); + } +} + class FatalLoreEffect extends OneShotEffect { - public FatalLoreEffect() { - super(Outcome.Neutral); - staticText = "An opponent chooses one - You draw three cards; or you destroy up to two target creatures that opponent controls and that player draws up to three cards. Those creatures can't be regenerated"; + FatalLoreEffect() { + super(Outcome.Benefit); + staticText = "That player draws up to three cards"; } - public FatalLoreEffect(final FatalLoreEffect effect) { + private FatalLoreEffect(final FatalLoreEffect effect) { super(effect); } @@ -62,30 +94,11 @@ class FatalLoreEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Player chosenOpponent = game.getPlayer(targetPointer.getFirst(game, source)); - if (controller != null - && chosenOpponent != null) { - if (chosenOpponent.chooseUse(Outcome.Neutral, "If you choose Yes, the controller draws three cards. If no, the controller gets to destroy up to two target creatures that you control and you get to draw up to 3 cards. Those creatures can't be regenerated.", source, game)) { - controller.drawCards(3, source, game); - } else { - FilterCreaturePermanent filter = new FilterCreaturePermanent("chosen opponent's creature"); - filter.add(new ControllerIdPredicate(chosenOpponent.getId())); - TargetCreaturePermanent target = new TargetCreaturePermanent(0, 2, filter, false); - if (target.canChoose(source.getSourceId(), controller.getId(), game) - && controller.choose(Outcome.DestroyPermanent, target, source.getSourceId(), game)) { - for (UUID targetId : target.getTargets()) { - Effect destroyCreature = new DestroyTargetEffect(true); - destroyCreature.setTargetPointer(new FixedTarget(targetId, game)); - destroyCreature.apply(game, source); - } - Effect opponentDrawsCards = new DrawCardTargetEffect(StaticValue.get(3), false, true); - opponentDrawsCards.setTargetPointer(new FixedTarget(chosenOpponent.getId())); - opponentDrawsCards.apply(game, source); - return true; - } - } + Player player = game.getPlayer((UUID) getValue("choosingPlayer")); + if (player == null) { + return false; } - return false; + int toDraw = player.getAmount(0, 3, "Choose how many cards to draw", game); + return player.drawCards(toDraw, source, game) > 0; } } diff --git a/Mage.Sets/src/mage/cards/f/FathomFleetSwordjack.java b/Mage.Sets/src/mage/cards/f/FathomFleetSwordjack.java index 19d57116cae..31c99ec2d5a 100644 --- a/Mage.Sets/src/mage/cards/f/FathomFleetSwordjack.java +++ b/Mage.Sets/src/mage/cards/f/FathomFleetSwordjack.java @@ -67,7 +67,7 @@ class FathomFleetSwordjackEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { int artifactCount = game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, - source.getSourceId(), source.getControllerId(), game + source.getControllerId(), source, game ); return artifactCount > 0 && game.damagePlayerOrPlaneswalker( game.getCombat().getDefenderId(source.getSourceId()), artifactCount, diff --git a/Mage.Sets/src/mage/cards/f/FathomSeer.java b/Mage.Sets/src/mage/cards/f/FathomSeer.java index bb4b72d591c..6daec04409f 100644 --- a/Mage.Sets/src/mage/cards/f/FathomSeer.java +++ b/Mage.Sets/src/mage/cards/f/FathomSeer.java @@ -33,7 +33,7 @@ public final class FathomSeer extends CardImpl { this.toughness = new MageInt(3); // Morph-Return two Islands you control to their owner's hand. - this.addAbility(new MorphAbility(this, new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(2,2, filter, true)))); + this.addAbility(new MorphAbility(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(2,2, filter, true)))); // When Fathom Seer is turned face up, draw two cards. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new DrawCardSourceControllerEffect(2))); } diff --git a/Mage.Sets/src/mage/cards/f/FathomTrawl.java b/Mage.Sets/src/mage/cards/f/FathomTrawl.java index 1815cb1a5ea..070a62fd964 100644 --- a/Mage.Sets/src/mage/cards/f/FathomTrawl.java +++ b/Mage.Sets/src/mage/cards/f/FathomTrawl.java @@ -52,7 +52,7 @@ public final class FathomTrawl extends CardImpl { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Player controller = game.getPlayer(source.getControllerId()); if (controller == null || sourceObject == null) { return false; diff --git a/Mage.Sets/src/mage/cards/f/FeastOfWorms.java b/Mage.Sets/src/mage/cards/f/FeastOfWorms.java index 1a2f718ae3e..eaa6b37e31b 100644 --- a/Mage.Sets/src/mage/cards/f/FeastOfWorms.java +++ b/Mage.Sets/src/mage/cards/f/FeastOfWorms.java @@ -77,7 +77,7 @@ class FeastOfWormsEffect extends OneShotEffect { filter.add(new ControllerIdPredicate(targetPlayer.getId())); TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, false); - if (target.canChoose(source.getSourceId(), targetPlayer.getId(), game)) { + if (target.canChoose(targetPlayer.getId(), source, game)) { targetPlayer.chooseTarget(Outcome.Sacrifice, target, source, game); Permanent land = game.getPermanent(target.getFirstTarget()); if (land != null) { diff --git a/Mage.Sets/src/mage/cards/f/FeastOrFamine.java b/Mage.Sets/src/mage/cards/f/FeastOrFamine.java index 6392c2b5766..05aa80ebf49 100644 --- a/Mage.Sets/src/mage/cards/f/FeastOrFamine.java +++ b/Mage.Sets/src/mage/cards/f/FeastOrFamine.java @@ -35,8 +35,7 @@ public final class FeastOrFamine extends CardImpl { this.getSpellAbility().addEffect(new CreateTokenEffect(new ZombieToken())); // or destroy target nonartifact, nonblack creature and it can't be regenerated. - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect(true)); + Mode mode = new Mode(new DestroyTargetEffect(true)); mode.addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FeatherTheRedeemed.java b/Mage.Sets/src/mage/cards/f/FeatherTheRedeemed.java index 40308e5297b..06383a0b005 100644 --- a/Mage.Sets/src/mage/cards/f/FeatherTheRedeemed.java +++ b/Mage.Sets/src/mage/cards/f/FeatherTheRedeemed.java @@ -79,14 +79,10 @@ class FeatherTheRedeemedTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (!event.getPlayerId().equals(this.getControllerId())) { + if (!isControlledBy(event.getPlayerId())) { return false; } Spell spell = game.getStack().getSpell(event.getTargetId()); - return checkSpell(spell, game); - } - - private boolean checkSpell(Spell spell, Game game) { if (spell == null) { return false; } @@ -166,15 +162,15 @@ class FeatherTheRedeemedEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { ZoneChangeEvent zEvent = ((ZoneChangeEvent) event); - if (zEvent.getFromZone() == Zone.STACK - && zEvent.getToZone() == Zone.GRAVEYARD - && event.getSourceId() != null) { - if (event.getSourceId().equals(event.getTargetId()) && mor.getZoneChangeCounter() == game.getState().getZoneChangeCounter(event.getSourceId())) { - Spell spell = game.getStack().getSpell(mor.getSourceId()); - return spell != null && spell.isInstantOrSorcery(game); - } + if (zEvent.getFromZone() != Zone.STACK + || zEvent.getToZone() != Zone.GRAVEYARD + || event.getSourceId() == null + || !event.getSourceId().equals(event.getTargetId()) + || mor.getZoneChangeCounter() != game.getState().getZoneChangeCounter(event.getSourceId())) { + return false; } - return false; + Spell spell = game.getStack().getSpell(mor.getSourceId()); + return spell != null && spell.isInstantOrSorcery(game); } @Override diff --git a/Mage.Sets/src/mage/cards/f/FeedThePack.java b/Mage.Sets/src/mage/cards/f/FeedThePack.java index 4351254bb29..f8d16ae5030 100644 --- a/Mage.Sets/src/mage/cards/f/FeedThePack.java +++ b/Mage.Sets/src/mage/cards/f/FeedThePack.java @@ -68,7 +68,7 @@ class FeedThePackEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Target target = new TargetPermanent(filter); Player player = game.getPlayer(source.getControllerId()); - if (player != null && player.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + if (player != null && player.choose(Outcome.PutCreatureInPlay, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null && permanent.sacrifice(source, game)) { int toughness = permanent.getToughness().getValue(); diff --git a/Mage.Sets/src/mage/cards/f/FelidarGuardian.java b/Mage.Sets/src/mage/cards/f/FelidarGuardian.java index 155d6d53fa7..5bb596028b0 100644 --- a/Mage.Sets/src/mage/cards/f/FelidarGuardian.java +++ b/Mage.Sets/src/mage/cards/f/FelidarGuardian.java @@ -36,7 +36,7 @@ public final class FelidarGuardian extends CardImpl { // When Felidar Guardian enters the battlefield, you may exile another target permanent you control, then return that card to the battlefield under its owner's control. Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect(), true); - ability.addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false)); + ability.addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false).concatBy(",")); ability.addTarget(new TargetControlledPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FelineSovereign.java b/Mage.Sets/src/mage/cards/f/FelineSovereign.java index 9644337613f..5bedbb9cc9a 100644 --- a/Mage.Sets/src/mage/cards/f/FelineSovereign.java +++ b/Mage.Sets/src/mage/cards/f/FelineSovereign.java @@ -19,7 +19,6 @@ import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; @@ -107,7 +106,7 @@ class FelineSovereignTriggeredAbility extends TriggeredAbilityImpl { DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; Permanent p = game.getPermanent(event.getSourceId()); if (damageEvent.isCombatDamage() && p != null && p.isControlledBy(this.getControllerId()) && - filter.match(p, getSourceId(), getControllerId(), game) && + filter.match(p, getControllerId(), this, game) && !damagedPlayerIds.contains(event.getPlayerId())) { damagedPlayerIds.add(event.getPlayerId()); this.getTargets().clear(); diff --git a/Mage.Sets/src/mage/cards/f/FellTheMighty.java b/Mage.Sets/src/mage/cards/f/FellTheMighty.java index 79e039b7a8a..b69a54b2d81 100644 --- a/Mage.Sets/src/mage/cards/f/FellTheMighty.java +++ b/Mage.Sets/src/mage/cards/f/FellTheMighty.java @@ -60,7 +60,7 @@ class FellTheMightyEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent targetCreature = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); if (controller != null && targetCreature != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), source, game)) { if (permanent.getPower().getValue() > targetCreature.getPower().getValue()) { permanent.destroy(source, game, false); } diff --git a/Mage.Sets/src/mage/cards/f/FendeepSummoner.java b/Mage.Sets/src/mage/cards/f/FendeepSummoner.java index d74e4f91e0c..6189ac73077 100644 --- a/Mage.Sets/src/mage/cards/f/FendeepSummoner.java +++ b/Mage.Sets/src/mage/cards/f/FendeepSummoner.java @@ -1,4 +1,3 @@ - package mage.cards.f; import mage.MageInt; @@ -11,10 +10,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterLandPermanent; +import mage.filter.FilterPermanent; import mage.game.permanent.token.custom.CreatureToken; -import mage.target.common.TargetLandPermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -23,11 +21,7 @@ import java.util.UUID; */ public final class FendeepSummoner extends CardImpl { - static final FilterLandPermanent filter = new FilterLandPermanent("Swamp"); - - static { - filter.add(SubType.SWAMP.getPredicate()); - } + static final FilterPermanent filter = new FilterPermanent(SubType.SWAMP, "Swamps"); public FendeepSummoner(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); @@ -38,10 +32,11 @@ public final class FendeepSummoner extends CardImpl { this.toughness = new MageInt(5); // {T}: Up to two target Swamps each become 3/5 Treefolk Warrior creatures in addition to their other types until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureTargetEffect( - new CreatureToken(3, 5, "3/5 Treefolk Warrior", SubType.TREEFOLK, SubType.WARRIOR), - false, false, Duration.EndOfTurn), new TapSourceCost()); - ability.addTarget(new TargetLandPermanent(0, 2, filter, false)); + Ability ability = new SimpleActivatedAbility(new BecomesCreatureTargetEffect(new CreatureToken( + 3, 5, "3/5 Treefolk Warrior creatures " + + "in addition to their other types", SubType.TREEFOLK, SubType.WARRIOR + ), false, false, Duration.EndOfTurn), new TapSourceCost()); + ability.addTarget(new TargetPermanent(0, 2, filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FerociousTigorilla.java b/Mage.Sets/src/mage/cards/f/FerociousTigorilla.java index 25e4776a2b3..d5b09548e57 100644 --- a/Mage.Sets/src/mage/cards/f/FerociousTigorilla.java +++ b/Mage.Sets/src/mage/cards/f/FerociousTigorilla.java @@ -27,8 +27,7 @@ public final class FerociousTigorilla extends CardImpl { // Ferocious Tigorilla enters the battlefield with your choice of a trample counter or a menace counter on it. this.addAbility(new EntersBattlefieldAbility( new AddCounterChoiceSourceEffect(CounterType.TRAMPLE, CounterType.MENACE), - "Ferocious Tigorilla enters the battlefield with your choice of " + - "a trample counter or a menace counter on it. " + + "with your choice of a trample counter or a menace counter on it. " + "(A creature with menace can't be blocked except by two or more creatures.)" )); } diff --git a/Mage.Sets/src/mage/cards/f/FerocityOfTheUnderworld.java b/Mage.Sets/src/mage/cards/f/FerocityOfTheUnderworld.java index 259cfad3b3a..857805637f9 100644 --- a/Mage.Sets/src/mage/cards/f/FerocityOfTheUnderworld.java +++ b/Mage.Sets/src/mage/cards/f/FerocityOfTheUnderworld.java @@ -37,14 +37,12 @@ public final class FerocityOfTheUnderworld extends CardImpl { this.getSpellAbility().addTarget(new TargetNonlandPermanent(filterMode1)); // Copy target instant or sorcery spell. You may choose new targets for the copy. - Mode mode = new Mode(); - mode.addEffect(new CopyTargetSpellEffect()); + Mode mode = new Mode(new CopyTargetSpellEffect()); mode.addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY)); this.getSpellAbility().addMode(mode); // Return target card from your graveyard to your hand. - mode = new Mode(); - mode.addEffect(new ReturnFromGraveyardToHandTargetEffect()); + mode = new Mode(new ReturnFromGraveyardToHandTargetEffect()); mode.addTarget(new TargetCardInYourGraveyard()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FertileImagination.java b/Mage.Sets/src/mage/cards/f/FertileImagination.java index 88f59648943..f122c197a22 100644 --- a/Mage.Sets/src/mage/cards/f/FertileImagination.java +++ b/Mage.Sets/src/mage/cards/f/FertileImagination.java @@ -76,7 +76,7 @@ class FertileImaginationEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Player player = game.getPlayer(source.getControllerId()); Player opponent = game.getPlayer(source.getFirstTarget()); if (player != null && opponent != null && sourceObject != null) { diff --git a/Mage.Sets/src/mage/cards/f/FertileThicket.java b/Mage.Sets/src/mage/cards/f/FertileThicket.java index 1144cf7cf1d..1d5b3faa942 100644 --- a/Mage.Sets/src/mage/cards/f/FertileThicket.java +++ b/Mage.Sets/src/mage/cards/f/FertileThicket.java @@ -69,7 +69,7 @@ class FertileThicketEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5)); controller.lookAtCards(sourceObject.getIdName(), cards, game); diff --git a/Mage.Sets/src/mage/cards/f/Festercreep.java b/Mage.Sets/src/mage/cards/f/Festercreep.java index 2d423ee32f8..355a5375f93 100644 --- a/Mage.Sets/src/mage/cards/f/Festercreep.java +++ b/Mage.Sets/src/mage/cards/f/Festercreep.java @@ -1,7 +1,6 @@ package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; @@ -13,18 +12,25 @@ import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.counters.CounterType; -import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; + +import java.util.UUID; /** - * * @author Loki */ public final class Festercreep extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("all other creatures"); + + static { + filter.add(AnotherPredicate.instance); + } + public Festercreep(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); this.subtype.add(SubType.ELEMENTAL); @@ -33,10 +39,12 @@ public final class Festercreep extends CardImpl { this.toughness = new MageInt(0); // Festercreep enters the battlefield with a +1/+1 counter on it. - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)))); + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), "with a +1/+1 counter on it")); // {1}{B}, Remove a +1/+1 counter from Festercreep: All other creatures get -1/-1 until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostAllEffect(-1, -1, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, true), new ManaCostsImpl("{1}{B}")); + Ability ability = new SimpleActivatedAbility(new BoostAllEffect( + -1, -1, Duration.EndOfTurn, filter, false + ), new ManaCostsImpl<>("{1}{B}")); ability.addCost(new RemoveCountersSourceCost(CounterType.P1P1.createInstance(1))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FesteringMarch.java b/Mage.Sets/src/mage/cards/f/FesteringMarch.java index ccf4b0cb319..09567b45d77 100644 --- a/Mage.Sets/src/mage/cards/f/FesteringMarch.java +++ b/Mage.Sets/src/mage/cards/f/FesteringMarch.java @@ -30,7 +30,7 @@ public final class FesteringMarch extends CardImpl { this.getSpellAbility().addEffect(new ExileSpellEffect()); // with three time counters on it. Effect effect = new AddCountersSourceEffect(CounterType.TIME.createInstance(), StaticValue.get(3), false, true); - effect.setText("with 3 time counters on it"); + effect.setText("with three time counters on it"); this.getSpellAbility().addEffect(effect); // Suspend 3-{2}{B} diff --git a/Mage.Sets/src/mage/cards/f/FesteringWound.java b/Mage.Sets/src/mage/cards/f/FesteringWound.java index 0c3af910d8d..d870c05fbec 100644 --- a/Mage.Sets/src/mage/cards/f/FesteringWound.java +++ b/Mage.Sets/src/mage/cards/f/FesteringWound.java @@ -68,7 +68,7 @@ class FesteringWoundEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - UUID sourceId = source.getSourceId(); + UUID sourceId = source != null ? source.getSourceId() : null; int amount = game.getPermanent(sourceId).getCounters(game).getCount(CounterType.INFECTION); UUID id = this.getTargetPointer().getFirst(game, source); Player player = game.getPlayer(id); diff --git a/Mage.Sets/src/mage/cards/f/FeverCharm.java b/Mage.Sets/src/mage/cards/f/FeverCharm.java index 81fdd9a9d4c..7921e494ded 100644 --- a/Mage.Sets/src/mage/cards/f/FeverCharm.java +++ b/Mage.Sets/src/mage/cards/f/FeverCharm.java @@ -34,13 +34,11 @@ public final class FeverCharm extends CardImpl { this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // or target creature gets +2/+0 until end of turn - Mode mode = new Mode(); - mode.addEffect(new BoostTargetEffect(2, 0, Duration.EndOfTurn)); + Mode mode = new Mode(new BoostTargetEffect(2, 0, Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or Fever Charm deals 3 damage to target Wizard creature. - mode = new Mode(); - mode.addEffect(new DamageTargetEffect(3)); + mode = new Mode(new DamageTargetEffect(3)); mode.addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FeveredSuspicion.java b/Mage.Sets/src/mage/cards/f/FeveredSuspicion.java new file mode 100644 index 00000000000..9032c3b34c9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FeveredSuspicion.java @@ -0,0 +1,88 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.ReboundAbility; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FeveredSuspicion extends CardImpl { + + public FeveredSuspicion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{6}{B}{R}"); + + // Each opponent exiles cards from the top of their library until they exile a nonland card. You may cast any number of spells from among those nonland cards without paying their mana costs. + this.getSpellAbility().addEffect(new FeveredSuspicionEffect()); + + // Rebound + this.addAbility(new ReboundAbility()); + } + + private FeveredSuspicion(final FeveredSuspicion card) { + super(card); + } + + @Override + public FeveredSuspicion copy() { + return new FeveredSuspicion(this); + } +} + +class FeveredSuspicionEffect extends OneShotEffect { + + FeveredSuspicionEffect() { + super(Outcome.Benefit); + staticText = "each opponent exiles cards from the top of their library until they exile a nonland card. " + + "You may cast any number of spells from among those nonland cards without paying their mana costs"; + } + + private FeveredSuspicionEffect(final FeveredSuspicionEffect effect) { + super(effect); + } + + @Override + public FeveredSuspicionEffect copy() { + return new FeveredSuspicionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Cards cards = new CardsImpl(); + Cards nonlands = new CardsImpl(); + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent == null) { + continue; + } + for (Card card : opponent.getLibrary().getCards(game)) { + cards.add(card); + if (!card.isLand(game)) { + nonlands.add(card); + break; + } + } + } + controller.moveCards(cards, Zone.EXILED, source, game); + nonlands.retainZone(Zone.EXILED, game); + CardUtil.castMultipleWithAttributeForFree( + controller, source, game, nonlands, + StaticFilters.FILTER_CARD + ); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FickleEfreet.java b/Mage.Sets/src/mage/cards/f/FickleEfreet.java index 4b32a9a51a7..b7fa0c2d222 100644 --- a/Mage.Sets/src/mage/cards/f/FickleEfreet.java +++ b/Mage.Sets/src/mage/cards/f/FickleEfreet.java @@ -72,8 +72,8 @@ class FickleEfreetChangeControlEffect extends OneShotEffect { if (!controller.flipCoin(source, game, true)) { if (sourcePermanent != null) { Target target = new TargetOpponent(true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - while (!target.isChosen() && target.canChoose(source.getSourceId(), controller.getId(), game) && controller.canRespond()) { + if (target.canChoose(controller.getId(), source, game)) { + while (!target.isChosen() && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target, source, game); } } diff --git a/Mage.Sets/src/mage/cards/f/FiendOfTheShadows.java b/Mage.Sets/src/mage/cards/f/FiendOfTheShadows.java index 04ac8592278..ac2b9cd96c9 100644 --- a/Mage.Sets/src/mage/cards/f/FiendOfTheShadows.java +++ b/Mage.Sets/src/mage/cards/f/FiendOfTheShadows.java @@ -80,7 +80,7 @@ class FiendOfTheShadowsEffect extends OneShotEffect { return false; } TargetCard targetCard = new TargetDiscard(player.getId()); - player.choose(outcome, targetCard, source.getSourceId(), game); + player.choose(outcome, targetCard, source, game); Card card = game.getCard(targetCard.getFirstTarget()); if (card == null) { return false; diff --git a/Mage.Sets/src/mage/cards/f/FieryConfluence.java b/Mage.Sets/src/mage/cards/f/FieryConfluence.java index 41e2bf37fa3..0c8be5af7d4 100644 --- a/Mage.Sets/src/mage/cards/f/FieryConfluence.java +++ b/Mage.Sets/src/mage/cards/f/FieryConfluence.java @@ -31,13 +31,11 @@ public final class FieryConfluence extends CardImpl { this.getSpellAbility().addEffect(new DamageAllEffect(1, new FilterCreaturePermanent())); // Fiery Confluence deals 2 damage to each opponent; - Mode mode = new Mode(); - mode.addEffect(new DamagePlayersEffect(2, TargetController.OPPONENT)); + Mode mode = new Mode(new DamagePlayersEffect(2, TargetController.OPPONENT)); this.getSpellAbility().getModes().addMode(mode); // Destroy target artifact. - mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetArtifactPermanent()); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FieryIntervention.java b/Mage.Sets/src/mage/cards/f/FieryIntervention.java index 23b15f7cb5d..5a6a28c3724 100644 --- a/Mage.Sets/src/mage/cards/f/FieryIntervention.java +++ b/Mage.Sets/src/mage/cards/f/FieryIntervention.java @@ -26,8 +26,7 @@ public final class FieryIntervention extends CardImpl { getSpellAbility().addTarget(new TargetCreaturePermanent()); // -Destroy target artifact. - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetArtifactPermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FieryTemper.java b/Mage.Sets/src/mage/cards/f/FieryTemper.java index f74df1d454d..69ba396b442 100644 --- a/Mage.Sets/src/mage/cards/f/FieryTemper.java +++ b/Mage.Sets/src/mage/cards/f/FieryTemper.java @@ -25,7 +25,7 @@ public final class FieryTemper extends CardImpl { this.getSpellAbility().addTarget(new TargetAnyTarget()); // Madness {R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{R}"))); } private FieryTemper(final FieryTemper card) { diff --git a/Mage.Sets/src/mage/cards/f/FightOrFlight.java b/Mage.Sets/src/mage/cards/f/FightOrFlight.java index fdf1419eb96..6e49d396493 100644 --- a/Mage.Sets/src/mage/cards/f/FightOrFlight.java +++ b/Mage.Sets/src/mage/cards/f/FightOrFlight.java @@ -72,7 +72,7 @@ class FightOrFlightEffect extends OneShotEffect { TargetCreaturePermanent creatures = new TargetCreaturePermanent(0, count, new FilterCreaturePermanent("creatures to put in the first pile"), true); List pile1 = new ArrayList<>(); creatures.setRequired(false); - if (player.choose(Outcome.Neutral, creatures, source.getSourceId(), game)) { + if (player.choose(Outcome.Neutral, creatures, source, game)) { List targets = creatures.getTargets(); for (UUID targetId : targets) { Permanent p = game.getPermanent(targetId); diff --git a/Mage.Sets/src/mage/cards/f/FightRigging.java b/Mage.Sets/src/mage/cards/f/FightRigging.java new file mode 100644 index 00000000000..0832d0e183b --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FightRigging.java @@ -0,0 +1,64 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.HideawayPlayEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.HideawayAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FightRigging extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 6)); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + + public FightRigging(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); + + // Hideaway 5 + this.addAbility(new HideawayAbility(5)); + + // At the beginning of combat on your turn, put a +1/+1 counter on target creature you control. Then if you control a creature with power 7 or greater, you may play the exiled card without paying its mana cost. + Ability ability = new BeginningOfCombatTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), + TargetController.YOU, false + ); + ability.addEffect(new ConditionalOneShotEffect( + new HideawayPlayEffect(), condition, "Then if you control a creature " + + "with power 7 or greater, you may play the exiled card without paying its mana cost" + )); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private FightRigging(final FightRigging card) { + super(card); + } + + @Override + public FightRigging copy() { + return new FightRigging(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FightToTheDeath.java b/Mage.Sets/src/mage/cards/f/FightToTheDeath.java index 46e2a65d8fa..1c0f9bc8247 100644 --- a/Mage.Sets/src/mage/cards/f/FightToTheDeath.java +++ b/Mage.Sets/src/mage/cards/f/FightToTheDeath.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.effects.common.DestroyAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -11,29 +9,27 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.BlockedPredicate; import mage.filter.predicate.permanent.BlockingPredicate; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class FightToTheDeath extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("all blocking creatures and all blocked creatures"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blocking creatures and all blocked creatures"); static { filter.add(Predicates.or( BlockingPredicate.instance, - BlockedPredicate.instance)); + BlockedPredicate.instance + )); } public FightToTheDeath(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}{W}"); - - - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}{W}"); // Destroy all blocking creatures and all blocked creatures. this.getSpellAbility().addEffect(new DestroyAllEffect(filter)); - } private FightToTheDeath(final FightToTheDeath card) { diff --git a/Mage.Sets/src/mage/cards/f/FinalPayment.java b/Mage.Sets/src/mage/cards/f/FinalPayment.java index 3050ed50f22..d7e7313162c 100644 --- a/Mage.Sets/src/mage/cards/f/FinalPayment.java +++ b/Mage.Sets/src/mage/cards/f/FinalPayment.java @@ -33,8 +33,8 @@ public final class FinalPayment extends CardImpl { final Cost lifeCost = new PayLifeCost(5); final Cost sacrificeCost = new SacrificeTargetCost(new TargetControlledPermanent(filter)); - this.getSpellAbility().addCost(new OrCost(lifeCost, sacrificeCost, - "pay 5 life or sacrifice a creature or enchantment")); + this.getSpellAbility().addCost(new OrCost("pay 5 life or sacrifice a creature or enchantment", lifeCost, sacrificeCost + )); // Destroy target creature this.getSpellAbility().addEffect(new DestroyTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/f/FinalRevels.java b/Mage.Sets/src/mage/cards/f/FinalRevels.java index 28e1f96279d..ee222a8c28b 100644 --- a/Mage.Sets/src/mage/cards/f/FinalRevels.java +++ b/Mage.Sets/src/mage/cards/f/FinalRevels.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.cards.CardImpl; @@ -10,8 +8,9 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author Loki */ public final class FinalRevels extends CardImpl { @@ -19,10 +18,14 @@ public final class FinalRevels extends CardImpl { public FinalRevels(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); - this.getSpellAbility().addEffect(new BoostAllEffect(2, 0, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, false)); - Mode mode = new Mode(); - mode.addEffect(new BoostAllEffect(0, -2, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, false)); - this.getSpellAbility().addMode(mode); + this.getSpellAbility().addEffect(new BoostAllEffect( + 2, 0, Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_ALL_CREATURES, false + )); + this.getSpellAbility().addMode(new Mode(new BoostAllEffect( + 0, -2, Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_ALL_CREATURES, false + ))); } private FinalRevels(final FinalRevels card) { diff --git a/Mage.Sets/src/mage/cards/f/FindFinality.java b/Mage.Sets/src/mage/cards/f/FindFinality.java index 47f69b73e71..609f697ee47 100644 --- a/Mage.Sets/src/mage/cards/f/FindFinality.java +++ b/Mage.Sets/src/mage/cards/f/FindFinality.java @@ -84,7 +84,7 @@ class FinalityEffect extends OneShotEffect { Target target = new TargetControlledCreaturePermanent(0, 1); target.setNotTarget(true); if (player.choose( - Outcome.BoostCreature, target, source.getSourceId(), game + Outcome.BoostCreature, target, source, game )) { Effect effect = new AddCountersTargetEffect( CounterType.P1P1.createInstance(2) diff --git a/Mage.Sets/src/mage/cards/f/FireJuggler.java b/Mage.Sets/src/mage/cards/f/FireJuggler.java index e68eb240e1c..98dfa91aa27 100644 --- a/Mage.Sets/src/mage/cards/f/FireJuggler.java +++ b/Mage.Sets/src/mage/cards/f/FireJuggler.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.BecomesBlockedSourceTriggeredAbility; import mage.abilities.effects.common.DamageAllEffect; @@ -11,16 +9,24 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.FilterPermanent; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; + +import java.util.UUID; /** - * * @author BursegSardaukar */ public final class FireJuggler extends CardImpl { - + + private static final FilterPermanent filter = new FilterCreaturePermanent("creature blocking it"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.BLOCKING); + } + public FireJuggler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.SHAMAN); @@ -28,9 +34,9 @@ public final class FireJuggler extends CardImpl { this.toughness = new MageInt(2); // Whenever Fire Juggler becomes blocked, clash with an opponent. If you win, Fire Juggler deals 4 damage to each creature blocking it. - FilterPermanent filter = new FilterPermanent("creature blocking it"); - filter.add(new BlockingAttackerIdPredicate(this.getId())); - this.addAbility(new BecomesBlockedSourceTriggeredAbility(new DoIfClashWonEffect(new DamageAllEffect(4,filter)),false)); + this.addAbility(new BecomesBlockedSourceTriggeredAbility( + new DoIfClashWonEffect(new DamageAllEffect(4, filter)), false + )); } private FireJuggler(final FireJuggler card) { diff --git a/Mage.Sets/src/mage/cards/f/Fireball.java b/Mage.Sets/src/mage/cards/f/Fireball.java index 69565eda842..2a444dcb2c0 100644 --- a/Mage.Sets/src/mage/cards/f/Fireball.java +++ b/Mage.Sets/src/mage/cards/f/Fireball.java @@ -57,7 +57,7 @@ class FireballEffect extends OneShotEffect { public FireballEffect() { super(Outcome.Damage); staticText = "this spell costs {1} more to cast for each target beyond the first.
{this} deals " + - "X damage divided evenly, rounded down, among any number of target creatures and/or players."; + "X damage divided evenly, rounded down, among any number of targets"; } public FireballEffect(final FireballEffect effect) { @@ -123,7 +123,7 @@ class FireballTargetCreatureOrPlayer extends TargetAnyTarget { } for (int numberTargets = 1; numberTargets == 1 || xVal / (numberTargets - 1) > 1; numberTargets++) { - Set possibleTargets = possibleTargets(source.getSourceId(), source.getControllerId(), game); + Set possibleTargets = possibleTargets(source.getControllerId(), source, game); // less possible targets than we're trying to set if (possibleTargets.size() < numberTargets) { return options; diff --git a/Mage.Sets/src/mage/cards/f/FiredrinkerSatyr.java b/Mage.Sets/src/mage/cards/f/FiredrinkerSatyr.java index f5877ae4dfa..f0b29a5c965 100644 --- a/Mage.Sets/src/mage/cards/f/FiredrinkerSatyr.java +++ b/Mage.Sets/src/mage/cards/f/FiredrinkerSatyr.java @@ -5,15 +5,12 @@ import mage.abilities.Ability; import mage.abilities.common.DealtDamageToSourceTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.game.Game; -import mage.players.Player; import java.util.UUID; @@ -31,12 +28,11 @@ public final class FiredrinkerSatyr extends CardImpl { this.toughness = new MageInt(1); // Whenever Firedrinker Satyr is dealt damage, it deals that much damage to you. - this.addAbility(new DealtDamageToSourceTriggeredAbility(new FiredrinkerSatyrDealDamageEffect(), false, false)); + this.addAbility(new DealtDamageToSourceTriggeredAbility( + new DamageControllerEffect(SavedDamageValue.MUCH, "it"), false)); // {1}{R}: Firedrinker Satyr gets +1/+0 until end of turn and deals 1 damage to you. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl("{1}{R}")); - Effect effect = new DamageControllerEffect(1); - effect.setText("and deals 1 damage to you"); - ability.addEffect(effect); + Ability ability = new SimpleActivatedAbility(new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl<>("{1}{R}")); + ability.addEffect(new DamageControllerEffect(1, "and")); this.addAbility(ability); } @@ -49,33 +45,3 @@ public final class FiredrinkerSatyr extends CardImpl { return new FiredrinkerSatyr(this); } } - -class FiredrinkerSatyrDealDamageEffect extends OneShotEffect { - - public FiredrinkerSatyrDealDamageEffect() { - super(Outcome.Damage); - this.staticText = "it deals that much damage to you"; - } - - public FiredrinkerSatyrDealDamageEffect(final FiredrinkerSatyrDealDamageEffect effect) { - super(effect); - } - - @Override - public FiredrinkerSatyrDealDamageEffect copy() { - return new FiredrinkerSatyrDealDamageEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int amount = (Integer) getValue("damage"); - if (amount > 0) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - player.damage(amount, source.getSourceId(), source, game); - return true; - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/f/Firespout.java b/Mage.Sets/src/mage/cards/f/Firespout.java index 395f2b72141..232736848be 100644 --- a/Mage.Sets/src/mage/cards/f/Firespout.java +++ b/Mage.Sets/src/mage/cards/f/Firespout.java @@ -38,7 +38,7 @@ public final class Firespout extends CardImpl { new ManaWasSpentCondition(ColoredManaSymbol.R), "{this} deals 3 damage to each creature without flying if {R} was spent to cast this spell")); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new DamageAllEffect(3, filter2), - new ManaWasSpentCondition(ColoredManaSymbol.G), "and 3 damage to each creature with flying if {G} was spent to cast it. (Do both if {R}{G} was spent.)")); + new ManaWasSpentCondition(ColoredManaSymbol.G), "and 3 damage to each creature with flying if {G} was spent to cast this spell. (Do both if {R}{G} was spent.)")); } private Firespout(final Firespout card) { diff --git a/Mage.Sets/src/mage/cards/f/FirjaJudgeOfValor.java b/Mage.Sets/src/mage/cards/f/FirjaJudgeOfValor.java index 7338716f68b..92d267fadce 100644 --- a/Mage.Sets/src/mage/cards/f/FirjaJudgeOfValor.java +++ b/Mage.Sets/src/mage/cards/f/FirjaJudgeOfValor.java @@ -2,8 +2,8 @@ package mage.cards.f; import mage.MageInt; import mage.abilities.common.CastSecondSpellTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.LifelinkAbility; import mage.cards.CardImpl; @@ -11,8 +11,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import java.util.UUID; @@ -36,11 +34,10 @@ public final class FirjaJudgeOfValor extends CardImpl { // Lifelink this.addAbility(LifelinkAbility.getInstance()); - // Whenever you cast your second spell each turn, look at the top three cards of your library. Put one of them into your hand and the rest into your graveyard. + // Whenever you cast your second spell each turn, look at the top three cards of your library. + // Put one of them into your hand and the rest into your graveyard. this.addAbility(new CastSecondSpellTriggeredAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(3), false, StaticValue.get(1), StaticFilters.FILTER_CARD, - Zone.GRAVEYARD, false, false, false, Zone.HAND, false - ))); + 3, 1, PutCards.HAND, PutCards.GRAVEYARD))); } private FirjaJudgeOfValor(final FirjaJudgeOfValor card) { diff --git a/Mage.Sets/src/mage/cards/f/FirjasRetribution.java b/Mage.Sets/src/mage/cards/f/FirjasRetribution.java index 7eb316a407e..5b9fde1d43c 100644 --- a/Mage.Sets/src/mage/cards/f/FirjasRetribution.java +++ b/Mage.Sets/src/mage/cards/f/FirjasRetribution.java @@ -80,7 +80,7 @@ enum FirjasRetributionPredicate implements ObjectSourcePlayerPredicate input, Game game) { - Permanent permanent = game.getPermanentOrLKIBattlefield(input.getSourceId()); + Permanent permanent = input.getSource().getSourcePermanentOrLKI(game); return permanent != null && input.getObject().getPower().getValue() < permanent.getPower().getValue(); } } diff --git a/Mage.Sets/src/mage/cards/f/FirstResponder.java b/Mage.Sets/src/mage/cards/f/FirstResponder.java new file mode 100644 index 00000000000..2bd3634a1b8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FirstResponder.java @@ -0,0 +1,92 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FirstResponder extends CardImpl { + + public FirstResponder(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // At the beginning of your end step, you may return another creature you control to its owner's hand, then put a number of +1/+1 counters equal to that creature's power on First Responder. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new FirstResponderEffect(), TargetController.YOU, false + )); + } + + private FirstResponder(final FirstResponder card) { + super(card); + } + + @Override + public FirstResponder copy() { + return new FirstResponder(this); + } +} + +class FirstResponderEffect extends OneShotEffect { + + FirstResponderEffect() { + super(Outcome.Benefit); + staticText = "you may return another creature you control to its owner's hand, " + + "then put a number of +1/+1 counters equal to that creature's power on {this}"; + } + + private FirstResponderEffect(final FirstResponderEffect effect) { + super(effect); + } + + @Override + public FirstResponderEffect copy() { + return new FirstResponderEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetPermanent target = new TargetPermanent( + 0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE + ); + target.setNotTarget(true); + player.choose(Outcome.ReturnToHand, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null) { + return false; + } + player.moveCards(permanent, Zone.HAND, source, game); + int power = permanent.getPower().getValue(); + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + if (power < 1 || sourcePermanent == null) { + sourcePermanent.addCounters(CounterType.P1P1.createInstance(power), source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FirstSliversChosen.java b/Mage.Sets/src/mage/cards/f/FirstSliversChosen.java index 6d30afa21aa..7fd150c1d1a 100644 --- a/Mage.Sets/src/mage/cards/f/FirstSliversChosen.java +++ b/Mage.Sets/src/mage/cards/f/FirstSliversChosen.java @@ -28,7 +28,7 @@ public final class FirstSliversChosen extends CardImpl { // Sliver creatures you control have exalted. this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( new ExaltedAbility(), Duration.WhileOnBattlefield, - StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS + StaticFilters.FILTER_PERMANENT_SLIVERS ))); } diff --git a/Mage.Sets/src/mage/cards/f/FissureVent.java b/Mage.Sets/src/mage/cards/f/FissureVent.java index 8f8929fa537..24a2727689c 100644 --- a/Mage.Sets/src/mage/cards/f/FissureVent.java +++ b/Mage.Sets/src/mage/cards/f/FissureVent.java @@ -25,8 +25,7 @@ public final class FissureVent extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetArtifactPermanent().withChooseHint("destroy")); - Mode mode1 = new Mode(); - mode1.addEffect(new DestroyTargetEffect()); + Mode mode1 = new Mode(new DestroyTargetEffect()); mode1.addTarget(new TargetNonBasicLandPermanent().withChooseHint("destroy")); this.getSpellAbility().addMode(mode1); } diff --git a/Mage.Sets/src/mage/cards/f/FiveAlarmFire.java b/Mage.Sets/src/mage/cards/f/FiveAlarmFire.java index c53a5a0ee99..d02ee912206 100644 --- a/Mage.Sets/src/mage/cards/f/FiveAlarmFire.java +++ b/Mage.Sets/src/mage/cards/f/FiveAlarmFire.java @@ -16,7 +16,6 @@ import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.events.DamagedEvent; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.target.common.TargetAnyTarget; @@ -89,7 +88,7 @@ class FiveAlarmFireTriggeredAbility extends TriggeredAbilityImpl { || event.getType() == GameEvent.EventType.DAMAGED_PLAYER) { if (((DamagedEvent) event).isCombatDamage() && !triggeringCreatures.contains(event.getSourceId())) { Permanent permanent = game.getPermanent(event.getSourceId()); - if (permanent != null && filter.match(permanent, sourceId, controllerId, game)) { + if (permanent != null && filter.match(permanent, controllerId, this, game)) { triggeringCreatures.add(event.getSourceId()); return true; } diff --git a/Mage.Sets/src/mage/cards/f/FlagstonesOfTrokair.java b/Mage.Sets/src/mage/cards/f/FlagstonesOfTrokair.java index 677916b820a..39b4365e948 100644 --- a/Mage.Sets/src/mage/cards/f/FlagstonesOfTrokair.java +++ b/Mage.Sets/src/mage/cards/f/FlagstonesOfTrokair.java @@ -32,7 +32,7 @@ public final class FlagstonesOfTrokair extends CardImpl { this.addAbility(new WhiteManaAbility()); // When Flagstones of Trokair is put into a graveyard from the battlefield, you may search your library for a Plains card and put it onto the battlefield tapped. If you do, shuffle your library. - this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(FILTER), true, false), true, false)); + this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(FILTER), true, true), true, false)); } private FlagstonesOfTrokair(final FlagstonesOfTrokair card) { diff --git a/Mage.Sets/src/mage/cards/f/FlamekinBladewhirl.java b/Mage.Sets/src/mage/cards/f/FlamekinBladewhirl.java index c79bf18007d..edae64c172b 100644 --- a/Mage.Sets/src/mage/cards/f/FlamekinBladewhirl.java +++ b/Mage.Sets/src/mage/cards/f/FlamekinBladewhirl.java @@ -34,9 +34,9 @@ public final class FlamekinBladewhirl extends CardImpl { // As an additional cost to cast Flamekin Bladewhirl, reveal an Elemental card from your hand or pay {3}. this.getSpellAbility().addCost(new OrCost( - new RevealTargetFromHandCost(new TargetCardInHand(filter)), - new GenericManaCost(3), - "reveal a Elemental card from your hand or pay {3}")); + "reveal an Elemental card from your hand or pay {3}", new RevealTargetFromHandCost(new TargetCardInHand(filter)), + new GenericManaCost(3) + )); } private FlamekinBladewhirl(final FlamekinBladewhirl card) { diff --git a/Mage.Sets/src/mage/cards/f/FlamerushRider.java b/Mage.Sets/src/mage/cards/f/FlamerushRider.java index a7d0b8c60a1..2e9b56b0f46 100644 --- a/Mage.Sets/src/mage/cards/f/FlamerushRider.java +++ b/Mage.Sets/src/mage/cards/f/FlamerushRider.java @@ -52,7 +52,7 @@ public final class FlamerushRider extends CardImpl { this.addAbility(ability); // Dash {2}{R}{R} - this.addAbility(new DashAbility(this, "{2}{R}{R}")); + this.addAbility(new DashAbility("{2}{R}{R}")); } private FlamerushRider(final FlamerushRider card) { diff --git a/Mage.Sets/src/mage/cards/f/FlamescrollCelebrant.java b/Mage.Sets/src/mage/cards/f/FlamescrollCelebrant.java index e901d7c39f8..003a0c07ccb 100644 --- a/Mage.Sets/src/mage/cards/f/FlamescrollCelebrant.java +++ b/Mage.Sets/src/mage/cards/f/FlamescrollCelebrant.java @@ -135,7 +135,7 @@ class RevelInSilenceEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { Player activePlayer = game.getPlayer(game.getActivePlayerId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (activePlayer == null || mageObject == null) { return null; } diff --git a/Mage.Sets/src/mage/cards/f/Flash.java b/Mage.Sets/src/mage/cards/f/Flash.java index 6e52b341c07..a5aba127c0d 100644 --- a/Mage.Sets/src/mage/cards/f/Flash.java +++ b/Mage.Sets/src/mage/cards/f/Flash.java @@ -67,7 +67,7 @@ class FlashEffect extends OneShotEffect { } TargetCardInHand target = new TargetCardInHand(StaticFilters.FILTER_CARD_CREATURE); - if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCreatureInPlay, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { controller.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/f/FlashFlood.java b/Mage.Sets/src/mage/cards/f/FlashFlood.java index 12e86f06c5f..70c3d26e27a 100644 --- a/Mage.Sets/src/mage/cards/f/FlashFlood.java +++ b/Mage.Sets/src/mage/cards/f/FlashFlood.java @@ -35,8 +35,7 @@ public final class FlashFlood extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent(filter1)); // or return target Mountain to its owner's hand. - Mode mode = new Mode(); - mode.addEffect(new ReturnToHandTargetEffect()); + Mode mode = new Mode(new ReturnToHandTargetEffect()); mode.addTarget(new TargetPermanent(filter2)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FlashOfInsight.java b/Mage.Sets/src/mage/cards/f/FlashOfInsight.java index c0eee07e074..8d03d4fff0b 100644 --- a/Mage.Sets/src/mage/cards/f/FlashOfInsight.java +++ b/Mage.Sets/src/mage/cards/f/FlashOfInsight.java @@ -1,46 +1,44 @@ - package mage.cards.f; -import java.util.UUID; -import mage.MageObject; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.costs.Cost; -import mage.abilities.costs.common.ExileFromGraveCost; import mage.abilities.costs.common.ExileXFromYourGraveCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.FlashbackAbility; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.TimingRule; -import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; + +import java.util.UUID; /** - * - * @author LevelX2 + * @author awjackson */ public final class FlashOfInsight extends CardImpl { + private static final FilterCard filter = new FilterCard("blue cards from your graveyard"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLUE)); + } + public FlashOfInsight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{1}{U}"); // Look at the top X cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order. - this.getSpellAbility().addEffect(new FlashOfInsightEffect()); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + FlashOfInsightValue.instance, 1, PutCards.HAND, PutCards.BOTTOM_ANY)); // Flashback-{1}{U}, Exile X blue cards from your graveyard. - Ability ability = new FlashbackAbility(this, new ManaCostsImpl("{1}{U}")); - FilterCard filter = new FilterCard("blue cards from your graveyard"); - filter.add(new ColorPredicate(ObjectColor.BLUE)); - filter.add(Predicates.not(new CardIdPredicate(getId()))); + Ability ability = new FlashbackAbility(this, new ManaCostsImpl<>("{1}{U}")); ability.addCost(new ExileXFromYourGraveCost(filter)); this.addAbility(ability); } @@ -55,51 +53,32 @@ public final class FlashOfInsight extends CardImpl { } } -class FlashOfInsightEffect extends OneShotEffect { +enum FlashOfInsightValue implements DynamicValue { + instance; - public FlashOfInsightEffect() { - super(Outcome.DrawCard); - this.staticText = "Look at the top X cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order"; - } - - public FlashOfInsightEffect(final FlashOfInsightEffect effect) { - super(effect); + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + int xValue = sourceAbility.getManaCostsToPay().getX(); + for (Cost cost : sourceAbility.getCosts()) { + if (cost instanceof ExileXFromYourGraveCost) { + xValue = ((ExileXFromYourGraveCost) cost).getAmount(); + } + } + return xValue; } @Override - public FlashOfInsightEffect copy() { - return new FlashOfInsightEffect(this); + public FlashOfInsightValue copy() { + return instance; } @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller == null || sourceObject == null) { - return false; - } + public String toString() { + return "X"; + } - int xValue = source.getManaCostsToPay().getX(); - - for (Cost cost : source.getCosts()) { - if (cost instanceof ExileFromGraveCost) { - xValue = ((ExileFromGraveCost) cost).getExiledCards().size(); - } - } - - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, xValue)); - controller.lookAtCards(sourceObject.getIdName(), cards, game); - - TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into your hand")); - target.setNotTarget(true); - if (controller.chooseTarget(Outcome.DrawCard, cards, target, source, game)) { - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - controller.moveCards(card, Zone.HAND, source, game); - cards.remove(card); - } - } - controller.putCardsOnBottomOfLibrary(cards, game, source, true); - return true; + @Override + public String getMessage() { + return ""; } } diff --git a/Mage.Sets/src/mage/cards/f/FlawlessForgery.java b/Mage.Sets/src/mage/cards/f/FlawlessForgery.java new file mode 100644 index 00000000000..0ded8c115d8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FlawlessForgery.java @@ -0,0 +1,93 @@ +package mage.cards.f; + +import mage.ApprovingObject; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.CasualtyAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.common.FilterInstantOrSorceryCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FlawlessForgery extends CardImpl { + + private static final FilterCard filter + = new FilterInstantOrSorceryCard("instant or sorcery card from an opponent's graveyard"); + + static { + filter.add(TargetController.OPPONENT.getOwnerPredicate()); + } + + public FlawlessForgery(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}{U}"); + + // Casualty 3 + this.addAbility(new CasualtyAbility(this, 3)); + + // Exile target instant or sorcery card from an opponent's graveyard. Copy that card. You may cast the copy without paying its mana cost. + this.getSpellAbility().addEffect(new FlawlessForgeryEffect()); + this.getSpellAbility().addTarget(new TargetCardInGraveyard(filter)); + } + + private FlawlessForgery(final FlawlessForgery card) { + super(card); + } + + @Override + public FlawlessForgery copy() { + return new FlawlessForgery(this); + } +} + +class FlawlessForgeryEffect extends OneShotEffect { + + FlawlessForgeryEffect() { + super(Outcome.Benefit); + staticText = "exile target instant or sorcery card from an opponent's graveyard. " + + "Copy that card. You may cast the copy without paying its mana cost"; + } + + private FlawlessForgeryEffect(final FlawlessForgeryEffect effect) { + super(effect); + } + + @Override + public FlawlessForgeryEffect copy() { + return new FlawlessForgeryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + if (player == null || card == null) { + return false; + } + player.moveCards(card, Zone.EXILED, source, game); + Card cardCopy = game.copyCard(card, source, source.getControllerId()); + if (!player.chooseUse(outcome, "Cast copy of " + + card.getName() + " without paying its mana cost?", source, game)) { + return true; + } + game.getState().setValue("PlayFromNotOwnHandZone" + cardCopy.getId(), Boolean.TRUE); + player.cast( + player.chooseAbilityForCast(cardCopy, game, true), + game, true, new ApprovingObject(source, game) + ); + game.getState().setValue("PlayFromNotOwnHandZone" + cardCopy.getId(), null); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FlayedNim.java b/Mage.Sets/src/mage/cards/f/FlayedNim.java index 2eb04278497..ea2df4f1ff0 100644 --- a/Mage.Sets/src/mage/cards/f/FlayedNim.java +++ b/Mage.Sets/src/mage/cards/f/FlayedNim.java @@ -5,17 +5,13 @@ import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToACreatureTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.LoseLifeTargetControllerEffect; import mage.abilities.effects.common.RegenerateSourceEffect; 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.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import java.util.UUID; @@ -32,10 +28,13 @@ public final class FlayedNim extends CardImpl { this.toughness = new MageInt(2); // Whenever Flayed Nim deals combat damage to a creature, that creature's controller loses that much life. - this.addAbility(new DealsCombatDamageToACreatureTriggeredAbility(new FlayedNimEffect(), false, true)); + this.addAbility(new DealsCombatDamageToACreatureTriggeredAbility( + new LoseLifeTargetControllerEffect(SavedDamageValue.MUCH) + .setText("that creature's controller loses that much life"), + false, true)); // {2}{B}: Regenerate Flayed Nim. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{2}{B}"))); + this.addAbility(new SimpleActivatedAbility(new RegenerateSourceEffect(), new ManaCostsImpl("{2}{B}"))); } private FlayedNim(final FlayedNim card) { @@ -47,35 +46,3 @@ public final class FlayedNim extends CardImpl { return new FlayedNim(this); } } - -class FlayedNimEffect extends OneShotEffect { - - FlayedNimEffect() { - super(Outcome.Benefit); - this.staticText = "that creature's controller loses that much life"; - } - - FlayedNimEffect(final FlayedNimEffect effect) { - super(effect); - } - - @Override - public FlayedNimEffect copy() { - return new FlayedNimEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent creature = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); - if (creature == null) { - return false; - } - Player player = game.getPlayer(creature.getControllerId()); - if (player == null) { - return false; - } - int damage = (int) this.getValue("damage"); - player.loseLife(damage, game, source, false); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/f/FledglingMawcor.java b/Mage.Sets/src/mage/cards/f/FledglingMawcor.java index 602831934d0..ab24f735900 100644 --- a/Mage.Sets/src/mage/cards/f/FledglingMawcor.java +++ b/Mage.Sets/src/mage/cards/f/FledglingMawcor.java @@ -38,7 +38,7 @@ public final class FledglingMawcor extends CardImpl { this.addAbility(ability); // Morph {U}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{U}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{U}{U}"))); } private FledglingMawcor(final FledglingMawcor card) { diff --git a/Mage.Sets/src/mage/cards/f/FleetSwallower.java b/Mage.Sets/src/mage/cards/f/FleetSwallower.java index 8dd4df8346e..a28c3c629e3 100644 --- a/Mage.Sets/src/mage/cards/f/FleetSwallower.java +++ b/Mage.Sets/src/mage/cards/f/FleetSwallower.java @@ -1,22 +1,18 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.constants.SubType; +import mage.abilities.effects.common.MillHalfLibraryTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.game.Game; -import mage.players.Player; +import mage.constants.SubType; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class FleetSwallower extends CardImpl { @@ -29,7 +25,7 @@ public final class FleetSwallower extends CardImpl { this.toughness = new MageInt(6); // Whenever Fleet Swallower attacks, target player puts the top half of their library, rounded up, into their graveyard. - Ability ability = new AttacksTriggeredAbility(new FleetSwallowerEffect(), false); + Ability ability = new AttacksTriggeredAbility(new MillHalfLibraryTargetEffect(true), false); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } @@ -43,32 +39,3 @@ public final class FleetSwallower extends CardImpl { return new FleetSwallower(this); } } - -class FleetSwallowerEffect extends OneShotEffect { - - public FleetSwallowerEffect() { - super(Outcome.Detriment); - staticText = "target player mills half their library, rounded up"; - } - - public FleetSwallowerEffect(final FleetSwallowerEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getFirstTarget()); - if (player != null) { - int amount = (int) Math.ceil(player.getLibrary().size() * .5); - player.millCards(amount, source, game); - return true; - } - return false; - } - - @Override - public FleetSwallowerEffect copy() { - return new FleetSwallowerEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/f/FleetfootDancer.java b/Mage.Sets/src/mage/cards/f/FleetfootDancer.java new file mode 100644 index 00000000000..088df351ae6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FleetfootDancer.java @@ -0,0 +1,45 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FleetfootDancer extends CardImpl { + + public FleetfootDancer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{G}{W}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // Haste + this.addAbility(HasteAbility.getInstance()); + } + + private FleetfootDancer(final FleetfootDancer card) { + super(card); + } + + @Override + public FleetfootDancer copy() { + return new FleetfootDancer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FleetingDistraction.java b/Mage.Sets/src/mage/cards/f/FleetingDistraction.java index 212f6e26899..31374f04c17 100644 --- a/Mage.Sets/src/mage/cards/f/FleetingDistraction.java +++ b/Mage.Sets/src/mage/cards/f/FleetingDistraction.java @@ -21,7 +21,7 @@ public final class FleetingDistraction extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}"); this.getSpellAbility().addEffect(new BoostTargetEffect(-1, 0, Duration.EndOfTurn)); - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/f/FleetwheelCruiser.java b/Mage.Sets/src/mage/cards/f/FleetwheelCruiser.java index eab6593b27f..504a212f336 100644 --- a/Mage.Sets/src/mage/cards/f/FleetwheelCruiser.java +++ b/Mage.Sets/src/mage/cards/f/FleetwheelCruiser.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect; @@ -14,8 +12,9 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; +import java.util.UUID; + /** - * * @author emerald000 */ public final class FleetwheelCruiser extends CardImpl { @@ -33,8 +32,9 @@ public final class FleetwheelCruiser extends CardImpl { this.addAbility(HasteAbility.getInstance()); // When Fleetwheel Cruiser enters the battlefield, it becomes an artifact creature until the end of turn. - this.addAbility(new EntersBattlefieldTriggeredAbility( - new AddCardTypeSourceEffect(Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new AddCardTypeSourceEffect( + Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE + ).setText("it becomes an artifact creature until end of turn"))); // Crew 2 this.addAbility(new CrewAbility(2)); diff --git a/Mage.Sets/src/mage/cards/f/FleshReaver.java b/Mage.Sets/src/mage/cards/f/FleshReaver.java index df4093ebc60..472f04a6f22 100644 --- a/Mage.Sets/src/mage/cards/f/FleshReaver.java +++ b/Mage.Sets/src/mage/cards/f/FleshReaver.java @@ -1,19 +1,17 @@ package mage.cards.f; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.DamageControllerEffect; 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.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.players.Player; import java.util.UUID; @@ -47,7 +45,7 @@ public final class FleshReaver extends CardImpl { class FleshReaverTriggeredAbility extends TriggeredAbilityImpl { FleshReaverTriggeredAbility() { - super(Zone.BATTLEFIELD, new FleshReaverEffect()); + super(Zone.BATTLEFIELD, new DamageControllerEffect(SavedDamageValue.MUCH)); } private FleshReaverTriggeredAbility(final FleshReaverTriggeredAbility effect) { @@ -80,39 +78,7 @@ class FleshReaverTriggeredAbility extends TriggeredAbilityImpl { } @Override - public String getRule() { - return "Whenever {this} deals damage to a creature or opponent, {this} deals that much damage to you."; - } - -} - -class FleshReaverEffect extends OneShotEffect { - - FleshReaverEffect() { - super(Outcome.Detriment); - this.staticText = "{this} deals that much damage to you."; - } - - private FleshReaverEffect(final FleshReaverEffect effect) { - super(effect); - } - - @Override - public FleshReaverEffect copy() { - return new FleshReaverEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent creature = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (creature == null || controller == null) { - return false; - } - int damageToDeal = (Integer) getValue("damage"); - if (damageToDeal > 0) { - controller.damage(damageToDeal, source.getSourceId(), source, game); - } - return true; + public String getTriggerPhrase() { + return "Whenever {this} deals damage to a creature or opponent, "; } } diff --git a/Mage.Sets/src/mage/cards/f/FloodOfTears.java b/Mage.Sets/src/mage/cards/f/FloodOfTears.java index b8d376cb1d9..4882ea2f870 100644 --- a/Mage.Sets/src/mage/cards/f/FloodOfTears.java +++ b/Mage.Sets/src/mage/cards/f/FloodOfTears.java @@ -66,7 +66,7 @@ class FloodOfTearsEffect extends OneShotEffect { return false; } List nonlands = game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_PERMANENT_NON_LAND, source.getControllerId(), source.getSourceId(), game + StaticFilters.FILTER_PERMANENT_NON_LAND, source.getControllerId(), source, game ); Cards cards = new CardsImpl(); if (!nonlands.isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/f/Floodchaser.java b/Mage.Sets/src/mage/cards/f/Floodchaser.java index 773fccb7ee0..7155cc4dd5b 100644 --- a/Mage.Sets/src/mage/cards/f/Floodchaser.java +++ b/Mage.Sets/src/mage/cards/f/Floodchaser.java @@ -36,7 +36,7 @@ public final class Floodchaser extends CardImpl { this.toughness = new MageInt(0); // Floodchaser enters the battlefield with six +1/+1 counters on it. - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(6)), "{this} enters the battlefield with six +1/+1 counters on it")); + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(6)), "with six +1/+1 counters on it")); // Floodchaser can't attack unless defending player controls an Island. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackUnlessDefenderControllsPermanent(new FilterLandPermanent(SubType.ISLAND,"an Island")))); diff --git a/Mage.Sets/src/mage/cards/f/FlourishingDefenses.java b/Mage.Sets/src/mage/cards/f/FlourishingDefenses.java index d9fc0642148..d262bf6a8e3 100644 --- a/Mage.Sets/src/mage/cards/f/FlourishingDefenses.java +++ b/Mage.Sets/src/mage/cards/f/FlourishingDefenses.java @@ -12,6 +12,7 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.permanent.token.ElfWarriorToken; +import java.util.Optional; import java.util.UUID; /** @@ -60,7 +61,10 @@ class FlourishingDefensesTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getData().equals(CounterType.M1M1.getName())) { - Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); + Permanent permanent = Optional + .ofNullable(game.getPermanentOrLKIBattlefield(event.getTargetId())) + .orElse(game.getPermanentEntering(event.getTargetId())); + return permanent != null && permanent.isCreature(game); } return false; diff --git a/Mage.Sets/src/mage/cards/f/FlowstoneBlade.java b/Mage.Sets/src/mage/cards/f/FlowstoneBlade.java index 6d1e85c8781..54b85d68033 100644 --- a/Mage.Sets/src/mage/cards/f/FlowstoneBlade.java +++ b/Mage.Sets/src/mage/cards/f/FlowstoneBlade.java @@ -36,7 +36,7 @@ public final class FlowstoneBlade extends CardImpl { this.addAbility(ability); // {R}: Enchanted creature gets +1/-1 until end of turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, -1, Duration.EndOfTurn), new ManaCostsImpl("R"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, -1, Duration.EndOfTurn), new ManaCostsImpl<>("{R}"))); } private FlowstoneBlade(final FlowstoneBlade card) { diff --git a/Mage.Sets/src/mage/cards/f/FlowstoneSalamander.java b/Mage.Sets/src/mage/cards/f/FlowstoneSalamander.java index dd2d39b3fc9..ae5146d2786 100644 --- a/Mage.Sets/src/mage/cards/f/FlowstoneSalamander.java +++ b/Mage.Sets/src/mage/cards/f/FlowstoneSalamander.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -11,28 +9,33 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LoneFox */ public final class FlowstoneSalamander extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("creature blocking it"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.BLOCKING); + } + public FlowstoneSalamander(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); this.subtype.add(SubType.SALAMANDER); this.power = new MageInt(3); this.toughness = new MageInt(4); // {R}: Flowstone Salamander deals 1 damage to target creature blocking it. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl("{R")); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking it"); - filter.add(new BlockingAttackerIdPredicate(this.getId())); - ability.addTarget(new TargetCreaturePermanent(filter)); + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new ManaCostsImpl<>("{R}")); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FodderLaunch.java b/Mage.Sets/src/mage/cards/f/FodderLaunch.java index 919ddf8629e..211152d0598 100644 --- a/Mage.Sets/src/mage/cards/f/FodderLaunch.java +++ b/Mage.Sets/src/mage/cards/f/FodderLaunch.java @@ -29,7 +29,7 @@ public final class FodderLaunch extends CardImpl { //Target creature gets -5/-5 until end of turn. Fodder Launch deals 5 damage to that creature's controller. this.getSpellAbility().addEffect(new BoostTargetEffect(-5, -5, Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new DamageTargetControllerEffect(5)); + this.getSpellAbility().addEffect(new DamageTargetControllerEffect(5).setText("{this} deals 5 damage to that creature's controller")); } private FodderLaunch(final FodderLaunch card) { diff --git a/Mage.Sets/src/mage/cards/f/FoldIntoAether.java b/Mage.Sets/src/mage/cards/f/FoldIntoAether.java index b50bab29071..007dbb93bf6 100644 --- a/Mage.Sets/src/mage/cards/f/FoldIntoAether.java +++ b/Mage.Sets/src/mage/cards/f/FoldIntoAether.java @@ -67,9 +67,9 @@ class FoldIntoAetherEffect extends OneShotEffect { if (game.getStack().counter(targetId, source, game)) { TargetCardInHand target = new TargetCardInHand(StaticFilters.FILTER_CARD_CREATURE); if (spellController != null - && target.canChoose(source.getSourceId(), spellController.getId(), game) + && target.canChoose(spellController.getId(), source, game) && spellController.chooseUse(Outcome.Neutral, "Put a creature card from your hand in play?", source, game) - && spellController.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + && spellController.choose(Outcome.PutCreatureInPlay, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { spellController.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/f/FolkOfAnHavva.java b/Mage.Sets/src/mage/cards/f/FolkOfAnHavva.java index 168ff674b0e..4df3fca5db2 100644 --- a/Mage.Sets/src/mage/cards/f/FolkOfAnHavva.java +++ b/Mage.Sets/src/mage/cards/f/FolkOfAnHavva.java @@ -1,4 +1,3 @@ - package mage.cards.f; import java.util.UUID; @@ -24,7 +23,7 @@ public final class FolkOfAnHavva extends CardImpl { this.toughness = new MageInt(1); // Whenever Folk of An-Havva blocks, it gets +2/+0 until end of turn. - this.addAbility(new BlocksSourceTriggeredAbility(new BoostSourceEffect(2, 0, Duration.EndOfTurn), false)); + this.addAbility(new BlocksSourceTriggeredAbility(new BoostSourceEffect(2, 0, Duration.EndOfTurn, "it"))); } private FolkOfAnHavva(final FolkOfAnHavva card) { diff --git a/Mage.Sets/src/mage/cards/f/FootbottomFeast.java b/Mage.Sets/src/mage/cards/f/FootbottomFeast.java index e8c1078ee90..7dae2624520 100644 --- a/Mage.Sets/src/mage/cards/f/FootbottomFeast.java +++ b/Mage.Sets/src/mage/cards/f/FootbottomFeast.java @@ -23,7 +23,7 @@ public final class FootbottomFeast extends CardImpl { this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, Integer.MAX_VALUE, StaticFilters.FILTER_CARD_CREATURES_YOUR_GRAVEYARD)); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private FootbottomFeast(final FootbottomFeast card) { diff --git a/Mage.Sets/src/mage/cards/f/FoothillGuide.java b/Mage.Sets/src/mage/cards/f/FoothillGuide.java index 71816c68830..631bdfd0340 100644 --- a/Mage.Sets/src/mage/cards/f/FoothillGuide.java +++ b/Mage.Sets/src/mage/cards/f/FoothillGuide.java @@ -34,7 +34,7 @@ public final class FoothillGuide extends CardImpl { // Protection from Goblins this.addAbility(new ProtectionAbility(filter)); // Morph {W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{W}"))); } private FoothillGuide(final FoothillGuide card) { diff --git a/Mage.Sets/src/mage/cards/f/ForTheFamily.java b/Mage.Sets/src/mage/cards/f/ForTheFamily.java new file mode 100644 index 00000000000..5706f2eaa8d --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/ForTheFamily.java @@ -0,0 +1,67 @@ +package mage.cards.f; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author weirddan455 + */ +public final class ForTheFamily extends CardImpl { + + public ForTheFamily(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}"); + + // Target creature gets +2/+2 until end of turn. If you control four or more creatures, that creature gets +4/+4 until end of turn instead. + this.getSpellAbility().addEffect(new ForTheFamilyEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private ForTheFamily(final ForTheFamily card) { + super(card); + } + + @Override + public ForTheFamily copy() { + return new ForTheFamily(this); + } +} + +class ForTheFamilyEffect extends OneShotEffect { + + public ForTheFamilyEffect() { + super(Outcome.BoostCreature); + this.staticText = "Target creature gets +2/+2 until end of turn. If you control four or more creatures, that creature gets +4/+4 until end of turn instead"; + } + + private ForTheFamilyEffect(final ForTheFamilyEffect effect) { + super(effect); + } + + @Override + public ForTheFamilyEffect copy() { + return new ForTheFamilyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int boost; + if (game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_CREATURE, source.getControllerId(), source, game) >= 4) { + boost = 4; + } else { + boost = 2; + } + game.addEffect(new BoostTargetEffect(boost, boost), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/f/ForbiddenAlchemy.java b/Mage.Sets/src/mage/cards/f/ForbiddenAlchemy.java index cdc2e92ae55..f8af6bdc37d 100644 --- a/Mage.Sets/src/mage/cards/f/ForbiddenAlchemy.java +++ b/Mage.Sets/src/mage/cards/f/ForbiddenAlchemy.java @@ -1,16 +1,13 @@ - package mage.cards.f; import java.util.UUID; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.FlashbackAbility; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.TimingRule; -import mage.constants.Zone; -import mage.filter.StaticFilters; /** * @@ -22,8 +19,7 @@ public final class ForbiddenAlchemy extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}"); // Look at the top four cards of your library. Put one of them into your hand and the rest into your graveyard. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(4), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.GRAVEYARD, false, false, false, Zone.HAND, false)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(4, 1, PutCards.HAND, PutCards.GRAVEYARD)); // Flashback {6}{B} this.addAbility(new FlashbackAbility(this, new ManaCostsImpl("{6}{B}"))); diff --git a/Mage.Sets/src/mage/cards/f/ForbiddenCrypt.java b/Mage.Sets/src/mage/cards/f/ForbiddenCrypt.java index 8b1f6031ddd..c35ac5b5df3 100644 --- a/Mage.Sets/src/mage/cards/f/ForbiddenCrypt.java +++ b/Mage.Sets/src/mage/cards/f/ForbiddenCrypt.java @@ -14,7 +14,6 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentToken; @@ -69,8 +68,8 @@ class ForbiddenCryptDrawCardReplacementEffect extends ReplacementEffectImpl { boolean cardReturned = false; TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - if (target.choose(Outcome.ReturnToHand, controller.getId(), source.getSourceId(), game)) { + if (target.canChoose(controller.getId(), source, game)) { + if (target.choose(Outcome.ReturnToHand, controller.getId(), source.getSourceId(), source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { controller.moveCards(card, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/f/ForceOfWill.java b/Mage.Sets/src/mage/cards/f/ForceOfWill.java index 43cb3c1aeee..a313bbe9d6a 100644 --- a/Mage.Sets/src/mage/cards/f/ForceOfWill.java +++ b/Mage.Sets/src/mage/cards/f/ForceOfWill.java @@ -9,8 +9,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterOwnedCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.TargetSpell; import mage.target.common.TargetCardInHand; @@ -22,14 +20,17 @@ import java.util.UUID; */ public final class ForceOfWill extends CardImpl { + private static final FilterOwnedCard filter + = new FilterOwnedCard("a blue card from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLUE)); + } + public ForceOfWill(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}{U}"); // You may pay 1 life and exile a blue card from your hand rather than pay Force of Will's mana cost. - FilterOwnedCard filter = new FilterOwnedCard("a blue card from your hand"); - filter.add(new ColorPredicate(ObjectColor.BLUE)); - filter.add(Predicates.not(new CardIdPredicate(this.getId()))); // the exile cost can never be paid with the card itself - AlternativeCostSourceAbility ability = new AlternativeCostSourceAbility(new PayLifeCost(1)); ability.addCost(new ExileFromHandCost(new TargetCardInHand(filter))); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/f/ForceStasis.java b/Mage.Sets/src/mage/cards/f/ForceStasis.java index 97ee0925d50..f5c68cead88 100644 --- a/Mage.Sets/src/mage/cards/f/ForceStasis.java +++ b/Mage.Sets/src/mage/cards/f/ForceStasis.java @@ -40,8 +40,7 @@ public final class ForceStasis extends CardImpl { getSpellAbility().addTarget(new TargetCreaturePermanent()); // Return target instant or sorcery spell you don't control to its owner's hand. - Mode mode = new Mode(); - mode.addEffect(new ReturnToHandTargetEffect()); + Mode mode = new Mode(new ReturnToHandTargetEffect()); mode.addTarget(new TargetSpell(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/ForcedFruition.java b/Mage.Sets/src/mage/cards/f/ForcedFruition.java index bc11aff54a2..95a7c83ffa3 100644 --- a/Mage.Sets/src/mage/cards/f/ForcedFruition.java +++ b/Mage.Sets/src/mage/cards/f/ForcedFruition.java @@ -23,7 +23,7 @@ public final class ForcedFruition extends CardImpl { // Whenever an opponent casts a spell, that player draws seven cards. this.addAbility(new SpellCastOpponentTriggeredAbility(Zone.BATTLEFIELD, new DrawCardTargetEffect(7), - StaticFilters.FILTER_SPELL, false, SetTargetPointer.PLAYER)); + StaticFilters.FILTER_SPELL_A, false, SetTargetPointer.PLAYER)); } private ForcedFruition(final ForcedFruition card) { diff --git a/Mage.Sets/src/mage/cards/f/ForcedMarch.java b/Mage.Sets/src/mage/cards/f/ForcedMarch.java index 89ef76f2001..ab807fb5df1 100644 --- a/Mage.Sets/src/mage/cards/f/ForcedMarch.java +++ b/Mage.Sets/src/mage/cards/f/ForcedMarch.java @@ -55,8 +55,7 @@ class ForcedMarchEffect extends OneShotEffect { // for(Permanent permanent : game.getBattlefield().getAllActivePermanents(CardType.CREATURE)) { for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), - source.getSourceId(), - game)) { + source, game)) { if (permanent.getManaValue() <= source.getManaCostsToPay().getX()) { permanent.destroy(source, game, false); } diff --git a/Mage.Sets/src/mage/cards/f/Forcefield.java b/Mage.Sets/src/mage/cards/f/Forcefield.java index 95248b163ad..bc6bf89cf61 100644 --- a/Mage.Sets/src/mage/cards/f/Forcefield.java +++ b/Mage.Sets/src/mage/cards/f/Forcefield.java @@ -75,7 +75,7 @@ class ForcefieldEffect extends OneShotEffect { MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { Target target = new TargetCreaturePermanent(1, 1, filter, true); - if (controller.choose(Outcome.PreventDamage, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PreventDamage, target, source, game)) { Permanent creature = game.getPermanent(target.getFirstTarget()); if (creature != null) { game.informPlayers(sourceObject.getLogName() + ": " + controller.getLogName() + " has chosen " + creature.getLogName()); diff --git a/Mage.Sets/src/mage/cards/f/ForgeBoss.java b/Mage.Sets/src/mage/cards/f/ForgeBoss.java new file mode 100644 index 00000000000..a6892300f02 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/ForgeBoss.java @@ -0,0 +1,50 @@ +package mage.cards.f; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SacrificeAllTriggeredAbility; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; + +/** + * + * @author weirddan455 + */ +public final class ForgeBoss extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("one or more other creatures"); + + static { + filter.add(AnotherPredicate.instance); + } + + public ForgeBoss(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Whenever you sacrifice one or more other creatures, Forge Boss deals 2 damage to each opponent. This ability triggers only once each turn. + this.addAbility(new SacrificeAllTriggeredAbility( + new DamagePlayersEffect(2, TargetController.OPPONENT), + filter, TargetController.YOU, false + ).setTriggersOnce(true)); + } + + private ForgeBoss(final ForgeBoss card) { + super(card); + } + + @Override + public ForgeBoss copy() { + return new ForgeBoss(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/ForgottenAncient.java b/Mage.Sets/src/mage/cards/f/ForgottenAncient.java index c255352f377..d23fa7bd949 100644 --- a/Mage.Sets/src/mage/cards/f/ForgottenAncient.java +++ b/Mage.Sets/src/mage/cards/f/ForgottenAncient.java @@ -97,11 +97,11 @@ public final class ForgottenAncient extends CardImpl { do { Target target = new TargetCreaturePermanent(1, 1, filter, true); - if (!target.canChoose(source.getSourceId(), controller.getId(), game)) { + if (!target.canChoose(controller.getId(), source, game)) { break; } - if (!target.choose(Outcome.BoostCreature, source.getControllerId(), source.getSourceId(), game)) { + if (!target.choose(Outcome.BoostCreature, source.getControllerId(), source.getSourceId(), source, game)) { break; } diff --git a/Mage.Sets/src/mage/cards/f/ForgottenLore.java b/Mage.Sets/src/mage/cards/f/ForgottenLore.java index bdd376c6911..fb29ad8060a 100644 --- a/Mage.Sets/src/mage/cards/f/ForgottenLore.java +++ b/Mage.Sets/src/mage/cards/f/ForgottenLore.java @@ -72,7 +72,7 @@ class ForgottenLoreEffect extends OneShotEffect { do { chosenCard = new TargetCardInGraveyard(filter); chosenCard.setNotTarget(true); - if (chosenCard.canChoose(source.getSourceId(), opponent.getId(), game)) { + if (chosenCard.canChoose(opponent.getId(), source, game)) { opponent.chooseTarget(Outcome.ReturnToHand, chosenCard, source, game); card = game.getCard(chosenCard.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/f/ForkInTheRoad.java b/Mage.Sets/src/mage/cards/f/ForkInTheRoad.java index 5f69825c1b1..83382ba1a24 100644 --- a/Mage.Sets/src/mage/cards/f/ForkInTheRoad.java +++ b/Mage.Sets/src/mage/cards/f/ForkInTheRoad.java @@ -61,7 +61,7 @@ class ForkInTheRoadEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/f/Fortify.java b/Mage.Sets/src/mage/cards/f/Fortify.java index 6a3d7db2e3c..ea48cf3da78 100644 --- a/Mage.Sets/src/mage/cards/f/Fortify.java +++ b/Mage.Sets/src/mage/cards/f/Fortify.java @@ -21,8 +21,7 @@ public final class Fortify extends CardImpl { // Choose one - Creatures you control get +2/+0 until end of turn; or creatures you control get +0/+2 until end of turn. this.getSpellAbility().addEffect(new BoostControlledEffect(2, 0, Duration.EndOfTurn)); - Mode mode = new Mode(); - mode.addEffect(new BoostControlledEffect(0, 2, Duration.EndOfTurn)); + Mode mode = new Mode(new BoostControlledEffect(0, 2, Duration.EndOfTurn)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FortressCyclops.java b/Mage.Sets/src/mage/cards/f/FortressCyclops.java index cfbdab2a7ec..6001d92887b 100644 --- a/Mage.Sets/src/mage/cards/f/FortressCyclops.java +++ b/Mage.Sets/src/mage/cards/f/FortressCyclops.java @@ -27,9 +27,9 @@ public final class FortressCyclops extends CardImpl { this.toughness = new MageInt(3); // Whenever Fortress Cyclops attacks, it gets +3/+0 until end of turn. - this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(3,0, Duration.EndOfTurn), false)); + this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(3, 0, Duration.EndOfTurn, "it"))); // Whenever Fortress Cyclops blocks, it gets +0/+3 until end of turn. - this.addAbility(new BlocksSourceTriggeredAbility(new BoostSourceEffect(0,3, Duration.EndOfTurn), false)); + this.addAbility(new BlocksSourceTriggeredAbility(new BoostSourceEffect(0, 3, Duration.EndOfTurn, "it"))); } private FortressCyclops(final FortressCyclops card) { diff --git a/Mage.Sets/src/mage/cards/f/FortuitousFind.java b/Mage.Sets/src/mage/cards/f/FortuitousFind.java index 6dd23eab946..3c36b6341aa 100644 --- a/Mage.Sets/src/mage/cards/f/FortuitousFind.java +++ b/Mage.Sets/src/mage/cards/f/FortuitousFind.java @@ -1,12 +1,11 @@ package mage.cards.f; import mage.abilities.Mode; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; -import mage.filter.common.FilterArtifactCard; import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; @@ -24,12 +23,11 @@ public final class FortuitousFind extends CardImpl { this.getSpellAbility().getModes().setMaxModes(2); // Return target artifact card from your graveyard to your hand.; - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard")).withChooseHint("return to hand")); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD).withChooseHint("return to hand")); // or Return target creature card from your graveyard to your hand. - Mode mode = new Mode(); - mode.addEffect(new ReturnToHandTargetEffect()); + Mode mode = new Mode(new ReturnFromGraveyardToHandTargetEffect()); mode.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD).withChooseHint("return to hand")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FortunateFew.java b/Mage.Sets/src/mage/cards/f/FortunateFew.java index add2923cdae..17ad5a29e6a 100644 --- a/Mage.Sets/src/mage/cards/f/FortunateFew.java +++ b/Mage.Sets/src/mage/cards/f/FortunateFew.java @@ -75,7 +75,7 @@ class FortunateFewEffect extends OneShotEffect { Target target = new TargetNonlandPermanent(filter); target.setNotTarget(true); - if (player.choose(Outcome.Exile, target, source.getSourceId(), game)) { + if (player.choose(Outcome.Exile, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { chosenCards.put(permanent, 1); @@ -85,7 +85,7 @@ class FortunateFewEffect extends OneShotEffect { } } - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterNonlandPermanent(), source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterNonlandPermanent(), source.getControllerId(), source, game)) { if (!chosenCards.containsKey(permanent)) { permanent.destroy(source, game, false); } diff --git a/Mage.Sets/src/mage/cards/f/FortuneThief.java b/Mage.Sets/src/mage/cards/f/FortuneThief.java index 9d58912cb7c..bae21315e06 100644 --- a/Mage.Sets/src/mage/cards/f/FortuneThief.java +++ b/Mage.Sets/src/mage/cards/f/FortuneThief.java @@ -37,7 +37,7 @@ public final class FortuneThief extends CardImpl { // Damage that would reduce your life total to less than 1 reduces it to 1 instead. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new FortuneThiefReplacementEffect())); // Morph {R}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{R}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{R}{R}"))); } private FortuneThief(final FortuneThief card) { diff --git a/Mage.Sets/src/mage/cards/f/FoulEmissary.java b/Mage.Sets/src/mage/cards/f/FoulEmissary.java index 5e0426843fa..16b296551e2 100644 --- a/Mage.Sets/src/mage/cards/f/FoulEmissary.java +++ b/Mage.Sets/src/mage/cards/f/FoulEmissary.java @@ -1,20 +1,19 @@ - package mage.cards.f; import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SacrificeSourceTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.EmergeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.FilterCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.token.EldraziHorrorToken; @@ -26,12 +25,6 @@ import mage.game.stack.Spell; */ public final class FoulEmissary extends CardImpl { - private static final FilterCard filter = new FilterCard("a creature card"); - - static { - filter.add(CardType.CREATURE.getPredicate()); - } - public FoulEmissary(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); this.subtype.add(SubType.HUMAN); @@ -40,7 +33,8 @@ public final class FoulEmissary extends CardImpl { this.toughness = new MageInt(1); // When Foul Emissary enters the battlefield, look at the top four cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in any order. - this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect(StaticValue.get(4), false, StaticValue.get(1), filter, false))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 4, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_ANY))); // When you sacrifice Foul Emissary while casting a spell with emerge, create a 3/2 colorless Eldrazi Horror creature token. this.addAbility(new FoulEmissaryTriggeredAbility(new CreateTokenEffect(new EldraziHorrorToken()), false)); diff --git a/Mage.Sets/src/mage/cards/f/FourthBridgeProwler.java b/Mage.Sets/src/mage/cards/f/FourthBridgeProwler.java index 12f1e809726..8c7ea0c9779 100644 --- a/Mage.Sets/src/mage/cards/f/FourthBridgeProwler.java +++ b/Mage.Sets/src/mage/cards/f/FourthBridgeProwler.java @@ -1,21 +1,18 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class FourthBridgeProwler extends CardImpl { @@ -29,9 +26,8 @@ public final class FourthBridgeProwler extends CardImpl { this.toughness = new MageInt(1); // When Fourth Bridge Prowler enters the battlefield, you may have target creature get -1/-1 until end of turn. - Effect effect = new BoostTargetEffect(-1, -1, Duration.EndOfTurn); - effect.setText("have target creature get -1/-1 until end of turn"); - Ability ability = new EntersBattlefieldTriggeredAbility(effect, true); + Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-1, -1) + .setText("you may have target creature get -1/-1 until end of turn"), true); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FracturedPowerstone.java b/Mage.Sets/src/mage/cards/f/FracturedPowerstone.java new file mode 100644 index 00000000000..cdb580f992c --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FracturedPowerstone.java @@ -0,0 +1,80 @@ +package mage.cards.f; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.abilities.Abilities; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.game.command.CommandObject; +import mage.game.command.Plane; +import mage.game.stack.StackAbility; +import mage.watchers.common.PlanarRollWatcher; + +public final class FracturedPowerstone extends CardImpl { + + public FracturedPowerstone(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + + // {tap}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + // {tap}: Add roll planar die. + Ability ability = new ActivateAsSorceryActivatedAbility( + new FracturedPowerstoneEffect(), new TapSourceCost() + ); + this.addAbility(ability); + } + + public FracturedPowerstone(final FracturedPowerstone card) { + super(card); + } + + @Override + public FracturedPowerstone copy() { + return new FracturedPowerstone(this); + } +} + +class FracturedPowerstoneEffect extends OneShotEffect { + + FracturedPowerstoneEffect() { + super(Outcome.Benefit); + staticText = "Roll the planar"; + } + + private FracturedPowerstoneEffect(final FracturedPowerstoneEffect effect) { + super(effect); + } + + @Override + public FracturedPowerstoneEffect copy() { + return new FracturedPowerstoneEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for(CommandObject commandObject : game.getState().getCommand()){ + if(commandObject instanceof Plane){ + Abilities abilities = commandObject.getAbilities(); + for(Ability ability : abilities){ + if(ability instanceof ActivateIfConditionActivatedAbility){ + StackAbility stackAbility = new StackAbility(ability,game.getActivePlayerId()); + stackAbility.createCopyOnStack(game, source, source.getControllerId(), true); + + PlanarRollWatcher watcher = game.getState().getWatcher(PlanarRollWatcher.class); + watcher.removePlanarDieRoll(game.getActivePlayerId()); + return true; + } + } + } + } + return false; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/FracturingGust.java b/Mage.Sets/src/mage/cards/f/FracturingGust.java index 35a58aa0eba..f0fad487032 100644 --- a/Mage.Sets/src/mage/cards/f/FracturingGust.java +++ b/Mage.Sets/src/mage/cards/f/FracturingGust.java @@ -62,7 +62,7 @@ class FracturingGustDestroyEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { int destroyedPermanents = 0; - for (Permanent permanent: game.getState().getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent: game.getState().getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (permanent.destroy(source, game, false)) { ++destroyedPermanents; } diff --git a/Mage.Sets/src/mage/cards/f/FranticPurification.java b/Mage.Sets/src/mage/cards/f/FranticPurification.java index 6d785afd5a3..e7f53c1e4de 100644 --- a/Mage.Sets/src/mage/cards/f/FranticPurification.java +++ b/Mage.Sets/src/mage/cards/f/FranticPurification.java @@ -25,7 +25,7 @@ public final class FranticPurification extends CardImpl { this.getSpellAbility().addTarget(new TargetEnchantmentPermanent()); // Madness {W} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{W}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{W}"))); } private FranticPurification(final FranticPurification card) { diff --git a/Mage.Sets/src/mage/cards/f/FrayingOmnipotence.java b/Mage.Sets/src/mage/cards/f/FrayingOmnipotence.java index 4c68897da8b..63c6e8a7236 100644 --- a/Mage.Sets/src/mage/cards/f/FrayingOmnipotence.java +++ b/Mage.Sets/src/mage/cards/f/FrayingOmnipotence.java @@ -89,7 +89,7 @@ class FrayingOmnipotenceEffect extends OneShotEffect { continue; } FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - int creaturesToSacrifice = (int) Math.ceil(game.getBattlefield().count(filter, source.getSourceId(), player.getId(), game) / 2.0); + int creaturesToSacrifice = (int) Math.ceil(game.getBattlefield().count(filter, player.getId(), source, game) / 2.0); if (creaturesToSacrifice == 0) { continue; } diff --git a/Mage.Sets/src/mage/cards/f/FreeForAll.java b/Mage.Sets/src/mage/cards/f/FreeForAll.java index c82f5d67618..630f6bc995c 100644 --- a/Mage.Sets/src/mage/cards/f/FreeForAll.java +++ b/Mage.Sets/src/mage/cards/f/FreeForAll.java @@ -73,7 +73,7 @@ class FreeForAllExileAllEffect extends OneShotEffect { } Cards cards = new CardsImpl(); game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game + StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game ).stream().forEach(cards::add); player.moveCardsToExile(cards.getCards(game), source, game, false, CardUtil.getExileZoneId(game, source), CardUtil.getSourceName(game, source)); cards.getCards(game) diff --git a/Mage.Sets/src/mage/cards/f/FreelanceMuscle.java b/Mage.Sets/src/mage/cards/f/FreelanceMuscle.java new file mode 100644 index 00000000000..3873f10494d --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FreelanceMuscle.java @@ -0,0 +1,89 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksOrBlocksTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.game.Game; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FreelanceMuscle extends CardImpl { + + private static final Hint hint = new ValueHint( + "Greatest power and/or toughness among other creatures you control", FreelanceMuscleValue.instance + ); + + public FreelanceMuscle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.subtype.add(SubType.RHINO); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever Freelance Muscle attacks or blocks, it gets +X/+X until end of turn, where X is the greatest power and/or toughness among other creatures you control. + this.addAbility(new AttacksOrBlocksTriggeredAbility(new BoostSourceEffect( + FreelanceMuscleValue.instance, FreelanceMuscleValue.instance, + Duration.EndOfTurn, true, "it" + ), false).addHint(hint)); + } + + private FreelanceMuscle(final FreelanceMuscle card) { + super(card); + } + + @Override + public FreelanceMuscle copy() { + return new FreelanceMuscle(this); + } +} + +enum FreelanceMuscleValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, + sourceAbility.getControllerId(), sourceAbility, game + ) + .stream() + .mapToInt(permanent -> Math.max( + permanent.getPower().getValue(), + permanent.getToughness().getValue() + )) + .max() + .orElse(0); + } + + @Override + public FreelanceMuscleValue copy() { + return this; + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return "the greatest power and/or toughness among other creatures you control"; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FreneticSliver.java b/Mage.Sets/src/mage/cards/f/FreneticSliver.java index 49275b38b04..8c33b99f5f8 100644 --- a/Mage.Sets/src/mage/cards/f/FreneticSliver.java +++ b/Mage.Sets/src/mage/cards/f/FreneticSliver.java @@ -77,7 +77,7 @@ class FreneticSliverEffect extends OneShotEffect { return false; } if (player.flipCoin(source, game, true)) { - return new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true).apply(game, source); + return new ExileReturnBattlefieldOwnerNextEndStepSourceEffect().apply(game, source); } else { return perm.sacrifice(source, game); } diff --git a/Mage.Sets/src/mage/cards/f/FreyaliseLlanowarsFury.java b/Mage.Sets/src/mage/cards/f/FreyaliseLlanowarsFury.java index afab8b04b86..b4ea2016cbe 100644 --- a/Mage.Sets/src/mage/cards/f/FreyaliseLlanowarsFury.java +++ b/Mage.Sets/src/mage/cards/f/FreyaliseLlanowarsFury.java @@ -3,7 +3,6 @@ package mage.cards.f; import mage.ObjectColor; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyTargetEffect; @@ -38,7 +37,7 @@ public final class FreyaliseLlanowarsFury extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.FREYALISE); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +2: Create a 1/1 green Elf Druid creature token with "{T}: Add {G}." this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new ElfDruidToken()), 2)); diff --git a/Mage.Sets/src/mage/cards/f/FriendlyFire.java b/Mage.Sets/src/mage/cards/f/FriendlyFire.java index 56e12f1db8b..d9ef0cad56a 100644 --- a/Mage.Sets/src/mage/cards/f/FriendlyFire.java +++ b/Mage.Sets/src/mage/cards/f/FriendlyFire.java @@ -56,7 +56,7 @@ class FriendlyFireEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); if (targetCreature != null) { diff --git a/Mage.Sets/src/mage/cards/f/FromUnderTheFloorboards.java b/Mage.Sets/src/mage/cards/f/FromUnderTheFloorboards.java index f6a97691ec0..396409c86ab 100644 --- a/Mage.Sets/src/mage/cards/f/FromUnderTheFloorboards.java +++ b/Mage.Sets/src/mage/cards/f/FromUnderTheFloorboards.java @@ -26,7 +26,7 @@ public final class FromUnderTheFloorboards extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}{B}"); // Madness {X}{B}{B} (If you discard this card discard it into exile. When you do cast it for its madness cost or put it into your graveyard. - Ability ability = (new MadnessAbility(this, new ManaCostsImpl("{X}{B}{B}"))); + Ability ability = (new MadnessAbility(new ManaCostsImpl("{X}{B}{B}"))); ability.setRuleAtTheTop(true); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/f/FrontlineStrategist.java b/Mage.Sets/src/mage/cards/f/FrontlineStrategist.java index d10a1194f81..37f6112f9ba 100644 --- a/Mage.Sets/src/mage/cards/f/FrontlineStrategist.java +++ b/Mage.Sets/src/mage/cards/f/FrontlineStrategist.java @@ -35,7 +35,7 @@ public final class FrontlineStrategist extends CardImpl { this.toughness = new MageInt(1); // Morph {W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{W}"))); // When Frontline Strategist is turned face up, prevent all combat damage non-Soldier creatures would deal this turn. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new PreventAllDamageByAllPermanentsEffect(filter, Duration.EndOfTurn, true).setText("prevent all combat damage non-Soldier creatures would deal this turn"))); } diff --git a/Mage.Sets/src/mage/cards/f/FrostwebSpider.java b/Mage.Sets/src/mage/cards/f/FrostwebSpider.java index a01f9ecc028..8abb6416750 100644 --- a/Mage.Sets/src/mage/cards/f/FrostwebSpider.java +++ b/Mage.Sets/src/mage/cards/f/FrostwebSpider.java @@ -3,7 +3,7 @@ package mage.cards.f; import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; @@ -16,13 +16,8 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; import mage.counters.CounterType; -import mage.constants.Zone; -import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; /** * * @author L_J @@ -48,7 +43,7 @@ public final class FrostwebSpider extends CardImpl { // Whenever Frostweb Spider blocks a creature with flying, put a +1/+1 counter on Frostweb Spider at end of combat. Effect effect = new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())), true); effect.setText("put a +1/+1 counter on {this} at end of combat"); - this.addAbility(new FrostwebSpiderTriggeredAbility(effect, filter, false)); + this.addAbility(new BlocksCreatureTriggeredAbility(effect, filter,false)); } private FrostwebSpider(final FrostwebSpider card) { @@ -59,45 +54,4 @@ public final class FrostwebSpider extends CardImpl { public FrostwebSpider copy() { return new FrostwebSpider(this); } -} - -class FrostwebSpiderTriggeredAbility extends TriggeredAbilityImpl { - - protected FilterPermanent filter; - - public FrostwebSpiderTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional) { - super(Zone.BATTLEFIELD, effect, optional); - this.filter = filter; - } - - public FrostwebSpiderTriggeredAbility(final FrostwebSpiderTriggeredAbility ability) { - super(ability); - this.filter = ability.filter; - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.BLOCKER_DECLARED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getSourceId().equals(this.getSourceId())) { - Permanent blocked = game.getPermanent(event.getTargetId()); - if (blocked != null && filter.match(blocked, game)) { - return true; - } - } - return false; - } - - @Override - public String getTriggerPhrase() { - return "Whenever {this} blocks a " + filter.getMessage() + ", " ; - } - - @Override - public FrostwebSpiderTriggeredAbility copy() { - return new FrostwebSpiderTriggeredAbility(this); - } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/FrostwindInvoker.java b/Mage.Sets/src/mage/cards/f/FrostwindInvoker.java index 7c73994e83a..71cc4f55c66 100644 --- a/Mage.Sets/src/mage/cards/f/FrostwindInvoker.java +++ b/Mage.Sets/src/mage/cards/f/FrostwindInvoker.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -10,18 +8,19 @@ import mage.abilities.keyword.FlyingAbility; 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.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author North */ public final class FrostwindInvoker extends CardImpl { public FrostwindInvoker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); this.subtype.add(SubType.MERFOLK); this.subtype.add(SubType.WIZARD); @@ -29,7 +28,10 @@ public final class FrostwindInvoker extends CardImpl { this.toughness = new MageInt(3); this.addAbility(FlyingAbility.getInstance()); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{8}"))); + this.addAbility(new SimpleActivatedAbility(new GainAbilityControlledEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURES + ), new ManaCostsImpl<>("{8}"))); } private FrostwindInvoker(final FrostwindInvoker card) { @@ -41,4 +43,3 @@ public final class FrostwindInvoker extends CardImpl { return new FrostwindInvoker(this); } } - diff --git a/Mage.Sets/src/mage/cards/f/Fumble.java b/Mage.Sets/src/mage/cards/f/Fumble.java index c5d056b86b1..1d0cbd6eed3 100644 --- a/Mage.Sets/src/mage/cards/f/Fumble.java +++ b/Mage.Sets/src/mage/cards/f/Fumble.java @@ -86,7 +86,7 @@ class FumbleEffect extends OneShotEffect { if (!attachments.isEmpty()) { Target target = new TargetCreaturePermanent(1, 1, StaticFilters.FILTER_PERMANENT_CREATURE, true); Permanent newCreature = null; - if (player.choose(Outcome.BoostCreature, target, source.getSourceId(), game)) { + if (player.choose(Outcome.BoostCreature, target, source, game)) { newCreature = game.getPermanent(target.getFirstTarget()); } for (Permanent attachment : attachments) { diff --git a/Mage.Sets/src/mage/cards/f/FumikoTheLowblood.java b/Mage.Sets/src/mage/cards/f/FumikoTheLowblood.java index 7f70d0ed82a..83efa4ea841 100644 --- a/Mage.Sets/src/mage/cards/f/FumikoTheLowblood.java +++ b/Mage.Sets/src/mage/cards/f/FumikoTheLowblood.java @@ -1,4 +1,3 @@ - package mage.cards.f; import java.util.UUID; @@ -12,10 +11,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.TargetController; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; -import mage.watchers.common.AttackedThisTurnWatcher; +import mage.filter.StaticFilters; /** * @@ -35,11 +31,8 @@ public final class FumikoTheLowblood extends CardImpl { // Fumiko the Lowblood has bushido X, where X is the number of attacking creatures. this.addAbility(new BushidoAbility(new AttackingCreatureCount("the number of attacking creatures."))); - // Creatures your opponents control attack each turn if able. - FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); - filter.add(TargetController.OPPONENT.getControllerPredicate()); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AttacksIfAbleAllEffect(filter)), new AttackedThisTurnWatcher()); - + // Creatures your opponents control attack each combat if able. + this.addAbility(new SimpleStaticAbility(new AttacksIfAbleAllEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES))); } private FumikoTheLowblood(final FumikoTheLowblood card) { diff --git a/Mage.Sets/src/mage/cards/f/FuneralCharm.java b/Mage.Sets/src/mage/cards/f/FuneralCharm.java index 486604b45cf..3f2877d48f4 100644 --- a/Mage.Sets/src/mage/cards/f/FuneralCharm.java +++ b/Mage.Sets/src/mage/cards/f/FuneralCharm.java @@ -27,12 +27,10 @@ public final class FuneralCharm extends CardImpl { // Choose one - Target player discards a card; or target creature gets +2/-1 until end of turn; or target creature gains swampwalk until end of turn. this.getSpellAbility().addEffect(new DiscardTargetEffect(1)); this.getSpellAbility().addTarget(new TargetPlayer()); - Mode mode = new Mode(); - mode.addEffect(new BoostTargetEffect(2, -1, Duration.EndOfTurn)); + Mode mode = new Mode(new BoostTargetEffect(2, -1, Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); - mode = new Mode(); - mode.addEffect(new GainAbilityTargetEffect(new SwampwalkAbility(), Duration.EndOfTurn)); + mode = new Mode(new GainAbilityTargetEffect(new SwampwalkAbility(), Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FuneralRites.java b/Mage.Sets/src/mage/cards/f/FuneralRites.java index 133370fa9b7..7c12689b3a0 100644 --- a/Mage.Sets/src/mage/cards/f/FuneralRites.java +++ b/Mage.Sets/src/mage/cards/f/FuneralRites.java @@ -23,7 +23,7 @@ public final class FuneralRites extends CardImpl { this.getSpellAbility().addEffect(new LoseLifeSourceControllerEffect(2) .setText(", lose 2 life")); this.getSpellAbility().addEffect(new MillCardsControllerEffect(2) - .concatBy(", and")); + .concatBy(", then")); } private FuneralRites(final FuneralRites card) { diff --git a/Mage.Sets/src/mage/cards/f/FungalBehemoth.java b/Mage.Sets/src/mage/cards/f/FungalBehemoth.java index 5da28803c9b..67548726576 100644 --- a/Mage.Sets/src/mage/cards/f/FungalBehemoth.java +++ b/Mage.Sets/src/mage/cards/f/FungalBehemoth.java @@ -115,6 +115,6 @@ class P1P1CountersOnControlledCreaturesCount implements DynamicValue { @Override public String getMessage() { - return "the number of +1/+1 counters on creatures you control"; + return "+1/+1 counters on creatures you control"; } } diff --git a/Mage.Sets/src/mage/cards/f/FuryCharm.java b/Mage.Sets/src/mage/cards/f/FuryCharm.java index 3092a53eb23..e45e5c2fcba 100644 --- a/Mage.Sets/src/mage/cards/f/FuryCharm.java +++ b/Mage.Sets/src/mage/cards/f/FuryCharm.java @@ -48,19 +48,17 @@ public final class FuryCharm extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetArtifactPermanent()); // or target creature gets +1/+1 and gains trample until end of turn; - Mode mode = new Mode(); Effect effect = new BoostTargetEffect(1,1, Duration.EndOfTurn); effect.setText("target creature gets +1/+1"); - mode.addEffect(effect); + Mode mode = new Mode(effect); effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(),Duration.EndOfTurn); effect.setText("and gains trample until end of turn"); mode.addEffect(effect); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().getModes().addMode(mode); // or remove two time counters from target permanent or suspended card. - mode = new Mode(); + mode = new Mode(new FuryCharmRemoveCounterEffect()); mode.addTarget(new TargetPermanentOrSuspendedCard()); - mode.addEffect(new FuryCharmRemoveCounterEffect()); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FurySliver.java b/Mage.Sets/src/mage/cards/f/FurySliver.java index 0a1c2188ca6..e29441344e9 100644 --- a/Mage.Sets/src/mage/cards/f/FurySliver.java +++ b/Mage.Sets/src/mage/cards/f/FurySliver.java @@ -30,7 +30,7 @@ public final class FurySliver extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield, - StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS + StaticFilters.FILTER_PERMANENT_ALL_SLIVERS ) )); } diff --git a/Mage.Sets/src/mage/cards/g/GaeasMight.java b/Mage.Sets/src/mage/cards/g/GaeasMight.java index 43338fa1f82..1f89d9ea4de 100644 --- a/Mage.Sets/src/mage/cards/g/GaeasMight.java +++ b/Mage.Sets/src/mage/cards/g/GaeasMight.java @@ -22,7 +22,7 @@ public final class GaeasMight extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}"); // Domain - Target creature gets +1/+1 until end of turn for each basic land type among lands you control. - this.getSpellAbility().addEffect(new BoostTargetEffect(new DomainValue(), new DomainValue(), Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new BoostTargetEffect(DomainValue.REGULAR, DomainValue.REGULAR, Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().setAbilityWord(AbilityWord.DOMAIN); this.getSpellAbility().addHint(DomainHint.instance); diff --git a/Mage.Sets/src/mage/cards/g/GaeasWill.java b/Mage.Sets/src/mage/cards/g/GaeasWill.java index 3ef6828f21c..b8deee17ab3 100644 --- a/Mage.Sets/src/mage/cards/g/GaeasWill.java +++ b/Mage.Sets/src/mage/cards/g/GaeasWill.java @@ -30,7 +30,7 @@ public final class GaeasWill extends CardImpl { this.color.setGreen(true); // Suspend 4—{G} - this.addAbility(new SuspendAbility(4, new ManaCostsImpl<>("G"), this)); + this.addAbility(new SuspendAbility(4, new ManaCostsImpl<>("{G}"), this)); // Until end of turn, you may play land cards and cast spells from your graveyard. this.getSpellAbility().addEffect(new GaeasWillGraveyardEffect()); diff --git a/Mage.Sets/src/mage/cards/g/GalaGreeters.java b/Mage.Sets/src/mage/cards/g/GalaGreeters.java new file mode 100644 index 00000000000..fe9dc63d303 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GalaGreeters.java @@ -0,0 +1,54 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.AllianceAbility; +import mage.abilities.effects.common.CreateTokenEffect; +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.counters.CounterType; +import mage.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GalaGreeters extends CardImpl { + + public GalaGreeters(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Alliance — Whenever another creature enters the battlefield under your control, choose one that hasn't been chosen this turn— + // • Put a +1/+1 counter on Gala Greeters. + Ability ability = new AllianceAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())); + ability.getModes().setEachModeOnlyOnce(true); + ability.getModes().setResetEachTurn(true); + + // • Create a tapped Treasure token. + ability.addMode(new Mode(new CreateTokenEffect(new TreasureToken(), 1, true, false))); + + // • You gain 2 life. + ability.addMode(new Mode(new GainLifeEffect(2))); + this.addAbility(ability); + } + + private GalaGreeters(final GalaGreeters card) { + super(card); + } + + @Override + public GalaGreeters copy() { + return new GalaGreeters(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GalepowderMage.java b/Mage.Sets/src/mage/cards/g/GalepowderMage.java index 8aecee8b049..7cd3bbcc429 100644 --- a/Mage.Sets/src/mage/cards/g/GalepowderMage.java +++ b/Mage.Sets/src/mage/cards/g/GalepowderMage.java @@ -82,7 +82,7 @@ class GalepowderMageEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { if (getTargetPointer().getFirst(game, source) != null) { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); diff --git a/Mage.Sets/src/mage/cards/g/GaleriderSliver.java b/Mage.Sets/src/mage/cards/g/GaleriderSliver.java index 9d6f32bbbfb..4992ac5c565 100644 --- a/Mage.Sets/src/mage/cards/g/GaleriderSliver.java +++ b/Mage.Sets/src/mage/cards/g/GaleriderSliver.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -9,13 +7,13 @@ import mage.abilities.keyword.FlyingAbility; 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.constants.SubType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class GaleriderSliver extends CardImpl { @@ -28,9 +26,10 @@ public final class GaleriderSliver extends CardImpl { this.toughness = new MageInt(1); // Sliver creatures you control have flying. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new GainAbilityControlledEffect(FlyingAbility.getInstance(), - Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS))); + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + FlyingAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_SLIVERS + ))); } private GaleriderSliver(final GaleriderSliver card) { diff --git a/Mage.Sets/src/mage/cards/g/GalvanicBombardment.java b/Mage.Sets/src/mage/cards/g/GalvanicBombardment.java index e4a7041c787..319645a2568 100644 --- a/Mage.Sets/src/mage/cards/g/GalvanicBombardment.java +++ b/Mage.Sets/src/mage/cards/g/GalvanicBombardment.java @@ -64,7 +64,7 @@ class GalvanicBombardmentCardsInControllerGraveyardCount implements DynamicValue int amount = 0; Player controller = game.getPlayer(sourceAbility.getControllerId()); if (controller != null) { - amount += controller.getGraveyard().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + amount += controller.getGraveyard().count(filter, sourceAbility.getControllerId(), sourceAbility, game); } return amount + 2; } diff --git a/Mage.Sets/src/mage/cards/g/GargoyleSentinel.java b/Mage.Sets/src/mage/cards/g/GargoyleSentinel.java index 91acc1a4865..5698e3cf249 100644 --- a/Mage.Sets/src/mage/cards/g/GargoyleSentinel.java +++ b/Mage.Sets/src/mage/cards/g/GargoyleSentinel.java @@ -1,20 +1,20 @@ - - package mage.cards.g; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.continuous.LoseAbilitySourceEffect; import mage.abilities.keyword.DefenderAbility; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; /** * @@ -29,7 +29,15 @@ public final class GargoyleSentinel extends CardImpl { this.toughness = new MageInt(3); this.addAbility(DefenderAbility.getInstance()); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GargoyleSentinelEffect(), new ManaCostsImpl("{3}"))); + + // {3}: Until end of turn, Gargoyle Sentinel loses defender and gains flying. + Effect effect = new LoseAbilitySourceEffect(DefenderAbility.getInstance(), Duration.EndOfTurn); + effect.setText("until end of turn, {this} loses defender"); + Ability ability = new SimpleActivatedAbility(effect, new GenericManaCost(3)); + effect = new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn); + effect.setText("and gains flying"); + ability.addEffect(effect); + this.addAbility(ability); } private GargoyleSentinel(final GargoyleSentinel card) { @@ -40,50 +48,4 @@ public final class GargoyleSentinel extends CardImpl { public GargoyleSentinel copy() { return new GargoyleSentinel(this); } - -} - -class GargoyleSentinelEffect extends ContinuousEffectImpl { - - public GargoyleSentinelEffect() { - super(Duration.EndOfTurn, Outcome.AddAbility); - staticText = "Until end of turn, {this} loses defender and gains flying"; - } - - public GargoyleSentinelEffect(final GargoyleSentinelEffect effect) { - super(effect); - } - - @Override - public GargoyleSentinelEffect copy() { - return new GargoyleSentinelEffect(this); - } - - @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - switch (layer) { - case AbilityAddingRemovingEffects_6: - if (sublayer == SubLayer.NA) { - permanent.removeAbility(DefenderAbility.getInstance(), source.getSourceId(), game); - permanent.getAbilities().add(FlyingAbility.getInstance()); - } - break; - } - return true; - } - return false; - } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } - - @Override - public boolean hasLayer(Layer layer) { - return layer == Layer.AbilityAddingRemovingEffects_6; - } - } diff --git a/Mage.Sets/src/mage/cards/g/GarrukApexPredator.java b/Mage.Sets/src/mage/cards/g/GarrukApexPredator.java index dbdfb814733..d5972b7ea95 100644 --- a/Mage.Sets/src/mage/cards/g/GarrukApexPredator.java +++ b/Mage.Sets/src/mage/cards/g/GarrukApexPredator.java @@ -2,7 +2,6 @@ package mage.cards.g; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; @@ -44,7 +43,7 @@ public final class GarrukApexPredator extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.GARRUK); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Destroy another target planeswalker. LoyaltyAbility ability = new LoyaltyAbility(new DestroyTargetEffect(), 1); diff --git a/Mage.Sets/src/mage/cards/g/GarrukCallerOfBeasts.java b/Mage.Sets/src/mage/cards/g/GarrukCallerOfBeasts.java index 85060e3b69c..1293041c4f5 100644 --- a/Mage.Sets/src/mage/cards/g/GarrukCallerOfBeasts.java +++ b/Mage.Sets/src/mage/cards/g/GarrukCallerOfBeasts.java @@ -4,7 +4,6 @@ package mage.cards.g; import java.util.UUID; import mage.ObjectColor; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect; import mage.abilities.effects.common.RevealLibraryPutIntoHandEffect; @@ -35,7 +34,7 @@ public final class GarrukCallerOfBeasts extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.GARRUK); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Reveal the top 5 cards of your library. Put all creature cards revealed this way into your hand and the rest on the bottom of your library in any order. this.addAbility(new LoyaltyAbility(new RevealLibraryPutIntoHandEffect(5, new FilterCreatureCard("creature cards"), Zone.LIBRARY), 1)); diff --git a/Mage.Sets/src/mage/cards/g/GarrukCursedHuntsman.java b/Mage.Sets/src/mage/cards/g/GarrukCursedHuntsman.java index fbd0483c5a0..e16b41871b3 100644 --- a/Mage.Sets/src/mage/cards/g/GarrukCursedHuntsman.java +++ b/Mage.Sets/src/mage/cards/g/GarrukCursedHuntsman.java @@ -2,7 +2,6 @@ package mage.cards.g; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -28,7 +27,7 @@ public final class GarrukCursedHuntsman extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.GARRUK); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // 0: Create two 2/2 black and green Wolf creature tokens with "When this creature dies, put a loyalty counter on each Garruk you control." this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new GarrukCursedHuntsmanToken(), 2), 0)); diff --git a/Mage.Sets/src/mage/cards/g/GarrukPrimalHunter.java b/Mage.Sets/src/mage/cards/g/GarrukPrimalHunter.java index 5ce38d35bfb..c31694f980e 100644 --- a/Mage.Sets/src/mage/cards/g/GarrukPrimalHunter.java +++ b/Mage.Sets/src/mage/cards/g/GarrukPrimalHunter.java @@ -4,7 +4,6 @@ package mage.cards.g; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; @@ -36,7 +35,7 @@ public final class GarrukPrimalHunter extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.GARRUK); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Create a 3/3 green Beast creature token. this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new BeastToken()), 1)); diff --git a/Mage.Sets/src/mage/cards/g/GarrukRelentless.java b/Mage.Sets/src/mage/cards/g/GarrukRelentless.java index 1ac3ece0df2..f81ee1874a0 100644 --- a/Mage.Sets/src/mage/cards/g/GarrukRelentless.java +++ b/Mage.Sets/src/mage/cards/g/GarrukRelentless.java @@ -4,7 +4,6 @@ package mage.cards.g; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.StateTriggeredAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; @@ -33,7 +32,7 @@ public final class GarrukRelentless extends CardImpl { this.secondSideCardClazz = GarrukTheVeilCursed.class; - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // When Garruk Relentless has two or fewer loyalty counters on him, transform him. this.addAbility(new TransformAbility()); diff --git a/Mage.Sets/src/mage/cards/g/GarrukSavageHerald.java b/Mage.Sets/src/mage/cards/g/GarrukSavageHerald.java index d668ae3abea..efa4203c131 100644 --- a/Mage.Sets/src/mage/cards/g/GarrukSavageHerald.java +++ b/Mage.Sets/src/mage/cards/g/GarrukSavageHerald.java @@ -3,7 +3,6 @@ package mage.cards.g; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.DamageAsThoughNotBlockedAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -39,7 +38,7 @@ public final class GarrukSavageHerald extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.GARRUK); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Reveal the top card of your library. If it's a creature card, put it into your hand. Otherwise, put it on the bottom of your library. this.addAbility(new LoyaltyAbility(new GarrukSavageHeraldEffect(), 1)); diff --git a/Mage.Sets/src/mage/cards/g/GarrukUnleashed.java b/Mage.Sets/src/mage/cards/g/GarrukUnleashed.java index 44e56a1345d..6ec137afbc6 100644 --- a/Mage.Sets/src/mage/cards/g/GarrukUnleashed.java +++ b/Mage.Sets/src/mage/cards/g/GarrukUnleashed.java @@ -1,7 +1,6 @@ package mage.cards.g; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.condition.common.OpponentControlsMoreCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.Effect; @@ -36,7 +35,7 @@ public final class GarrukUnleashed extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.GARRUK); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Up to one target creature gets +3/+3 and gains trample until end of turn. Effect effect = new BoostTargetEffect(3, 3, Duration.EndOfTurn) diff --git a/Mage.Sets/src/mage/cards/g/GarrukWildspeaker.java b/Mage.Sets/src/mage/cards/g/GarrukWildspeaker.java index c6a719311f9..fae4c36f535 100644 --- a/Mage.Sets/src/mage/cards/g/GarrukWildspeaker.java +++ b/Mage.Sets/src/mage/cards/g/GarrukWildspeaker.java @@ -3,7 +3,6 @@ package mage.cards.g; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; import mage.abilities.effects.common.CreateTokenEffect; @@ -34,7 +33,7 @@ public final class GarrukWildspeaker extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.GARRUK); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Untap two target lands. LoyaltyAbility ability1 = new LoyaltyAbility(new UntapTargetEffect(), 1); diff --git a/Mage.Sets/src/mage/cards/g/GarruksHarbinger.java b/Mage.Sets/src/mage/cards/g/GarruksHarbinger.java index 1d21b265a21..76aa2ff778f 100644 --- a/Mage.Sets/src/mage/cards/g/GarruksHarbinger.java +++ b/Mage.Sets/src/mage/cards/g/GarruksHarbinger.java @@ -1,20 +1,17 @@ package mage.cards.g; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.HexproofFromBlackAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; -import mage.game.Game; import java.util.UUID; @@ -24,9 +21,20 @@ import java.util.UUID; */ public final class GarruksHarbinger extends CardImpl { + private static final FilterCard filter = new FilterCard("creature card or Garruk planeswalker card"); + static { + filter.add(Predicates.or( + CardType.CREATURE.getPredicate(), + Predicates.and( + CardType.PLANESWALKER.getPredicate(), + SubType.GARRUK.getPredicate() + ) + )); + } + public GarruksHarbinger(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{G}"); - + this.subtype.add(SubType.BEAST); this.power = new MageInt(4); this.toughness = new MageInt(3); @@ -34,11 +42,12 @@ public final class GarruksHarbinger extends CardImpl { // Hexproof from Black this.addAbility(HexproofFromBlackAbility.getInstance()); - // Whenever Garruk's Harbinger deals combat damage to a player or planeswalker, look at that many cards from the top of your library. You may reveal a creature card or Garruk planeswalker card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. - this.addAbility( - new DealsCombatDamageToAPlayerTriggeredAbility(new GarruksHarbingerEffect(), false, true) - .setOrPlaneswalker(true) - ); + // Whenever Garruk's Harbinger deals combat damage to a player or planeswalker, look at that many cards from the top of your library. + // You may reveal a creature card or Garruk planeswalker card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new LookLibraryAndPickControllerEffect(SavedDamageValue.MANY, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM), + false, true).setOrPlaneswalker(true)); } private GarruksHarbinger(final GarruksHarbinger card) { @@ -50,37 +59,3 @@ public final class GarruksHarbinger extends CardImpl { return new GarruksHarbinger(this); } } - -class GarruksHarbingerEffect extends OneShotEffect { - - private static final FilterCard filter = new FilterCard("a creature or Garruk planeswalker card"); - - static { - filter.add(Predicates.or(CardType.CREATURE.getPredicate(), Predicates.and(CardType.PLANESWALKER.getPredicate(), SubType.GARRUK.getPredicate()))); - } - - GarruksHarbingerEffect() { - super(Outcome.Benefit); - staticText = "look at that many cards from the top of your library. You may reveal a creature card or Garruk planeswalker card from among them and put it into your hand. Put the rest on the bottom of your library in a random order"; - } - - private GarruksHarbingerEffect(GarruksHarbingerEffect effect) { - super(effect); - } - - @Override - public GarruksHarbingerEffect copy() { - return new GarruksHarbingerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Integer damage = (Integer) getValue("damage"); - if (damage != null) { - LookLibraryAndPickControllerEffect effect = new LookLibraryAndPickControllerEffect(StaticValue.get(damage), false, StaticValue.get(1), filter, false); - effect.setBackInRandomOrder(true); - return effect.apply(game, source); - } - return false; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GatewayShade.java b/Mage.Sets/src/mage/cards/g/GatewayShade.java index 5112bcf88db..de34de52f0f 100644 --- a/Mage.Sets/src/mage/cards/g/GatewayShade.java +++ b/Mage.Sets/src/mage/cards/g/GatewayShade.java @@ -37,7 +37,7 @@ public final class GatewayShade extends CardImpl { this.toughness = new MageInt(1); // {B}: Gateway Shade gets +1/+1 until end of turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1,1, Duration.EndOfTurn),new ManaCostsImpl("{B"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1,1, Duration.EndOfTurn),new ManaCostsImpl("{B}"))); // Tap an untapped Gate you control: Gateway Shade gets +2/+2 until end of turn. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(2,2, Duration.EndOfTurn),new TapTargetCost(new TargetControlledPermanent(1,1,filter, true)))); diff --git a/Mage.Sets/src/mage/cards/g/GathanRaiders.java b/Mage.Sets/src/mage/cards/g/GathanRaiders.java index c5e1678b598..7436c391235 100644 --- a/Mage.Sets/src/mage/cards/g/GathanRaiders.java +++ b/Mage.Sets/src/mage/cards/g/GathanRaiders.java @@ -35,7 +35,7 @@ public final class GathanRaiders extends CardImpl { new BoostSourceEffect(2,2,Duration.WhileOnBattlefield), HellbentCondition.instance, "Hellbent — {this} gets +2/+2 as long as you have no cards in hand"))); // Morph-Discard a card. - this.addAbility(new MorphAbility(this, new DiscardCardCost())); + this.addAbility(new MorphAbility(new DiscardCardCost())); } private GathanRaiders(final GathanRaiders card) { diff --git a/Mage.Sets/src/mage/cards/g/GatherThePack.java b/Mage.Sets/src/mage/cards/g/GatherThePack.java index 90c9164598c..f5a462cbe3e 100644 --- a/Mage.Sets/src/mage/cards/g/GatherThePack.java +++ b/Mage.Sets/src/mage/cards/g/GatherThePack.java @@ -1,35 +1,37 @@ package mage.cards.g; import java.util.UUID; -import mage.MageObject; -import mage.abilities.Ability; import mage.abilities.condition.common.SpellMasteryCondition; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.effects.common.RevealLibraryPickControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.constants.AbilityWord; 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.TargetCard; /** * - * @author LevelX2 + * @author awjackson */ public final class GatherThePack extends CardImpl { + private static final String rule = "Reveal the top five cards of your library. " + + "You may put a creature card from among them into your hand. Put the rest into your graveyard.
" + + AbilityWord.SPELL_MASTERY.formatWord() + "If " + SpellMasteryCondition.instance.toString() + + ", put up to two creature cards from among the revealed cards into your hand instead of one"; + public GatherThePack(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); // Reveal the top five cards of your library. You may put a creature card from among them into your hand. Put the rest into your graveyard. // Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, put up to two creature cards from among the revealed cards into your hand instead of one. - this.getSpellAbility().addEffect(new GatherThePackEffect()); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new RevealLibraryPickControllerEffect(5, 2, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.GRAVEYARD), + new RevealLibraryPickControllerEffect(5, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.GRAVEYARD), + SpellMasteryCondition.instance, rule + )); } private GatherThePack(final GatherThePack card) { @@ -41,53 +43,3 @@ public final class GatherThePack extends CardImpl { return new GatherThePack(this); } } - -class GatherThePackEffect extends OneShotEffect { - - public GatherThePackEffect(final GatherThePackEffect effect) { - super(effect); - } - - public GatherThePackEffect() { - super(Outcome.PutCreatureInPlay); - this.staticText = "Reveal the top five cards of your library. You may put a creature card from among them into your hand. Put the rest into your graveyard." - + "
Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, put up to two creature cards from among the revealed cards into your hand instead of one"; - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (controller == null || sourceObject == null) { - return false; - } - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5)); - if (!cards.isEmpty()) { - controller.revealCards(sourceObject.getIdName(), cards, game); - int creatures = cards.count(StaticFilters.FILTER_CARD_CREATURE, source.getSourceId(), source.getControllerId(), game); - if (creatures > 0) { - int max = 1; - if (SpellMasteryCondition.instance.apply(game, source) && creatures > 1) { - max++; - } - TargetCard target = new TargetCard(0, max, Zone.LIBRARY, new FilterCreatureCard("creature card" + (max > 1 ? "s" : "") + " to put into your hand")); - if (controller.choose(Outcome.PutCreatureInPlay, cards, target, game)) { - Cards cardsToHand = new CardsImpl(target.getTargets()); - if (!cardsToHand.isEmpty()) { - cards.removeAll(cardsToHand); - controller.moveCards(cardsToHand, Zone.HAND, source, game); - } - } - } - if (!cards.isEmpty()) { - controller.moveCards(cards, Zone.GRAVEYARD, source, game); - } - } - return true; - } - - @Override - public GatherThePackEffect copy() { - return new GatherThePackEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GatheringThrong.java b/Mage.Sets/src/mage/cards/g/GatheringThrong.java new file mode 100644 index 00000000000..05ea13dd378 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GatheringThrong.java @@ -0,0 +1,50 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GatheringThrong extends CardImpl { + + private static final FilterCard filter = new FilterCard("cards named Gathering Throng"); + + static { + filter.add(new NamePredicate("Gathering Throng")); + } + + public GatheringThrong(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // When Gathering Throng enters the battlefield, you may search your library for any number of cards named Gathering Throng, reveal them, put them into your hand, then shuffle. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect( + new TargetCardInLibrary(0, Integer.MAX_VALUE, filter), true, true + ), true)); + } + + private GatheringThrong(final GatheringThrong card) { + super(card); + } + + @Override + public GatheringThrong copy() { + return new GatheringThrong(this); + } +} +// nothing to see here, folks diff --git a/Mage.Sets/src/mage/cards/g/GauntletsOfChaos.java b/Mage.Sets/src/mage/cards/g/GauntletsOfChaos.java index 62b186cb372..00b45620169 100644 --- a/Mage.Sets/src/mage/cards/g/GauntletsOfChaos.java +++ b/Mage.Sets/src/mage/cards/g/GauntletsOfChaos.java @@ -83,13 +83,13 @@ class GauntletsOfChaosFirstTarget extends TargetControlledPermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { // get all cardtypes from opponents permanents - Set cardTypes = getOpponentPermanentCardTypes(sourceId, sourceControllerId, game); + Set cardTypes = getOpponentPermanentCardTypes(source.getSourceId(), sourceControllerId, game); Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); if (targetSource != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { for (CardType type : permanent.getCardType(game)) { if (cardTypes.contains(type)) { @@ -153,12 +153,12 @@ class GauntletsOfChaosSecondTarget extends TargetPermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); if (firstTarget != null) { - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); if (targetSource != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { if (permanent.shareTypes(firstTarget, game)) { possibleTargets.add(permanent.getId()); diff --git a/Mage.Sets/src/mage/cards/g/GavelOfTheRighteous.java b/Mage.Sets/src/mage/cards/g/GavelOfTheRighteous.java new file mode 100644 index 00000000000..7e3b55d1d67 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GavelOfTheRighteous.java @@ -0,0 +1,89 @@ +package mage.cards.g; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.OrCost; +import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.Counter; +import mage.counters.CounterType; +import mage.game.Game; + +import java.util.*; +import java.util.stream.IntStream; + +/** + * @author TheElk801 + */ +public final class GavelOfTheRighteous extends CardImpl { + + private static final DynamicValue xValue = new CountersSourceCount(null); + + public GavelOfTheRighteous(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + this.subtype.add(SubType.EQUIPMENT); + + // At the beginning of combat on your turn, put a charge counter on Gavel of the Righteous. + this.addAbility(new BeginningOfCombatTriggeredAbility( + new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), TargetController.YOU, false + )); + + // Equipped creature gets +1/+1 for each counter on Gavel of the Righteous. + this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(xValue, xValue))); + + // As long as Gavel of the Righteous has four or more counters on it, equipped creature has double strike. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilityAttachedEffect(DoubleStrikeAbility.getInstance(), AttachmentType.EQUIPMENT), + GavelOfTheRighteousCondition.instance, "as long as {this} has four " + + "or more counters on it, equipped creature has double strike" + ))); + + // Equip—Pay {3} or remove a counter from Gavel of the Righteous. + this.addAbility(new EquipAbility( + Outcome.BoostCreature, + new OrCost( + "Pay {3} or remove a counter from {this}", + new GenericManaCost(3), new RemoveCountersSourceCost() + ) + )); + } + + private GavelOfTheRighteous(final GavelOfTheRighteous card) { + super(card); + } + + @Override + public GavelOfTheRighteous copy() { + return new GavelOfTheRighteous(this); + } +} + +enum GavelOfTheRighteousCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return Optional.of(source.getSourcePermanentIfItStillExists(game)) + .filter(Objects::nonNull) + .map(permanent -> permanent.getCounters(game)) + .map(HashMap::values) + .map(Collection::stream) + .map(x -> x.mapToInt(Counter::getCount)) + .map(IntStream::sum) + .orElse(0) >= 4; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GavonyDawnguard.java b/Mage.Sets/src/mage/cards/g/GavonyDawnguard.java index 88f5cce5f93..9042e4536ad 100644 --- a/Mage.Sets/src/mage/cards/g/GavonyDawnguard.java +++ b/Mage.Sets/src/mage/cards/g/GavonyDawnguard.java @@ -3,16 +3,15 @@ package mage.cards.g; import mage.MageInt; import mage.abilities.common.BecomeDayAsEntersAbility; import mage.abilities.common.BecomesDayOrNightTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.WardAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.ManaValuePredicate; @@ -24,7 +23,7 @@ import java.util.UUID; */ public final class GavonyDawnguard extends CardImpl { - private static final FilterCard filter = new FilterCreatureCard("creature card with mana value 3 or less"); + private static final FilterCard filter = new FilterCreatureCard("a creature card with mana value 3 or less"); static { filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); @@ -39,18 +38,14 @@ public final class GavonyDawnguard extends CardImpl { this.toughness = new MageInt(3); // Ward {1} - this.addAbility(new WardAbility(new ManaCostsImpl<>("{1}"))); + this.addAbility(new WardAbility(new GenericManaCost(1))); // If it's neither day nor night, it becomes day as Gavony Dawnguard enters the battlefield. this.addAbility(new BecomeDayAsEntersAbility()); // Whenever day becomes night or night becomes day, look at the top four cards of your library. You may reveal a creature card with mana value 3 or less from among them and put it into your hand. Put the rest on the bottom of your library in any order. this.addAbility(new BecomesDayOrNightTriggeredAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(1), filter, Zone.LIBRARY, false, - true, false, Zone.HAND, true, false, false - ).setBackInRandomOrder(true).setText("look at the top four cards of your library. " + - "You may reveal a creature card with mana value 3 or less from among them " + - "and put it into your hand. Put the rest on the bottom of your library in any order"))); + 4, 1, filter, PutCards.HAND, PutCards.BOTTOM_ANY))); } private GavonyDawnguard(final GavonyDawnguard card) { diff --git a/Mage.Sets/src/mage/cards/g/GazeOfTheGorgon.java b/Mage.Sets/src/mage/cards/g/GazeOfTheGorgon.java index a8446ec66e0..cc4ac222032 100644 --- a/Mage.Sets/src/mage/cards/g/GazeOfTheGorgon.java +++ b/Mage.Sets/src/mage/cards/g/GazeOfTheGorgon.java @@ -101,7 +101,7 @@ class GazeOfTheGorgonEffect extends OneShotEffect { BlockedAttackerWatcher watcher = game.getState().getWatcher(BlockedAttackerWatcher.class); if (watcher != null) { List toDestroy = new ArrayList<>(); - for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { if (!creature.getId().equals(targetCreature.getSourceId())) { if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), targetCreature, game) || watcher.creatureHasBlockedAttacker(targetCreature, new MageObjectReference(creature, game), game)) { toDestroy.add(creature); diff --git a/Mage.Sets/src/mage/cards/g/GeistlightSnare.java b/Mage.Sets/src/mage/cards/g/GeistlightSnare.java index db17414ca14..812c7523c31 100644 --- a/Mage.Sets/src/mage/cards/g/GeistlightSnare.java +++ b/Mage.Sets/src/mage/cards/g/GeistlightSnare.java @@ -42,6 +42,7 @@ public final class GeistlightSnare extends CardImpl { ).setRuleAtTheTop(true); ability.addEffect(new SpellCostReductionSourceEffect(1, condition2).setCanWorksOnStackOnly(true) .setText("It also costs {1} less to cast if you control an enchantment")); + this.addAbility(ability); // Counter target spell unless its controller pays {3}. this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(new GenericManaCost(3))); diff --git a/Mage.Sets/src/mage/cards/g/GemstoneCaverns.java b/Mage.Sets/src/mage/cards/g/GemstoneCaverns.java index d04721cd29c..9164ea6c027 100644 --- a/Mage.Sets/src/mage/cards/g/GemstoneCaverns.java +++ b/Mage.Sets/src/mage/cards/g/GemstoneCaverns.java @@ -82,7 +82,7 @@ class GemstoneCavernsAbility extends StaticAbility implements OpeningHandAction @Override public String getRule() { - return "If {this} is in your opening hand and you're not playing first, you may begin the game with {this} on the battlefield with a luck counter on it. If you do, exile a card from your hand."; + return "If {this} is in your opening hand and you're not the starting player, you may begin the game with {this} on the battlefield with a luck counter on it. If you do, exile a card from your hand."; } @Override diff --git a/Mage.Sets/src/mage/cards/g/GeneralsRegalia.java b/Mage.Sets/src/mage/cards/g/GeneralsRegalia.java index 2bdabe9cf07..903fb86398c 100644 --- a/Mage.Sets/src/mage/cards/g/GeneralsRegalia.java +++ b/Mage.Sets/src/mage/cards/g/GeneralsRegalia.java @@ -67,7 +67,7 @@ class GeneralsRegaliaEffect extends RedirectionEffect { @Override public void init(Ability source, Game game) { - this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); super.init(source, game); } diff --git a/Mage.Sets/src/mage/cards/g/GenesisHydra.java b/Mage.Sets/src/mage/cards/g/GenesisHydra.java index 2b5cd6c7a21..fd9e56ba7f7 100644 --- a/Mage.Sets/src/mage/cards/g/GenesisHydra.java +++ b/Mage.Sets/src/mage/cards/g/GenesisHydra.java @@ -80,7 +80,7 @@ class GenesisHydraPutOntoBattlefieldEffect extends OneShotEffect { filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, count + 1)); TargetCard target1 = new TargetCard(Zone.LIBRARY, filter); target1.setRequired(false); - if (cards.count(filter, controller.getId(), source.getSourceId(), game) > 0) { + if (cards.count(filter, source.getSourceId(), source, game) > 0) { if (controller.choose(Outcome.PutCardInPlay, cards, target1, game)) { Card card = cards.get(target1.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/g/GenesisUltimatum.java b/Mage.Sets/src/mage/cards/g/GenesisUltimatum.java index 210cf9f1683..bc52296d2c8 100644 --- a/Mage.Sets/src/mage/cards/g/GenesisUltimatum.java +++ b/Mage.Sets/src/mage/cards/g/GenesisUltimatum.java @@ -1,34 +1,32 @@ package mage.cards.g; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.ExileSpellEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterPermanentCard; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInLibrary; import java.util.UUID; /** - * @author TheElk801 + * @author awjackson */ public final class GenesisUltimatum extends CardImpl { + private static final FilterCard filter = new FilterPermanentCard("permanent cards"); + public GenesisUltimatum(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}{G}{U}{U}{U}{R}{R}"); - // Look at the top five cards of your library. Put any number of permanent cards from among them onto the battlefield and the rest into your hand. Exile Genesis Ultimatum. - this.getSpellAbility().addEffect(new GenesisUltimatumEffect()); + // Look at the top five cards of your library. + // Put any number of permanent cards from among them onto the battlefield and the rest into your hand. + // Exile Genesis Ultimatum. + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + 5, Integer.MAX_VALUE, filter, PutCards.BATTLEFIELD, PutCards.HAND, false + ).setText("look at the top five cards of your library. Put any number of permanent cards from among them onto the battlefield and the rest into your hand")); this.getSpellAbility().addEffect(new ExileSpellEffect()); } @@ -41,45 +39,3 @@ public final class GenesisUltimatum extends CardImpl { return new GenesisUltimatum(this); } } - -class GenesisUltimatumEffect extends OneShotEffect { - - private static final FilterCard filter = new FilterPermanentCard("any number of permanent cards"); - - GenesisUltimatumEffect() { - super(Outcome.PutCardInPlay); - staticText = "Look at the top five cards of your library. Put any number of permanent cards " + - "from among them onto the battlefield and the rest into your hand"; - } - - private GenesisUltimatumEffect(final GenesisUltimatumEffect effect) { - super(effect); - } - - @Override - public GenesisUltimatumEffect copy() { - return new GenesisUltimatumEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Cards toHand = new CardsImpl(player.getLibrary().getTopCards(game, 5)); - player.lookAtCards(source, null, toHand, game); - TargetCard targetCard = new TargetCardInLibrary(0, 5, filter); - targetCard.withChooseHint("put to battlefield"); - player.choose(outcome, toHand, targetCard, game); - Cards toBattlefield = new CardsImpl(targetCard.getTargets()); - if (player.moveCards(toBattlefield, Zone.BATTLEFIELD, source, game)) { - toBattlefield - .stream() - .filter(id -> Zone.BATTLEFIELD.equals(game.getState().getZone(id))) - .forEach(toHand::remove); - } - player.moveCards(toHand, Zone.HAND, source, game); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/g/GeodeGolem.java b/Mage.Sets/src/mage/cards/g/GeodeGolem.java index bdc737f1a8b..6f547c790fa 100644 --- a/Mage.Sets/src/mage/cards/g/GeodeGolem.java +++ b/Mage.Sets/src/mage/cards/g/GeodeGolem.java @@ -1,22 +1,23 @@ package mage.cards.g; -import mage.ApprovingObject; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.TrampleAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.Cards; import mage.cards.CardsImpl; -import mage.constants.*; -import mage.filter.FilterCard; +import mage.constants.CardType; +import mage.constants.CommanderCardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; +import mage.util.CardUtil; -import java.util.Set; import java.util.UUID; /** @@ -35,7 +36,7 @@ public final class GeodeGolem extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Whenever Geode Golem deals combat damage to a player, you may cast your commander from the command zone without paying its mana cost. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new GeodeGolemEffect(), true)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new GeodeGolemEffect(), false)); } private GeodeGolem(final GeodeGolem card) { @@ -63,48 +64,13 @@ class GeodeGolemEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Card selectedCommander = null; - - Set commandersInCommandZone = game.getCommanderCardsFromCommandZone(controller, CommanderCardType.COMMANDER_OR_OATHBREAKER); - if (commandersInCommandZone.isEmpty()) { - return false; - } - - // select from commanders - if (commandersInCommandZone.size() == 1) { - selectedCommander = commandersInCommandZone.stream().findFirst().get(); - } else { - TargetCard target = new TargetCard(Zone.COMMAND, new FilterCard("commander to cast without mana cost")); - target.setNotTarget(true); - if (controller.canRespond() - && controller.choose(Outcome.PlayForFree, new CardsImpl(commandersInCommandZone), target, game)) { - selectedCommander = commandersInCommandZone.stream() - .filter(c -> c.getId().equals(target.getFirstTarget())) - .findFirst() - .orElse(null); - - } - } - - if (selectedCommander == null) { - return false; - } - - // commander tax applies as additional cost - if (selectedCommander.getSpellAbility() != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + selectedCommander.getId(), Boolean.TRUE); - Boolean commanderWasCast = controller.cast(controller.chooseAbilityForCast(selectedCommander, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + selectedCommander.getId(), null); - return commanderWasCast; - } else { - // play commander as land is xmage feature, but mtg rules for text "cast commander" doesn't allow that - // TODO: improve lands support for "cast your commander" (allow land play from mdf cards)? - return controller.playLand(selectedCommander, game, true); - } + if (controller == null) { + return false; } - return false; + Cards cards = new CardsImpl(game.getCommanderCardsFromCommandZone( + controller, CommanderCardType.COMMANDER_OR_OATHBREAKER + )); + return CardUtil.castSpellWithAttributesForFree(controller, source, game, cards, StaticFilters.FILTER_CARD); } @Override diff --git a/Mage.Sets/src/mage/cards/g/GeodeRager.java b/Mage.Sets/src/mage/cards/g/GeodeRager.java index 049b0f0fdcb..91435e17034 100644 --- a/Mage.Sets/src/mage/cards/g/GeodeRager.java +++ b/Mage.Sets/src/mage/cards/g/GeodeRager.java @@ -69,12 +69,12 @@ class GeodeRagerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { for (Permanent permanent : game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_CONTROLLED_CREATURE, source.getFirstTarget(), source.getSourceId(), game + StaticFilters.FILTER_CONTROLLED_CREATURE, source.getFirstTarget(), source, game )) { if (permanent == null) { continue; } - new GoadTargetEffect().setTargetPointer(new FixedTarget(permanent, game)).apply(game, source); + game.addEffect(new GoadTargetEffect().setTargetPointer(new FixedTarget(permanent, game)), source); } return true; } diff --git a/Mage.Sets/src/mage/cards/g/GerrardWeatherlightHero.java b/Mage.Sets/src/mage/cards/g/GerrardWeatherlightHero.java index 5e756d89b67..2f22fbb9fcc 100644 --- a/Mage.Sets/src/mage/cards/g/GerrardWeatherlightHero.java +++ b/Mage.Sets/src/mage/cards/g/GerrardWeatherlightHero.java @@ -85,7 +85,7 @@ class GerrardWeatherlightHeroEffect extends OneShotEffect { return false; } return player.moveCards(player.getGraveyard().getCards( - filter, source.getSourceId(), source.getControllerId(), game + filter, source.getControllerId(), source, game ), Zone.BATTLEFIELD, source, game); } } diff --git a/Mage.Sets/src/mage/cards/g/Gerrymandering.java b/Mage.Sets/src/mage/cards/g/Gerrymandering.java index 0c2ce27e9a3..6e6a2fc6e85 100644 --- a/Mage.Sets/src/mage/cards/g/Gerrymandering.java +++ b/Mage.Sets/src/mage/cards/g/Gerrymandering.java @@ -66,7 +66,7 @@ class GerrymanderingEffect extends OneShotEffect { if (controller != null) { // Exile all lands. Cards exiledCards = new CardsImpl(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LANDS, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LANDS, source.getControllerId(), source, game)) { exiledCards.add(permanent); playerLandCount.putIfAbsent(permanent.getControllerId(), 0); playerLandCount.put(permanent.getControllerId(), playerLandCount.get(permanent.getControllerId()) + 1); diff --git a/Mage.Sets/src/mage/cards/g/GetawayCar.java b/Mage.Sets/src/mage/cards/g/GetawayCar.java new file mode 100644 index 00000000000..96e17e69328 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GetawayCar.java @@ -0,0 +1,143 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.AttacksOrBlocksTriggeredAbility; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.constants.WatcherScope; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.MageObjectReferencePredicate; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class GetawayCar extends CardImpl { + + public GetawayCar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Whenever Getaway Car attacks or blocks, return up to one target creature that crewed it this turn to its owner's hand. + this.addAbility(new AttacksOrBlocksTriggeredAbility( + new ReturnToHandTargetEffect() + .setText("return up to one target creature that crewed it this turn to its owner's hand"), + false + ).setTargetAdjuster(GetawayCarAdjuster.instance), new GetawayCarWatcher()); + + // Crew 1 + this.addAbility(new CrewAbility(1)); + } + + private GetawayCar(final GetawayCar card) { + super(card); + } + + @Override + public GetawayCar copy() { + return new GetawayCar(this); + } +} + +enum GetawayCarAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetPermanent( + 0, 1, GetawayCarWatcher.makeFilter(ability, game) + )); + } +} + +class GetawayCarWatcher extends Watcher { + + private final Map> crewMap = new HashMap<>(); + private static final FilterPermanent invalidFilter = new FilterPermanent(); + + static { + invalidFilter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, -2)); + } + + GetawayCarWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + Permanent vehicle; + Permanent crewer; + switch (event.getType()) { + case VEHICLE_CREWED: + vehicle = game.getPermanent(event.getTargetId()); + crewer = null; + break; + case CREWED_VEHICLE: + vehicle = game.getPermanent(event.getSourceId()); + crewer = game.getPermanent(event.getTargetId()); + break; + default: + return; + } + if (vehicle == null) { + return; + } + crewMap.computeIfAbsent( + new MageObjectReference(vehicle, game), x -> new HashSet<>() + ).add(new MageObjectReference(crewer, game)); + } + + @Override + public void reset() { + super.reset(); + crewMap.clear(); + } + + public static FilterPermanent makeFilter(Ability source, Game game) { + Set predicates = game + .getState() + .getWatcher(GetawayCarWatcher.class) + .crewMap + .computeIfAbsent(new MageObjectReference(source), x -> new HashSet<>()) + .stream() + .filter(mor -> { + Permanent permanent = mor.getPermanent(game); + return permanent != null && permanent.isCreature(game); + }).map(MageObjectReferencePredicate::new) + .collect(Collectors.toSet()); + if (predicates.isEmpty()) { + return invalidFilter; + } + FilterPermanent filterPermanent = new FilterPermanent( + "creature that crewed " + CardUtil.getSourceName(game, source) + " this turn" + ); + filterPermanent.add(Predicates.or(predicates)); + return filterPermanent; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GeyadroneDihada.java b/Mage.Sets/src/mage/cards/g/GeyadroneDihada.java index 67bc26f82ce..41a627a630c 100644 --- a/Mage.Sets/src/mage/cards/g/GeyadroneDihada.java +++ b/Mage.Sets/src/mage/cards/g/GeyadroneDihada.java @@ -4,7 +4,6 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.effects.common.UntapTargetEffect; @@ -47,7 +46,7 @@ public final class GeyadroneDihada extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.DIHADA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // Protection from permanents with corruption counters on them this.addAbility(new ProtectionAbility(filter)); diff --git a/Mage.Sets/src/mage/cards/g/GhastlordOfFugue.java b/Mage.Sets/src/mage/cards/g/GhastlordOfFugue.java index 9c6f0c5d343..63af38912c6 100644 --- a/Mage.Sets/src/mage/cards/g/GhastlordOfFugue.java +++ b/Mage.Sets/src/mage/cards/g/GhastlordOfFugue.java @@ -70,7 +70,7 @@ class GhastlordOfFugueEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (targetPlayer != null && sourceObject != null && controller != null) { diff --git a/Mage.Sets/src/mage/cards/g/GhastlyDiscovery.java b/Mage.Sets/src/mage/cards/g/GhastlyDiscovery.java index 6243e09fe49..aed7f17c206 100644 --- a/Mage.Sets/src/mage/cards/g/GhastlyDiscovery.java +++ b/Mage.Sets/src/mage/cards/g/GhastlyDiscovery.java @@ -25,7 +25,7 @@ public final class GhastlyDiscovery extends CardImpl { this.getSpellAbility().addEffect(new GhastlyDiscoveryEffect()); // Conspire - this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.NONE)); + this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.NONE)); } private GhastlyDiscovery(final GhastlyDiscovery card) { diff --git a/Mage.Sets/src/mage/cards/g/GhirapurGuide.java b/Mage.Sets/src/mage/cards/g/GhirapurGuide.java index c6c7a27c841..b3f84186494 100644 --- a/Mage.Sets/src/mage/cards/g/GhirapurGuide.java +++ b/Mage.Sets/src/mage/cards/g/GhirapurGuide.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -10,16 +8,16 @@ 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.ComparisonType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author fireshoes */ public final class GhirapurGuide extends CardImpl { @@ -31,15 +29,17 @@ public final class GhirapurGuide extends CardImpl { } public GhirapurGuide(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.SCOUT); this.power = new MageInt(3); this.toughness = new MageInt(2); // {2}{G}: Target creature you control can't be blocked by creatures with power 2 or less this turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CantBeBlockedByAllTargetEffect(filter, Duration.EndOfTurn), new ManaCostsImpl("{2}{G}")); - ability.addTarget(new TargetCreaturePermanent()); + Ability ability = new SimpleActivatedAbility( + new CantBeBlockedByAllTargetEffect(filter, Duration.EndOfTurn), new ManaCostsImpl<>("{2}{G}") + ); + ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GhostCouncilOfOrzhova.java b/Mage.Sets/src/mage/cards/g/GhostCouncilOfOrzhova.java index 51099f92ec8..08c01994e6e 100644 --- a/Mage.Sets/src/mage/cards/g/GhostCouncilOfOrzhova.java +++ b/Mage.Sets/src/mage/cards/g/GhostCouncilOfOrzhova.java @@ -44,7 +44,7 @@ public final class GhostCouncilOfOrzhova extends CardImpl { // {1}, Sacrifice a creature: Exile Ghost Council of Orzhova. Return it to the battlefield under its owner's control at the beginning of the next end step. ability = new SimpleActivatedAbility( Zone.BATTLEFIELD, - new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true), + new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(), new GenericManaCost(1)); ability.addCost(new SacrificeTargetCost( new TargetControlledCreaturePermanent( diff --git a/Mage.Sets/src/mage/cards/g/Ghostfire.java b/Mage.Sets/src/mage/cards/g/Ghostfire.java index 7d8d129ebff..997d2fd1a00 100644 --- a/Mage.Sets/src/mage/cards/g/Ghostfire.java +++ b/Mage.Sets/src/mage/cards/g/Ghostfire.java @@ -1,27 +1,30 @@ - package mage.cards.g; -import java.util.UUID; import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.InfoEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Zone; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author dustinconrad */ public final class Ghostfire extends CardImpl { public Ghostfire(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); // Ghostfire is colorless. this.color = new ObjectColor(); - this.getSpellAbility().addEffect(new InfoEffect("{this} is colorless")); + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new InfoEffect("{this} is colorless") + ).setRuleAtTheTop(true)); // Ghostfire deals 3 damage to any target. this.getSpellAbility().addEffect(new DamageTargetEffect(3)); diff --git a/Mage.Sets/src/mage/cards/g/GhoulcallersChant.java b/Mage.Sets/src/mage/cards/g/GhoulcallersChant.java index ef63b31ed13..37d561a54b5 100644 --- a/Mage.Sets/src/mage/cards/g/GhoulcallersChant.java +++ b/Mage.Sets/src/mage/cards/g/GhoulcallersChant.java @@ -1,9 +1,7 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.Mode; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -12,8 +10,9 @@ import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author North */ public final class GhoulcallersChant extends CardImpl { @@ -28,11 +27,10 @@ public final class GhoulcallersChant extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); // Choose one - Return target creature card from your graveyard to your hand - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); 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.addEffect(new ReturnToHandTargetEffect()); + Mode mode = new Mode(new ReturnFromGraveyardToHandTargetEffect()); mode.addTarget(new TargetCardInYourGraveyard(2, filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/g/GiadaFontOfHope.java b/Mage.Sets/src/mage/cards/g/GiadaFontOfHope.java new file mode 100644 index 00000000000..ff7bc957e29 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GiadaFontOfHope.java @@ -0,0 +1,124 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.mana.ConditionalColoredManaAbility; +import mage.abilities.mana.conditional.ConditionalSpellManaBuilder; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterSpell; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author woshikie + */ +public final class GiadaFontOfHope extends CardImpl { + private static final FilterSpell ANGEL_SPELL_FILTER = new FilterSpell("an Angel spell"); + + static { + ANGEL_SPELL_FILTER.add(SubType.ANGEL.getPredicate()); + } + + public GiadaFontOfHope(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ANGEL); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Each other Angel you control enters the battlefield with an additional +1/+1 counter on it for each Angel you already control. + this.addAbility( + new SimpleStaticAbility( + Zone.BATTLEFIELD, + new GiadaFontOfHopeEntersBattlefieldEffect() + ) + ); + + // {T}: Add {W}. Spend this mana only to cast an Angel spell. + this.addAbility( + new ConditionalColoredManaAbility( + Mana.WhiteMana(1), + new ConditionalSpellManaBuilder(ANGEL_SPELL_FILTER) + ) + + ); + } + + private GiadaFontOfHope(final GiadaFontOfHope card) { + super(card); + } + + @Override + public GiadaFontOfHope copy() { + return new GiadaFontOfHope(this); + } +} + + +class GiadaFontOfHopeEntersBattlefieldEffect extends ReplacementEffectImpl { + + public GiadaFontOfHopeEntersBattlefieldEffect() { + super(Duration.WhileOnBattlefield, Outcome.BoostCreature); + staticText = "Each other Angel you control enters the battlefield with an additional +1/+1 counter on it for each Angel you already control."; + } + + private GiadaFontOfHopeEntersBattlefieldEffect(GiadaFontOfHopeEntersBattlefieldEffect effect) { + super(effect); + } + + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + if (permanent != null) { + int amount = + (int) game.getBattlefield().getAllActivePermanents().stream().filter(perm -> { + return perm.hasSubtype(SubType.ANGEL, game) // perm is Angel + && perm.isControlledBy(source.getControllerId()); // perm is Controlled by player + }).count(); + if (amount > 0) + permanent.addCounters(CounterType.P1P1.createInstance(amount), source.getControllerId(), source, game); + } + return false; + + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + return permanent != null + && permanent.isControlledBy(source.getControllerId()) + && permanent.hasSubtype(SubType.ANGEL, game) + && !event.getTargetId().equals(source.getSourceId()); + + } + + @Override + public GiadaFontOfHopeEntersBattlefieldEffect copy() { + return new GiadaFontOfHopeEntersBattlefieldEffect(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GiantAmbushBeetle.java b/Mage.Sets/src/mage/cards/g/GiantAmbushBeetle.java index 6a946f5feca..70a21ac639a 100644 --- a/Mage.Sets/src/mage/cards/g/GiantAmbushBeetle.java +++ b/Mage.Sets/src/mage/cards/g/GiantAmbushBeetle.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -10,31 +8,31 @@ import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class GiantAmbushBeetle extends CardImpl { public GiantAmbushBeetle(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B/G}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B/G}{R}"); this.subtype.add(SubType.INSECT); - - - - this.power = new MageInt(4); this.toughness = new MageInt(3); // Haste this.addAbility(HasteAbility.getInstance()); - + // When Giant Ambush Beetle enters the battlefield, you may have target creature block it this turn if able. - Ability ability = new EntersBattlefieldTriggeredAbility(new MustBeBlockedByTargetSourceEffect(Duration.EndOfTurn), true); + Ability ability = new EntersBattlefieldTriggeredAbility( + new MustBeBlockedByTargetSourceEffect(Duration.EndOfTurn) + .setText("target creature block it this turn if able"), true + ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GiantBadger.java b/Mage.Sets/src/mage/cards/g/GiantBadger.java index c1a0186cc5c..89c98c57789 100644 --- a/Mage.Sets/src/mage/cards/g/GiantBadger.java +++ b/Mage.Sets/src/mage/cards/g/GiantBadger.java @@ -1,4 +1,3 @@ - package mage.cards.g; import java.util.UUID; @@ -25,7 +24,7 @@ public final class GiantBadger extends CardImpl { this.toughness = new MageInt(2); // Whenever Giant Badger blocks, it gets +2/+2 until end of turn. - this.addAbility(new BlocksSourceTriggeredAbility(new BoostSourceEffect(2, 2, Duration.EndOfTurn), false)); + this.addAbility(new BlocksSourceTriggeredAbility(new BoostSourceEffect(2, 2, Duration.EndOfTurn, "it"))); } private GiantBadger(final GiantBadger card) { diff --git a/Mage.Sets/src/mage/cards/g/Giantbaiting.java b/Mage.Sets/src/mage/cards/g/Giantbaiting.java index 4f688b34145..112ce1272ee 100644 --- a/Mage.Sets/src/mage/cards/g/Giantbaiting.java +++ b/Mage.Sets/src/mage/cards/g/Giantbaiting.java @@ -26,7 +26,7 @@ public final class Giantbaiting extends CardImpl { this.getSpellAbility().addEffect(new GiantbaitingEffect()); // Conspire - this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.NONE)); + this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.NONE)); } diff --git a/Mage.Sets/src/mage/cards/g/GibberingDescent.java b/Mage.Sets/src/mage/cards/g/GibberingDescent.java index 906f0c3cf01..5340efc284c 100644 --- a/Mage.Sets/src/mage/cards/g/GibberingDescent.java +++ b/Mage.Sets/src/mage/cards/g/GibberingDescent.java @@ -1,15 +1,11 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.HellbentCondition; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.keyword.MadnessAbility; @@ -18,34 +14,30 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; + +import java.util.UUID; /** - * * @author emerald000 */ public final class GibberingDescent extends CardImpl { public GibberingDescent(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{B}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{B}{B}"); // At the beginning of each player's upkeep, that player loses 1 life and discards a card. - Effect effect = new LoseLifeTargetEffect(1); - effect.setText("that player loses 1 life"); - Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, effect, TargetController.ANY, false, true); - effect = new DiscardTargetEffect(1); - effect.setText("and discards a card"); - ability.addEffect(effect); + Ability ability = new BeginningOfUpkeepTriggeredAbility( + Zone.BATTLEFIELD, new LoseLifeTargetEffect(1).setText("that player loses 1 life"), + TargetController.ANY, false, true + ); + ability.addEffect(new DiscardTargetEffect(1).setText("and discards a card")); this.addAbility(ability); - + // Hellbent - Skip your upkeep step if you have no cards in hand. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousRuleModifyingEffect( - new GibberingDescentSkipUpkeepEffect(), - HellbentCondition.instance))); - + this.addAbility(new SimpleStaticAbility(new GibberingDescentSkipUpkeepEffect()).setAbilityWord(AbilityWord.HELLBENT)); + // Madness {2}{B}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{2}{B}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{2}{B}{B}"))); } private GibberingDescent(final GibberingDescent card) { @@ -62,7 +54,7 @@ class GibberingDescentSkipUpkeepEffect extends ContinuousRuleModifyingEffectImpl GibberingDescentSkipUpkeepEffect() { super(Duration.WhileOnBattlefield, Outcome.Neutral); - this.staticText = "Hellbent - Skip your upkeep step if you have no cards in hand"; + this.staticText = "skip your upkeep step if you have no cards in hand"; } GibberingDescentSkipUpkeepEffect(final GibberingDescentSkipUpkeepEffect effect) { @@ -78,9 +70,9 @@ class GibberingDescentSkipUpkeepEffect extends ContinuousRuleModifyingEffectImpl public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.UPKEEP_STEP; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { - return event.getPlayerId().equals(source.getControllerId()); + return source.isControlledBy(event.getPlayerId()) && HellbentCondition.instance.apply(game, source); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/g/GideonAllyOfZendikar.java b/Mage.Sets/src/mage/cards/g/GideonAllyOfZendikar.java index df069125b58..d58a6d72caf 100644 --- a/Mage.Sets/src/mage/cards/g/GideonAllyOfZendikar.java +++ b/Mage.Sets/src/mage/cards/g/GideonAllyOfZendikar.java @@ -4,7 +4,6 @@ package mage.cards.g; import java.util.UUID; import mage.MageInt; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -32,7 +31,7 @@ public final class GideonAllyOfZendikar extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.GIDEON); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Until end of turn, Gideon, Ally of Zendikar becomes a 5/5 Human Soldier Ally creature with indestructible that's still a planeswalker. Prevent all damage that would be dealt to him this turn. LoyaltyAbility ability = new LoyaltyAbility(new BecomesCreatureSourceEffect(new GideonAllyOfZendikarToken(), "planeswalker", Duration.EndOfTurn), 1); diff --git a/Mage.Sets/src/mage/cards/g/GideonBattleForged.java b/Mage.Sets/src/mage/cards/g/GideonBattleForged.java index 740ad27a0b8..67ddfbe2f58 100644 --- a/Mage.Sets/src/mage/cards/g/GideonBattleForged.java +++ b/Mage.Sets/src/mage/cards/g/GideonBattleForged.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.common.PreventAllDamageToSourceEffect; @@ -43,7 +42,7 @@ public final class GideonBattleForged extends CardImpl { this.nightCard = true; - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +2: Up to one target creature an opponent controls attacks Gideon, Battle-Forged during its controller's next turn if able. LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new GideonBattleForgedAttacksIfAbleTargetEffect(Duration.Custom), 2); diff --git a/Mage.Sets/src/mage/cards/g/GideonBlackblade.java b/Mage.Sets/src/mage/cards/g/GideonBlackblade.java index 00e7ec80c04..9e8e88aa423 100644 --- a/Mage.Sets/src/mage/cards/g/GideonBlackblade.java +++ b/Mage.Sets/src/mage/cards/g/GideonBlackblade.java @@ -3,7 +3,6 @@ package mage.cards.g; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.decorator.ConditionalContinuousEffect; @@ -52,7 +51,7 @@ public final class GideonBlackblade extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.GIDEON); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // As long as it's your turn, Gideon Blackblade is a 4/4 Human Soldier creature with indestructible that's still a planeswalker. this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( diff --git a/Mage.Sets/src/mage/cards/g/GideonChampionOfJustice.java b/Mage.Sets/src/mage/cards/g/GideonChampionOfJustice.java index 93e3ba6cf0a..99270065921 100644 --- a/Mage.Sets/src/mage/cards/g/GideonChampionOfJustice.java +++ b/Mage.Sets/src/mage/cards/g/GideonChampionOfJustice.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.LockedInDynamicValue; import mage.abilities.dynamicvalue.common.CountersSourceCount; import mage.abilities.dynamicvalue.common.PermanentsTargetOpponentControlsCount; @@ -39,7 +38,7 @@ public final class GideonChampionOfJustice extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.GIDEON); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Put a loyalty counter on Gideon, Champion of Justice for each creature target opponent controls. LoyaltyAbility ability1 = new LoyaltyAbility( diff --git a/Mage.Sets/src/mage/cards/g/GideonJura.java b/Mage.Sets/src/mage/cards/g/GideonJura.java index 335e547b331..6da6c4e7efb 100644 --- a/Mage.Sets/src/mage/cards/g/GideonJura.java +++ b/Mage.Sets/src/mage/cards/g/GideonJura.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.common.DestroyTargetEffect; @@ -39,7 +38,7 @@ public final class GideonJura extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.GIDEON); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(6)); + this.setStartingLoyalty(6); // +2: During target opponent's next turn, creatures that player controls attack Gideon Jura if able. LoyaltyAbility ability1 = new LoyaltyAbility(new GideonJuraEffect(), 2); diff --git a/Mage.Sets/src/mage/cards/g/GideonMartialParagon.java b/Mage.Sets/src/mage/cards/g/GideonMartialParagon.java index 4f500d35a03..92d5e3c294f 100644 --- a/Mage.Sets/src/mage/cards/g/GideonMartialParagon.java +++ b/Mage.Sets/src/mage/cards/g/GideonMartialParagon.java @@ -4,7 +4,6 @@ package mage.cards.g; import java.util.UUID; import mage.MageInt; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.PreventAllDamageToSourceEffect; import mage.abilities.effects.common.TapAllEffect; @@ -34,7 +33,7 @@ public final class GideonMartialParagon extends CardImpl { this.subtype.add(SubType.GIDEON); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +2: Untap all creatures you control. Those creatures get +1/+1 until end of turn. LoyaltyAbility ability = new LoyaltyAbility(new UntapAllEffect(new FilterControlledCreaturePermanent()), 2); diff --git a/Mage.Sets/src/mage/cards/g/GideonOfTheTrials.java b/Mage.Sets/src/mage/cards/g/GideonOfTheTrials.java index eb3a1608152..594df5eab77 100644 --- a/Mage.Sets/src/mage/cards/g/GideonOfTheTrials.java +++ b/Mage.Sets/src/mage/cards/g/GideonOfTheTrials.java @@ -4,7 +4,6 @@ package mage.cards.g; import java.util.UUID; import mage.MageInt; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.PreventAllDamageToSourceEffect; @@ -33,7 +32,7 @@ public final class GideonOfTheTrials extends CardImpl { this.subtype.add(SubType.GIDEON); //Starting Loyalty: 3 - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Until your next turn, prevent all damage target permanent would deal. Effect effect = new PreventDamageByTargetEffect(Duration.UntilYourNextTurn); diff --git a/Mage.Sets/src/mage/cards/g/GideonTheOathsworn.java b/Mage.Sets/src/mage/cards/g/GideonTheOathsworn.java index e110f6619a8..463ae961d0c 100644 --- a/Mage.Sets/src/mage/cards/g/GideonTheOathsworn.java +++ b/Mage.Sets/src/mage/cards/g/GideonTheOathsworn.java @@ -5,7 +5,6 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileAllEffect; import mage.abilities.effects.common.ExileSourceEffect; @@ -35,7 +34,7 @@ public final class GideonTheOathsworn extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.GIDEON); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // Whenever you attack with two or more non-Gideon creatures, put a +1/+1 counter on each of those creatures. this.addAbility(new GideonTheOathswornTriggeredAbility()); diff --git a/Mage.Sets/src/mage/cards/g/GideonsIntervention.java b/Mage.Sets/src/mage/cards/g/GideonsIntervention.java index 1549b31485a..72aaaf97791 100644 --- a/Mage.Sets/src/mage/cards/g/GideonsIntervention.java +++ b/Mage.Sets/src/mage/cards/g/GideonsIntervention.java @@ -73,7 +73,7 @@ class GideonsInterventionCantCastEffect extends ContinuousRuleModifyingEffectImp @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); if (mageObject != null && cardName != null) { return "You can't cast a card named " + cardName + " (" + mageObject.getIdName() + ")."; diff --git a/Mage.Sets/src/mage/cards/g/GideonsSacrifice.java b/Mage.Sets/src/mage/cards/g/GideonsSacrifice.java index 49ee47ae86e..d4fc9a84db1 100644 --- a/Mage.Sets/src/mage/cards/g/GideonsSacrifice.java +++ b/Mage.Sets/src/mage/cards/g/GideonsSacrifice.java @@ -80,7 +80,7 @@ class GideonsSacrificeEffect extends OneShotEffect { } Target target = new TargetPermanent(filter); target.setNotTarget(true); - if (!player.choose(outcome, target, source.getSourceId(), game)) { + if (!player.choose(outcome, target, source, game)) { return false; } game.addEffect(new GideonsSacrificeEffectReplacementEffect( diff --git a/Mage.Sets/src/mage/cards/g/GiftOfDoom.java b/Mage.Sets/src/mage/cards/g/GiftOfDoom.java index 15265c8dc64..6d0f82e7bdf 100644 --- a/Mage.Sets/src/mage/cards/g/GiftOfDoom.java +++ b/Mage.Sets/src/mage/cards/g/GiftOfDoom.java @@ -64,7 +64,7 @@ public final class GiftOfDoom extends CardImpl { this.addAbility(ability2); // Morph—Sacrifice another creature. - this.addAbility(new MorphAbility(this, new SacrificeTargetCost( + this.addAbility(new MorphAbility(new SacrificeTargetCost( new TargetControlledPermanent(filter) ))); @@ -128,7 +128,7 @@ class GiftOfDoomEffect extends OneShotEffect { } TargetCreaturePermanent target = new TargetCreaturePermanent(filter); target.setNotTarget(true); - if (player.choose(outcome, target, source.getSourceId(), game) + if (player.choose(outcome, target, source, game) && game.getPermanent(target.getFirstTarget()) != null && !game.getPermanent(target.getFirstTarget()).cantBeAttachedBy(giftOfDoom, source, game, false)) { game.getState().setValue("attachTo:" + giftOfDoom.getId(), target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/g/GiftOfGranite.java b/Mage.Sets/src/mage/cards/g/GiftOfGranite.java index 67f46b8f045..ee0cb8a22d2 100644 --- a/Mage.Sets/src/mage/cards/g/GiftOfGranite.java +++ b/Mage.Sets/src/mage/cards/g/GiftOfGranite.java @@ -40,7 +40,7 @@ public final class GiftOfGranite extends CardImpl { this.addAbility(ability); // Enchanted creature gets +0/+2. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 2, Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(0, 2, Duration.WhileOnBattlefield))); } private GiftOfGranite(final GiftOfGranite card) { diff --git a/Mage.Sets/src/mage/cards/g/GiftOfTheWoods.java b/Mage.Sets/src/mage/cards/g/GiftOfTheWoods.java index c6518ace39d..2dd91bd49d2 100644 --- a/Mage.Sets/src/mage/cards/g/GiftOfTheWoods.java +++ b/Mage.Sets/src/mage/cards/g/GiftOfTheWoods.java @@ -1,30 +1,28 @@ - package mage.cards.g; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.common.BlocksOrBecomesBlockedSourceTriggeredAbility; +import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.constants.Outcome; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * - * @author Ketsuban + * @author TheElk801 */ public final class GiftOfTheWoods extends CardImpl { public GiftOfTheWoods(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[] { CardType.ENCHANTMENT }, "{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}"); this.subtype.add(SubType.AURA); @@ -32,15 +30,10 @@ public final class GiftOfTheWoods extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Benefit)); this.getSpellAbility().addTarget(auraTarget); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); - // Whenever enchanted creature blocks or becomes blocked, it gets +0/+3 until - // end of turn and you gain 1 life. - Ability ability2 = new BlocksOrBecomesBlockedSourceTriggeredAbility( - new BoostEnchantedEffect(0, 3, Duration.EndOfTurn), false); - ability2.addEffect(new GainLifeEffect(1).concatBy("and")); - this.addAbility(ability2); + // Whenever enchanted creature blocks or becomes blocked, it gets +0/+3 until end of turn and you gain 1 life. + this.addAbility(new GiftOfTheWoodsTriggeredAbility()); } private GiftOfTheWoods(final GiftOfTheWoods card) { @@ -52,3 +45,39 @@ public final class GiftOfTheWoods extends CardImpl { return new GiftOfTheWoods(this); } } + +class GiftOfTheWoodsTriggeredAbility extends TriggeredAbilityImpl { + + GiftOfTheWoodsTriggeredAbility() { + super(Zone.BATTLEFIELD, new BoostEnchantedEffect(0, 3, Duration.EndOfTurn)); + this.addEffect(new GainLifeEffect(1)); + } + + private GiftOfTheWoodsTriggeredAbility(final GiftOfTheWoodsTriggeredAbility ability) { + super(ability); + } + + @Override + public GiftOfTheWoodsTriggeredAbility copy() { + return new GiftOfTheWoodsTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.BLOCKER_DECLARED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent permanent = getSourcePermanentIfItStillExists(game); + return permanent != null && permanent.getAttachedTo() != null + && (event.getSourceId().equals(permanent.getAttachedTo()) + || event.getTargetId().equals(permanent.getAttachedTo())); + } + + @Override + public String getRule() { + return "Whenever enchanted creature blocks or becomes blocked, " + + "it gets +0/+3 until end of turn and you gain 1 life."; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GiftsUngiven.java b/Mage.Sets/src/mage/cards/g/GiftsUngiven.java index 34ef730d9f4..bd5b87deb8a 100644 --- a/Mage.Sets/src/mage/cards/g/GiftsUngiven.java +++ b/Mage.Sets/src/mage/cards/g/GiftsUngiven.java @@ -2,7 +2,10 @@ package mage.cards.g; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -11,6 +14,7 @@ import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCardWithDifferentNameInLibrary; import mage.target.common.TargetOpponent; import java.util.UUID; @@ -40,9 +44,14 @@ public final class GiftsUngiven extends CardImpl { class GiftsUngivenEffect extends OneShotEffect { + private static final FilterCard filter = new FilterCard("cards with different names"); + private static final FilterCard filter2 = new FilterCard("cards to put in graveyard"); + public GiftsUngivenEffect() { super(Outcome.DrawCard); - this.staticText = "Search your library for up to four cards with different names and reveal them. Target opponent chooses two of those cards. Put the chosen cards into your graveyard and the rest into your hand. Then shuffle"; + this.staticText = "Search your library for up to four cards with different names and reveal them. " + + "Target opponent chooses two of those cards. Put the chosen cards into your graveyard " + + "and the rest into your hand. Then shuffle"; } public GiftsUngivenEffect(final GiftsUngivenEffect effect) { @@ -57,74 +66,32 @@ class GiftsUngivenEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Card sourceCard = game.getCard(source.getSourceId()); - if (player == null || sourceCard == null) { - return false; - } Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (opponent == null) { + if (player == null || opponent == null) { return false; } - GiftsUngivenTarget target = new GiftsUngivenTarget(); - if (player.searchLibrary(target, source, game)) { - if (!target.getTargets().isEmpty()) { - Cards cards = new CardsImpl(); - for (UUID cardId : target.getTargets()) { - Card card = player.getLibrary().remove(cardId, game); - if (card != null) { - cards.add(card); - } - } - player.revealCards(sourceCard.getIdName(), cards, game); - - CardsImpl cardsToKeep = new CardsImpl(); - if (cards.size() > 2) { - cardsToKeep.addAll(cards); - TargetCard targetDiscard = new TargetCard(2, Zone.LIBRARY, new FilterCard("cards to put in graveyard")); - if (opponent.choose(Outcome.Discard, cards, targetDiscard, game)) { - cardsToKeep.removeAll(targetDiscard.getTargets()); - cards.removeAll(cardsToKeep); - } - } - - player.moveCards(cards, Zone.GRAVEYARD, source, game); - player.moveCards(cardsToKeep, Zone.HAND, source, game); - } + TargetCardInLibrary target = new TargetCardWithDifferentNameInLibrary(0, 4, filter); + player.searchLibrary(target, source, game); + Cards cards = new CardsImpl(target.getTargets()); + cards.retainZone(Zone.LIBRARY, game); + if (cards.isEmpty()) { player.shuffleLibrary(source, game); - return true; } - player.shuffleLibrary(source, game); - return false; - } -} + player.revealCards(source, cards, game); -class GiftsUngivenTarget extends TargetCardInLibrary { - - public GiftsUngivenTarget() { - super(0, 4, new FilterCard("cards with different names")); - } - - public GiftsUngivenTarget(final GiftsUngivenTarget target) { - super(target); - } - - @Override - public GiftsUngivenTarget copy() { - return new GiftsUngivenTarget(this); - } - - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Cards cards, Game game) { - Card card = cards.get(id, game); - if (card != null) { - for (UUID targetId : this.getTargets()) { - Card iCard = game.getCard(targetId); - if (iCard != null && iCard.getName().equals(card.getName())) { - return false; - } + if (cards.size() > 2) { + Cards cardsToKeep = new CardsImpl(); + cardsToKeep.addAll(cards); + TargetCard targetDiscard = new TargetCard(2, Zone.LIBRARY, filter2); + if (opponent.choose(Outcome.Discard, cards, targetDiscard, game)) { + cardsToKeep.removeIf(targetDiscard.getTargets()::contains); + cards.removeAll(cardsToKeep); } - return filter.match(card, playerId, game); + player.moveCards(cardsToKeep, Zone.HAND, source, game); } - return false; + + player.moveCards(cards, Zone.GRAVEYARD, source, game); + player.shuffleLibrary(source, game); + return true; } } diff --git a/Mage.Sets/src/mage/cards/g/Gigadrowse.java b/Mage.Sets/src/mage/cards/g/Gigadrowse.java index 73c140561b5..6cdd0d17d56 100644 --- a/Mage.Sets/src/mage/cards/g/Gigadrowse.java +++ b/Mage.Sets/src/mage/cards/g/Gigadrowse.java @@ -20,7 +20,7 @@ public final class Gigadrowse extends CardImpl { // Replicate {U} - this.addAbility(new ReplicateAbility(this, "{U}")); + this.addAbility(new ReplicateAbility("{U}")); // Tap target permanent. this.getSpellAbility().addEffect(new TapTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent()); diff --git a/Mage.Sets/src/mage/cards/g/GildedCerodon.java b/Mage.Sets/src/mage/cards/g/GildedCerodon.java index 11efa1b2afa..40d5fec95c6 100644 --- a/Mage.Sets/src/mage/cards/g/GildedCerodon.java +++ b/Mage.Sets/src/mage/cards/g/GildedCerodon.java @@ -1,10 +1,9 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.condition.Condition; +import mage.abilities.condition.common.DesertControlledOrGraveyardCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.combat.CantBlockTargetEffect; import mage.cards.CardImpl; @@ -12,14 +11,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.filter.FilterCard; -import mage.filter.FilterPermanent; -import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class GildedCerodon extends CardImpl { @@ -35,9 +31,12 @@ public final class GildedCerodon extends CardImpl { this.toughness = new MageInt(4); // Whenever Gilded Cerodon attacks, if you control a Desert or there is a Desert card in your graveyard, target creature can't block this turn. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new AttacksTriggeredAbility(new CantBlockTargetEffect(Duration.EndOfTurn), false), new GildedCerodonCondition(), rule); + Ability ability = new ConditionalInterveningIfTriggeredAbility( + new AttacksTriggeredAbility(new CantBlockTargetEffect(Duration.EndOfTurn), false), + DesertControlledOrGraveyardCondition.instance, rule + ); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); + this.addAbility(ability.addHint(DesertControlledOrGraveyardCondition.getHint())); } @@ -50,27 +49,3 @@ public final class GildedCerodon extends CardImpl { return new GildedCerodon(this); } } - -class GildedCerodonCondition implements Condition { - - private static final FilterPermanent filter = new FilterPermanent(); - private static final FilterCard filter2 = new FilterCard(); - - static { - filter.add(SubType.DESERT.getPredicate()); - filter2.add(SubType.DESERT.getPredicate()); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - return (!game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game).isEmpty() - || !controller.getGraveyard().getCards(filter2, game).isEmpty()); - } - - @Override - public String toString() { - return "if you control a Desert or there is a Desert card in your graveyard"; - } - -} diff --git a/Mage.Sets/src/mage/cards/g/GildedPinions.java b/Mage.Sets/src/mage/cards/g/GildedPinions.java new file mode 100644 index 00000000000..2fad2c8f7c4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GildedPinions.java @@ -0,0 +1,48 @@ +package mage.cards.g; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +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.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GildedPinions extends CardImpl { + + public GildedPinions(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + this.subtype.add(SubType.EQUIPMENT); + + // When Gilded Pinions enters the battlefield, create a Treasure token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new TreasureToken()))); + + // Equipped creature has flying. + this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( + FlyingAbility.getInstance(), AttachmentType.EQUIPMENT + ))); + + // Equip {2} + this.addAbility(new EquipAbility(2)); + } + + private GildedPinions(final GildedPinions card) { + super(card); + } + + @Override + public GildedPinions copy() { + return new GildedPinions(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GiltLeafArchdruid.java b/Mage.Sets/src/mage/cards/g/GiltLeafArchdruid.java index 2fb280e358d..8f64e8251ee 100644 --- a/Mage.Sets/src/mage/cards/g/GiltLeafArchdruid.java +++ b/Mage.Sets/src/mage/cards/g/GiltLeafArchdruid.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -13,27 +11,35 @@ import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.FilterSpell; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPlayer; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author Plopman */ public final class GiltLeafArchdruid extends CardImpl { - private static final FilterSpell filterSpell = new FilterSpell("a Druid spell"); + private static final FilterSpell filter = new FilterSpell("a Druid spell"); + private static final FilterControlledPermanent filter2 + = new FilterControlledPermanent(SubType.DRUID, "untapped Druids you control"); static { - filterSpell.add(SubType.DRUID.getPredicate()); + filter.add(SubType.DRUID.getPredicate()); + filter2.add(TappedPredicate.UNTAPPED); } public GiltLeafArchdruid(UUID ownerId, CardSetInfo setInfo) { @@ -45,10 +51,15 @@ public final class GiltLeafArchdruid extends CardImpl { this.toughness = new MageInt(3); // Whenever you cast a Druid spell, you may draw a card. - this.addAbility(new SpellCastControllerTriggeredAbility(new DrawCardSourceControllerEffect(1), filterSpell, true)); + this.addAbility(new SpellCastControllerTriggeredAbility( + new DrawCardSourceControllerEffect(1), filter, true + )); // Tap seven untapped Druids you control: Gain control of all lands target player controls. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GiltLeafArchdruidEffect(), new TapTargetCost(new TargetControlledCreaturePermanent(7, 7, new FilterControlledCreaturePermanent(SubType.DRUID, "Druids you control"), true))); + Ability ability = new SimpleActivatedAbility( + new GiltLeafArchdruidEffect(), + new TapTargetCost(new TargetControlledPermanent(7, filter2)) + ); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GiltLeafPalace.java b/Mage.Sets/src/mage/cards/g/GiltLeafPalace.java index 4c47f0b7438..5a32e451415 100644 --- a/Mage.Sets/src/mage/cards/g/GiltLeafPalace.java +++ b/Mage.Sets/src/mage/cards/g/GiltLeafPalace.java @@ -29,7 +29,7 @@ public final class GiltLeafPalace extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.LAND},""); // As Gilt-Leaf Palace enters the battlefield, you may reveal an Elf card from your hand. If you don't, Gilt-Leaf Palace enters the battlefield tapped. - this.addAbility(new AsEntersBattlefieldAbility(new TapSourceUnlessPaysEffect(new RevealTargetFromHandCost(new TargetCardInHand(filter))), "you may reveal a Elf card from your hand. If you don't, {this} enters the battlefield tapped")); + this.addAbility(new AsEntersBattlefieldAbility(new TapSourceUnlessPaysEffect(new RevealTargetFromHandCost(new TargetCardInHand(filter))), "you may reveal an Elf card from your hand. If you don't, {this} enters the battlefield tapped")); // {tap}: Add {B} or {G}. this.addAbility(new BlackManaAbility()); this.addAbility(new GreenManaAbility()); diff --git a/Mage.Sets/src/mage/cards/g/GiltspireAvenger.java b/Mage.Sets/src/mage/cards/g/GiltspireAvenger.java index fa18a622a6a..4cb287eddd8 100644 --- a/Mage.Sets/src/mage/cards/g/GiltspireAvenger.java +++ b/Mage.Sets/src/mage/cards/g/GiltspireAvenger.java @@ -76,8 +76,8 @@ class GiltspireAvengerTarget extends TargetPermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set availablePossibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set availablePossibleTargets = super.possibleTargets(sourceControllerId, source, game); Set possibleTargets = new HashSet<>(); PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, sourceControllerId); for (UUID targetId : availablePossibleTargets) { @@ -90,15 +90,15 @@ class GiltspireAvengerTarget extends TargetPermanent { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { int remainingTargets = this.minNumberOfTargets - targets.size(); if (remainingTargets == 0) { return true; } int count = 0; - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, sourceControllerId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && watcher != null && watcher.hasSourceDoneDamage(permanent.getId(), game)) { count++; diff --git a/Mage.Sets/src/mage/cards/g/GirderGoons.java b/Mage.Sets/src/mage/cards/g/GirderGoons.java new file mode 100644 index 00000000000..6a3de2c90d3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GirderGoons.java @@ -0,0 +1,45 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.BlitzAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.RogueToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GirderGoons extends CardImpl { + + public GirderGoons(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // When Girder Goons dies, create a tapped 2/2 black Rogue creature token. + this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect( + new RogueToken(), 1, true, false + ))); + + // Blitz {3}{B} + this.addAbility(new BlitzAbility(this, "{3}{B}")); + } + + private GirderGoons(final GirderGoons card) { + super(card); + } + + @Override + public GirderGoons copy() { + return new GirderGoons(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GisasBidding.java b/Mage.Sets/src/mage/cards/g/GisasBidding.java index ef1b33ea2b3..a8862d89f2e 100644 --- a/Mage.Sets/src/mage/cards/g/GisasBidding.java +++ b/Mage.Sets/src/mage/cards/g/GisasBidding.java @@ -23,7 +23,7 @@ public final class GisasBidding extends CardImpl { this.getSpellAbility().addEffect(new CreateTokenEffect(new ZombieToken(), 2)); // Madness {2}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{2}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{2}{B}"))); } private GisasBidding(final GisasBidding card) { diff --git a/Mage.Sets/src/mage/cards/g/GlacialCrasher.java b/Mage.Sets/src/mage/cards/g/GlacialCrasher.java index 3d6ddd350c2..14e1ce95714 100644 --- a/Mage.Sets/src/mage/cards/g/GlacialCrasher.java +++ b/Mage.Sets/src/mage/cards/g/GlacialCrasher.java @@ -76,7 +76,7 @@ class GlacialCrasherEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(source.getSourceId())) { - return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) < 1; + return game.getBattlefield().count(filter, source.getControllerId(), source, game) < 1; } return false; } diff --git a/Mage.Sets/src/mage/cards/g/GlacialRevelation.java b/Mage.Sets/src/mage/cards/g/GlacialRevelation.java index 0c14bd38de4..18da214a7c3 100644 --- a/Mage.Sets/src/mage/cards/g/GlacialRevelation.java +++ b/Mage.Sets/src/mage/cards/g/GlacialRevelation.java @@ -1,33 +1,35 @@ package mage.cards.g; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.effects.common.RevealLibraryPickControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterPermanentCard; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; import java.util.UUID; /** - * @author TheElk801 + * @author awjackson */ public final class GlacialRevelation extends CardImpl { + private static final FilterCard filter = new FilterPermanentCard("snow permanent cards"); + + static { + filter.add(SuperType.SNOW.getPredicate()); + } + public GlacialRevelation(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); - // Reveal the top six cards of your library. You may put any number of snow permanent cards from among them into your hand. Put the rest into your graveyard. - this.getSpellAbility().addEffect(new GlacialRevelationEffect()); + // Reveal the top six cards of your library. + // You may put any number of snow permanent cards from among them into your hand. + // Put the rest into your graveyard. + this.getSpellAbility().addEffect(new RevealLibraryPickControllerEffect( + 6, Integer.MAX_VALUE, filter, PutCards.HAND, PutCards.GRAVEYARD)); } private GlacialRevelation(final GlacialRevelation card) { @@ -39,45 +41,3 @@ public final class GlacialRevelation extends CardImpl { return new GlacialRevelation(this); } } - -class GlacialRevelationEffect extends OneShotEffect { - - private static final FilterCard filter = new FilterPermanentCard("snow permanent cards"); - - static { - filter.add(SuperType.SNOW.getPredicate()); - } - - GlacialRevelationEffect() { - super(Outcome.Benefit); - staticText = "Reveal the top six cards of your library. You may put any number of snow permanent cards " + - "from among them into your hand. Put the rest into your graveyard."; - } - - private GlacialRevelationEffect(final GlacialRevelationEffect effect) { - super(effect); - } - - @Override - public GlacialRevelationEffect copy() { - return new GlacialRevelationEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 6)); - player.revealCards(source, cards, game); - TargetCard targetCard = new TargetCard(0, Integer.MAX_VALUE, Zone.LIBRARY, filter); - targetCard.setNotTarget(true); - if (player.choose(outcome, cards, targetCard, game)) { - Cards toHand = new CardsImpl(targetCard.getTargets()); - cards.removeAll(targetCard.getTargets()); - player.moveCards(toHand, Zone.HAND, source, game); - } - return player.moveCards(cards, Zone.GRAVEYARD, source, game); - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GlacialStalker.java b/Mage.Sets/src/mage/cards/g/GlacialStalker.java index 2abb38d3799..1ba3afbe7f0 100644 --- a/Mage.Sets/src/mage/cards/g/GlacialStalker.java +++ b/Mage.Sets/src/mage/cards/g/GlacialStalker.java @@ -24,7 +24,7 @@ public final class GlacialStalker extends CardImpl { this.toughness = new MageInt(5); // Morph {4}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{U}"))); } private GlacialStalker(final GlacialStalker card) { diff --git a/Mage.Sets/src/mage/cards/g/GlacianPowerstoneEngineer.java b/Mage.Sets/src/mage/cards/g/GlacianPowerstoneEngineer.java index fd5cdfc454e..ca751d63529 100644 --- a/Mage.Sets/src/mage/cards/g/GlacianPowerstoneEngineer.java +++ b/Mage.Sets/src/mage/cards/g/GlacianPowerstoneEngineer.java @@ -130,7 +130,7 @@ class GlacianPowerstoneEngineerCost extends VariableCostImpl { @Override public int getMaxValue(Ability source, Game game) { - return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + return game.getBattlefield().count(filter, source.getControllerId(), source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/g/GlamerSpinners.java b/Mage.Sets/src/mage/cards/g/GlamerSpinners.java index bc4ac48c054..135212959c8 100644 --- a/Mage.Sets/src/mage/cards/g/GlamerSpinners.java +++ b/Mage.Sets/src/mage/cards/g/GlamerSpinners.java @@ -102,8 +102,8 @@ class GlamerSpinnersEffect extends OneShotEffect { LinkedList auras = new LinkedList<>(); auras.addAll(targetPermanent.getAttachments()); if (source.getSourceObjectZoneChangeCounter() == glamerSpinners.getZoneChangeCounter(game) // not blinked - && chosenPermanentToAttachAuras.canChoose(source.getSourceId(), source.getControllerId(), game) - && controller.choose(Outcome.Neutral, chosenPermanentToAttachAuras, source.getSourceId(), game)) { + && chosenPermanentToAttachAuras.canChoose(source.getControllerId(), source, game) + && controller.choose(Outcome.Neutral, chosenPermanentToAttachAuras, source, game)) { Permanent permanentToAttachAuras = game.getPermanent(chosenPermanentToAttachAuras.getFirstTarget()); if (permanentToAttachAuras != null) { for (UUID auraId : auras) { diff --git a/Mage.Sets/src/mage/cards/g/GlamorousOutlaw.java b/Mage.Sets/src/mage/cards/g/GlamorousOutlaw.java new file mode 100644 index 00000000000..23a42c33d84 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GlamorousOutlaw.java @@ -0,0 +1,49 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.GiveManaAbilityAndCastSourceAbility; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GlamorousOutlaw extends CardImpl { + + public GlamorousOutlaw(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{B}{R}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // When Glamorous Outlaw enters the battlefield, it deals 2 damage to each opponent and you scry 2. + Ability ability = new EntersBattlefieldTriggeredAbility( + new DamagePlayersEffect(2, TargetController.OPPONENT, "it") + ); + ability.addEffect(new ScryEffect(2, false).concatBy("and you")); + this.addAbility(ability); + + // {2}, Exile Glamorous Outlaw from your hand: Target land gains "{T}: Add {U}, {B}, or {R}" until Glamorous Outlaw is cast from exile. You may cast Glamorous Outlaw for as long as it remains exiled. + this.addAbility(new GiveManaAbilityAndCastSourceAbility("UBR")); + } + + private GlamorousOutlaw(final GlamorousOutlaw card) { + super(card); + } + + @Override + public GlamorousOutlaw copy() { + return new GlamorousOutlaw(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GlassAsp.java b/Mage.Sets/src/mage/cards/g/GlassAsp.java index e8802e0d938..4ac368e349a 100644 --- a/Mage.Sets/src/mage/cards/g/GlassAsp.java +++ b/Mage.Sets/src/mage/cards/g/GlassAsp.java @@ -28,7 +28,7 @@ public final class GlassAsp extends CardImpl { // Whenever Glass Asp deals combat damage to a player, that player loses 2 life at the beginning of their next draw step unless they pay {2} before that step. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new UnlessPaysDelayedEffect( new ManaCostsImpl("{2}"), new LoseLifeTargetEffect(2), PhaseStep.DRAW, true, - "that player loses 2 life at the beginning of their next draw step unless they pay {2} before that draw step."), + "that player loses 2 life at the beginning of their next draw step unless they pay {2} before that step."), false, true)); } diff --git a/Mage.Sets/src/mage/cards/g/GleefulSabotage.java b/Mage.Sets/src/mage/cards/g/GleefulSabotage.java index b8740eb911d..86b8463fb5b 100644 --- a/Mage.Sets/src/mage/cards/g/GleefulSabotage.java +++ b/Mage.Sets/src/mage/cards/g/GleefulSabotage.java @@ -25,7 +25,7 @@ public final class GleefulSabotage extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); // Conspire - this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE)); + this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.ONE)); } private GleefulSabotage(final GleefulSabotage card) { diff --git a/Mage.Sets/src/mage/cards/g/Glimmerpost.java b/Mage.Sets/src/mage/cards/g/Glimmerpost.java index 82a56d59f20..499490f6a32 100644 --- a/Mage.Sets/src/mage/cards/g/Glimmerpost.java +++ b/Mage.Sets/src/mage/cards/g/Glimmerpost.java @@ -63,7 +63,7 @@ class GlimmerpostEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int amount = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int amount = game.getBattlefield().count(filter, source.getControllerId(), source, game); Player player = game.getPlayer(source.getControllerId()); if (player != null) { player.gainLife(amount, game, source); diff --git a/Mage.Sets/src/mage/cards/g/GlimpseOfTomorrow.java b/Mage.Sets/src/mage/cards/g/GlimpseOfTomorrow.java index aafcd2a15ea..88a839b2184 100644 --- a/Mage.Sets/src/mage/cards/g/GlimpseOfTomorrow.java +++ b/Mage.Sets/src/mage/cards/g/GlimpseOfTomorrow.java @@ -77,7 +77,7 @@ class GlimpseOfTomorrowEffect extends OneShotEffect { return false; } List permanents = game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game ); int count = permanents.size(); player.shuffleCardsToLibrary(new CardsImpl(permanents), game, source); diff --git a/Mage.Sets/src/mage/cards/g/GlimpseTheCosmos.java b/Mage.Sets/src/mage/cards/g/GlimpseTheCosmos.java index be986830a9e..67ef251b584 100644 --- a/Mage.Sets/src/mage/cards/g/GlimpseTheCosmos.java +++ b/Mage.Sets/src/mage/cards/g/GlimpseTheCosmos.java @@ -4,14 +4,13 @@ import java.util.HashSet; import java.util.Set; import mage.abilities.Ability; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.game.events.GameEvent; @@ -35,12 +34,7 @@ public class GlimpseTheCosmos extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}"); // Look at the top three cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(3), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.LIBRARY, false, - false, false, Zone.HAND, false - ).setText("look at the top three cards of your library. " - + "Put one of them into your hand and the rest on the bottom of your library in any order")); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.BOTTOM_ANY)); //As long as you control a Giant, you may cast Glimpse the Cosmos from your graveyard by paying {U} rather than paying its mana cost. If you cast Glimpse the Cosmos this way and it would be put into your graveyard, exile it instead. this.addAbility(new SimpleStaticAbility(Zone.GRAVEYARD, @@ -105,7 +99,7 @@ class GlimpseTheCosmosReplacementEffect extends ReplacementEffectImpl { public GlimpseTheCosmosReplacementEffect() { super(Duration.EndOfGame, Outcome.Benefit); - staticText = "As long as you control a Giant, you may cast {this} from your graveyard by paying {U} rather than paying its mana cost. If you cast {this} this way and it would be put into your graveyard, exile it instead"; + staticText = "As long as you control a Giant, you may cast {this} from your graveyard by paying {U} rather than paying its mana cost. If you cast {this} this way and it would be put into your graveyard, exile it instead"; } public GlimpseTheCosmosReplacementEffect(final GlimpseTheCosmosReplacementEffect effect) { diff --git a/Mage.Sets/src/mage/cards/g/GlimpseTheFuture.java b/Mage.Sets/src/mage/cards/g/GlimpseTheFuture.java index b4c84cc801a..3cbac75e0cc 100644 --- a/Mage.Sets/src/mage/cards/g/GlimpseTheFuture.java +++ b/Mage.Sets/src/mage/cards/g/GlimpseTheFuture.java @@ -1,13 +1,11 @@ - package mage.cards.g; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; -import mage.cards.*; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.StaticFilters; /** * @@ -19,9 +17,7 @@ public final class GlimpseTheFuture extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}"); // Look at the top three cards of your library. Put one of them into your hand and the rest into your graveyard. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(3), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.GRAVEYARD, false, false, false, Zone.HAND, false)); - + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.GRAVEYARD)); } private GlimpseTheFuture(final GlimpseTheFuture card) { diff --git a/Mage.Sets/src/mage/cards/g/GlintEyeNephilim.java b/Mage.Sets/src/mage/cards/g/GlintEyeNephilim.java index 999efefb61e..c78d7e82ee4 100644 --- a/Mage.Sets/src/mage/cards/g/GlintEyeNephilim.java +++ b/Mage.Sets/src/mage/cards/g/GlintEyeNephilim.java @@ -1,4 +1,3 @@ - package mage.cards.g; import java.util.UUID; @@ -8,7 +7,8 @@ import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -16,9 +16,6 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.constants.Zone; -import mage.game.Game; -import mage.players.Player; /** * @author fenhl @@ -33,10 +30,12 @@ public final class GlintEyeNephilim extends CardImpl { this.toughness = new MageInt(2); // Whenever Glint-Eye Nephilim deals combat damage to a player, draw that many cards. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new GlintEyeNephilimEffect(), false, true)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DrawCardSourceControllerEffect(SavedDamageValue.MANY), + false, true)); // {1}, Discard a card: Glint-Eye Nephilim gets +1/+1 until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 1, Duration.EndOfTurn), new GenericManaCost(1)); + Ability ability = new SimpleActivatedAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn), new GenericManaCost(1)); ability.addCost(new DiscardCardCost()); this.addAbility(ability); @@ -51,33 +50,3 @@ public final class GlintEyeNephilim extends CardImpl { return new GlintEyeNephilim(this); } } - -class GlintEyeNephilimEffect extends OneShotEffect { - - public GlintEyeNephilimEffect() { - super(Outcome.DrawCard); - this.staticText = "draw that many cards"; - } - - public GlintEyeNephilimEffect(final GlintEyeNephilimEffect effect) { - super(effect); - } - - @Override - public GlintEyeNephilimEffect copy() { - return new GlintEyeNephilimEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int amount = (Integer) getValue("damage"); - if (amount > 0) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - controller.drawCards(amount, source, game); - return true; - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/g/GlintHawk.java b/Mage.Sets/src/mage/cards/g/GlintHawk.java index 9ed60010291..deeb51a55f4 100644 --- a/Mage.Sets/src/mage/cards/g/GlintHawk.java +++ b/Mage.Sets/src/mage/cards/g/GlintHawk.java @@ -69,7 +69,7 @@ class GlintHawkEffect extends OneShotEffect { } TargetPermanent target = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), controller.getId(), game) + if (target.canChoose(controller.getId(), source, game) && controller.chooseUse(outcome, "Return an artifact you control to its owner's hand?", source, game)) { controller.chooseTarget(Outcome.ReturnToHand, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/g/GlintNestCrane.java b/Mage.Sets/src/mage/cards/g/GlintNestCrane.java index 3a0a5d6d2f7..0edbeddcb23 100644 --- a/Mage.Sets/src/mage/cards/g/GlintNestCrane.java +++ b/Mage.Sets/src/mage/cards/g/GlintNestCrane.java @@ -1,17 +1,15 @@ - package mage.cards.g; import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; /** @@ -29,11 +27,11 @@ public final class GlintNestCrane extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - // When Glint-Nest Crane enters the battlefield, look at the top four cards of your library. You may reveal an artifact card from among them and - // put it into your hand. Put the rest on the bottom of your library in any order. - this.addAbility(new EntersBattlefieldTriggeredAbility( - new LookLibraryAndPickControllerEffect(StaticValue.get(4), false, StaticValue.get(1), - StaticFilters.FILTER_CARD_ARTIFACT_AN, Zone.LIBRARY, false, true, false, Zone.HAND, true))); + // When Glint-Nest Crane enters the battlefield, look at the top four cards of your library. + // You may reveal an artifact card from among them and put it into your hand. + // Put the rest on the bottom of your library in any order. + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 4, 1, StaticFilters.FILTER_CARD_ARTIFACT_AN, PutCards.HAND, PutCards.BOTTOM_ANY))); } private GlintNestCrane(final GlintNestCrane card) { diff --git a/Mage.Sets/src/mage/cards/g/GlintSleeveSiphoner.java b/Mage.Sets/src/mage/cards/g/GlintSleeveSiphoner.java index dad8c4c9ba7..fb07399e7bc 100644 --- a/Mage.Sets/src/mage/cards/g/GlintSleeveSiphoner.java +++ b/Mage.Sets/src/mage/cards/g/GlintSleeveSiphoner.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; import mage.abilities.costs.common.PayEnergyCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; @@ -15,7 +14,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; -import mage.constants.Zone; import java.util.UUID; @@ -39,11 +37,9 @@ public final class GlintSleeveSiphoner extends CardImpl { this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new GetEnergyCountersControllerEffect(1))); // At the beginning of your upkeep, you may pay {E}{E}. If you do, draw a card and you lose 1 life. - DoIfCostPaid doIfCostPaidEffect = new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new PayEnergyCost(2)); - Effect effect = new LoseLifeSourceControllerEffect(1); - doIfCostPaidEffect.addEffect(effect.concatBy("and")); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, doIfCostPaidEffect, TargetController.YOU, false, false, - "At the beginning of your upkeep, ")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DoIfCostPaid( + new DrawCardSourceControllerEffect(1).setText("you draw a card"), new PayEnergyCost(2) + ).addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")), TargetController.YOU, false)); } private GlintSleeveSiphoner(final GlintSleeveSiphoner card) { diff --git a/Mage.Sets/src/mage/cards/g/GlissaTheTraitor.java b/Mage.Sets/src/mage/cards/g/GlissaTheTraitor.java index f71ddd940ea..edff54dff55 100644 --- a/Mage.Sets/src/mage/cards/g/GlissaTheTraitor.java +++ b/Mage.Sets/src/mage/cards/g/GlissaTheTraitor.java @@ -1,11 +1,9 @@ - - package mage.cards.g; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; @@ -13,21 +11,25 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.FilterCard; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.ZoneChangeEvent; -import mage.game.permanent.Permanent; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Loki */ public final class GlissaTheTraitor extends CardImpl { - public GlissaTheTraitor (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}{G}{G}"); + + private static final FilterCard filter = new FilterCard("artifact card from your graveyard"); + + static { + filter.add(CardType.ARTIFACT.getPredicate()); + } + + public GlissaTheTraitor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{G}{G}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); @@ -38,13 +40,20 @@ public final class GlissaTheTraitor extends CardImpl { this.toughness = new MageInt(3); // First strike, this.addAbility(FirstStrikeAbility.getInstance()); + // Deathtouch this.addAbility(DeathtouchAbility.getInstance()); + // Whenever a creature an opponent controls dies, you may return target artifact card from your graveyard to your hand. - this.addAbility(new GlissaTheTraitorTriggeredAbility()); + Ability ability = new DiesCreatureTriggeredAbility( + new ReturnFromGraveyardToHandTargetEffect(), false, + StaticFilters.FILTER_OPPONENTS_PERMANENT_A_CREATURE + ); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); } - public GlissaTheTraitor (final GlissaTheTraitor card) { + public GlissaTheTraitor(final GlissaTheTraitor card) { super(card); } @@ -52,48 +61,4 @@ public final class GlissaTheTraitor extends CardImpl { public GlissaTheTraitor copy() { return new GlissaTheTraitor(this); } - -} - -class GlissaTheTraitorTriggeredAbility extends TriggeredAbilityImpl { - private static final FilterCard filter = new FilterCard("artifact card from your graveyard"); - - static { - filter.add(CardType.ARTIFACT.getPredicate()); - } - - GlissaTheTraitorTriggeredAbility() { - super(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), true); - this.addTarget(new TargetCardInYourGraveyard(filter)); - } - - GlissaTheTraitorTriggeredAbility(final GlissaTheTraitorTriggeredAbility ability) { - super(ability); - } - - @Override - public GlissaTheTraitorTriggeredAbility copy() { - return new GlissaTheTraitorTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ZONE_CHANGE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (((ZoneChangeEvent)event).isDiesEvent()) { - Permanent p = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); - if (p != null && p.isCreature(game) && game.getOpponents(this.getControllerId()).contains(p.getControllerId())) { - return true; - } - } - return false; - } - - @Override - public String getTriggerPhrase() { - return "Whenever a creature an opponent controls is put into a graveyard from the battlefield, " ; - } } diff --git a/Mage.Sets/src/mage/cards/g/GlitteringStockpile.java b/Mage.Sets/src/mage/cards/g/GlitteringStockpile.java new file mode 100644 index 00000000000..b80abdd7c07 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GlitteringStockpile.java @@ -0,0 +1,55 @@ +package mage.cards.g; + +import java.util.UUID; + +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.mana.DynamicManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; + +/** + * + * @author weirddan455 + */ +public final class GlitteringStockpile extends CardImpl { + + private static final DynamicValue xValue = new CountersSourceCount(CounterType.STASH); + + public GlitteringStockpile(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{R}"); + + this.subtype.add(SubType.TREASURE); + + // {T}: Add {R}. Put a stash counter on Glittering Stockpile. + Ability ability = new RedManaAbility(); + ability.addEffect(new AddCountersSourceEffect(CounterType.STASH.createInstance())); + this.addAbility(ability); + + // {T}, Sacrifice Glittering Stockpile: Add X mana of any one color, where X is the number of stash counters on Glittering Stockpile. + ability = new DynamicManaAbility( + new Mana(0, 0, 0, 0, 0, 0, 1, 0), + xValue, new TapSourceCost(), "Add X mana of any one color, where X is the number of stash counters on {this}", true + ); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private GlitteringStockpile(final GlitteringStockpile card) { + super(card); + } + + @Override + public GlitteringStockpile copy() { + return new GlitteringStockpile(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/Glittermonger.java b/Mage.Sets/src/mage/cards/g/Glittermonger.java new file mode 100644 index 00000000000..a480cefb849 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/Glittermonger.java @@ -0,0 +1,40 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Glittermonger extends CardImpl { + + public Glittermonger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // {T}: Create a Treasure token. + this.addAbility(new SimpleActivatedAbility(new CreateTokenEffect(new TreasureToken()), new TapSourceCost())); + } + + private Glittermonger(final Glittermonger card) { + super(card); + } + + @Override + public Glittermonger copy() { + return new Glittermonger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GlobalRuin.java b/Mage.Sets/src/mage/cards/g/GlobalRuin.java index 320840510c6..23cf7b005f0 100644 --- a/Mage.Sets/src/mage/cards/g/GlobalRuin.java +++ b/Mage.Sets/src/mage/cards/g/GlobalRuin.java @@ -70,7 +70,7 @@ class GlobalRuinDestroyLandEffect extends OneShotEffect { FilterControlledLandPermanent filter = new FilterControlledLandPermanent(landName + " you control"); filter.add(landName.getPredicate()); Target target = new TargetControlledPermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(outcome, target, source, game); lands.add(target.getFirstTarget()); } diff --git a/Mage.Sets/src/mage/cards/g/GloomSurgeon.java b/Mage.Sets/src/mage/cards/g/GloomSurgeon.java index 7b60e91a577..1579ebf61ab 100644 --- a/Mage.Sets/src/mage/cards/g/GloomSurgeon.java +++ b/Mage.Sets/src/mage/cards/g/GloomSurgeon.java @@ -52,15 +52,11 @@ class GloomSurgeonEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - GameEvent preventEvent = new PreventDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), event.getAmount(), ((DamageEvent) event).isCombatDamage()); - if (!game.replaceEvent(preventEvent)) { - int preventedDamage = event.getAmount(); - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), preventedDamage)); - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - player.moveCards(player.getLibrary().getTopCards(game, preventedDamage), Zone.EXILED, source, game); - } - return true; + int damage = event.getAmount(); + game.preventDamage(event, source, game, Integer.MAX_VALUE); + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + player.moveCards(player.getLibrary().getTopCards(game, damage), Zone.EXILED, source, game); } return false; } diff --git a/Mage.Sets/src/mage/cards/g/GloriousCharge.java b/Mage.Sets/src/mage/cards/g/GloriousCharge.java index cb27fa88372..642252eaed5 100644 --- a/Mage.Sets/src/mage/cards/g/GloriousCharge.java +++ b/Mage.Sets/src/mage/cards/g/GloriousCharge.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -9,8 +7,9 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author Loki */ public final class GloriousCharge extends CardImpl { @@ -19,7 +18,10 @@ public final class GloriousCharge extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); // Creatures you control get +1/+1 until end of turn. - this.getSpellAbility().addEffect(new BoostControlledEffect(1, 1, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, false)); + this.getSpellAbility().addEffect(new BoostControlledEffect( + 1, 1, Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURES, false + )); } private GloriousCharge(final GloriousCharge card) { diff --git a/Mage.Sets/src/mage/cards/g/GloriousProtector.java b/Mage.Sets/src/mage/cards/g/GloriousProtector.java index 6dce19bb5da..bdc56b54e00 100644 --- a/Mage.Sets/src/mage/cards/g/GloriousProtector.java +++ b/Mage.Sets/src/mage/cards/g/GloriousProtector.java @@ -95,7 +95,7 @@ class GloriousProtectorEffect extends OneShotEffect { return false; } TargetPermanent target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); if (target.getTargets().isEmpty()) { return false; } diff --git a/Mage.Sets/src/mage/cards/g/GlowsporeShaman.java b/Mage.Sets/src/mage/cards/g/GlowsporeShaman.java index c058d1667cb..7954c5ee4b8 100644 --- a/Mage.Sets/src/mage/cards/g/GlowsporeShaman.java +++ b/Mage.Sets/src/mage/cards/g/GlowsporeShaman.java @@ -79,7 +79,7 @@ class GlowsporeShamanEffect extends OneShotEffect { } Target target = new TargetCardInYourGraveyard(0, 1, filter, true); if (player.chooseUse(outcome, "Put a land card on top of your library?", source, game) - && player.choose(outcome, target, source.getSourceId(), game)) { + && player.choose(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { return player.putCardsOnTopOfLibrary(new CardsImpl(card), game, source, false); diff --git a/Mage.Sets/src/mage/cards/g/GlyphOfDelusion.java b/Mage.Sets/src/mage/cards/g/GlyphOfDelusion.java index 13e76804812..14fbd9ab1c9 100644 --- a/Mage.Sets/src/mage/cards/g/GlyphOfDelusion.java +++ b/Mage.Sets/src/mage/cards/g/GlyphOfDelusion.java @@ -74,14 +74,14 @@ class GlyphOfDelusionSecondTarget extends TargetPermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); if (firstTarget != null) { BlockedAttackerWatcher watcher = game.getState().getWatcher(BlockedAttackerWatcher.class); if (watcher != null) { - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); if (targetSource != null) { - for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, sourceId, game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, source, game)) { if (!targets.containsKey(creature.getId()) && creature.canBeTargetedBy(targetSource, sourceControllerId, game)) { if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), new MageObjectReference(firstTarget, game), game)) { possibleTargets.add(creature.getId()); diff --git a/Mage.Sets/src/mage/cards/g/GlyphOfDoom.java b/Mage.Sets/src/mage/cards/g/GlyphOfDoom.java index 6c010d962d6..ed663973bc9 100644 --- a/Mage.Sets/src/mage/cards/g/GlyphOfDoom.java +++ b/Mage.Sets/src/mage/cards/g/GlyphOfDoom.java @@ -108,7 +108,7 @@ class GlyphOfDoomEffect extends OneShotEffect { BlockedAttackerWatcher watcher = game.getState().getWatcher(BlockedAttackerWatcher.class); if (watcher != null) { List toDestroy = new ArrayList<>(); - for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { if (!creature.getId().equals(targetCreature.getSourceId())) { if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), targetCreature, game)) { toDestroy.add(creature); diff --git a/Mage.Sets/src/mage/cards/g/GlyphOfReincarnation.java b/Mage.Sets/src/mage/cards/g/GlyphOfReincarnation.java index 96e569be88d..cc59afba816 100644 --- a/Mage.Sets/src/mage/cards/g/GlyphOfReincarnation.java +++ b/Mage.Sets/src/mage/cards/g/GlyphOfReincarnation.java @@ -85,7 +85,7 @@ class GlyphOfReincarnationEffect extends OneShotEffect { BlockedAttackerWatcher watcher = game.getState().getWatcher(BlockedAttackerWatcher.class); if (watcher != null) { Map destroyed = new HashMap<>(); - for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { if (!creature.getId().equals(targetWall.getId())) { if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), new MageObjectReference(targetWall, game), game)) { if (creature.destroy(source, game, true) @@ -108,7 +108,7 @@ class GlyphOfReincarnationEffect extends OneShotEffect { filter.add(new OwnerIdPredicate(player.getId())); Target targetCreature = new TargetCardInGraveyard(filter); targetCreature.setNotTarget(true); - if (targetCreature.canChoose(source.getSourceId(), controller.getId(), game) + if (targetCreature.canChoose(controller.getId(), source, game) && controller.chooseTarget(outcome, targetCreature, source, game)) { Card card = game.getCard(targetCreature.getFirstTarget()); if (card != null && game.getState().getZone(card.getId()) == Zone.GRAVEYARD) { diff --git a/Mage.Sets/src/mage/cards/g/GnarledEffigy.java b/Mage.Sets/src/mage/cards/g/GnarledEffigy.java index 702e16d7b47..f4c12c554ed 100644 --- a/Mage.Sets/src/mage/cards/g/GnarledEffigy.java +++ b/Mage.Sets/src/mage/cards/g/GnarledEffigy.java @@ -25,7 +25,7 @@ public final class GnarledEffigy extends CardImpl { // {4}, {tap}: Put a -1/-1 counter on target creature. SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.M1M1.createInstance()), - new ManaCostsImpl("4")); + new ManaCostsImpl<>("{4}")); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/g/GnarlrootTrapper.java b/Mage.Sets/src/mage/cards/g/GnarlrootTrapper.java index 2453f52ae2a..a06cc5c3f86 100644 --- a/Mage.Sets/src/mage/cards/g/GnarlrootTrapper.java +++ b/Mage.Sets/src/mage/cards/g/GnarlrootTrapper.java @@ -88,7 +88,7 @@ class GnarlrootTrapperManaCondition extends CreatureCastManaCondition { @Override public boolean apply(Game game, Ability source) { if (super.apply(game, source)) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && object.hasSubtype(SubType.ELF, game) && object.isCreature(game); } diff --git a/Mage.Sets/src/mage/cards/g/GoShintaiOfHiddenCruelty.java b/Mage.Sets/src/mage/cards/g/GoShintaiOfHiddenCruelty.java index fdcf7b47f61..e1568353f42 100644 --- a/Mage.Sets/src/mage/cards/g/GoShintaiOfHiddenCruelty.java +++ b/Mage.Sets/src/mage/cards/g/GoShintaiOfHiddenCruelty.java @@ -87,7 +87,7 @@ enum GoShintaiOfHiddenCrueltyPredicate implements ObjectSourcePlayerPredicate input, Game game) { return input.getObject().getToughness().getValue() <= game.getBattlefield().count( - filter, input.getSourceId(), input.getPlayerId(), game + filter, input.getPlayerId(), input.getSource(), game ); } } diff --git a/Mage.Sets/src/mage/cards/g/GoShintaiOfLifesOrigin.java b/Mage.Sets/src/mage/cards/g/GoShintaiOfLifesOrigin.java new file mode 100644 index 00000000000..5bfa45393be --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoShintaiOfLifesOrigin.java @@ -0,0 +1,72 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterEnchantmentCard; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.ShrineToken; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GoShintaiOfLifesOrigin extends CardImpl { + + private static final FilterCard filter + = new FilterEnchantmentCard("enchantment card from your graveyard"); + private static final FilterPermanent filter2 + = new FilterControlledPermanent(SubType.SHRINE, "nontoken Shrine"); + + static { + filter2.add(TokenPredicate.FALSE); + } + + public GoShintaiOfLifesOrigin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{3}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SHRINE); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // {W}{U}{B}{R}{G}, {T}: Return target enchantment card from your graveyard to the battlefield. + Ability ability = new SimpleActivatedAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect(), + new ManaCostsImpl<>("{W}{U}{B}{R}{G}") + ); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); + + // Whenever Go-Shintai of Life's Origin or another nontoken Shrine enters the battlefield under your control, create a 1/1 colorless Shrine enchantment creature token. + this.addAbility(new EntersBattlefieldThisOrAnotherTriggeredAbility( + new CreateTokenEffect(new ShrineToken()), + filter2, false, true + )); + } + + private GoShintaiOfLifesOrigin(final GoShintaiOfLifesOrigin card) { + super(card); + } + + @Override + public GoShintaiOfLifesOrigin copy() { + return new GoShintaiOfLifesOrigin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoblinArtillery.java b/Mage.Sets/src/mage/cards/g/GoblinArtillery.java index a8148d63bc3..77b0946d7be 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinArtillery.java +++ b/Mage.Sets/src/mage/cards/g/GoblinArtillery.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -12,25 +10,25 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author Loki */ public final class GoblinArtillery extends CardImpl { public GoblinArtillery(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.WARRIOR); this.power = new MageInt(1); this.toughness = new MageInt(3); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new TapSourceCost()); + ability.addEffect(new DamageControllerEffect(3).setText("and 3 damage to you")); ability.addTarget(new TargetAnyTarget()); - ability.addEffect(new DamageControllerEffect(3)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinAssassin.java b/Mage.Sets/src/mage/cards/g/GoblinAssassin.java index 4c84b403a93..9ff79b9becc 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinAssassin.java +++ b/Mage.Sets/src/mage/cards/g/GoblinAssassin.java @@ -69,7 +69,7 @@ class GoblinAssassinTriggeredEffect extends OneShotEffect { if (player != null && !player.flipCoin(source, game, false)) { TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Sacrifice, target, source, game); perms.addAll(target.getTargets()); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinAssault.java b/Mage.Sets/src/mage/cards/g/GoblinAssault.java index 545b8539150..8a0e9fa5ebc 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinAssault.java +++ b/Mage.Sets/src/mage/cards/g/GoblinAssault.java @@ -11,10 +11,8 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.TargetController; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.permanent.token.GoblinToken; -import mage.watchers.common.AttackedThisTurnWatcher; /** * @@ -28,8 +26,8 @@ public final class GoblinAssault extends CardImpl { // At the beginning of your upkeep, create a 1/1 red Goblin creature token with haste. this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CreateTokenEffect(new GoblinToken(true)), TargetController.YOU, false)); - // Goblin creatures attack each turn if able. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AttacksIfAbleAllEffect(StaticFilters.FILTER_PERMANENT_CREATURE_GOBLINS, Duration.WhileOnBattlefield)), new AttackedThisTurnWatcher()); + // Goblin creatures attack each combat if able. + this.addAbility(new SimpleStaticAbility(new AttacksIfAbleAllEffect(StaticFilters.FILTER_PERMANENT_CREATURE_GOBLINS))); } private GoblinAssault(final GoblinAssault card) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinCharbelcher.java b/Mage.Sets/src/mage/cards/g/GoblinCharbelcher.java index 4c3cebb5812..e443c2d2eb7 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinCharbelcher.java +++ b/Mage.Sets/src/mage/cards/g/GoblinCharbelcher.java @@ -62,7 +62,7 @@ class GoblinCharbelcherEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { boolean isMountain = false; - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Player controller = game.getPlayer(source.getControllerId()); if (controller == null || sourceObject == null) { return false; diff --git a/Mage.Sets/src/mage/cards/g/GoblinCratermaker.java b/Mage.Sets/src/mage/cards/g/GoblinCratermaker.java index e86ae628099..173289b048a 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinCratermaker.java +++ b/Mage.Sets/src/mage/cards/g/GoblinCratermaker.java @@ -49,8 +49,7 @@ public final class GoblinCratermaker extends CardImpl { ability.addTarget(new TargetCreaturePermanent()); // • Destroy target colorless nonland permanent. - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetPermanent(filter)); ability.addMode(mode); diff --git a/Mage.Sets/src/mage/cards/g/GoblinDarkDwellers.java b/Mage.Sets/src/mage/cards/g/GoblinDarkDwellers.java index d07ba81c428..7eaddbb3127 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinDarkDwellers.java +++ b/Mage.Sets/src/mage/cards/g/GoblinDarkDwellers.java @@ -72,7 +72,7 @@ class GoblinDarkDwellersEffect extends OneShotEffect { super(Outcome.PlayForFree); this.staticText = "you may cast target instant or sorcery card with " + "mana value 3 or less from your graveyard without paying its mana cost. " - + "If that card would be put into your graveyard this turn, exile it instead"; + + "If that spell would be put into your graveyard this turn, exile it instead"; } GoblinDarkDwellersEffect(final GoblinDarkDwellersEffect effect) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinFestival.java b/Mage.Sets/src/mage/cards/g/GoblinFestival.java index 66510d6bec5..4b59c287929 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinFestival.java +++ b/Mage.Sets/src/mage/cards/g/GoblinFestival.java @@ -71,8 +71,8 @@ class GoblinFestivalChangeControlEffect extends OneShotEffect { if (!controller.flipCoin(source, game, true)) { if (sourcePermanent != null) { Target target = new TargetOpponent(true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - while (!target.isChosen() && target.canChoose(source.getSourceId(), controller.getId(), game) && controller.canRespond()) { + if (target.canChoose(controller.getId(), source, game)) { + while (!target.isChosen() && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target, source, game); } } diff --git a/Mage.Sets/src/mage/cards/g/GoblinGathering.java b/Mage.Sets/src/mage/cards/g/GoblinGathering.java index 7f93f57fbc8..8c4fff2afba 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinGathering.java +++ b/Mage.Sets/src/mage/cards/g/GoblinGathering.java @@ -56,8 +56,8 @@ enum GoblinGatheringDynamicValue implements DynamicValue { Player player = game.getPlayer(sourceAbility.getControllerId()); if (player != null) { amount += player.getGraveyard().count( - filter, sourceAbility.getSourceId(), - sourceAbility.getControllerId(), game + filter, + sourceAbility.getControllerId(), sourceAbility, game ); } return amount + 2; diff --git a/Mage.Sets/src/mage/cards/g/GoblinGuide.java b/Mage.Sets/src/mage/cards/g/GoblinGuide.java index d70184c2b71..330bfa84700 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinGuide.java +++ b/Mage.Sets/src/mage/cards/g/GoblinGuide.java @@ -119,7 +119,7 @@ class GoblinGuideEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player defender = game.getPlayer(getTargetPointer().getFirst(game, source)); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && defender != null) { Card card = defender.getLibrary().getFromTop(game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinHeelcutter.java b/Mage.Sets/src/mage/cards/g/GoblinHeelcutter.java index b295216b91b..09f0bf4e699 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinHeelcutter.java +++ b/Mage.Sets/src/mage/cards/g/GoblinHeelcutter.java @@ -33,7 +33,7 @@ public final class GoblinHeelcutter extends CardImpl { this.addAbility(ability); // Dash {2}{R} (You may cast this spell for its dash cost. If you do, it gains haste, and it's returned from the battlefield to its owner's hand at the beginning of the next end step.) - this.addAbility(new DashAbility(this, "{2}{R}")); + this.addAbility(new DashAbility("{2}{R}")); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinJavelineer.java b/Mage.Sets/src/mage/cards/g/GoblinJavelineer.java index d8879575b88..074ccd261ae 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinJavelineer.java +++ b/Mage.Sets/src/mage/cards/g/GoblinJavelineer.java @@ -1,25 +1,32 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BecomesBlockedSourceTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; -import mage.constants.SubType; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class GoblinJavelineer extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("creature blocking it"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.BLOCKING); + } + public GoblinJavelineer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); @@ -32,10 +39,10 @@ public final class GoblinJavelineer extends CardImpl { this.addAbility(HasteAbility.getInstance()); // Whenever Goblin Javelineer becomes blocked, it deals 1 damage to target creature blocking it. - Ability ability = new BecomesBlockedSourceTriggeredAbility(new DamageTargetEffect(1, "it"), false); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking it"); - filter.add(new BlockingAttackerIdPredicate(this.getId())); - ability.addTarget(new TargetCreaturePermanent(filter)); + Ability ability = new BecomesBlockedSourceTriggeredAbility( + new DamageTargetEffect(1, "it"), false + ); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinPsychopath.java b/Mage.Sets/src/mage/cards/g/GoblinPsychopath.java index d143fc2df33..6deeeeca435 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinPsychopath.java +++ b/Mage.Sets/src/mage/cards/g/GoblinPsychopath.java @@ -98,7 +98,7 @@ class GoblinPsychopathEffect extends ReplacementEffectImpl { } // TODO: make this redirect damage from all blockers controller.damage(event.getAmount(), source.getSourceId(), source, game); - String sourceLogName = game.getObject(source.getSourceId()).getLogName() + ": "; + String sourceLogName = game.getObject(source).getLogName() + ": "; game.informPlayers(sourceLogName + "Redirected " + event.getAmount() + " damage to " + controller.getLogName()); this.discard(); return true; diff --git a/Mage.Sets/src/mage/cards/g/GoblinRabblemaster.java b/Mage.Sets/src/mage/cards/g/GoblinRabblemaster.java index 51e57715cfe..0ea0233356e 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinRabblemaster.java +++ b/Mage.Sets/src/mage/cards/g/GoblinRabblemaster.java @@ -46,14 +46,14 @@ public final class GoblinRabblemaster extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); - // Other Goblin creatures you control attack each turn if able. - this.addAbility(new SimpleStaticAbility(new AttacksIfAbleAllEffect(otherGoblinFilter, Duration.WhileOnBattlefield, true))); + // Other Goblin creatures you control attack each combat if able. + this.addAbility(new SimpleStaticAbility(new AttacksIfAbleAllEffect(otherGoblinFilter))); // At the beginning of combat on your turn, create a 1/1 red Goblin creature token with haste. this.addAbility(new BeginningOfCombatTriggeredAbility(new CreateTokenEffect(new GoblinToken(true)), TargetController.YOU, false)); // When Goblin Rabblemaster attacks, it gets +1/+0 until end of turn for each other attacking Goblin. - this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(new PermanentsOnBattlefieldCount(attackingFilter), StaticValue.get(0), Duration.EndOfTurn, true), false)); + this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(new PermanentsOnBattlefieldCount(attackingFilter), StaticValue.get(0), Duration.EndOfTurn, true, "it"), false)); } private GoblinRabblemaster(final GoblinRabblemaster card) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinRazerunners.java b/Mage.Sets/src/mage/cards/g/GoblinRazerunners.java index d60674eeb85..fa861bae0ab 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinRazerunners.java +++ b/Mage.Sets/src/mage/cards/g/GoblinRazerunners.java @@ -44,7 +44,7 @@ public final class GoblinRazerunners extends CardImpl { this.addAbility(ability); // At the beginning of your end step, you may have Goblin Razerunners deal damage equal to the number of +1/+1 counters on it to target player. - ability = new BeginningOfYourEndStepTriggeredAbility(new DamageTargetEffect(new CountersSourceCount(CounterType.P1P1)), true); + ability = new BeginningOfYourEndStepTriggeredAbility(new DamageTargetEffect(new CountersSourceCount(CounterType.P1P1)).setText("you may have {this} deal damage equal to the number of +1/+1 counters on it to target player or planeswalker"), true); ability.addTarget(new TargetPlayerOrPlaneswalker()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinSecretAgent.java b/Mage.Sets/src/mage/cards/g/GoblinSecretAgent.java index 9a03bbee82c..ed754f85e04 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinSecretAgent.java +++ b/Mage.Sets/src/mage/cards/g/GoblinSecretAgent.java @@ -67,7 +67,7 @@ class GoblinSecretAgentEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { if (!controller.getHand().isEmpty()) { CardsImpl randomCard = new CardsImpl(); diff --git a/Mage.Sets/src/mage/cards/g/GoblinShrine.java b/Mage.Sets/src/mage/cards/g/GoblinShrine.java index a94b797c423..ff992ab47bf 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinShrine.java +++ b/Mage.Sets/src/mage/cards/g/GoblinShrine.java @@ -83,7 +83,7 @@ class EnchantedPermanentSubtypeCondition implements Condition { if (enchantment != null) { Permanent permanent = game.getPermanent(enchantment.getAttachedTo()); if (permanent != null) { - return filter.match(permanent, source.getSourceId(), enchantment.getControllerId(), game); + return filter.match(permanent, enchantment.getControllerId(), source, game); } } return false; diff --git a/Mage.Sets/src/mage/cards/g/GoblinSkycutter.java b/Mage.Sets/src/mage/cards/g/GoblinSkycutter.java index 1342125e7fe..b06a7ee85f1 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinSkycutter.java +++ b/Mage.Sets/src/mage/cards/g/GoblinSkycutter.java @@ -40,7 +40,7 @@ public final class GoblinSkycutter extends CardImpl { this.toughness = new MageInt(1); // Sacrifice Goblin Skycutter: Goblin Skycutter deals 2 damage to target creature with flying. That creature loses flying until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new SacrificeSourceCost()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2, "it"), new SacrificeSourceCost()); ability.addEffect(new LoseAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn).setText("that creature loses flying until end of turn")); ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/g/GoblinSnowman.java b/Mage.Sets/src/mage/cards/g/GoblinSnowman.java index 3864aeb71e5..3b21db0dfce 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinSnowman.java +++ b/Mage.Sets/src/mage/cards/g/GoblinSnowman.java @@ -1,53 +1,53 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BlocksSourceTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.PreventCombatDamageBySourceEffect; import mage.abilities.effects.common.PreventCombatDamageToSourceEffect; 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.FilterAttackingCreature; -import mage.filter.predicate.permanent.BlockedByIdPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author BursegSardaukar */ public final class GoblinSnowman extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("creature it's blocking"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.BLOCKED_BY); + } + public GoblinSnowman(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.subtype.add(SubType.GOBLIN); this.power = new MageInt(1); this.toughness = new MageInt(1); //Whenever Goblin Snowman blocks, prevent all combat damage that would be dealt to and dealt by it this turn. - Effect effect = new PreventCombatDamageBySourceEffect(Duration.EndOfTurn); - effect.setText("prevent all combat damage that would be dealt to"); - Ability ability = new BlocksSourceTriggeredAbility(effect, false); - effect = new PreventCombatDamageToSourceEffect(Duration.EndOfTurn); - effect.setText("and dealt by it this turn"); - ability.addEffect(effect); + Ability ability = new BlocksSourceTriggeredAbility(new PreventCombatDamageBySourceEffect(Duration.EndOfTurn) + .setText("prevent all combat damage that would be dealt to")); + ability.addEffect(new PreventCombatDamageToSourceEffect(Duration.EndOfTurn) + .setText("and dealt by it this turn")); this.addAbility(ability); //{T}: Goblin Snowman deals 1 damage to target creature it's blocking. - FilterAttackingCreature filter = new FilterAttackingCreature("creature it's blocking"); - filter.add(new BlockedByIdPredicate(this.getId())); - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new TapSourceCost()); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinTaskmaster.java b/Mage.Sets/src/mage/cards/g/GoblinTaskmaster.java index ba2061dd64c..e5be2d3f5f0 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinTaskmaster.java +++ b/Mage.Sets/src/mage/cards/g/GoblinTaskmaster.java @@ -41,7 +41,7 @@ public final class GoblinTaskmaster extends CardImpl { this.addAbility(ability); // Morph {R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{R}"))); } private GoblinTaskmaster(final GoblinTaskmaster card) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinTrenches.java b/Mage.Sets/src/mage/cards/g/GoblinTrenches.java index 6b826865ab5..67a40caddde 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinTrenches.java +++ b/Mage.Sets/src/mage/cards/g/GoblinTrenches.java @@ -1,4 +1,3 @@ - package mage.cards.g; import java.util.UUID; @@ -10,10 +9,8 @@ import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledLandPermanent; -import mage.filter.common.FilterControlledPermanent; -import mage.game.permanent.token.GoblinTrenchesToken; +import mage.filter.StaticFilters; +import mage.game.permanent.token.GoblinSoldierToken; import mage.target.common.TargetControlledPermanent; /** @@ -22,14 +19,12 @@ import mage.target.common.TargetControlledPermanent; */ public final class GoblinTrenches extends CardImpl { - static final FilterControlledPermanent filter = new FilterControlledLandPermanent("a land"); - public GoblinTrenches(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{W}"); // {2}, Sacrifice a land: Create two 1/1 red and white Goblin Soldier creature tokens. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new GoblinTrenchesToken(), 2), new GenericManaCost(2)); - ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); + Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new GoblinSoldierToken(), 2), new GenericManaCost(2)); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_LAND_SHORT_TEXT))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinTutor.java b/Mage.Sets/src/mage/cards/g/GoblinTutor.java index 2754eeb0eab..bc1a43ff11a 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinTutor.java +++ b/Mage.Sets/src/mage/cards/g/GoblinTutor.java @@ -50,7 +50,12 @@ class GoblinTutorEffect extends OneShotEffect { public GoblinTutorEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "Roll a six-sided die. If you roll a 1, {this} has no effect. Otherwise, search your library for the indicated card, reveal it, put it into your hand, then shuffle. 2 - A card named Goblin Tutor 3 - An enchantment card 4 - An artifact card 5 - A creature card 6 - An instant or sorcery card"; + this.staticText = "Roll a six-sided die. If you roll a 1, {this} has no effect. Otherwise, search your library for the indicated card, reveal it, put it into your hand, then shuffle." + + "
2 - A card named Goblin Tutor" + + "
3 - An enchantment" + + "
4 - An artifact" + + "
5 - A creature" + + "
6 - An instant or sorcery"; } public GoblinTutorEffect(final GoblinTutorEffect effect) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinWarCry.java b/Mage.Sets/src/mage/cards/g/GoblinWarCry.java index 8357c4a0c29..5379a244223 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinWarCry.java +++ b/Mage.Sets/src/mage/cards/g/GoblinWarCry.java @@ -67,8 +67,8 @@ class GoblinWarCryEffect extends OneShotEffect { FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); filter.add(new ControllerIdPredicate(player.getId())); Target target = new TargetPermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { - while (!target.isChosen() && target.canChoose(source.getSourceId(), player.getId(), game) && player.canRespond()) { + if (target.canChoose(player.getId(), source, game)) { + while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) { player.chooseTarget(Outcome.DestroyPermanent, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/g/GodEternalBontu.java b/Mage.Sets/src/mage/cards/g/GodEternalBontu.java index 0aacb71005e..9ecefcfaa55 100644 --- a/Mage.Sets/src/mage/cards/g/GodEternalBontu.java +++ b/Mage.Sets/src/mage/cards/g/GodEternalBontu.java @@ -86,7 +86,7 @@ class GodEternalBontuEffect extends OneShotEffect { return false; } Target target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); - if (!player.choose(outcome, target, source.getSourceId(), game)) { + if (!player.choose(outcome, target, source, game)) { return false; } int counter = 0; diff --git a/Mage.Sets/src/mage/cards/g/GodPharaohsGift.java b/Mage.Sets/src/mage/cards/g/GodPharaohsGift.java index 70677d46ea6..efecd2d6ba2 100644 --- a/Mage.Sets/src/mage/cards/g/GodPharaohsGift.java +++ b/Mage.Sets/src/mage/cards/g/GodPharaohsGift.java @@ -77,7 +77,7 @@ class GodPharaohsGiftEffect extends OneShotEffect { TargetCardInYourGraveyard target = new TargetCardInYourGraveyard( 0, 1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD, true ); - controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game); + controller.choose(Outcome.PutCreatureInPlay, target, source, game); Card cardChosen = game.getCard(target.getFirstTarget()); if (cardChosen == null || !controller.moveCards(cardChosen, Zone.EXILED, source, game)) { return false; diff --git a/Mage.Sets/src/mage/cards/g/GodosIrregulars.java b/Mage.Sets/src/mage/cards/g/GodosIrregulars.java index 140a514322b..0509a8cf862 100644 --- a/Mage.Sets/src/mage/cards/g/GodosIrregulars.java +++ b/Mage.Sets/src/mage/cards/g/GodosIrregulars.java @@ -1,7 +1,6 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -11,19 +10,26 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class GodosIrregulars extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("creature blocking it"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.BLOCKING); + } + public GodosIrregulars(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WARRIOR); @@ -31,10 +37,8 @@ public final class GodosIrregulars extends CardImpl { this.toughness = new MageInt(1); // {R}: Godo's Irregulars deals 1 damage to target creature blocking it. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl("{R")); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking it"); - filter.add(new BlockingAttackerIdPredicate(this.getId())); - ability.addTarget(new TargetCreaturePermanent(filter)); + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new ManaCostsImpl<>("{R}")); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/Godsend.java b/Mage.Sets/src/mage/cards/g/Godsend.java index 082174f9971..fb7a68cc1c2 100644 --- a/Mage.Sets/src/mage/cards/g/Godsend.java +++ b/Mage.Sets/src/mage/cards/g/Godsend.java @@ -181,7 +181,7 @@ class GodsendRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast this spell because a card with the same name is exiled by " + mageObject.getLogName() + '.'; } diff --git a/Mage.Sets/src/mage/cards/g/GodtrackerOfJund.java b/Mage.Sets/src/mage/cards/g/GodtrackerOfJund.java index faef422294f..93561bd5dbe 100644 --- a/Mage.Sets/src/mage/cards/g/GodtrackerOfJund.java +++ b/Mage.Sets/src/mage/cards/g/GodtrackerOfJund.java @@ -27,7 +27,7 @@ public final class GodtrackerOfJund extends CardImpl { filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 4)); } - String rule = "Whenever a creature with power 5 or greater enters the battlefield under your control, you may put a +1/+1 counter on {this}."; + private static final String rule = "Whenever a creature with power 5 or greater enters the battlefield under your control, you may put a +1/+1 counter on {this}."; public GodtrackerOfJund(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}{G}"); diff --git a/Mage.Sets/src/mage/cards/g/GoldenDemise.java b/Mage.Sets/src/mage/cards/g/GoldenDemise.java index 8a1da17de89..094d83de5d3 100644 --- a/Mage.Sets/src/mage/cards/g/GoldenDemise.java +++ b/Mage.Sets/src/mage/cards/g/GoldenDemise.java @@ -1,7 +1,8 @@ package mage.cards.g; import mage.abilities.condition.common.CitysBlessingCondition; -import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.AddContinuousEffectToGame; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.effects.keyword.AscendEffect; import mage.abilities.hint.common.CitysBlessingHint; @@ -10,8 +11,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; import java.util.UUID; @@ -29,11 +29,9 @@ public final class GoldenDemise extends CardImpl { this.getSpellAbility().addHint(PermanentsYouControlHint.instance); // All creatures get -2/-2 until end of turn. If you have the city's blessing, instead only creatures your opponents control get -2/-2 until end of turn. - FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponents control"); - filter.add(TargetController.OPPONENT.getControllerPredicate()); - this.getSpellAbility().addEffect(new ConditionalContinuousEffect( - new BoostAllEffect(-2, -2, Duration.EndOfTurn, filter, false), - new BoostAllEffect(-2, -2, Duration.EndOfTurn), + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new AddContinuousEffectToGame(new BoostAllEffect(-2, -2, Duration.EndOfTurn, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, false)), + new AddContinuousEffectToGame(new BoostAllEffect(-2, -2, Duration.EndOfTurn)), CitysBlessingCondition.instance, "All creatures get -2/-2 until end of turn. If you have the city's blessing, instead only creatures your opponents control get -2/-2 until end of turn" )); diff --git a/Mage.Sets/src/mage/cards/g/GoldenRatio.java b/Mage.Sets/src/mage/cards/g/GoldenRatio.java index 174d40baf80..bd2a099d8b8 100644 --- a/Mage.Sets/src/mage/cards/g/GoldenRatio.java +++ b/Mage.Sets/src/mage/cards/g/GoldenRatio.java @@ -48,7 +48,7 @@ enum GoldenRatioValue implements DynamicValue { .getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - sourceAbility.getControllerId(), sourceAbility.getSourceId(), game + sourceAbility.getControllerId(), sourceAbility, game ) .stream() .filter(Objects::nonNull) diff --git a/Mage.Sets/src/mage/cards/g/Goldhound.java b/Mage.Sets/src/mage/cards/g/Goldhound.java new file mode 100644 index 00000000000..0b5fa40edd3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/Goldhound.java @@ -0,0 +1,52 @@ + +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.MenaceAbility; +import mage.abilities.mana.AnyColorManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * + * @author Hiddevb + */ +public final class Goldhound extends CardImpl { + + public Goldhound(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{R}"); + + this.subtype.add(SubType.TREASURE); + this.subtype.add(SubType.DOG); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // First Strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // Menace + this.addAbility(new MenaceAbility(true)); + + // {T}, Sacrifice Goldhound: Add one mana of any color. + Ability ability = new AnyColorManaAbility(); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private Goldhound(final Goldhound card) { + super(card); + } + + @Override + public Goldhound copy() { + return new Goldhound(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoldmeadowStalwart.java b/Mage.Sets/src/mage/cards/g/GoldmeadowStalwart.java index 216dbcec536..f7b7778ac3f 100644 --- a/Mage.Sets/src/mage/cards/g/GoldmeadowStalwart.java +++ b/Mage.Sets/src/mage/cards/g/GoldmeadowStalwart.java @@ -34,9 +34,9 @@ public final class GoldmeadowStalwart extends CardImpl { // As an additional cost to cast Goldmeadow Stalwart, reveal a Kithkin card from your hand or pay {3}. this.getSpellAbility().addCost(new OrCost( - new RevealTargetFromHandCost(new TargetCardInHand(filter)), - new GenericManaCost(3), - "reveal a Kithkin card from your hand or pay {3}")); + "reveal a Kithkin card from your hand or pay {3}", new RevealTargetFromHandCost(new TargetCardInHand(filter)), + new GenericManaCost(3) + )); } private GoldmeadowStalwart(final GoldmeadowStalwart card) { diff --git a/Mage.Sets/src/mage/cards/g/GolgariCharm.java b/Mage.Sets/src/mage/cards/g/GolgariCharm.java index 7311f917a06..5fe0b4f363a 100644 --- a/Mage.Sets/src/mage/cards/g/GolgariCharm.java +++ b/Mage.Sets/src/mage/cards/g/GolgariCharm.java @@ -26,14 +26,12 @@ public final class GolgariCharm extends CardImpl { this.getSpellAbility().addEffect(new BoostAllEffect(-1, -1, Duration.EndOfTurn)); // or destroy target enchantment; - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetEnchantmentPermanent()); this.getSpellAbility().addMode(mode); // or regenerate each creature you control. - mode = new Mode(); - mode.addEffect(new RegenerateAllEffect(new FilterControlledCreaturePermanent())); + mode = new Mode(new RegenerateAllEffect(new FilterControlledCreaturePermanent())); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/g/GolgariGuildmage.java b/Mage.Sets/src/mage/cards/g/GolgariGuildmage.java index 364acf34dff..c765a85134e 100644 --- a/Mage.Sets/src/mage/cards/g/GolgariGuildmage.java +++ b/Mage.Sets/src/mage/cards/g/GolgariGuildmage.java @@ -1,28 +1,27 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.StaticFilters; -import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; + /** - * * @author Loki */ public final class GolgariGuildmage extends CardImpl { @@ -34,11 +33,11 @@ public final class GolgariGuildmage extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{4}{B}")); + Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl<>("{4}{B}")); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); 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 = new SimpleActivatedAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl<>("{4}{G}")); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } @@ -51,5 +50,4 @@ public final class GolgariGuildmage extends CardImpl { public GolgariGuildmage copy() { return new GolgariGuildmage(this); } - } diff --git a/Mage.Sets/src/mage/cards/g/GorgonFlail.java b/Mage.Sets/src/mage/cards/g/GorgonFlail.java index be28a0dc46e..a27497ef8f1 100644 --- a/Mage.Sets/src/mage/cards/g/GorgonFlail.java +++ b/Mage.Sets/src/mage/cards/g/GorgonFlail.java @@ -1,9 +1,7 @@ - package mage.cards.g; -import java.util.UUID; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.DeathtouchAbility; @@ -13,22 +11,25 @@ import mage.cards.CardSetInfo; import mage.constants.AttachmentType; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Outcome; -import mage.constants.Zone; + +import java.util.UUID; /** - * * @author North */ public final class GorgonFlail extends CardImpl { public GorgonFlail(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); this.subtype.add(SubType.EQUIPMENT); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(1, 1))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(DeathtouchAbility.getInstance(), AttachmentType.EQUIPMENT))); - this.addAbility(new EquipAbility(Outcome.BoostCreature, new ManaCostsImpl("{2}"))); + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(1, 1)); + ability.addEffect(new GainAbilityAttachedEffect( + DeathtouchAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and has deathtouch")); + this.addAbility(ability); + + this.addAbility(new EquipAbility(2)); } private GorgonFlail(final GorgonFlail card) { diff --git a/Mage.Sets/src/mage/cards/g/GorgonRecluse.java b/Mage.Sets/src/mage/cards/g/GorgonRecluse.java index 4e9e042078e..d428a6d6390 100644 --- a/Mage.Sets/src/mage/cards/g/GorgonRecluse.java +++ b/Mage.Sets/src/mage/cards/g/GorgonRecluse.java @@ -33,7 +33,7 @@ public final class GorgonRecluse extends CardImpl { this.addAbility(new BlocksOrBecomesBlockedSourceTriggeredAbility(effect, StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK, false)); // Madness {B}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{B}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{B}{B}"))); } private GorgonRecluse(final GorgonRecluse card) { diff --git a/Mage.Sets/src/mage/cards/g/GrabTheReins.java b/Mage.Sets/src/mage/cards/g/GrabTheReins.java index 4efa20f4451..bf9d7c668a2 100644 --- a/Mage.Sets/src/mage/cards/g/GrabTheReins.java +++ b/Mage.Sets/src/mage/cards/g/GrabTheReins.java @@ -45,8 +45,7 @@ public final class GrabTheReins extends CardImpl { target.setTargetName("a creature to take control of"); this.getSpellAbility().addTarget(target); // or sacrifice a creature, then Grab the Reins deals damage equal to that creature's power to any target. - Mode mode = new Mode(); - mode.addEffect(new GrabTheReinsEffect()); + Mode mode = new Mode(new GrabTheReinsEffect()); TargetAnyTarget target2 = new TargetAnyTarget(); target2.setTargetName("a creature or player to damage"); mode.addTarget(target2); @@ -83,7 +82,7 @@ class GrabTheReinsEffect extends OneShotEffect { Target target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); target.setTargetName("a creature to sacrifice"); - if (!target.canChoose(source.getSourceId(), controllerId, game)) { + if (!target.canChoose(controllerId, source, game)) { return false; } Player player = game.getPlayer(controllerId); diff --git a/Mage.Sets/src/mage/cards/g/GrandAbolisher.java b/Mage.Sets/src/mage/cards/g/GrandAbolisher.java index 87043a8ced6..cc81e188852 100644 --- a/Mage.Sets/src/mage/cards/g/GrandAbolisher.java +++ b/Mage.Sets/src/mage/cards/g/GrandAbolisher.java @@ -70,7 +70,7 @@ class GrandAbolisherEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { Player activePlayer = game.getPlayer(game.getActivePlayerId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (activePlayer != null && mageObject != null) { return "You can't cast spells or activate abilities of artifacts, creatures, or enchantments during the turns of " + activePlayer.getLogName() + " (" + mageObject.getLogName() + ')'; diff --git a/Mage.Sets/src/mage/cards/g/GrandArchitect.java b/Mage.Sets/src/mage/cards/g/GrandArchitect.java index 27dc7d00e9a..2a53c4a73b3 100644 --- a/Mage.Sets/src/mage/cards/g/GrandArchitect.java +++ b/Mage.Sets/src/mage/cards/g/GrandArchitect.java @@ -140,7 +140,7 @@ class GrandArchitectManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && object.isArtifact(game); } } diff --git a/Mage.Sets/src/mage/cards/g/GrandCrescendo.java b/Mage.Sets/src/mage/cards/g/GrandCrescendo.java new file mode 100644 index 00000000000..496606e7506 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GrandCrescendo.java @@ -0,0 +1,42 @@ +package mage.cards.g; + +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.StaticFilters; +import mage.game.permanent.token.CitizenGreenWhiteToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GrandCrescendo extends CardImpl { + + public GrandCrescendo(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{W}{W}"); + + // Create X 1/1 green and white Citizen creature tokens. Creatures you control gain indestructible until end of turn. + this.getSpellAbility().addEffect(new CreateTokenEffect( + new CitizenGreenWhiteToken(), ManacostVariableValue.REGULAR + )); + this.getSpellAbility().addEffect(new GainAbilityAllEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURES + )); + } + + private GrandCrescendo(final GrandCrescendo card) { + super(card); + } + + @Override + public GrandCrescendo copy() { + return new GrandCrescendo(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GrandMasterOfFlowers.java b/Mage.Sets/src/mage/cards/g/GrandMasterOfFlowers.java index 14815a56916..623682eb1a4 100644 --- a/Mage.Sets/src/mage/cards/g/GrandMasterOfFlowers.java +++ b/Mage.Sets/src/mage/cards/g/GrandMasterOfFlowers.java @@ -2,7 +2,6 @@ package mage.cards.g; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.combat.CantAttackTargetEffect; @@ -47,7 +46,7 @@ public final class GrandMasterOfFlowers extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.BAHAMUT); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // As long as Grand Master of Flowers has seven or more loyalty counters on him, he's a 7/7 Dragon God creature with flying and indestructible. this.addAbility(new SimpleStaticAbility(new GrandMasterOfFlowersEffect())); diff --git a/Mage.Sets/src/mage/cards/g/GraniteShard.java b/Mage.Sets/src/mage/cards/g/GraniteShard.java index b0edd313684..86fea06fa9c 100644 --- a/Mage.Sets/src/mage/cards/g/GraniteShard.java +++ b/Mage.Sets/src/mage/cards/g/GraniteShard.java @@ -27,9 +27,8 @@ public final class GraniteShard extends CardImpl { Ability ability = new SimpleActivatedAbility( new DamageTargetEffect(1), new OrCost( - new CompositeCost(new GenericManaCost(3), new TapSourceCost(), "{3}, {T}"), - new CompositeCost(new ManaCostsImpl<>("{R}"), new TapSourceCost(), "{R}, {T}"), - "{3}, {T} or {R}, {T}" + "{3}, {T} or {R}, {T}", new CompositeCost(new GenericManaCost(3), new TapSourceCost(), "{3}, {T}"), + new CompositeCost(new ManaCostsImpl<>("{R}"), new TapSourceCost(), "{R}, {T}") ) ); ability.addTarget(new TargetAnyTarget()); diff --git a/Mage.Sets/src/mage/cards/g/GrappleWithThePast.java b/Mage.Sets/src/mage/cards/g/GrappleWithThePast.java index 540beb7a986..50333867a55 100644 --- a/Mage.Sets/src/mage/cards/g/GrappleWithThePast.java +++ b/Mage.Sets/src/mage/cards/g/GrappleWithThePast.java @@ -72,9 +72,9 @@ class GrappleWithThePastEffect extends OneShotEffect { } TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(filter); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + if (target.canChoose(source.getControllerId(), source, game) && controller.chooseUse(outcome, "Return a creature or land card from your graveyard to hand?", source, game) - && controller.choose(Outcome.ReturnToHand, target, source.getSourceId(), game)) { + && controller.choose(Outcome.ReturnToHand, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { controller.moveCards(card, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/g/GraveConsequences.java b/Mage.Sets/src/mage/cards/g/GraveConsequences.java new file mode 100644 index 00000000000..7ecdae2a3d3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GraveConsequences.java @@ -0,0 +1,90 @@ +package mage.cards.g; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class GraveConsequences extends CardImpl { + + public GraveConsequences(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); + + // Each player may exile any number of cards from their graveyard. Then each player loses 1 life for each card in their graveyard. + this.getSpellAbility().addEffect(new GraveConsequencesEffect()); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); + } + + private GraveConsequences(final GraveConsequences card) { + super(card); + } + + @Override + public GraveConsequences copy() { + return new GraveConsequences(this); + } +} + +class GraveConsequencesEffect extends OneShotEffect { + + GraveConsequencesEffect() { + super(Outcome.Exile); + staticText = "each player may exile any number of cards from their graveyard. " + + "Then each player loses 1 life for each card in their graveyard"; + } + + private GraveConsequencesEffect(final GraveConsequencesEffect effect) { + super(effect); + } + + @Override + public GraveConsequencesEffect copy() { + return new GraveConsequencesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + List players = game + .getState() + .getPlayersInRange(source.getControllerId(), game) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + for (Player player : players) { + TargetCard target = new TargetCardInYourGraveyard(0, Integer.MAX_VALUE); + target.setNotTarget(true); + player.choose(outcome, target, source, game); + Cards cards = new CardsImpl(target.getTargets()); + if (!cards.isEmpty()) { + player.moveCards(cards, Zone.EXILED, source, game); + } + } + for (Player player : players) { + if (!player.getGraveyard().isEmpty()) { + player.loseLife(player.getLife(), game, source, false); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GraveEndeavor.java b/Mage.Sets/src/mage/cards/g/GraveEndeavor.java index 410fb8dc9f7..5835cbf62f5 100644 --- a/Mage.Sets/src/mage/cards/g/GraveEndeavor.java +++ b/Mage.Sets/src/mage/cards/g/GraveEndeavor.java @@ -82,7 +82,7 @@ class GraveEndeavorEffect extends OneShotEffect { if (player.getGraveyard().count(StaticFilters.FILTER_CARD_CREATURE, game) > 0) { TargetCard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); target.setNotTarget(true); - player.choose(outcome, target, source.getControllerId(), game); + player.choose(outcome, target, source, game); if (target.getFirstTarget() != null) { new ReturnFromGraveyardToBattlefieldWithCounterTargetEffect( CounterType.P1P1.createInstance(first) diff --git a/Mage.Sets/src/mage/cards/g/GraveExchange.java b/Mage.Sets/src/mage/cards/g/GraveExchange.java index 892e85c2f24..cd1dc65f8fa 100644 --- a/Mage.Sets/src/mage/cards/g/GraveExchange.java +++ b/Mage.Sets/src/mage/cards/g/GraveExchange.java @@ -1,26 +1,24 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; 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.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.TargetPlayer; import mage.target.common.TargetCardInYourGraveyard; -import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author North */ public final class GraveExchange extends CardImpl { @@ -29,8 +27,9 @@ public final class GraveExchange extends CardImpl { 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().addEffect(new ReturnFromGraveyardToHandTargetEffect()); 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()); @@ -69,8 +68,10 @@ class GraveExchangeEffect extends OneShotEffect { return false; } - Target target = new TargetControlledPermanent(new FilterControlledCreaturePermanent()); - if (target.canChoose(source.getSourceId(), player.getId(), game) && player.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) { + Target target = new TargetControlledCreaturePermanent(); + target.setNotTarget(true); + if (target.canChoose(player.getId(), source, game) + && player.choose(Outcome.Sacrifice, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { return permanent.sacrifice(source, game); diff --git a/Mage.Sets/src/mage/cards/g/GravePact.java b/Mage.Sets/src/mage/cards/g/GravePact.java index c49d11236e6..7f400126ed8 100644 --- a/Mage.Sets/src/mage/cards/g/GravePact.java +++ b/Mage.Sets/src/mage/cards/g/GravePact.java @@ -104,7 +104,7 @@ class GravePactEffect extends OneShotEffect { if (player != null && !playerId.equals(source.getControllerId())) { TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Sacrifice, target, source, game); perms.addAll(target.getTargets()); } diff --git a/Mage.Sets/src/mage/cards/g/GraveRobbers.java b/Mage.Sets/src/mage/cards/g/GraveRobbers.java index 6764815a786..82cfdb2873a 100644 --- a/Mage.Sets/src/mage/cards/g/GraveRobbers.java +++ b/Mage.Sets/src/mage/cards/g/GraveRobbers.java @@ -1,7 +1,6 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -14,11 +13,12 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class GraveRobbers extends CardImpl { @@ -33,7 +33,7 @@ public final class GraveRobbers extends CardImpl { // {B}, {tap}: Exile target artifact card from a graveyard. You gain 2 life. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(), new ManaCostsImpl("{B}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCardInGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + ability.addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); ability.addEffect(new GainLifeEffect(2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GraveScrabbler.java b/Mage.Sets/src/mage/cards/g/GraveScrabbler.java index 8123f0f3989..2af5869d941 100644 --- a/Mage.Sets/src/mage/cards/g/GraveScrabbler.java +++ b/Mage.Sets/src/mage/cards/g/GraveScrabbler.java @@ -26,7 +26,7 @@ public final class GraveScrabbler extends CardImpl { this.toughness = new MageInt(2); //Madness {1}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{1}{B}"))); //When Grave Scrabbler enters the battlefield, if its madness cost was paid, //you may return target creature card from a graveyard to its owner's hand. diff --git a/Mage.Sets/src/mage/cards/g/GraveSifter.java b/Mage.Sets/src/mage/cards/g/GraveSifter.java index 849376547fb..ca2a8f5de39 100644 --- a/Mage.Sets/src/mage/cards/g/GraveSifter.java +++ b/Mage.Sets/src/mage/cards/g/GraveSifter.java @@ -70,7 +70,7 @@ class GraveSifterEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Choice typeChoice = new ChoiceCreatureType(game.getObject(source.getSourceId())); + Choice typeChoice = new ChoiceCreatureType(game.getObject(source)); typeChoice.setMessage("Choose creature type to return cards from your graveyard"); Player controller = game.getPlayer(source.getControllerId()); Set toHand = new HashSet<>(); diff --git a/Mage.Sets/src/mage/cards/g/Gravedigger.java b/Mage.Sets/src/mage/cards/g/Gravedigger.java index 30a04247b45..a79a5a3b19b 100644 --- a/Mage.Sets/src/mage/cards/g/Gravedigger.java +++ b/Mage.Sets/src/mage/cards/g/Gravedigger.java @@ -1,11 +1,9 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -13,8 +11,9 @@ import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public final class Gravedigger extends CardImpl { @@ -26,7 +25,7 @@ public final class Gravedigger extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); - Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), true); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } @@ -39,5 +38,4 @@ public final class Gravedigger extends CardImpl { public Gravedigger copy() { return new Gravedigger(this); } - } diff --git a/Mage.Sets/src/mage/cards/g/GravelSlinger.java b/Mage.Sets/src/mage/cards/g/GravelSlinger.java index 211117d5582..a35cd707f16 100644 --- a/Mage.Sets/src/mage/cards/g/GravelSlinger.java +++ b/Mage.Sets/src/mage/cards/g/GravelSlinger.java @@ -35,7 +35,7 @@ public final class GravelSlinger extends CardImpl { ability.addTarget(new TargetCreaturePermanent(new FilterAttackingOrBlockingCreature())); this.addAbility(ability); // Morph {1}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{W}"))); } private GravelSlinger(final GravelSlinger card) { diff --git a/Mage.Sets/src/mage/cards/g/GraveyardShift.java b/Mage.Sets/src/mage/cards/g/GraveyardShift.java new file mode 100644 index 00000000000..30c73a1b37a --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GraveyardShift.java @@ -0,0 +1,50 @@ +package mage.cards.g; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.DifferentManaValuesInGraveCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.DifferentManaValuesInGraveHint; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GraveyardShift extends CardImpl { + + public GraveyardShift(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); + + // This spell has flash as long as there are five or more mana values among cards in your graveyard. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, + new ConditionalContinuousEffect(new GainAbilitySourceEffect( + FlashAbility.getInstance(), Duration.WhileOnBattlefield, true + ), DifferentManaValuesInGraveCondition.FIVE, "this spell has flash " + + "as long as there are five or more mana values among cards in your graveyard") + ).setRuleAtTheTop(true).addHint(DifferentManaValuesInGraveHint.instance)); + + // Return target creature card from your graveyard to the battlefield. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + } + + private GraveyardShift(final GraveyardShift card) { + super(card); + } + + @Override + public GraveyardShift copy() { + return new GraveyardShift(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/Graxiplon.java b/Mage.Sets/src/mage/cards/g/Graxiplon.java new file mode 100644 index 00000000000..6649e3605ab --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/Graxiplon.java @@ -0,0 +1,56 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalRestrictionEffect; +import mage.abilities.dynamicvalue.common.GreatestSharedCreatureTypeCount; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Graxiplon extends CardImpl { + + public Graxiplon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Graxiplon can't be blocked unless defending player controls three or more creatures that share a creature type. + this.addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect( + new CantBeBlockedSourceEffect(), GraxiplonCondition.instance, "{this} can't be blocked " + + "unless defending player controls three or more creatures that share a creature type" + ))); + } + + private Graxiplon(final Graxiplon card) { + super(card); + } + + @Override + public Graxiplon copy() { + return new Graxiplon(this); + } +} + +enum GraxiplonCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(game.getCombat().getDefendingPlayerId(source.getSourceId(), game)); + return player == null || GreatestSharedCreatureTypeCount.getValue(player.getId(), source, game) < 3; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GraypeltHunter.java b/Mage.Sets/src/mage/cards/g/GraypeltHunter.java index ee55865c0fa..d21b2ea0db7 100644 --- a/Mage.Sets/src/mage/cards/g/GraypeltHunter.java +++ b/Mage.Sets/src/mage/cards/g/GraypeltHunter.java @@ -28,7 +28,7 @@ public final class GraypeltHunter extends CardImpl { this.toughness = new MageInt(2); this.addAbility(TrampleAbility.getInstance()); - this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true)); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true).setAbilityWord(null)); } private GraypeltHunter(final GraypeltHunter card) { diff --git a/Mage.Sets/src/mage/cards/g/GrazilaxxIllithidScholar.java b/Mage.Sets/src/mage/cards/g/GrazilaxxIllithidScholar.java index 551c0ee72a8..22461db6b5b 100644 --- a/Mage.Sets/src/mage/cards/g/GrazilaxxIllithidScholar.java +++ b/Mage.Sets/src/mage/cards/g/GrazilaxxIllithidScholar.java @@ -3,7 +3,7 @@ package mage.cards.g; import java.util.UUID; import mage.MageInt; import mage.abilities.common.BecomesBlockedAllTriggeredAbility; -import mage.abilities.common.ControlledCreaturesDealCombatDamagePlayerTriggeredAbility; +import mage.abilities.common.DealCombatDamageControlledTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.constants.SubType; @@ -40,7 +40,7 @@ public final class GrazilaxxIllithidScholar extends CardImpl { )); // Whenever one or more creatures you control deal combat damage to a player, draw a card. - this.addAbility(new ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(new DrawCardSourceControllerEffect(1))); + this.addAbility(new DealCombatDamageControlledTriggeredAbility(new DrawCardSourceControllerEffect(1))); } private GrazilaxxIllithidScholar(final GrazilaxxIllithidScholar card) { diff --git a/Mage.Sets/src/mage/cards/g/Greedo.java b/Mage.Sets/src/mage/cards/g/Greedo.java index f5192db19eb..e0af3f9f168 100644 --- a/Mage.Sets/src/mage/cards/g/Greedo.java +++ b/Mage.Sets/src/mage/cards/g/Greedo.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -10,29 +8,39 @@ import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.FilterCard; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.BlockedByIdPredicate; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author Styxo */ public final class Greedo extends CardImpl { + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature blocking or blocked by {this}"); private static final FilterCard filterCard = new FilterCard("Hunter or Rogue card"); static { - filterCard.add(Predicates.or(SubType.ROGUE.getPredicate(), SubType.HUNTER.getPredicate())); + filter.add(BlockingOrBlockedBySourcePredicate.EITHER); + filterCard.add(Predicates.or( + SubType.ROGUE.getPredicate(), + SubType.HUNTER.getPredicate() + )); } public Greedo(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.RODIAN); this.subtype.add(SubType.HUNTER); @@ -40,12 +48,15 @@ public final class Greedo extends CardImpl { this.toughness = new MageInt(4); // Creatures blocking or blocked by Greedo have first strike. - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(Predicates.or(new BlockedByIdPredicate(this.getId()), new BlockingAttackerIdPredicate(this.getId()))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield, filter, "Creatures blocking or blocked by {this} have first strike"))); + this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( + FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield, filter, + "Creatures blocking or blocked by {this} have first strike" + ))); // When Greedo dies, you may search your library for Hunter or Rogue card, reveal it, and put it into your hand. - this.addAbility(new DiesSourceTriggeredAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filterCard), true), true)); + this.addAbility(new DiesSourceTriggeredAbility(new SearchLibraryPutInHandEffect( + new TargetCardInLibrary(filterCard), true + ), true)); } private Greedo(final Greedo card) { diff --git a/Mage.Sets/src/mage/cards/g/GreenWard.java b/Mage.Sets/src/mage/cards/g/GreenWard.java index 7d0782ee67f..ecbd3d18eea 100644 --- a/Mage.Sets/src/mage/cards/g/GreenWard.java +++ b/Mage.Sets/src/mage/cards/g/GreenWard.java @@ -1,10 +1,7 @@ - package mage.cards.g; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; @@ -13,28 +10,20 @@ 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.Zone; -import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.ColorPredicate; +import mage.constants.SubType; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LoneFox */ public final class GreenWard extends CardImpl { - private static final FilterCard filter = new FilterCard("green"); - - static { - filter.add(new ColorPredicate(ObjectColor.GREEN)); - } - public GreenWard(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -42,12 +31,11 @@ public final class GreenWard extends CardImpl { this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Protect)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // Enchanted creature has protection from green. This effect doesn't remove Green Ward. - ProtectionAbility gainedAbility = new ProtectionAbility(filter); - gainedAbility.setAuraIdNotToBeRemoved(this.getId()); - Effect effect = new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA); - effect.setText("Enchanted creature has protection from green. This effect doesn't remove {this}."); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( + ProtectionAbility.from(ObjectColor.GREEN), AttachmentType.AURA + ).setDoesntRemoveItself(true))); } private GreenWard(final GreenWard card) { diff --git a/Mage.Sets/src/mage/cards/g/GreenwardenOfMurasa.java b/Mage.Sets/src/mage/cards/g/GreenwardenOfMurasa.java index 97bfb2e151e..b7e14e50623 100644 --- a/Mage.Sets/src/mage/cards/g/GreenwardenOfMurasa.java +++ b/Mage.Sets/src/mage/cards/g/GreenwardenOfMurasa.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; @@ -15,8 +13,9 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class GreenwardenOfMurasa extends CardImpl { @@ -33,8 +32,9 @@ public final class GreenwardenOfMurasa extends CardImpl { this.addAbility(ability); // When Greenwarden of Murasa dies, you may exile it. If you do, return target card from your graveyard to your hand. - ability = new DiesSourceTriggeredAbility(new DoIfCostPaid(new ReturnFromGraveyardToHandTargetEffect(), new ExileSourceFromGraveCost(), - "Exile {this} and return target card from your graveyard to your hand?", true), false); + ability = new DiesSourceTriggeredAbility(new DoIfCostPaid( + new ReturnFromGraveyardToHandTargetEffect(), new ExileSourceFromGraveCost().setText("exile it") + ), false); ability.addTarget(new TargetCardInYourGraveyard()); this.addAbility(ability); } @@ -47,4 +47,4 @@ public final class GreenwardenOfMurasa extends CardImpl { public GreenwardenOfMurasa copy() { return new GreenwardenOfMurasa(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/g/GremlinInfestation.java b/Mage.Sets/src/mage/cards/g/GremlinInfestation.java index c99b79595aa..d0b7af76ebb 100644 --- a/Mage.Sets/src/mage/cards/g/GremlinInfestation.java +++ b/Mage.Sets/src/mage/cards/g/GremlinInfestation.java @@ -39,9 +39,7 @@ public final class GremlinInfestation extends CardImpl { this.addAbility(ability); // At the beginning of your end step, Gremlin Infestation deals 2 damage to enchanted artifact's controller. - Effect effect = new DamageAttachedControllerEffect(2); - effect.setText("{this} deals 2 damage to enchanted artifact's controller"); - this.addAbility(new BeginningOfEndStepTriggeredAbility(new DamageAttachedControllerEffect(2), TargetController.YOU, false)); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new DamageAttachedControllerEffect(2).setText("{this} deals 2 damage to enchanted artifact's controller"), TargetController.YOU, false)); // When enchanted artifact is put into a graveyard, create a 2/2 red Gremlin creature token. this.addAbility(new DiesAttachedTriggeredAbility(new CreateTokenEffect(new GremlinToken()), "enchanted artifact", false, false)); diff --git a/Mage.Sets/src/mage/cards/g/GrenzoHavocRaiser.java b/Mage.Sets/src/mage/cards/g/GrenzoHavocRaiser.java index ecd8a733a19..7b2a6338ad3 100644 --- a/Mage.Sets/src/mage/cards/g/GrenzoHavocRaiser.java +++ b/Mage.Sets/src/mage/cards/g/GrenzoHavocRaiser.java @@ -47,8 +47,7 @@ public final class GrenzoHavocRaiser extends CardImpl { effect.setText(goadEffectName); Ability ability = new GrenzoHavocRaiserTriggeredAbility(effect); //or Exile the top card of that player's library. Until end of turn, you may cast that card and you may spend mana as though it were mana of any color to cast it. - Mode mode = new Mode(); - mode.addEffect(new GrenzoHavocRaiserEffect()); + Mode mode = new Mode(new GrenzoHavocRaiserEffect()); ability.addMode(mode); this.addAbility(ability); } @@ -147,7 +146,7 @@ class GrenzoHavocRaiserEffect extends OneShotEffect { if (controller != null) { Player damagedPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); if (damagedPlayer != null) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); UUID exileId = CardUtil.getCardExileZoneId(game, source); Card card = damagedPlayer.getLibrary().getFromTop(game); if (card != null && sourceObject != null) { diff --git a/Mage.Sets/src/mage/cards/g/GrenzosRuffians.java b/Mage.Sets/src/mage/cards/g/GrenzosRuffians.java index 4087ba1dfa6..b0aada02c58 100644 --- a/Mage.Sets/src/mage/cards/g/GrenzosRuffians.java +++ b/Mage.Sets/src/mage/cards/g/GrenzosRuffians.java @@ -66,7 +66,7 @@ class GrenzosRuffiansEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { UUID damagedOpponent = this.getTargetPointer().getFirst(game, source); int amount = (Integer) getValue("damage"); - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object != null && amount > 0 && damagedOpponent != null) { for (UUID playerId : game.getOpponents(source.getControllerId())) { if (!Objects.equals(playerId, damagedOpponent)) { diff --git a/Mage.Sets/src/mage/cards/g/GrevenPredatorCaptain.java b/Mage.Sets/src/mage/cards/g/GrevenPredatorCaptain.java index 5e4ff833ca6..90c3adf21af 100644 --- a/Mage.Sets/src/mage/cards/g/GrevenPredatorCaptain.java +++ b/Mage.Sets/src/mage/cards/g/GrevenPredatorCaptain.java @@ -113,7 +113,7 @@ class GrevenPredatorCaptainEffect extends OneShotEffect { TargetPermanent target = new TargetPermanent( 0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, true ); - if (!player.choose(outcome, target, source.getSourceId(), game)) { + if (!player.choose(outcome, target, source, game)) { return false; } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/g/GriefTyrant.java b/Mage.Sets/src/mage/cards/g/GriefTyrant.java index 2897b77d1a2..554125ec054 100644 --- a/Mage.Sets/src/mage/cards/g/GriefTyrant.java +++ b/Mage.Sets/src/mage/cards/g/GriefTyrant.java @@ -31,7 +31,7 @@ public final class GriefTyrant extends CardImpl { this.toughness = new MageInt(8); // Grief Tyrant enters the battlefield with four -1/-1 counters on it. - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance(4)))); + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance(4)),"with four -1/-1 counters on it")); // When Grief Tyrant dies, put a -1/-1 counter on target creature for each -1/-1 counter on Grief Tyrant. Ability ability = new DiesSourceTriggeredAbility(new GriefTyrantEffect()); diff --git a/Mage.Sets/src/mage/cards/g/GriftersBlade.java b/Mage.Sets/src/mage/cards/g/GriftersBlade.java index 71f1249d8f0..1690e79066d 100644 --- a/Mage.Sets/src/mage/cards/g/GriftersBlade.java +++ b/Mage.Sets/src/mage/cards/g/GriftersBlade.java @@ -80,7 +80,7 @@ class GriftersBladeChooseCreatureEffect extends OneShotEffect { if (controller != null && mageObject != null) { TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (controller.choose(this.outcome, target, source.getSourceId(), game)) { + if (controller.choose(this.outcome, target, source, game)) { Permanent attachToCreature = game.getPermanent(target.getFirstTarget()); if (attachToCreature != null) { attachToCreature.addAttachment(mageObject.getId(), source, game); diff --git a/Mage.Sets/src/mage/cards/g/GrimCaptainsCall.java b/Mage.Sets/src/mage/cards/g/GrimCaptainsCall.java index 93a422646f1..363b2ac7f2c 100644 --- a/Mage.Sets/src/mage/cards/g/GrimCaptainsCall.java +++ b/Mage.Sets/src/mage/cards/g/GrimCaptainsCall.java @@ -72,7 +72,7 @@ class GrimCaptainsCallEffect extends OneShotEffect { FilterCreatureCard filter = new FilterCreatureCard(subType.getDescription() + " card"); filter.add(subType.getPredicate()); TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(new FilterCreatureCard(filter)); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (target.canChoose(source.getControllerId(), source, game)) { if (controller.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/g/GrimDiscovery.java b/Mage.Sets/src/mage/cards/g/GrimDiscovery.java index f3a2515eabc..b9a5dfc4d96 100644 --- a/Mage.Sets/src/mage/cards/g/GrimDiscovery.java +++ b/Mage.Sets/src/mage/cards/g/GrimDiscovery.java @@ -1,7 +1,7 @@ package mage.cards.g; import mage.abilities.Mode; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -24,14 +24,15 @@ public final class GrimDiscovery extends CardImpl { // 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().addEffect(new ReturnFromGraveyardToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD).withChooseHint("return to hand")); + // and/or return target land card from your graveyard to your hand. - Mode mode1 = new Mode(); - mode1.addEffect(new ReturnToHandTargetEffect()); - mode1.addTarget(new TargetCardInYourGraveyard(filterLandCard).withChooseHint("return to hand")); - this.getSpellAbility().addMode(mode1); + Mode mode = new Mode(new ReturnFromGraveyardToHandTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard(filterLandCard).withChooseHint("return to hand")); + this.getSpellAbility().addMode(mode); } private GrimDiscovery(final GrimDiscovery card) { diff --git a/Mage.Sets/src/mage/cards/g/GrimFlayer.java b/Mage.Sets/src/mage/cards/g/GrimFlayer.java index dd720fda3c0..e145da19f8c 100644 --- a/Mage.Sets/src/mage/cards/g/GrimFlayer.java +++ b/Mage.Sets/src/mage/cards/g/GrimFlayer.java @@ -7,19 +7,17 @@ import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.hint.common.CardTypesInGraveyardHint; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; -import mage.filter.FilterCard; +import mage.constants.SubType; /** * @author fireshoes @@ -36,19 +34,18 @@ public final class GrimFlayer extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); - // Whenever Grim Flayer deals combat damage to a player, look at the top three cards of your library. Put any number of them into your graveyard - // and the rest back on top of your library in any order. - Effect effect = new LookLibraryAndPickControllerEffect( - StaticValue.get(3), false, StaticValue.get(3), new FilterCard(), Zone.LIBRARY, true, false, true, Zone.GRAVEYARD, false); - effect.setText("look at the top three cards of your library. Put any number of them into your graveyard and the rest back on top of your library in any order"); - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(effect, false)); + // Whenever Grim Flayer deals combat damage to a player, look at the top three cards of your library. + // Put any number of them into your graveyard and the rest back on top of your library in any order. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new LookLibraryAndPickControllerEffect(3, Integer.MAX_VALUE, PutCards.GRAVEYARD, PutCards.TOP_ANY), + false)); // Delirium — Grim Flayer gets +2/+2 as long as there are four or more card types among cards in your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), DeliriumCondition.instance, - "Delirium — {this} gets +2/+2 as long as there are four or more card types among cards in your graveyard")) - .addHint(CardTypesInGraveyardHint.YOU)); + "{this} gets +2/+2 as long as there are four or more card types among cards in your graveyard")) + .setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardHint.YOU)); } private GrimFlayer(final GrimFlayer card) { diff --git a/Mage.Sets/src/mage/cards/g/GrimHaruspex.java b/Mage.Sets/src/mage/cards/g/GrimHaruspex.java index 02d74b1d658..4edec729c6a 100644 --- a/Mage.Sets/src/mage/cards/g/GrimHaruspex.java +++ b/Mage.Sets/src/mage/cards/g/GrimHaruspex.java @@ -39,7 +39,7 @@ public final class GrimHaruspex extends CardImpl { this.toughness = new MageInt(2); // Morph {B} - this.addAbility(new MorphAbility(this, new ColoredManaCost(ColoredManaSymbol.B))); + this.addAbility(new MorphAbility(new ColoredManaCost(ColoredManaSymbol.B))); // Whenever another nontoken creature you control dies, draw a card. this.addAbility(new DiesCreatureTriggeredAbility(new DrawCardSourceControllerEffect(1), false, filter)); diff --git a/Mage.Sets/src/mage/cards/g/GrimHarvest.java b/Mage.Sets/src/mage/cards/g/GrimHarvest.java index ef70c8abfc8..39d8233f9fc 100644 --- a/Mage.Sets/src/mage/cards/g/GrimHarvest.java +++ b/Mage.Sets/src/mage/cards/g/GrimHarvest.java @@ -1,9 +1,7 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.RecoverAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -11,8 +9,9 @@ import mage.constants.CardType; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class GrimHarvest extends CardImpl { @@ -21,11 +20,11 @@ public final class GrimHarvest extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); // Return target creature card from your graveyard to your hand. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); 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)); + this.addAbility(new RecoverAbility(new ManaCostsImpl<>("{2}{B}"), this)); } private GrimHarvest(final GrimHarvest card) { diff --git a/Mage.Sets/src/mage/cards/g/GrimHireling.java b/Mage.Sets/src/mage/cards/g/GrimHireling.java index 0df709311e9..e50f4ea0fef 100644 --- a/Mage.Sets/src/mage/cards/g/GrimHireling.java +++ b/Mage.Sets/src/mage/cards/g/GrimHireling.java @@ -3,7 +3,7 @@ package mage.cards.g; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; -import mage.abilities.common.ControlledCreaturesDealCombatDamagePlayerTriggeredAbility; +import mage.abilities.common.DealCombatDamageControlledTriggeredAbility; import mage.abilities.costs.common.SacrificeXTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.GetXValue; @@ -39,7 +39,7 @@ public final class GrimHireling extends CardImpl { this.toughness = new MageInt(2); // Whenever one or more creatures you control deal combat damage to a player, create two Treasure tokens. - this.addAbility(new ControlledCreaturesDealCombatDamagePlayerTriggeredAbility( + this.addAbility(new DealCombatDamageControlledTriggeredAbility( new CreateTokenEffect(new TreasureToken(), 2) )); diff --git a/Mage.Sets/src/mage/cards/g/GrimPoppet.java b/Mage.Sets/src/mage/cards/g/GrimPoppet.java index 02acd710738..8d365e8ee15 100644 --- a/Mage.Sets/src/mage/cards/g/GrimPoppet.java +++ b/Mage.Sets/src/mage/cards/g/GrimPoppet.java @@ -38,7 +38,7 @@ public final class GrimPoppet extends CardImpl { this.toughness = new MageInt(4); // Grim Poppet enters the battlefield with three -1/-1 counters on it. - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance(3), false))); + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance(3)), "with three -1/-1 counters on it")); // Remove a -1/-1 counter from Grim Poppet: Put a -1/-1 counter on another target creature. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.M1M1.createInstance()), new RemoveCountersSourceCost(CounterType.M1M1.createInstance())); diff --git a/Mage.Sets/src/mage/cards/g/GrimTutor.java b/Mage.Sets/src/mage/cards/g/GrimTutor.java index 4ca8bd99de4..bb8c3f5d687 100644 --- a/Mage.Sets/src/mage/cards/g/GrimTutor.java +++ b/Mage.Sets/src/mage/cards/g/GrimTutor.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.cards.CardImpl; @@ -9,22 +7,21 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author emerald000 */ public final class GrimTutor extends CardImpl { public GrimTutor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{B}"); // Search your library for a card and put that card into your hand, then shuffle your library. - TargetCardInLibrary target = new TargetCardInLibrary(); - this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(target).setText("search your library for a card and put that card into your hand, then shuffle")); + this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary())); + // You lose 3 life. this.getSpellAbility().addEffect(new LoseLifeSourceControllerEffect(3)); - } private GrimTutor(final GrimTutor card) { diff --git a/Mage.Sets/src/mage/cards/g/GrimeGorger.java b/Mage.Sets/src/mage/cards/g/GrimeGorger.java new file mode 100644 index 00000000000..899fbd973c4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GrimeGorger.java @@ -0,0 +1,141 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.dynamicvalue.common.CardTypeAssignment; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.*; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.predicate.card.OwnerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; + +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GrimeGorger extends CardImpl { + + public GrimeGorger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{G}"); + + this.subtype.add(SubType.HORROR); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Menace + this.addAbility(new MenaceAbility(false)); + + // Whenever Grime Gorger attacks, exile up to one card of each card type from defending player's graveyard. Put a +1/+1 counter on Grime Gorger for each card exiled this way. + this.addAbility(new AttacksTriggeredAbility( + new GrimeGorgerEffect(), false, null, SetTargetPointer.PLAYER + )); + } + + private GrimeGorger(final GrimeGorger card) { + super(card); + } + + @Override + public GrimeGorger copy() { + return new GrimeGorger(this); + } +} + +class GrimeGorgerEffect extends OneShotEffect { + + GrimeGorgerEffect() { + super(Outcome.Benefit); + staticText = "exile up to one card of each card type from defending player's graveyard. " + + "Put a +1/+1 counter on {this} for each card exiled this way"; + } + + private GrimeGorgerEffect(final GrimeGorgerEffect effect) { + super(effect); + } + + @Override + public GrimeGorgerEffect copy() { + return new GrimeGorgerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + UUID defenderId = getTargetPointer().getFirst(game, source); + if (player == null || defenderId == null) { + return false; + } + TargetCardInGraveyard target = new GrimeGorgerTarget(defenderId); + player.choose(outcome, target, source, game); + Cards cards = new CardsImpl(target.getTargets()); + if (cards.isEmpty()) { + return false; + } + player.moveCards(cards, Zone.EXILED, source, game); + cards.retainZone(Zone.EXILED, game); + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent != null) { + permanent.addCounters(CounterType.P1P1.createInstance(cards.size()), source, game); + } + return true; + } +} + +class GrimeGorgerTarget extends TargetCardInGraveyard { + + private static final CardTypeAssignment cardTypeAssigner = new CardTypeAssignment(CardType.values()); + + GrimeGorgerTarget(UUID playerId) { + super(0, Integer.MAX_VALUE, makeFilter(playerId)); + this.notTarget = true; + } + + private GrimeGorgerTarget(final GrimeGorgerTarget target) { + super(target); + } + + @Override + public GrimeGorgerTarget copy() { + return new GrimeGorgerTarget(this); + } + + @Override + public boolean canTarget(UUID playerId, UUID id, Ability ability, Game game) { + if (!super.canTarget(playerId, id, ability, game)) { + return false; + } + Card card = game.getCard(id); + if (card == null) { + return false; + } + if (this.getTargets().isEmpty()) { + return true; + } + Cards cards = new CardsImpl(this.getTargets()); + cards.add(card); + return cardTypeAssigner.getRoleCount(cards, game) >= cards.size(); + } + + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); + possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, null, game)); + return possibleTargets; + } + + private static FilterCard makeFilter(UUID playerId) { + FilterCard filter = new FilterCard("a card of each card type"); + filter.add(new OwnerIdPredicate(playerId)); + return filter; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GrimoireThief.java b/Mage.Sets/src/mage/cards/g/GrimoireThief.java index ac8ddc947e5..201b6e2e16d 100644 --- a/Mage.Sets/src/mage/cards/g/GrimoireThief.java +++ b/Mage.Sets/src/mage/cards/g/GrimoireThief.java @@ -120,7 +120,7 @@ class GrimoireThiefLookEffect extends AsThoughEffectImpl { public GrimoireThiefLookEffect() { super(AsThoughEffectType.LOOK_AT_FACE_DOWN, Duration.EndOfGame, Outcome.Benefit); - staticText = "You may look at the cards exiled with {this}"; + staticText = "You may look at cards exiled with {this}"; } public GrimoireThiefLookEffect(final GrimoireThiefLookEffect effect) { @@ -182,7 +182,7 @@ class GrimoireThiefCounterspellEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Cards cards = new CardsImpl(); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Set exileZones = (Set) game.getState().getValue( GrimoireThief.VALUE_PREFIX + source.getSourceId().toString()); if (exileZones != null && sourceObject != null) { diff --git a/Mage.Sets/src/mage/cards/g/GrinningDemon.java b/Mage.Sets/src/mage/cards/g/GrinningDemon.java index ecaa24d51e5..9a7ef93e650 100644 --- a/Mage.Sets/src/mage/cards/g/GrinningDemon.java +++ b/Mage.Sets/src/mage/cards/g/GrinningDemon.java @@ -28,7 +28,7 @@ public final class GrinningDemon extends CardImpl { // At the beginning of your upkeep, you lose 2 life. this.addAbility(new BeginningOfUpkeepTriggeredAbility(new LoseLifeSourceControllerEffect(2), TargetController.YOU, false)); // Morph {2}{B}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{B}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{B}{B}"))); } private GrinningDemon(final GrinningDemon card) { diff --git a/Mage.Sets/src/mage/cards/g/GrinningTotem.java b/Mage.Sets/src/mage/cards/g/GrinningTotem.java index f9a1a54ddbe..65c4191f305 100644 --- a/Mage.Sets/src/mage/cards/g/GrinningTotem.java +++ b/Mage.Sets/src/mage/cards/g/GrinningTotem.java @@ -1,8 +1,5 @@ - package mage.cards.g; -import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -10,7 +7,6 @@ import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; @@ -19,26 +15,26 @@ import mage.constants.*; import mage.game.ExileZone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.players.Player; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetOpponent; import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author Quercitron */ public final class GrinningTotem extends CardImpl { public GrinningTotem(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // {2}, {tap}, Sacrifice Grinning Totem: Search target opponent's library for a card and exile it. Then that player shuffles their library. // Until the beginning of your next upkeep, you may play that card. // At the beginning of your next upkeep, if you haven't played it, put it into its owner's graveyard. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GrinningTotemSearchAndExileEffect(), new ManaCostsImpl("{2}")); + Ability ability = new SimpleActivatedAbility(new GrinningTotemSearchAndExileEffect(), new ManaCostsImpl<>("{2}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetOpponent()); @@ -63,7 +59,7 @@ class GrinningTotemSearchAndExileEffect extends OneShotEffect { "Until the beginning of your next upkeep, you may play that card. " + "At the beginning of your next upkeep, if you haven't played it, put it into its owner's graveyard"; } - + public GrinningTotemSearchAndExileEffect(final GrinningTotemSearchAndExileEffect effect) { super(effect); } @@ -72,45 +68,38 @@ class GrinningTotemSearchAndExileEffect extends OneShotEffect { public GrinningTotemSearchAndExileEffect copy() { return new GrinningTotemSearchAndExileEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player you = game.getPlayer(source.getControllerId()); Player targetOpponent = game.getPlayer(source.getFirstTarget()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (you != null && targetOpponent != null && sourceObject != null) { - if (targetOpponent.getLibrary().hasCards()) { - TargetCardInLibrary targetCard = new TargetCardInLibrary(); - if (you.searchLibrary(targetCard, source, game, targetOpponent.getId())) { - Card card = targetOpponent.getLibrary().remove(targetCard.getFirstTarget(), game); - if (card != null) { - UUID exileZoneId = CardUtil.getCardExileZoneId(game, source); - you.moveCardToExileWithInfo(card, exileZoneId, sourceObject.getIdName(), source, game, Zone.LIBRARY, true); - ContinuousEffect effect = new GrinningTotemMayPlayEffect(); - effect.setTargetPointer(new FixedTarget(card.getId())); - game.addEffect(effect, source); - - game.addDelayedTriggeredAbility(new GrinningTotemDelayedTriggeredAbility(exileZoneId), source); - } - } - } - targetOpponent.shuffleLibrary(source, game); - return true; + if (you == null || targetOpponent == null) { + return false; } - return false; + TargetCardInLibrary targetCard = new TargetCardInLibrary(); + you.searchLibrary(targetCard, source, game, targetOpponent.getId()); + Card card = targetOpponent.getLibrary().getCard(targetCard.getFirstTarget(), game); + if (card != null) { + UUID exileZoneId = CardUtil.getCardExileZoneId(game, source); + you.moveCardsToExile(card, source, game, true, exileZoneId, CardUtil.getSourceName(game, source)); + game.addEffect(new GrinningTotemMayPlayEffect().setTargetPointer(new FixedTarget(card.getId())), source); + game.addDelayedTriggeredAbility(new GrinningTotemDelayedTriggeredAbility(exileZoneId), source); + } + targetOpponent.shuffleLibrary(source, game); + return true; } - + } class GrinningTotemMayPlayEffect extends AsThoughEffectImpl { - + private boolean sameStep = true; public GrinningTotemMayPlayEffect() { super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit); this.staticText = "Until the beginning of your next upkeep, you may play that card."; } - + public GrinningTotemMayPlayEffect(final GrinningTotemMayPlayEffect effect) { super(effect); } @@ -131,7 +120,7 @@ class GrinningTotemMayPlayEffect extends AsThoughEffectImpl { } return false; } - + @Override public boolean apply(Game game, Ability source) { return true; @@ -142,7 +131,7 @@ class GrinningTotemMayPlayEffect extends AsThoughEffectImpl { return source.isControlledBy(affectedControllerId) && sourceId.equals(getTargetPointer().getFirst(game, source)); } - + } class GrinningTotemDelayedTriggeredAbility extends DelayedTriggeredAbility { @@ -194,7 +183,7 @@ class GrinningTotemPutIntoGraveyardEffect extends OneShotEffect { super(Outcome.Detriment); this.exileZoneId = exileZoneId; } - + public GrinningTotemPutIntoGraveyardEffect(final GrinningTotemPutIntoGraveyardEffect effect) { super(effect); this.exileZoneId = effect.exileZoneId; @@ -204,7 +193,7 @@ class GrinningTotemPutIntoGraveyardEffect extends OneShotEffect { public GrinningTotemPutIntoGraveyardEffect copy() { return new GrinningTotemPutIntoGraveyardEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); @@ -214,5 +203,5 @@ class GrinningTotemPutIntoGraveyardEffect extends OneShotEffect { } return false; } - + } diff --git a/Mage.Sets/src/mage/cards/g/GripOfChaos.java b/Mage.Sets/src/mage/cards/g/GripOfChaos.java index 37665fb7bd7..ed7f08fd01a 100644 --- a/Mage.Sets/src/mage/cards/g/GripOfChaos.java +++ b/Mage.Sets/src/mage/cards/g/GripOfChaos.java @@ -1,10 +1,8 @@ package mage.cards.g; -import java.util.Iterator; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; +import mage.abilities.Modes; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -15,14 +13,15 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.stack.StackObject; import mage.target.Target; import mage.target.targetpointer.FixedTarget; import mage.util.RandomUtil; +import java.util.*; +import java.util.stream.Collectors; + /** - * * @author emerald000 */ public final class GripOfChaos extends CardImpl { @@ -50,7 +49,7 @@ class GripOfChaosTriggeredAbility extends TriggeredAbilityImpl { super(Zone.BATTLEFIELD, new GripOfChaosEffect()); } - GripOfChaosTriggeredAbility(final GripOfChaosTriggeredAbility ability) { + private GripOfChaosTriggeredAbility(final GripOfChaosTriggeredAbility ability) { super(ability); } @@ -64,30 +63,32 @@ class GripOfChaosTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getTargetId())); - return true; - } - return false; + this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId())); + return true; } @Override public boolean checkInterveningIfClause(Game game) { - StackObject stackObject = null; - for (Effect effect : this.getEffects()) { - stackObject = game.getStack().getStackObject(effect.getTargetPointer().getFirst(game, this)); + StackObject stackObject = this + .getEffects() + .stream() + .findFirst() + .filter(Objects::nonNull) + .map(Effect::getTargetPointer) + .map(tp -> tp.getFirst(game, this)) + .map(game.getStack()::getStackObject) + .orElse(null); + if (stackObject == null) { + return false; } - if (stackObject != null) { - int numberOfTargets = 0; - for (UUID modeId : stackObject.getStackAbility().getModes().getSelectedModes()) { - Mode mode = stackObject.getStackAbility().getModes().get(modeId); - for (Target target : mode.getTargets()) { - numberOfTargets += target.getTargets().size(); - } - } - return numberOfTargets == 1; - } - return false; + Modes modes = stackObject.getStackAbility().getModes(); + return modes + .getSelectedModes() + .stream() + .map(modes::get) + .map(Mode::getTargets) + .mapToInt(ArrayList::size) + .sum() == 1; } @Override @@ -108,7 +109,7 @@ class GripOfChaosEffect extends OneShotEffect { this.staticText = "reselect its target at random"; } - GripOfChaosEffect(final GripOfChaosEffect effect) { + private GripOfChaosEffect(final GripOfChaosEffect effect) { super(effect); } @@ -120,31 +121,30 @@ class GripOfChaosEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { StackObject stackObject = game.getStack().getStackObject(this.getTargetPointer().getFirst(game, source)); - if (stackObject != null) { - for (UUID modeId : stackObject.getStackAbility().getModes().getSelectedModes()) { - Mode mode = stackObject.getStackAbility().getModes().get(modeId); - for (Target target : mode.getTargets()) { - UUID oldTargetId = target.getFirstTarget(); - Set possibleTargets = target.possibleTargets(stackObject.getSourceId(), stackObject.getControllerId(), game); - if (possibleTargets.contains(stackObject.getId())) { // The stackObject can't target itself - possibleTargets.remove(stackObject.getId()); - } - if (!possibleTargets.isEmpty()) { - int i = 0; - int rnd = RandomUtil.nextInt(possibleTargets.size()); - Iterator it = possibleTargets.iterator(); - while (i < rnd) { - it.next(); - i++; - } - UUID newTargetId = it.next(); - target.remove(oldTargetId); - target.add(newTargetId, game); - } - } - } - return true; + if (stackObject == null) { + return false; } - return false; + Modes modes = stackObject.getStackAbility().getModes(); + for (Target target : modes + .getSelectedModes() + .stream() + .map(modes::get) + .map(Mode::getTargets) + .flatMap(Collection::stream) + .collect(Collectors.toList())) { + UUID oldTargetId = target.getFirstTarget(); + Set possibleTargets = target.possibleTargets( + stackObject.getControllerId(), stackObject.getStackAbility(), game + ); + if (possibleTargets.contains(stackObject.getId())) { // The stackObject can't target itself + possibleTargets.remove(stackObject.getId()); + } + if (!possibleTargets.isEmpty()) { + UUID newTargetId = RandomUtil.randomFromCollection(possibleTargets); + target.remove(oldTargetId); + target.add(newTargetId, game); + } + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/g/GripOfPhyresis.java b/Mage.Sets/src/mage/cards/g/GripOfPhyresis.java index f06e877cbb6..f1cf33c3286 100644 --- a/Mage.Sets/src/mage/cards/g/GripOfPhyresis.java +++ b/Mage.Sets/src/mage/cards/g/GripOfPhyresis.java @@ -69,7 +69,7 @@ class GripOfPhyresisEffect extends CreateTokenEffect { if (controller != null && equipment != null) { if (super.apply(game, source)) { - Permanent germ = game.getPermanent(this.getLastAddedTokenId()); + Permanent germ = game.getPermanent(this.getLastAddedTokenIds().stream().findFirst().orElse(null)); if (germ != null) { germ.addAttachment(equipment.getId(), source, game); return true; diff --git a/Mage.Sets/src/mage/cards/g/GrislySalvage.java b/Mage.Sets/src/mage/cards/g/GrislySalvage.java index d2941a50269..2ab1d716f62 100644 --- a/Mage.Sets/src/mage/cards/g/GrislySalvage.java +++ b/Mage.Sets/src/mage/cards/g/GrislySalvage.java @@ -1,30 +1,28 @@ - package mage.cards.g; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.cards.*; + +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.effects.common.RevealLibraryPickControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; +import mage.filter.StaticFilters; /** * - * @author LevelX2 + * @author awjackson */ public final class GrislySalvage extends CardImpl { public GrislySalvage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}{G}"); - // Reveal the top five cards of your library. You may put a creature or land card from among them into your hand. Put the rest into your graveyard. - this.getSpellAbility().addEffect(new GrislySalvageEffect()); + // Reveal the top five cards of your library. + // You may put a creature or land card from among them into your hand. + // Put the rest into your graveyard. + this.getSpellAbility().addEffect(new RevealLibraryPickControllerEffect( + 5, 1, StaticFilters.FILTER_CARD_CREATURE_OR_LAND, PutCards.HAND, PutCards.GRAVEYARD)); } private GrislySalvage(final GrislySalvage card) { @@ -36,50 +34,3 @@ public final class GrislySalvage extends CardImpl { return new GrislySalvage(this); } } - -class GrislySalvageEffect extends OneShotEffect { - - private static final FilterCard filterPutInHand = new FilterCard("creature or land card to put in hand"); - - static { - filterPutInHand.add(Predicates.or(CardType.CREATURE.getPredicate(), CardType.LAND.getPredicate())); - } - - public GrislySalvageEffect() { - super(Outcome.DrawCard); - this.staticText = "Reveal the top five cards of your library. You may put a creature or land card from among them into your hand. Put the rest into your graveyard"; - } - - public GrislySalvageEffect(final GrislySalvageEffect effect) { - super(effect); - } - - @Override - public GrislySalvageEffect copy() { - return new GrislySalvageEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5)); - boolean properCardFound = cards.count(filterPutInHand, game) > 0; - if (!cards.isEmpty()) { - controller.revealCards(source, cards, game); - TargetCard target = new TargetCard(Zone.LIBRARY, filterPutInHand); - if (properCardFound && controller.chooseUse(outcome, "Put a creature or land card from the revealed cards into your hand?", source, game) - && controller.choose(Outcome.DrawCard, cards, target, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - controller.moveCards(card, Zone.HAND, source, game); - cards.remove(card); - } - } - controller.moveCards(cards, Zone.GRAVEYARD, source, game); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/g/GrislySigil.java b/Mage.Sets/src/mage/cards/g/GrislySigil.java new file mode 100644 index 00000000000..2d49c4e13ce --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GrislySigil.java @@ -0,0 +1,114 @@ +package mage.cards.g; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.CasualtyAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.DamagedEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreatureOrPlaneswalker; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GrislySigil extends CardImpl { + + public GrislySigil(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); + + // Casualty 1 + this.addAbility(new CasualtyAbility(this, 1)); + + // Choose target creature or planeswalker. If it was dealt noncombat damage this turn, Grisly Sigil deals 3 damage to it and you gain 3 life. Otherwise, Grisly Sigil deals 1 damage to it and you gain 1 life. + this.getSpellAbility().addEffect(new GrislySigilEffect()); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + this.getSpellAbility().addWatcher(new GrislySigilWatcher()); + } + + private GrislySigil(final GrislySigil card) { + super(card); + } + + @Override + public GrislySigil copy() { + return new GrislySigil(this); + } +} + +class GrislySigilEffect extends OneShotEffect { + + GrislySigilEffect() { + super(Outcome.Benefit); + staticText = "choose target creature or planeswalker. If it was dealt noncombat damage this turn, {this} " + + "deals 3 damage to it and you gain 3 life. Otherwise, {this} deals 1 damage to it and you gain 1 life"; + } + + private GrislySigilEffect(final GrislySigilEffect effect) { + super(effect); + } + + @Override + public GrislySigilEffect copy() { + return new GrislySigilEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + return false; + } + int amount = GrislySigilWatcher.checkPermanent(permanent, game) ? 3 : 1; + permanent.damage(amount, source, game); + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + player.gainLife(amount, game, source); + } + return true; + } +} + +class GrislySigilWatcher extends Watcher { + + private final Set morSet = new HashSet<>(); + + GrislySigilWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.DAMAGED_PERMANENT + && !((DamagedEvent) event).isCombatDamage()) { + morSet.add(new MageObjectReference(event.getTargetId(), game)); + } + } + + @Override + public void reset() { + super.reset(); + morSet.clear(); + } + + static boolean checkPermanent(Permanent permanent, Game game) { + return game + .getState() + .getWatcher(GrislySigilWatcher.class) + .morSet + .stream() + .anyMatch(mor -> mor.refersTo(permanent, game)); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GristTheHungerTide.java b/Mage.Sets/src/mage/cards/g/GristTheHungerTide.java index 2db1bc837a5..c97b6fc2d0e 100644 --- a/Mage.Sets/src/mage/cards/g/GristTheHungerTide.java +++ b/Mage.Sets/src/mage/cards/g/GristTheHungerTide.java @@ -3,7 +3,6 @@ package mage.cards.g; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.costs.common.SacrificeTargetCost; @@ -44,7 +43,7 @@ public final class GristTheHungerTide extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.GRIST); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // As long as Grist, the Hunger Tide isn't on the battlefield, it's a 1/1 Insect creature in addition to its other types. this.addAbility(new SimpleStaticAbility(Zone.ALL, new GristTheHungerTideTypeEffect())); diff --git a/Mage.Sets/src/mage/cards/g/GrixisCharm.java b/Mage.Sets/src/mage/cards/g/GrixisCharm.java index d6091f54fb8..7615bf94244 100644 --- a/Mage.Sets/src/mage/cards/g/GrixisCharm.java +++ b/Mage.Sets/src/mage/cards/g/GrixisCharm.java @@ -27,13 +27,11 @@ public final class GrixisCharm extends CardImpl { this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent()); // or target creature gets -4/-4 until end of turn; - Mode mode = new Mode(); - mode.addEffect(new BoostTargetEffect(-4, -4, Duration.EndOfTurn)); + Mode mode = new Mode(new BoostTargetEffect(-4, -4, Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or creatures you control get +2/+0 until end of turn. - mode = new Mode(); - mode.addEffect(new BoostControlledEffect(2, 0, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, false)); + mode = new Mode(new BoostControlledEffect(2, 0, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES, false)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/g/GrixisSojourners.java b/Mage.Sets/src/mage/cards/g/GrixisSojourners.java index 5b42f507f31..9883885b482 100644 --- a/Mage.Sets/src/mage/cards/g/GrixisSojourners.java +++ b/Mage.Sets/src/mage/cards/g/GrixisSojourners.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.CycleTriggeredAbility; @@ -9,40 +7,41 @@ import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.keyword.CyclingAbility; +import mage.abilities.meta.OrTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.FilterCard; -import mage.target.common.TargetCardInASingleGraveyard; +import mage.constants.Zone; +import mage.target.common.TargetCardInGraveyard; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class GrixisSojourners extends CardImpl { public GrixisSojourners(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}{R}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.OGRE); - - - - this.power = new MageInt(4); this.toughness = new MageInt(3); // When you cycle Grixis Sojourners or it dies, you may exile target card from a graveyard. - Ability ability1 = new CycleTriggeredAbility(new ExileTargetEffect(), true); - Ability ability2 = new DiesSourceTriggeredAbility(new ExileTargetEffect(), true); - ability1.addTarget(new TargetCardInASingleGraveyard(1, 1, new FilterCard())); - ability2.addTarget(new TargetCardInASingleGraveyard(1, 1, new FilterCard())); - this.addAbility(ability1); - this.addAbility(ability2); - + Ability ability = new OrTriggeredAbility(Zone.ALL, + new ExileTargetEffect(), + true, + "When you cycle {this} or it dies, ", + new CycleTriggeredAbility(null, true), + new DiesSourceTriggeredAbility(null, true) + ); + ability.addTarget(new TargetCardInGraveyard()); + this.addAbility(ability); + // Cycling {2}{B} - this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}{B}"))); + this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{2}{B}"))); } private GrixisSojourners(final GrixisSojourners card) { diff --git a/Mage.Sets/src/mage/cards/g/GrizzledAngler.java b/Mage.Sets/src/mage/cards/g/GrizzledAngler.java index 3726aae9f96..59d3015cdc2 100644 --- a/Mage.Sets/src/mage/cards/g/GrizzledAngler.java +++ b/Mage.Sets/src/mage/cards/g/GrizzledAngler.java @@ -76,7 +76,7 @@ class GrizzledAnglerEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { controller.millCards(2, source, game); - if (controller.getGraveyard().count(filter, source.getSourceId(), source.getControllerId(), game) >= 1) { + if (controller.getGraveyard().count(filter, source.getControllerId(), source, game) >= 1) { return new TransformSourceEffect().apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/g/Groffskithur.java b/Mage.Sets/src/mage/cards/g/Groffskithur.java index c536006bf64..0aca5e7e818 100644 --- a/Mage.Sets/src/mage/cards/g/Groffskithur.java +++ b/Mage.Sets/src/mage/cards/g/Groffskithur.java @@ -1,11 +1,10 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BecomesBlockedSourceTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -14,26 +13,27 @@ import mage.filter.FilterCard; import mage.filter.predicate.mageobject.NamePredicate; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class Groffskithur extends CardImpl { - + private static final FilterCard filter = new FilterCard("card named Groffskithur from your graveyard"); - + static { filter.add(new NamePredicate("Groffskithur")); } public Groffskithur(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}"); this.subtype.add(SubType.BEAST); this.power = new MageInt(3); this.toughness = new MageInt(3); // Whenever Groffskithur becomes blocked, you may return target card named Groffskithur from your graveyard to your hand. - Ability ability = new BecomesBlockedSourceTriggeredAbility(new ReturnToHandTargetEffect(), true); + Ability ability = new BecomesBlockedSourceTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), true); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/Groundbreaker.java b/Mage.Sets/src/mage/cards/g/Groundbreaker.java index 564797eeb32..8dadb394261 100644 --- a/Mage.Sets/src/mage/cards/g/Groundbreaker.java +++ b/Mage.Sets/src/mage/cards/g/Groundbreaker.java @@ -31,7 +31,7 @@ public final class Groundbreaker extends CardImpl { // Haste this.addAbility(HasteAbility.getInstance()); // At the beginning of the end step, sacrifice Groundbreaker. - this.addAbility(new BeginningOfEndStepTriggeredAbility(new SacrificeSourceEffect(), TargetController.ANY, false)); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new SacrificeSourceEffect(), TargetController.NEXT, false)); } private Groundbreaker(final Groundbreaker card) { diff --git a/Mage.Sets/src/mage/cards/g/GroundshakerSliver.java b/Mage.Sets/src/mage/cards/g/GroundshakerSliver.java index 5c35d4afa93..e18edf0c197 100644 --- a/Mage.Sets/src/mage/cards/g/GroundshakerSliver.java +++ b/Mage.Sets/src/mage/cards/g/GroundshakerSliver.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -9,13 +7,13 @@ import mage.abilities.keyword.TrampleAbility; 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.constants.SubType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class GroundshakerSliver extends CardImpl { @@ -28,9 +26,10 @@ public final class GroundshakerSliver extends CardImpl { this.toughness = new MageInt(5); // Sliver creatures you control have trample. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new GainAbilityControlledEffect(TrampleAbility.getInstance(), - Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS))); + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_SLIVERS + ))); } private GroundshakerSliver(final GroundshakerSliver card) { diff --git a/Mage.Sets/src/mage/cards/g/Groundskeeper.java b/Mage.Sets/src/mage/cards/g/Groundskeeper.java index 9330f688b68..b5b35ee5935 100644 --- a/Mage.Sets/src/mage/cards/g/Groundskeeper.java +++ b/Mage.Sets/src/mage/cards/g/Groundskeeper.java @@ -1,36 +1,37 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterCard; import mage.filter.common.FilterBasicLandCard; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class Groundskeeper extends CardImpl { + private static final FilterCard filter = new FilterBasicLandCard("basic land card from your graveyard"); + public Groundskeeper(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.DRUID); this.power = new MageInt(1); this.toughness = new MageInt(1); // {1}{G}: Return target basic land card from your graveyard to your hand. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{1}{G}")); - ability.addTarget(new TargetCardInYourGraveyard(new FilterBasicLandCard("basic land card from your graveyard"))); + Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl<>("{1}{G}")); + ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GrowingRitesOfItlimoc.java b/Mage.Sets/src/mage/cards/g/GrowingRitesOfItlimoc.java index a4216f7cb5b..c39a4047953 100644 --- a/Mage.Sets/src/mage/cards/g/GrowingRitesOfItlimoc.java +++ b/Mage.Sets/src/mage/cards/g/GrowingRitesOfItlimoc.java @@ -1,4 +1,3 @@ - package mage.cards.g; import java.util.UUID; @@ -8,6 +7,7 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.TransformAbility; import mage.cards.CardImpl; @@ -16,8 +16,6 @@ import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SuperType; import mage.constants.TargetController; -import mage.constants.Zone; -import mage.filter.FilterCard; import mage.filter.StaticFilters; /** @@ -25,12 +23,6 @@ import mage.filter.StaticFilters; */ public final class GrowingRitesOfItlimoc extends CardImpl { - private static final FilterCard filter = new FilterCard("a creature card"); - - static { - filter.add(CardType.CREATURE.getPredicate()); - } - public GrowingRitesOfItlimoc(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); @@ -41,7 +33,8 @@ public final class GrowingRitesOfItlimoc extends CardImpl { // When Growing Rites of Itlimoc enters the battlefield, look at the top four cards of your library. // You may reveal a creature card from among them and put it into your hand. // Put the rest on the bottom of your library in any order. - this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect(4, 1, filter, true, true, Zone.HAND, false))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 4, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_ANY))); // At the beginning of your end step, if you control four or more creatures, transform Growing Rites of Itlimoc. this.addAbility(new TransformAbility()); @@ -59,4 +52,4 @@ public final class GrowingRitesOfItlimoc extends CardImpl { public GrowingRitesOfItlimoc copy() { return new GrowingRitesOfItlimoc(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/g/Grozoth.java b/Mage.Sets/src/mage/cards/g/Grozoth.java index efd51bc413e..9bafeffc8be 100644 --- a/Mage.Sets/src/mage/cards/g/Grozoth.java +++ b/Mage.Sets/src/mage/cards/g/Grozoth.java @@ -1,55 +1,57 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.SearchEffect; import mage.abilities.effects.common.continuous.LoseAbilitySourceEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.keyword.DefenderAbility; import mage.abilities.keyword.TransmuteAbility; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.ManaValuePredicate; -import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author fireshoes */ public final class Grozoth extends CardImpl { + private static final FilterCard filter = new FilterCard("cards that have mana value 9"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, 9)); + } + public Grozoth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{6}{U}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{U}{U}{U}"); this.subtype.add(SubType.LEVIATHAN); this.power = new MageInt(9); this.toughness = new MageInt(9); // Defender this.addAbility(DefenderAbility.getInstance()); - + // When Grozoth enters the battlefield, you may search your library for any number of cards that have converted mana cost 9, reveal them, and put them into your hand. If you do, shuffle your library. - this.addAbility(new EntersBattlefieldTriggeredAbility(new GrozothEffect(), true)); - + this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect( + new TargetCardInLibrary(0, Integer.MAX_VALUE, filter), true, true + ), true)); + // {4}: Grozoth loses defender until end of turn. - this.addAbility(new SimpleActivatedAbility( - Zone.BATTLEFIELD, - new LoseAbilitySourceEffect(DefenderAbility.getInstance(), Duration.EndOfTurn), - new ManaCostsImpl("{4}"))); - + this.addAbility(new SimpleActivatedAbility(new LoseAbilitySourceEffect( + DefenderAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl<>("{4}"))); + // Transmute {1}{U}{U} - this.addAbility(new TransmuteAbility("{1}{U}{U}")); + this.addAbility(new TransmuteAbility("{1}{U}{U}")); } private Grozoth(final Grozoth card) { @@ -61,48 +63,3 @@ public final class Grozoth extends CardImpl { return new Grozoth(this); } } - -class GrozothEffect extends SearchEffect { - - private static final FilterCard filter = new FilterCard(); - - static { - filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, 9)); - } - - public GrozothEffect() { - super(new TargetCardInLibrary(0, Integer.MAX_VALUE, filter), Outcome.DrawCard); - staticText = "search your library for any number of cards that have mana value 9, reveal them, put them into your hand, then shuffle"; - } - - public GrozothEffect(final GrozothEffect effect) { - super(effect); - } - - @Override - public GrozothEffect copy() { - return new GrozothEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Card sourceCard = game.getCard(source.getSourceId()); - if (sourceCard != null && player != null && player.searchLibrary(target, source, game)) { - if (!target.getTargets().isEmpty()) { - Cards cards = new CardsImpl(); - for (UUID cardId : target.getTargets()) { - Card card = player.getLibrary().remove(cardId, game); - if (card != null) { - cards.add(card); - } - } - player.revealCards(sourceCard.getIdName(), cards, game); - player.moveCards(cards, Zone.HAND, source, game); - } - player.shuffleLibrary(source, game); - return true; - } - return false; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GruesomeFate.java b/Mage.Sets/src/mage/cards/g/GruesomeFate.java index 088a916e14d..958419c7253 100644 --- a/Mage.Sets/src/mage/cards/g/GruesomeFate.java +++ b/Mage.Sets/src/mage/cards/g/GruesomeFate.java @@ -1,7 +1,7 @@ - package mage.cards.g; import java.util.UUID; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.cards.CardImpl; @@ -15,11 +15,15 @@ import mage.filter.StaticFilters; */ public final class GruesomeFate extends CardImpl { + private static final DynamicValue xValue + = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED); + public GruesomeFate(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); // Each opponent loses 1 life for each creature you control. - this.getSpellAbility().addEffect(new LoseLifeOpponentsEffect(new PermanentsOnBattlefieldCount(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED))); + this.getSpellAbility().addEffect(new LoseLifeOpponentsEffect(xValue) + .setText("each opponent loses 1 life for each creature you control")); } private GruesomeFate(final GruesomeFate card) { diff --git a/Mage.Sets/src/mage/cards/g/GruesomeMenagerie.java b/Mage.Sets/src/mage/cards/g/GruesomeMenagerie.java index d033c58cfae..586f9b41fa6 100644 --- a/Mage.Sets/src/mage/cards/g/GruesomeMenagerie.java +++ b/Mage.Sets/src/mage/cards/g/GruesomeMenagerie.java @@ -85,7 +85,7 @@ class GruesomeMenagerieEffect extends OneShotEffect { Target target; target = new TargetCardInYourGraveyard(filter1); target.setNotTarget(true); - if (player.choose(outcome, target, source.getSourceId(), game)) { + if (player.choose(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { cards.add(card); @@ -93,7 +93,7 @@ class GruesomeMenagerieEffect extends OneShotEffect { } target = new TargetCardInYourGraveyard(filter2); target.setNotTarget(true); - if (player.choose(outcome, target, source.getSourceId(), game)) { + if (player.choose(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { cards.add(card); @@ -101,7 +101,7 @@ class GruesomeMenagerieEffect extends OneShotEffect { } target = new TargetCardInYourGraveyard(filter3); target.setNotTarget(true); - if (player.choose(outcome, target, source.getSourceId(), game)) { + if (player.choose(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { cards.add(card); diff --git a/Mage.Sets/src/mage/cards/g/GruulCharm.java b/Mage.Sets/src/mage/cards/g/GruulCharm.java index e9f9b567bf9..b5b12de4a06 100644 --- a/Mage.Sets/src/mage/cards/g/GruulCharm.java +++ b/Mage.Sets/src/mage/cards/g/GruulCharm.java @@ -41,14 +41,10 @@ public final class GruulCharm extends CardImpl { this.getSpellAbility().addEffect(new CantBlockAllEffect(filter, Duration.EndOfTurn)); // or gain control of all permanents you own; - Mode mode = new Mode(); - mode.addEffect(new GainControlAllEffect(Duration.EndOfGame, filter2)); - this.getSpellAbility().addMode(mode); + this.getSpellAbility().addMode(new Mode(new GainControlAllEffect(Duration.EndOfGame, filter2))); // or Gruul Charm deals 3 damage to each creature with flying. - Mode mode2 = new Mode(); - mode2.addEffect(new DamageAllEffect(3, filter3)); - this.getSpellAbility().addMode(mode2); + this.getSpellAbility().addMode(new Mode(new DamageAllEffect(3, filter3))); } private GruulCharm(final GruulCharm card) { diff --git a/Mage.Sets/src/mage/cards/g/GuardDogs.java b/Mage.Sets/src/mage/cards/g/GuardDogs.java index 8c470c10fb4..3659e5dc4a3 100644 --- a/Mage.Sets/src/mage/cards/g/GuardDogs.java +++ b/Mage.Sets/src/mage/cards/g/GuardDogs.java @@ -69,7 +69,7 @@ class GuardDogsEffect extends PreventionEffectImpl { public void init(Ability source, Game game) { this.controlledTarget = new TargetControlledPermanent(); this.controlledTarget.setNotTarget(true); - this.controlledTarget.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.controlledTarget.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); super.init(source, game); } diff --git a/Mage.Sets/src/mage/cards/g/GuardianBeast.java b/Mage.Sets/src/mage/cards/g/GuardianBeast.java index 8b6a57b819d..6cf9aeb058f 100644 --- a/Mage.Sets/src/mage/cards/g/GuardianBeast.java +++ b/Mage.Sets/src/mage/cards/g/GuardianBeast.java @@ -1,20 +1,19 @@ package mage.cards.g; -import java.util.Objects; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.SourceTappedCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.FilterObject; import mage.filter.FilterStackObject; import mage.filter.StaticFilters; @@ -25,8 +24,10 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.stack.StackObject; +import java.util.Objects; +import java.util.UUID; + /** - * * @author spjspj */ public final class GuardianBeast extends CardImpl { @@ -48,13 +49,14 @@ public final class GuardianBeast extends CardImpl { // As long as Guardian Beast is untapped, noncreature artifacts you control can't be enchanted, they're indestructible, and other players can't gain control of them. // This effect doesn't remove Auras already attached to those artifacts. - Effect effect = new ConditionalContinuousEffect(new GainAbilityControlledEffect(IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield, filter), - SourceTappedCondition.UNTAPPED, - "As long as Guardian Beast is untapped, noncreature artifacts you control can't be enchanted, they're indestructible"); - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); - ability.addEffect(new GuardianBeastConditionalEffect(this.getId())); + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilityControlledEffect( + IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield, filter + ), SourceTappedCondition.UNTAPPED, "As long as {this} is untapped, " + + "noncreature artifacts you control can't be enchanted, they're indestructible" + )); + ability.addEffect(new GuardianBeastConditionalEffect()); this.addAbility(ability); - } private GuardianBeast(final GuardianBeast card) { @@ -69,17 +71,13 @@ public final class GuardianBeast extends CardImpl { class GuardianBeastConditionalEffect extends ContinuousRuleModifyingEffectImpl { - private final UUID guardianBeastId; - - public GuardianBeastConditionalEffect(UUID guardianBeastId) { + public GuardianBeastConditionalEffect() { super(Duration.WhileOnBattlefield, Outcome.Neutral); staticText = ", and other players can't gain control of them. This effect doesn't remove Auras already attached to those artifacts"; - this.guardianBeastId = guardianBeastId; } public GuardianBeastConditionalEffect(final GuardianBeastConditionalEffect effect) { super(effect); - this.guardianBeastId = effect.guardianBeastId; } @Override @@ -99,15 +97,14 @@ class GuardianBeastConditionalEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent sourceObject = game.getPermanent(source.getSourceId()); + Permanent permanent = source.getSourcePermanentIfItStillExists(game); Permanent targetPermanent = game.getPermanent(event.getTargetId()); - Permanent guardianBeast = game.getPermanent(guardianBeastId); - if (guardianBeast == null || guardianBeast.isTapped() || sourceObject == null || targetPermanent == null) { + if (permanent == null || permanent.isTapped() || targetPermanent == null) { return false; } - if (!Objects.equals(targetPermanent.getControllerId(), guardianBeast.getControllerId())) { + if (!Objects.equals(targetPermanent.getControllerId(), permanent.getControllerId())) { return false; } diff --git a/Mage.Sets/src/mage/cards/g/GuardianOfFaith.java b/Mage.Sets/src/mage/cards/g/GuardianOfFaith.java index c6504703b78..11761a1bc93 100644 --- a/Mage.Sets/src/mage/cards/g/GuardianOfFaith.java +++ b/Mage.Sets/src/mage/cards/g/GuardianOfFaith.java @@ -44,7 +44,7 @@ public final class GuardianOfFaith extends CardImpl { // When Guardian of Faith enters the battlefield, any number of other target creatures you control phase out. Ability ability = new EntersBattlefieldTriggeredAbility(new PhaseOutTargetEffect( - "any number of other target creatures you control", false + "any number of other target creatures you control" )); ability.addTarget(new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, false)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/g/GuardianOfTheAges.java b/Mage.Sets/src/mage/cards/g/GuardianOfTheAges.java index 05917c5dd75..08d836f4352 100644 --- a/Mage.Sets/src/mage/cards/g/GuardianOfTheAges.java +++ b/Mage.Sets/src/mage/cards/g/GuardianOfTheAges.java @@ -26,7 +26,7 @@ import mage.game.permanent.Permanent; */ public final class GuardianOfTheAges extends CardImpl { public GuardianOfTheAges(UUID ownerId, CardSetInfo setInfo){ - super(ownerId,setInfo,new CardType[]{CardType.CREATURE,CardType.ARTIFACT},"{7}"); + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{7}"); this.subtype.add(SubType.GOLEM); this.power = new MageInt(7); diff --git a/Mage.Sets/src/mage/cards/g/GuardianOfTheGateless.java b/Mage.Sets/src/mage/cards/g/GuardianOfTheGateless.java index 6499ae14de6..16dea26e991 100644 --- a/Mage.Sets/src/mage/cards/g/GuardianOfTheGateless.java +++ b/Mage.Sets/src/mage/cards/g/GuardianOfTheGateless.java @@ -1,10 +1,11 @@ - package mage.cards.g; import java.util.UUID; import mage.MageInt; import mage.abilities.common.BlocksSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.combat.CanBlockAdditionalCreatureEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.FlyingAbility; @@ -13,7 +14,8 @@ 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.permanent.BlockingOrBlockedBySourcePredicate; /** * @@ -21,6 +23,15 @@ import mage.constants.Zone; */ public final class GuardianOfTheGateless extends CardImpl { + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creature it's blocking"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.BLOCKED_BY); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + public GuardianOfTheGateless(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{W}"); this.subtype.add(SubType.ANGEL); @@ -32,10 +43,11 @@ public final class GuardianOfTheGateless extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Guardian of the Gateless can block any number of creatures. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CanBlockAdditionalCreatureEffect(0))); + this.addAbility(new SimpleStaticAbility(new CanBlockAdditionalCreatureEffect(0))); // Whenever Guardian of the Gateless blocks, it gets +1/+1 until end of turn for each creature it's blocking. - this.addAbility(new BlocksSourceTriggeredAbility(new BoostSourceEffect(1,1, Duration.EndOfTurn),false)); + this.addAbility(new BlocksSourceTriggeredAbility( + new BoostSourceEffect(xValue, xValue, Duration.EndOfTurn, true, "it"))); } private GuardianOfTheGateless(final GuardianOfTheGateless card) { diff --git a/Mage.Sets/src/mage/cards/g/GuardianProject.java b/Mage.Sets/src/mage/cards/g/GuardianProject.java index 27f3158c6cc..8807dc986ec 100644 --- a/Mage.Sets/src/mage/cards/g/GuardianProject.java +++ b/Mage.Sets/src/mage/cards/g/GuardianProject.java @@ -72,7 +72,7 @@ class GuardianProjectTriggeredAbility extends EntersBattlefieldAllTriggeredAbili @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); - if (!filter.match(permanent, sourceId, controllerId, game)) { + if (!filter.match(permanent, controllerId, this, game)) { return false; } diff --git a/Mage.Sets/src/mage/cards/g/GuardianShieldBearer.java b/Mage.Sets/src/mage/cards/g/GuardianShieldBearer.java index 39e07e9915b..d7810c327f5 100644 --- a/Mage.Sets/src/mage/cards/g/GuardianShieldBearer.java +++ b/Mage.Sets/src/mage/cards/g/GuardianShieldBearer.java @@ -37,7 +37,7 @@ public final class GuardianShieldBearer extends CardImpl { this.toughness = new MageInt(1); // Megamorph {3}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{G}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{G}"), true)); // When Guardian Shield-Bearer is turned face up, put a +1/+1 counter on another target creature you control. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false); diff --git a/Mage.Sets/src/mage/cards/g/GuardianZendikon.java b/Mage.Sets/src/mage/cards/g/GuardianZendikon.java index 5617b175e7d..65b69f4c033 100644 --- a/Mage.Sets/src/mage/cards/g/GuardianZendikon.java +++ b/Mage.Sets/src/mage/cards/g/GuardianZendikon.java @@ -44,7 +44,7 @@ public final class GuardianZendikon extends CardImpl { this.addAbility(ability); Ability ability2 = new SimpleStaticAbility(Zone.BATTLEFIELD, new BecomesCreatureAttachedEffect( - new GuardianZendikonWallToken(), "Enchanted land is a 2/6 white wall creature with defender. It's still a land", Duration.WhileOnBattlefield, BecomesCreatureAttachedEffect.LoseType.COLOR)); + new GuardianZendikonWallToken(), "Enchanted land is a 2/6 white Wall creature with defender. It's still a land", Duration.WhileOnBattlefield, BecomesCreatureAttachedEffect.LoseType.COLOR)); this.addAbility(ability2); Ability ability3 = new DiesAttachedTriggeredAbility(new ReturnToHandAttachedEffect(), "enchanted land", false); @@ -64,7 +64,7 @@ public final class GuardianZendikon extends CardImpl { class GuardianZendikonWallToken extends TokenImpl { GuardianZendikonWallToken() { - super("", "2/6 white wall creature with defender"); + super("", "2/6 white Wall creature with defender"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.WALL); diff --git a/Mage.Sets/src/mage/cards/g/GudulLurker.java b/Mage.Sets/src/mage/cards/g/GudulLurker.java index 6e7d7af371c..ddac8b13454 100644 --- a/Mage.Sets/src/mage/cards/g/GudulLurker.java +++ b/Mage.Sets/src/mage/cards/g/GudulLurker.java @@ -27,7 +27,7 @@ public final class GudulLurker extends CardImpl { this.addAbility(new CantBeBlockedSourceAbility()); // Megamorph {U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{U}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{U}"), true)); } private GudulLurker(final GudulLurker card) { diff --git a/Mage.Sets/src/mage/cards/g/GuidedPassage.java b/Mage.Sets/src/mage/cards/g/GuidedPassage.java index ee90202993f..f2af2b4f1ec 100644 --- a/Mage.Sets/src/mage/cards/g/GuidedPassage.java +++ b/Mage.Sets/src/mage/cards/g/GuidedPassage.java @@ -71,7 +71,7 @@ class GuidedPassageEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/g/GuildSummit.java b/Mage.Sets/src/mage/cards/g/GuildSummit.java index d3b79f90809..271258213ba 100644 --- a/Mage.Sets/src/mage/cards/g/GuildSummit.java +++ b/Mage.Sets/src/mage/cards/g/GuildSummit.java @@ -81,7 +81,7 @@ class GuildSummitEffect extends OneShotEffect { int tappedAmount = 0; Player you = game.getPlayer(source.getControllerId()); TargetPermanent target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) && target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), game)) { + if (target.canChoose(source.getControllerId(), source, game) && target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), source, game)) { for (UUID creatureId : target.getTargets()) { Permanent creature = game.getPermanent(creatureId); if (creature != null) { diff --git a/Mage.Sets/src/mage/cards/g/GuileSonicSoldier.java b/Mage.Sets/src/mage/cards/g/GuileSonicSoldier.java new file mode 100644 index 00000000000..5476369962c --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GuileSonicSoldier.java @@ -0,0 +1,107 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.LifelinkAbility; +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.players.Player; +import mage.target.common.TargetAnyTarget; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GuileSonicSoldier extends CardImpl { + + public GuileSonicSoldier(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{R}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever Guile, Sonic Soldier enters the battlefield or attacks, put a charge counter on him or remove one from him. When you remove a counter this way, choose one— + // • Sonic Boom—Guile, Sonic Soldier deals 4 damage to any target. + // • Flash Kick—Guile, Sonic Soldier gains lifelink and indestructible until end of turn. + this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new GuileSonicSoldierEffect())); + } + + private GuileSonicSoldier(final GuileSonicSoldier card) { + super(card); + } + + @Override + public GuileSonicSoldier copy() { + return new GuileSonicSoldier(this); + } +} + +class GuileSonicSoldierEffect extends OneShotEffect { + + private final ReflexiveTriggeredAbility ability = makeAbility(); + + GuileSonicSoldierEffect() { + super(Outcome.Benefit); + staticText = "put a charge counter on him or remove one from him. When you remove a counter this way, " + + CardUtil.getTextWithFirstCharLowerCase(ability.getRule()); + } + + private GuileSonicSoldierEffect(final GuileSonicSoldierEffect effect) { + super(effect); + } + + @Override + public GuileSonicSoldierEffect copy() { + return new GuileSonicSoldierEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (player == null || permanent == null) { + return false; + } + if (!permanent.getCounters(game).containsKey(CounterType.CHARGE) || player.chooseUse( + outcome, "Add or remove a charge counter?", null, + "Add", "Remove", source, game + )) { + permanent.addCounters(CounterType.CHARGE.createInstance(), source, game); + } else { + permanent.removeCounters(CounterType.CHARGE.createInstance(), source, game); + game.fireReflexiveTriggeredAbility(ability, source); + } + return true; + } + + private static final ReflexiveTriggeredAbility makeAbility() { + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( + new DamageTargetEffect(4), false + ); + ability.addTarget(new TargetAnyTarget()); + Mode mode = new Mode(new GainAbilitySourceEffect( + LifelinkAbility.getInstance(), Duration.EndOfTurn + ).setText("{this} gains lifelink")); + mode.addEffect(new GainAbilitySourceEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn + ).setText("and indestructible until end of turn")); + ability.withFirstModeFlavorWord("Sonic Boom").addMode(mode.withFlavorWord("Flash Kick")); + return ability; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GuiltyConscience.java b/Mage.Sets/src/mage/cards/g/GuiltyConscience.java index 67b8e14442e..ee7e3cfdc93 100644 --- a/Mage.Sets/src/mage/cards/g/GuiltyConscience.java +++ b/Mage.Sets/src/mage/cards/g/GuiltyConscience.java @@ -1,31 +1,30 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DealsDamageAttachedTriggeredAbility; -import mage.abilities.dynamicvalue.common.NumericSetToEffectValues; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.DamageAttachedEffect; 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.Zone; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author HanClinto */ public final class GuiltyConscience extends CardImpl { public GuiltyConscience(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); - + this.subtype.add(SubType.AURA); // Enchant creature @@ -36,7 +35,7 @@ public final class GuiltyConscience extends CardImpl { this.addAbility(ability); // Whenever enchanted creature deals damage, Guilty Conscience deals that much damage to that creature. - this.addAbility(new DealsDamageAttachedTriggeredAbility(Zone.BATTLEFIELD, new DamageAttachedEffect(new NumericSetToEffectValues("that much", "damage")), false)); + this.addAbility(new DealsDamageAttachedTriggeredAbility(Zone.BATTLEFIELD, new DamageAttachedEffect(SavedDamageValue.MUCH).setText("that much damage to that creature"), false)); } private GuiltyConscience(final GuiltyConscience card) { diff --git a/Mage.Sets/src/mage/cards/g/GurmagDrowner.java b/Mage.Sets/src/mage/cards/g/GurmagDrowner.java index ebd7cb33103..93cb5bef3a7 100644 --- a/Mage.Sets/src/mage/cards/g/GurmagDrowner.java +++ b/Mage.Sets/src/mage/cards/g/GurmagDrowner.java @@ -1,17 +1,15 @@ - package mage.cards.g; import java.util.UUID; import mage.MageInt; import mage.abilities.common.ExploitCreatureTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.ExploitAbility; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.StaticFilters; /** * @@ -29,9 +27,10 @@ public final class GurmagDrowner extends CardImpl { // Exploit this.addAbility(new ExploitAbility()); - // When Gurmag Drowner exploits a creature, look at the top four cards of your library. Put one of them into your hand and the rest into your graveyard. - this.addAbility(new ExploitCreatureTriggeredAbility(new LookLibraryAndPickControllerEffect(StaticValue.get(4), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.GRAVEYARD, false, false, false, Zone.HAND, false), false)); + // When Gurmag Drowner exploits a creature, look at the top four cards of your library. + // Put one of them into your hand and the rest into your graveyard. + this.addAbility(new ExploitCreatureTriggeredAbility( + new LookLibraryAndPickControllerEffect(4, 1, PutCards.HAND, PutCards.GRAVEYARD))); } private GurmagDrowner(final GurmagDrowner card) { diff --git a/Mage.Sets/src/mage/cards/g/Gurzigost.java b/Mage.Sets/src/mage/cards/g/Gurzigost.java index a8782180369..8a2c0a46be8 100644 --- a/Mage.Sets/src/mage/cards/g/Gurzigost.java +++ b/Mage.Sets/src/mage/cards/g/Gurzigost.java @@ -77,7 +77,7 @@ class GurzigostCost extends CostImpl { public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { - if (targets.choose(Outcome.Removal, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.Removal, controllerId, source.getSourceId(), source, game)) { for (UUID targetId: targets.get(0).getTargets()) { Card card = game.getCard(targetId); if (card == null || game.getState().getZone(targetId) != Zone.GRAVEYARD) { @@ -93,7 +93,7 @@ class GurzigostCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/g/GustOfWind.java b/Mage.Sets/src/mage/cards/g/GustOfWind.java index 19c5a506f20..b114d177736 100644 --- a/Mage.Sets/src/mage/cards/g/GustOfWind.java +++ b/Mage.Sets/src/mage/cards/g/GustOfWind.java @@ -51,7 +51,7 @@ public final class GustOfWind extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent(filter2)); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private GustOfWind(final GustOfWind card) { diff --git a/Mage.Sets/src/mage/cards/g/GusthasScepter.java b/Mage.Sets/src/mage/cards/g/GusthasScepter.java index 0cd624e4790..633ff738d4f 100644 --- a/Mage.Sets/src/mage/cards/g/GusthasScepter.java +++ b/Mage.Sets/src/mage/cards/g/GusthasScepter.java @@ -1,37 +1,31 @@ package mage.cards.g; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; -import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.AsThoughEffectImpl; 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.AsThoughEffectType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; -import mage.game.Game; import mage.game.ExileZone; +import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.players.Player; -import mage.target.Target; +import mage.target.TargetCard; import mage.target.common.TargetCardInExile; import mage.target.common.TargetCardInHand; +import mage.util.CardUtil; + +import java.util.UUID; /** - * - * @author LevelX2, jeffwadsworth & L_J + * @author LevelX2, jeffwadsworth, L_J & TheElk801 */ public final class GusthasScepter extends CardImpl { @@ -39,16 +33,13 @@ public final class GusthasScepter extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{0}"); // {T}: Exile a card from your hand face down. You may look at it for as long as it remains exiled. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GusthasScepterExileEffect(), new TapSourceCost())); + this.addAbility(new SimpleActivatedAbility(new GusthasScepterExileEffect(), new TapSourceCost())); // {T}: Return a card you own exiled with Gustha’s Scepter to your hand. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new TapSourceCost()); - ability.addTarget(new TargetCardInGusthasScepterExile(this.getId())); - this.addAbility(ability); + this.addAbility(new SimpleActivatedAbility(new GusthasScepterReturnEffect(), new TapSourceCost())); // When you lose control of Gustha’s Scepter, put all cards exiled with Gustha’s Scepter into their owner’s graveyard. this.addAbility(new GusthasScepterLoseControlAbility()); - } private GusthasScepter(final GusthasScepter card) { @@ -65,7 +56,7 @@ class GusthasScepterExileEffect extends OneShotEffect { public GusthasScepterExileEffect() { super(Outcome.DrawCard); - staticText = "Exile a card from your hand face down. You may look at it for as long as it remains exiled"; + staticText = "exile a card from your hand face down. You may look at it for as long as it remains exiled"; } public GusthasScepterExileEffect(final GusthasScepterExileEffect effect) { @@ -75,25 +66,23 @@ class GusthasScepterExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Target target = new TargetCardInHand(new FilterCard("card to exile")); - if (controller.chooseTarget(outcome, target, source, game)) { - Card card = game.getCard(target.getFirstTarget()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (card != null && sourceObject != null) { - UUID exileId = source.getSourceId(); - if (card.moveToExile(exileId, - sourceObject.getIdName(), - source, - game)) { - card.setFaceDown(true, game); - game.addEffect(new GusthasScepterLookAtCardEffect(card.getId()), source); - return true; - } - } - } + if (controller == null || controller.getHand().isEmpty()) { + return false; } - return false; + TargetCard target = new TargetCardInHand(); + controller.chooseTarget(outcome, controller.getHand(), target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return false; + } + controller.moveCardsToExile( + card, source, game, false, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + card.setFaceDown(true, game); + game.addEffect(new GusthasScepterLookAtCardEffect(card, game), source); + return true; } @Override @@ -102,81 +91,54 @@ class GusthasScepterExileEffect extends OneShotEffect { } } -class TargetCardInGusthasScepterExile extends TargetCardInExile { +class GusthasScepterReturnEffect extends OneShotEffect { - public TargetCardInGusthasScepterExile(UUID cardId) { - super(1, 1, new FilterCard("card exiled with Gustha's Scepter"), null); + private static final FilterCard filter = new FilterCard("card you own exiled with this permanent"); + + GusthasScepterReturnEffect() { + super(Outcome.Benefit); + staticText = "return a card you own exiled with {this} to your hand"; } - public TargetCardInGusthasScepterExile(final TargetCardInGusthasScepterExile target) { - super(target); + private GusthasScepterReturnEffect(final GusthasScepterReturnEffect effect) { + super(effect); } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet<>(); - Card sourceCard = game.getCard(sourceId); - if (sourceCard != null) { - UUID exileId = sourceId; - ExileZone exile = game.getExile().getExileZone(exileId); - if (exile != null && !exile.isEmpty()) { - possibleTargets.addAll(exile); - } + public GusthasScepterReturnEffect copy() { + return new GusthasScepterReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; } - return possibleTargets; - } - - @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - Card sourceCard = game.getCard(sourceId); - if (sourceCard != null) { - UUID exileId = sourceId; - ExileZone exile = game.getExile().getExileZone(exileId); - if (exile != null && !exile.isEmpty()) { - return true; - } + TargetCard target = new TargetCardInExile(filter, CardUtil.getExileZoneId(game, source)); + target.setNotTarget(true); + if (!target.canChoose(source.getControllerId(), source, game)) { + return false; } - return false; - } - - @Override - public boolean canTarget(UUID id, Ability source, Game game) { - Card card = game.getCard(id); - if (card != null - && game.getState().getZone(card.getId()) == Zone.EXILED) { - ExileZone exile = null; - Card sourceCard = game.getCard(source.getSourceId()); - if (sourceCard != null) { - UUID exileId = source.getSourceId(); - exile = game.getExile().getExileZone(exileId); - } - if (exile != null - && exile.contains(id)) { - return filter.match(card, source.getControllerId(), game); - } - } - return false; - } - - @Override - public TargetCardInGusthasScepterExile copy() { - return new TargetCardInGusthasScepterExile(this); + player.choose(outcome, target, source, game); + Card card = game.getCard(target.getFirstTarget()); + return card != null && player.moveCards(card, Zone.HAND, source, game); } } class GusthasScepterLookAtCardEffect extends AsThoughEffectImpl { - private final UUID cardId; + private final MageObjectReference mor; - public GusthasScepterLookAtCardEffect(UUID cardId) { + public GusthasScepterLookAtCardEffect(Card card, Game game) { super(AsThoughEffectType.LOOK_AT_FACE_DOWN, Duration.EndOfGame, Outcome.Benefit); - this.cardId = cardId; + this.mor = new MageObjectReference(card, game); staticText = "You may look at it for as long as it remains exiled"; } public GusthasScepterLookAtCardEffect(final GusthasScepterLookAtCardEffect effect) { super(effect); - this.cardId = effect.cardId; + this.mor = effect.mor; } @Override @@ -191,26 +153,16 @@ class GusthasScepterLookAtCardEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (objectId.equals(cardId) && affectedControllerId.equals(source.getControllerId())) { - MageObject sourceObject = source.getSourceObject(game); - if (sourceObject != null) { - UUID exileId = source.getSourceId(); - ExileZone exileZone = game.getExile().getExileZone(exileId); - if (exileZone != null - && exileZone.contains(cardId)) { - Player controller = game.getPlayer(source.getControllerId()); - Card card = game.getCard(cardId); - if (controller != null - && card != null - && game.getState().getZone(cardId) == Zone.EXILED) { - return true; - } - } else { - discard(); - } - } + if (!mor.zoneCounterIsCurrent(game)) { + discard(); + return false; } - return false; + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + if (exileZone == null || !exileZone.contains(mor.getSourceId())) { + discard(); + return false; + } + return mor.refersTo(objectId, game) && source.isControlledBy(affectedControllerId); } } @@ -236,14 +188,12 @@ class GusthasScepterLoseControlAbility extends DelayedTriggeredAbility { } public boolean checkTrigger(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.LOST_CONTROL) { - return event.getPlayerId().equals(controllerId) - && event.getTargetId().equals(this.getSourceId()); - } else if (event.getType() == GameEvent.EventType.ZONE_CHANGE) { - if (event.getTargetId().equals(this.getSourceId())) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - return (zEvent.getFromZone() == Zone.BATTLEFIELD); - } + switch (event.getType()) { + case LOST_CONTROL: + return event.getPlayerId().equals(controllerId) + && event.getTargetId().equals(this.getSourceId()); + case ZONE_CHANGE: + return event.getTargetId().equals(this.getSourceId()) && ((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD; } return false; } @@ -258,7 +208,6 @@ class GusthasScepterPutExiledCardsInOwnersGraveyard extends OneShotEffect { public GusthasScepterPutExiledCardsInOwnersGraveyard() { super(Outcome.Neutral); - staticText = " put all cards exiled with {this} into their owner's graveyard"; } public GusthasScepterPutExiledCardsInOwnersGraveyard(final GusthasScepterPutExiledCardsInOwnersGraveyard effect) { @@ -268,14 +217,11 @@ class GusthasScepterPutExiledCardsInOwnersGraveyard extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - UUID exileId = source.getSourceId(); - ExileZone exileZone = game.getExile().getExileZone(exileId); - if (exileZone != null) { - return controller.moveCards(exileZone.getCards(game), Zone.GRAVEYARD, source, game); - } + if (controller == null) { + return false; } - return false; + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + return exileZone != null && controller.moveCards(exileZone.getCards(game), Zone.GRAVEYARD, source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/g/GustriderExuberant.java b/Mage.Sets/src/mage/cards/g/GustriderExuberant.java index 405b4f53b49..3374284409a 100644 --- a/Mage.Sets/src/mage/cards/g/GustriderExuberant.java +++ b/Mage.Sets/src/mage/cards/g/GustriderExuberant.java @@ -1,36 +1,36 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; import mage.constants.Duration; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import java.util.UUID; + /** - * * @author North */ public final class GustriderExuberant extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with power 5 or greater"); + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("creatures you control with power 5 or greater"); static { filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 4)); } public GustriderExuberant(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.WIZARD); @@ -38,9 +38,9 @@ public final class GustriderExuberant extends CardImpl { this.toughness = new MageInt(2); this.addAbility(FlyingAbility.getInstance()); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new GainAbilityControlledEffect(FlyingAbility.getInstance(), Duration.EndOfTurn, filter), - new SacrificeSourceCost())); + this.addAbility(new SimpleActivatedAbility(new GainAbilityAllEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn, filter + ), new SacrificeSourceCost())); } private GustriderExuberant(final GustriderExuberant card) { diff --git a/Mage.Sets/src/mage/cards/g/GyrusWakerOfCorpses.java b/Mage.Sets/src/mage/cards/g/GyrusWakerOfCorpses.java index 88f599718fc..a3eb3d82a3a 100644 --- a/Mage.Sets/src/mage/cards/g/GyrusWakerOfCorpses.java +++ b/Mage.Sets/src/mage/cards/g/GyrusWakerOfCorpses.java @@ -109,7 +109,7 @@ class GyrusWakerOfCorpsesPowerLessThanSourcePredicate implements ObjectSourcePla @Override public boolean apply(ObjectSourcePlayer input, Game game) { - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(input.getSourceId()); + Permanent sourcePermanent = input.getSource().getSourcePermanentOrLKI(game); return sourcePermanent != null && input.getObject().getPower().getValue() < sourcePermanent.getPower().getValue(); } diff --git a/Mage.Sets/src/mage/cards/h/HadaFreeblade.java b/Mage.Sets/src/mage/cards/h/HadaFreeblade.java index 5ef0ba3de77..0945dd010c9 100644 --- a/Mage.Sets/src/mage/cards/h/HadaFreeblade.java +++ b/Mage.Sets/src/mage/cards/h/HadaFreeblade.java @@ -26,7 +26,7 @@ public final class HadaFreeblade extends CardImpl { this.power = new MageInt(0); this.toughness = new MageInt(1); - this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true)); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true).setAbilityWord(null)); } private HadaFreeblade(final HadaFreeblade card) { diff --git a/Mage.Sets/src/mage/cards/h/HagHedgeMage.java b/Mage.Sets/src/mage/cards/h/HagHedgeMage.java index bf5be6e35eb..0374a5b1b44 100644 --- a/Mage.Sets/src/mage/cards/h/HagHedgeMage.java +++ b/Mage.Sets/src/mage/cards/h/HagHedgeMage.java @@ -33,8 +33,8 @@ public final class HagHedgeMage extends CardImpl { filter2.add(SubType.FOREST.getPredicate()); } - private String rule = "When {this} enters the battlefield, if you control two or more Swamps, you may have target player discard a card."; - private String rule2 = "When {this} enters the battlefield, if you control two or more Forests, you may put target card from your graveyard on top of your library."; + private static final String rule = "When {this} enters the battlefield, if you control two or more Swamps, you may have target player discard a card."; + private static final String rule2 = "When {this} enters the battlefield, if you control two or more Forests, you may put target card from your graveyard on top of your library."; public HagHedgeMage(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B/G}"); diff --git a/Mage.Sets/src/mage/cards/h/HagraDiabolist.java b/Mage.Sets/src/mage/cards/h/HagraDiabolist.java index d05f888b206..b5e5e9c9191 100644 --- a/Mage.Sets/src/mage/cards/h/HagraDiabolist.java +++ b/Mage.Sets/src/mage/cards/h/HagraDiabolist.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AllyEntersBattlefieldTriggeredAbility; @@ -15,8 +13,9 @@ import mage.constants.TargetController; import mage.filter.common.FilterControlledCreaturePermanent; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author North */ public final class HagraDiabolist extends CardImpl { @@ -29,7 +28,7 @@ public final class HagraDiabolist extends CardImpl { } public HagraDiabolist(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.OGRE); this.subtype.add(SubType.SHAMAN); this.subtype.add(SubType.ALLY); @@ -37,9 +36,9 @@ public final class HagraDiabolist extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(2); - Ability ability = new AllyEntersBattlefieldTriggeredAbility(new LoseLifeTargetEffect(new PermanentsOnBattlefieldCount(filter)), true); + Ability ability = new AllyEntersBattlefieldTriggeredAbility(new LoseLifeTargetEffect(new PermanentsOnBattlefieldCount(filter)).setText("you may have target player lose life equal to the number of Allies you control"), true); ability.addTarget(new TargetPlayer()); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(null)); } private HagraDiabolist(final HagraDiabolist card) { diff --git a/Mage.Sets/src/mage/cards/h/HagraMauling.java b/Mage.Sets/src/mage/cards/h/HagraMauling.java index e0c1fd0a4ba..7041fbeb24b 100644 --- a/Mage.Sets/src/mage/cards/h/HagraMauling.java +++ b/Mage.Sets/src/mage/cards/h/HagraMauling.java @@ -86,7 +86,7 @@ enum HagraMaulingCondition implements Condition { public boolean apply(Game game, Ability source) { for (UUID playerId : game.getOpponents(source.getControllerId())) { Player player = game.getPlayer(playerId); - if (player != null && game.getBattlefield().count(filter, source.getSourceId(), playerId, game) == 0) { + if (player != null && game.getBattlefield().count(filter, playerId, source, game) == 0) { return true; } } diff --git a/Mage.Sets/src/mage/cards/h/HakimLoreweaver.java b/Mage.Sets/src/mage/cards/h/HakimLoreweaver.java index 8828f590c57..be8563dd853 100644 --- a/Mage.Sets/src/mage/cards/h/HakimLoreweaver.java +++ b/Mage.Sets/src/mage/cards/h/HakimLoreweaver.java @@ -1,4 +1,3 @@ - package mage.cards.h; import mage.MageInt; @@ -17,19 +16,18 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterCard; import mage.filter.FilterPermanent; -import mage.filter.predicate.mageobject.CardIdPredicate; +import mage.filter.predicate.Predicate; import mage.filter.predicate.card.AuraCardCanAttachToPermanentId; -import mage.filter.predicate.permanent.AttachedToPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; +import java.util.Objects; import java.util.UUID; /** - * * @author jeffwadsworth, TheElk801 */ public final class HakimLoreweaver extends CardImpl { @@ -58,22 +56,16 @@ public final class HakimLoreweaver extends CardImpl { Ability ability = new ConditionalActivatedAbility( Zone.BATTLEFIELD, new HakimLoreweaverEffect(), - new ManaCostsImpl("{U}{U}"), - new HakimLoreweaverCondition()); + new ManaCostsImpl<>("{U}{U}"), + HakimLoreweaverCondition.instance + ); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); // {U}{U}, {tap}: Destroy all Auras attached to Hakim. - FilterPermanent filterAurasOnHakim = new FilterPermanent("Auras attached to Hakim"); - filterAurasOnHakim.add(CardType.ENCHANTMENT.getPredicate()); - filterAurasOnHakim.add(SubType.AURA.getPredicate()); - FilterPermanent filterSourceId = new FilterPermanent(); - filterSourceId.add(new CardIdPredicate(this.getId())); - filterAurasOnHakim.add(new AttachedToPredicate(filterSourceId)); - Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyAllEffect(filterAurasOnHakim), new ManaCostsImpl("{U}{U}")); + Ability ability2 = new SimpleActivatedAbility(new HakimLoreweaverEffect(), new ManaCostsImpl<>("{U}{U}")); ability2.addCost(new TapSourceCost()); this.addAbility(ability2); - } private HakimLoreweaver(final HakimLoreweaver card) { @@ -123,8 +115,8 @@ class HakimLoreweaverEffect extends OneShotEffect { } } -class HakimLoreweaverCondition implements Condition { - +enum HakimLoreweaverCondition implements Condition { + instance; static private final FilterPermanent auras = new FilterPermanent(); static { @@ -133,18 +125,18 @@ class HakimLoreweaverCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Permanent hakimLoreweaver = game.getPermanent(source.getSourceId()); - if (hakimLoreweaver != null) { - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(auras, game)) { - if (permanent != null - && hakimLoreweaver.getAttachments().contains(permanent.getId())) { - return false; - } - } - return PhaseStep.UPKEEP == game.getStep().getType() - && game.isActivePlayer(source.getControllerId()); + if (PhaseStep.UPKEEP != game.getStep().getType() + || !game.isActivePlayer(source.getControllerId())) { + return false; } - return false; + Permanent hakimLoreweaver = source.getSourcePermanentIfItStillExists(game); + return hakimLoreweaver != null + && hakimLoreweaver + .getAttachments() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .anyMatch(permanent -> permanent.hasSubtype(SubType.AURA, game)); } @Override @@ -152,3 +144,46 @@ class HakimLoreweaverCondition implements Condition { return "during your upkeep and only if {this} isn't enchanted"; } } + +class HakimLoreweaverDestroyEffect extends OneShotEffect { + + HakimLoreweaverDestroyEffect() { + super(Outcome.Benefit); + staticText = "destroy all Auras attached to {this}"; + } + + private HakimLoreweaverDestroyEffect(final HakimLoreweaverDestroyEffect effect) { + super(effect); + } + + @Override + public HakimLoreweaverDestroyEffect copy() { + return new HakimLoreweaverDestroyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + return false; + } + FilterPermanent filter = new FilterPermanent(); + filter.add(SubType.AURA.getPredicate()); + filter.add(new HakimLoreweaverPredicate(permanent)); + return new DestroyAllEffect(filter).apply(game, source); + } +} + +class HakimLoreweaverPredicate implements Predicate { + + private final Permanent permanent; + + HakimLoreweaverPredicate(Permanent permanent) { + this.permanent = permanent; + } + + @Override + public boolean apply(Permanent input, Game game) { + return input.isAttachedTo(permanent.getId()); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/h/HaktosTheUnscarred.java b/Mage.Sets/src/mage/cards/h/HaktosTheUnscarred.java index dd5a6e39c14..9d8380face6 100644 --- a/Mage.Sets/src/mage/cards/h/HaktosTheUnscarred.java +++ b/Mage.Sets/src/mage/cards/h/HaktosTheUnscarred.java @@ -106,7 +106,7 @@ enum HaktosTheUnscarredPredicate implements ObjectSourcePlayerPredicate { @Override public boolean apply(ObjectSourcePlayer input, Game game) { - Object obj = game.getState().getValue(input.getSourceId() + "" + game.getState().getZoneChangeCounter(input.getSourceId()) + "_haktos_number"); + Object obj = game.getState().getValue(input.getSourceId() + "" + input.getSource().getSourceObjectZoneChangeCounter() + "_haktos_number"); if (!(obj instanceof Integer)) { return false; } diff --git a/Mage.Sets/src/mage/cards/h/HalimarExcavator.java b/Mage.Sets/src/mage/cards/h/HalimarExcavator.java index 830b480db32..5dd7f98f012 100644 --- a/Mage.Sets/src/mage/cards/h/HalimarExcavator.java +++ b/Mage.Sets/src/mage/cards/h/HalimarExcavator.java @@ -38,7 +38,7 @@ public final class HalimarExcavator extends CardImpl { this.toughness = new MageInt(3); Ability ability = new AllyEntersBattlefieldTriggeredAbility(new PutLibraryIntoGraveTargetEffect(new PermanentsOnBattlefieldCount(filter)), false); ability.addTarget(new TargetPlayer()); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(null)); } private HalimarExcavator(final HalimarExcavator card) { diff --git a/Mage.Sets/src/mage/cards/h/HalimarTidecaller.java b/Mage.Sets/src/mage/cards/h/HalimarTidecaller.java index 9be88f74626..0662f04939c 100644 --- a/Mage.Sets/src/mage/cards/h/HalimarTidecaller.java +++ b/Mage.Sets/src/mage/cards/h/HalimarTidecaller.java @@ -1,28 +1,27 @@ package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.AwakenAbility; import mage.abilities.keyword.FlyingAbility; 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.constants.SubType; import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class HalimarTidecaller extends CardImpl { @@ -37,7 +36,7 @@ public final class HalimarTidecaller extends CardImpl { } public HalimarTidecaller(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.HUMAN); this.subtype.add(SubType.WIZARD); this.subtype.add(SubType.ALLY); @@ -45,14 +44,14 @@ public final class HalimarTidecaller extends CardImpl { this.toughness = new MageInt(3); // When Halimar Tidecaller enters the battlefield, you may return target card with awaken from your graveyard to your hand. - Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), true); ability.addTarget(new TargetCardInYourGraveyard(filterCard)); - this.addAbility(ability); // Land creatures you control have flying. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield, filter))); - + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + FlyingAbility.getInstance(), Duration.WhileOnBattlefield, filter + ))); } private HalimarTidecaller(final HalimarTidecaller card) { diff --git a/Mage.Sets/src/mage/cards/h/HallowedBurial.java b/Mage.Sets/src/mage/cards/h/HallowedBurial.java index 2711f8ea3a5..0ce0602ae9c 100644 --- a/Mage.Sets/src/mage/cards/h/HallowedBurial.java +++ b/Mage.Sets/src/mage/cards/h/HallowedBurial.java @@ -42,7 +42,7 @@ class HallowedBurialEffect extends OneShotEffect { public HallowedBurialEffect() { super(Outcome.Neutral); - this.staticText = "Put all creatures on the bottom of their owner's libraries"; + this.staticText = "Put all creatures on the bottom of their owners' libraries"; } public HallowedBurialEffect(final HallowedBurialEffect effect) { @@ -58,7 +58,7 @@ class HallowedBurialEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), source, game)) { controller.moveCardToLibraryWithInfo(creature, source, game, Zone.BATTLEFIELD, false, true); } return true; diff --git a/Mage.Sets/src/mage/cards/h/HaloFountain.java b/Mage.Sets/src/mage/cards/h/HaloFountain.java new file mode 100644 index 00000000000..1a28be0903b --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HaloFountain.java @@ -0,0 +1,70 @@ +package mage.cards.h; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.common.UntapTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.WinGameSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.permanent.token.CitizenGreenWhiteToken; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HaloFountain extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledCreaturePermanent("tapped creature you control"); + + static { + filter.add(TappedPredicate.TAPPED); + } + + public HaloFountain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{W}"); + + // {W}, {T}, Untap an tapped creature you control: Create a 1/1 green and white Citizen creature token. + Ability ability = new SimpleActivatedAbility( + new CreateTokenEffect(new CitizenGreenWhiteToken()), new ManaCostsImpl<>("{W}") + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new UntapTargetCost(new TargetControlledPermanent(filter))); + this.addAbility(ability); + + // {W}{W}, {T}, Untap two tapped creatures you control: Draw a card. + ability = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{W}{W}") + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new UntapTargetCost(new TargetControlledPermanent(2, filter))); + this.addAbility(ability); + + // {W}{W}{W}{W}{W}, {T}, Untap fifteen tapped creatures you control: You win the game. + ability = new SimpleActivatedAbility( + new WinGameSourceControllerEffect(), new ManaCostsImpl<>("{W}{W}{W}{W}{W}") + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new UntapTargetCost(new TargetControlledPermanent(15, filter))); + this.addAbility(ability); + } + + private HaloFountain(final HaloFountain card) { + super(card); + } + + @Override + public HaloFountain copy() { + return new HaloFountain(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HaloScarab.java b/Mage.Sets/src/mage/cards/h/HaloScarab.java new file mode 100644 index 00000000000..77856b69418 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HaloScarab.java @@ -0,0 +1,46 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.ExileSourceFromGraveCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HaloScarab extends CardImpl { + + public HaloScarab(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); + + this.subtype.add(SubType.INSECT); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // {2}, Exile Halo Scarab from your graveyard: Create a Treasure token. + Ability ability = new SimpleActivatedAbility( + Zone.GRAVEYARD, new CreateTokenEffect(new TreasureToken()), new GenericManaCost(2) + ); + ability.addCost(new ExileSourceFromGraveCost()); + this.addAbility(ability); + } + + private HaloScarab(final HaloScarab card) { + super(card); + } + + @Override + public HaloScarab copy() { + return new HaloScarab(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HalvarGodOfBattle.java b/Mage.Sets/src/mage/cards/h/HalvarGodOfBattle.java index 243f813dd5e..ae523ae739c 100644 --- a/Mage.Sets/src/mage/cards/h/HalvarGodOfBattle.java +++ b/Mage.Sets/src/mage/cards/h/HalvarGodOfBattle.java @@ -193,7 +193,7 @@ class HalvarGodOfBattlePredicate implements ObjectSourcePlayerPredicate input, Game game) { UUID attachedTo = input.getObject().getAttachedTo(); Permanent permanent = game.getPermanent(attachedTo); - return permanent != null && filter.match(permanent, input.getSourceId(), input.getPlayerId(), game); + return permanent != null && filter.match(permanent, input.getPlayerId(), input.getSource(), game); } @Override diff --git a/Mage.Sets/src/mage/cards/h/HammerMage.java b/Mage.Sets/src/mage/cards/h/HammerMage.java index 43bbc3f775c..28517cfec32 100644 --- a/Mage.Sets/src/mage/cards/h/HammerMage.java +++ b/Mage.Sets/src/mage/cards/h/HammerMage.java @@ -71,7 +71,7 @@ class HammerMageEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { FilterArtifactPermanent filter = new FilterArtifactPermanent(); filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, source.getManaCostsToPay().getX() + 1)); - for(Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for(Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanent.destroy(source, game, false); } return true; diff --git a/Mage.Sets/src/mage/cards/h/HanaKami.java b/Mage.Sets/src/mage/cards/h/HanaKami.java index 4a666877926..6f83c4d0390 100644 --- a/Mage.Sets/src/mage/cards/h/HanaKami.java +++ b/Mage.Sets/src/mage/cards/h/HanaKami.java @@ -1,22 +1,20 @@ - - package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** * @author Loki */ @@ -29,12 +27,12 @@ public final class HanaKami extends CardImpl { } public HanaKami(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(1); this.toughness = new MageInt(1); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{1}{G}")); + Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl("{1}{G}")); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); @@ -48,5 +46,4 @@ public final class HanaKami extends CardImpl { public HanaKami copy() { return new HanaKami(this); } - } diff --git a/Mage.Sets/src/mage/cards/h/HandOfEmrakul.java b/Mage.Sets/src/mage/cards/h/HandOfEmrakul.java index a91653ef4d6..b4078028fc0 100644 --- a/Mage.Sets/src/mage/cards/h/HandOfEmrakul.java +++ b/Mage.Sets/src/mage/cards/h/HandOfEmrakul.java @@ -11,7 +11,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.mageobject.NamePredicate; import mage.target.common.TargetControlledPermanent; /** @@ -20,10 +19,11 @@ import mage.target.common.TargetControlledPermanent; */ public final class HandOfEmrakul extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("four Eldrazi Spawn"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("Eldrazi Spawn"); static { - filter.add(new NamePredicate("Eldrazi Spawn")); + filter.add(SubType.ELDRAZI.getPredicate()); + filter.add(SubType.SPAWN.getPredicate()); } public HandOfEmrakul(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/HandOfVecna.java b/Mage.Sets/src/mage/cards/h/HandOfVecna.java index 75afa618457..5869b9e4deb 100644 --- a/Mage.Sets/src/mage/cards/h/HandOfVecna.java +++ b/Mage.Sets/src/mage/cards/h/HandOfVecna.java @@ -96,7 +96,7 @@ class HandOfVecnaEffect extends OneShotEffect { Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); Permanent equipped = game.getPermanent(sourcePermanent != null ? sourcePermanent.getAttachedTo() : null); List chooseable = game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game ); if (equipped != null) { chooseable.add(equipped); @@ -118,7 +118,7 @@ class HandOfVecnaEffect extends OneShotEffect { )); TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); toBoost = game.getPermanent(target.getFirstTarget()); } int xValue = player.getHand().size(); diff --git a/Mage.Sets/src/mage/cards/h/HandToHand.java b/Mage.Sets/src/mage/cards/h/HandToHand.java index 8592b589bbf..a16e107c437 100644 --- a/Mage.Sets/src/mage/cards/h/HandToHand.java +++ b/Mage.Sets/src/mage/cards/h/HandToHand.java @@ -60,7 +60,7 @@ class HandToHandEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "During combat, players can't cast instant spells or activate abilities that aren't mana abilities (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/h/Hankyu.java b/Mage.Sets/src/mage/cards/h/Hankyu.java index 7f32ff0c4c9..0738177750b 100644 --- a/Mage.Sets/src/mage/cards/h/Hankyu.java +++ b/Mage.Sets/src/mage/cards/h/Hankyu.java @@ -4,11 +4,14 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.Cost; -import mage.abilities.costs.CostImpl; +import mage.abilities.costs.UseAttachedCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.EquipAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -16,13 +19,14 @@ import mage.constants.*; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetAnyTarget; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; import java.util.UUID; /** - * @author North + * @author TheElk801 */ public final class Hankyu extends CardImpl { @@ -30,18 +34,8 @@ public final class Hankyu extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); this.subtype.add(SubType.EQUIPMENT); - /* Equipped creature has "{T}: Put an aim counter on Hankyu" and */ - SimpleActivatedAbility ability1 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new HankyuAddCounterEffect(this.getId()), new TapSourceCost()); - ability1.setSourceId(this.getId()); // to know where to put the counters on - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ability1, AttachmentType.EQUIPMENT))); - - /* "{T}, Remove all aim counters from Hankyu: This creature deals - * damage to any target equal to the number of - * aim counters removed this way." */ - SimpleActivatedAbility ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new HankyuDealsDamageEffect(), new TapSourceCost()); - ability2.addCost(new HankyuCountersSourceCost(this.getId())); - ability2.addTarget(new TargetAnyTarget()); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ability2, AttachmentType.EQUIPMENT))); + // Equipped creature has "{T}: Put an aim counter on {this}" and "{T}, Remove all aim counters from {this}: This creature deals damage to any target equal to the number of aim counters removed this way." + this.addAbility(new SimpleStaticAbility(new HankyuEffect())); // Equip {4} ({4}: Attach to target creature you control. Equip only as a sorcery.) this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(4))); @@ -57,121 +51,125 @@ public final class Hankyu extends CardImpl { } } -class HankyuAddCounterEffect extends OneShotEffect { +class HankyuEffect extends ContinuousEffectImpl { - private UUID effectGivingEquipmentId; - - public HankyuAddCounterEffect(UUID effectGivingEquipmentId) { - super(Outcome.Benefit); - this.effectGivingEquipmentId = effectGivingEquipmentId; - staticText = "Put an aim counter on Hankyu"; + HankyuEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "equipped creature has \"{T}: Put an aim counter on {this}\" and " + + "\"{T}, Remove all aim counters from {this}: This creature deals damage " + + "to any target equal to the number of aim counters removed this way.\""; } - public HankyuAddCounterEffect(final HankyuAddCounterEffect effect) { + private HankyuEffect(final HankyuEffect effect) { super(effect); - this.effectGivingEquipmentId = effect.effectGivingEquipmentId; + } + + @Override + public HankyuEffect copy() { + return new HankyuEffect(this); } @Override public boolean apply(Game game, Ability source) { - Permanent equipment = game.getPermanent(this.effectGivingEquipmentId); - if (equipment != null) { - equipment.addCounters(CounterType.AIM.createInstance(), source.getControllerId(), source, game); + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + return false; } + Permanent creature = game.getPermanent(permanent.getAttachedTo()); + if (creature == null) { + return false; + } + creature.addAbility(new SimpleActivatedAbility( + new AddCountersTargetEffect(CounterType.AIM.createInstance()) + .setTargetPointer(new FixedTarget(permanent, game)) + .setText("put an aim counter on " + permanent.getName()), + new TapSourceCost() + ), source.getSourceId(), game); + Ability ability = new SimpleActivatedAbility( + new DamageTargetEffect(HankyuValue.instance) + .setText("this creature deals damage to any target equal " + + "to the number of aim counters removed this way"), + new TapSourceCost() + ); + ability.addCost(new HankyuCost().setMageObjectReference(source, game)); + ability.addTarget(new TargetAnyTarget()); + creature.addAbility(ability, source.getSourceId(), game); return true; } - - @Override - public HankyuAddCounterEffect copy() { - return new HankyuAddCounterEffect(this); - } - - } +enum HankyuValue implements DynamicValue { + instance; -class HankyuDealsDamageEffect extends OneShotEffect { - - public HankyuDealsDamageEffect() { - super(Outcome.Damage); - staticText = "This creature deals damage to any target equal to the number of aim counters removed this way"; - } - - public HankyuDealsDamageEffect(final HankyuDealsDamageEffect effect) { - super(effect); + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return CardUtil.castStream( + sourceAbility.getCosts().stream(), HankyuCost.class + ).mapToInt(HankyuCost::getRemovedCounters).sum(); } @Override - public HankyuDealsDamageEffect copy() { - return new HankyuDealsDamageEffect(this); + public HankyuValue copy() { + return this; } @Override - public boolean apply(Game game, Ability source) { - // get the number of removed counters as damage amount - HankyuCountersSourceCost cost = (HankyuCountersSourceCost) source.getCosts().get(1); - if (cost != null) { - int damageAmount = cost.getRemovedCounters(); - if (damageAmount > 0) { - - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent != null) { - permanent.damage(damageAmount, source.getSourceId(), source, game, false, true); - } - Player player = game.getPlayer(source.getFirstTarget()); - if (player != null) { - player.damage(damageAmount, source.getSourceId(), source, game); - } - } - return true; - } - return false; + public String getMessage() { + return ""; } - } -class HankyuCountersSourceCost extends CostImpl { +class HankyuCost extends UseAttachedCost { - private int removedCounters; - private UUID effectGivingEquipmentId; + private int removedCounters = 0; - public HankyuCountersSourceCost(UUID effectGivingEquipmentId) { + HankyuCost() { super(); - this.removedCounters = 0; - this.effectGivingEquipmentId = effectGivingEquipmentId; - this.text = "Remove all aim counters from Hankyu"; } - public HankyuCountersSourceCost(HankyuCountersSourceCost cost) { + private HankyuCost(final HankyuCost cost) { super(cost); - this.effectGivingEquipmentId = cost.effectGivingEquipmentId; this.removedCounters = cost.removedCounters; } - @Override - public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return true; - } - @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - Permanent equipment = game.getPermanent(this.effectGivingEquipmentId); - if (equipment != null) { - this.removedCounters = equipment.getCounters(game).getCount(CounterType.AIM); - if (this.removedCounters > 0) { - equipment.removeCounters("aim", this.removedCounters, source, game); - } + if (mageObjectReference == null) { + return false; } - this.paid = true; - return true; + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + return paid; + } + for (UUID attachmentId : permanent.getAttachments()) { + if (!this.mageObjectReference.refersTo(attachmentId, game)) { + continue; + } + Permanent equipment = mageObjectReference.getPermanent(game); + if (equipment == null) { + continue; + } + int count = equipment.getCounters(game).getCount(CounterType.AIM); + equipment.removeCounters(CounterType.AIM.createInstance(count), source, game); + paid = true; + removedCounters = count; + break; + } + + return paid; } @Override - public HankyuCountersSourceCost copy() { - return new HankyuCountersSourceCost(this); + public HankyuCost copy() { + return new HankyuCost(this); + } + + @Override + public String getText() { + return "remove all aim counters from " + this.name; } public int getRemovedCounters() { - return this.removedCounters; + return removedCounters; } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/h/HansEriksson.java b/Mage.Sets/src/mage/cards/h/HansEriksson.java index 8b9d8743c62..9ab3cfa6b5e 100644 --- a/Mage.Sets/src/mage/cards/h/HansEriksson.java +++ b/Mage.Sets/src/mage/cards/h/HansEriksson.java @@ -96,7 +96,7 @@ class HansErikssonEffect extends OneShotEffect { UUID defenderId; if (game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_PERMANENT_PLANESWALKER, - source.getSourceId(), defendingPlayerId, game + defendingPlayerId, source, game ) < 1) { defenderId = defendingPlayerId; } else { @@ -107,7 +107,7 @@ class HansErikssonEffect extends OneShotEffect { filter.getPermanentFilter().add(new ControllerIdPredicate(defendingPlayerId)); TargetPlayerOrPlaneswalker target = new TargetPlayerOrPlaneswalker(filter); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); defenderId = target.getFirstTarget(); } if (defenderId != null) { diff --git a/Mage.Sets/src/mage/cards/h/HaphazardBombardment.java b/Mage.Sets/src/mage/cards/h/HaphazardBombardment.java index c47128fc40a..65df8af396f 100644 --- a/Mage.Sets/src/mage/cards/h/HaphazardBombardment.java +++ b/Mage.Sets/src/mage/cards/h/HaphazardBombardment.java @@ -79,7 +79,7 @@ class HaphazardBombardmentEffect extends OneShotEffect { FilterPermanent filter = new FilterPermanent("nonenchantment permanents you don't control"); filter.add(Predicates.not(CardType.ENCHANTMENT.getPredicate())); filter.add(TargetController.OPPONENT.getControllerPredicate()); - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); if (permanents.size() > 4) { permanents.clear(); TargetPermanent target = new TargetPermanent(4, 4, filter, true); @@ -127,7 +127,7 @@ class HaphazardBombardmentEndOfTurnEffect extends OneShotEffect { filter.add(TargetController.NOT_YOU.getControllerPredicate()); filter.add(CounterType.AIM.getPredicate()); filter.add(Predicates.not(new AbilityPredicate(IndestructibleAbility.class))); - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); if (!permanents.isEmpty()) { Permanent permanent = permanents.get(RandomUtil.nextInt(permanents.size())); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/h/HaraldKingOfSkemfar.java b/Mage.Sets/src/mage/cards/h/HaraldKingOfSkemfar.java index c5aaaccb7ba..65586694fc0 100644 --- a/Mage.Sets/src/mage/cards/h/HaraldKingOfSkemfar.java +++ b/Mage.Sets/src/mage/cards/h/HaraldKingOfSkemfar.java @@ -2,15 +2,14 @@ package mage.cards.h; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.MenaceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; @@ -43,13 +42,11 @@ public final class HaraldKingOfSkemfar extends CardImpl { // Menace this.addAbility(new MenaceAbility()); - // When Harald, King of Skemfar enters the battlefield, look at the top five cards of your library. You may reveal an Elf, Warrior, or Tyvar card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. + // When Harald, King of Skemfar enters the battlefield, look at the top five cards of your library. + // You may reveal an Elf, Warrior, or Tyvar card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), filter, Zone.LIBRARY, false, - true, false, Zone.HAND, true, false, false - ).setBackInRandomOrder(true).setText("look at the top five cards of your library." + - " You may reveal an Elf, Warrior, or Tyvar card from among them and put it into your hand. " + - "Put the rest on the bottom of your library in a random order"))); + 5, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM))); } private HaraldKingOfSkemfar(final HaraldKingOfSkemfar card) { diff --git a/Mage.Sets/src/mage/cards/h/HaraldUnitesTheElves.java b/Mage.Sets/src/mage/cards/h/HaraldUnitesTheElves.java index 0f3a8467b21..e27bf4964f5 100644 --- a/Mage.Sets/src/mage/cards/h/HaraldUnitesTheElves.java +++ b/Mage.Sets/src/mage/cards/h/HaraldUnitesTheElves.java @@ -105,7 +105,7 @@ class HaraldUnitesTheElvesEffect extends OneShotEffect { } player.millCards(3, source, game); TargetCard targetCard = new TargetCardInYourGraveyard(0, 1, filter, true); - player.choose(outcome, targetCard, source.getSourceId(), game); + player.choose(outcome, targetCard, source, game); Card card = player.getGraveyard().get(targetCard.getFirstTarget(), game); if (card != null) { player.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/h/HarborSerpent.java b/Mage.Sets/src/mage/cards/h/HarborSerpent.java index f2e1ed29835..2d1cef11242 100644 --- a/Mage.Sets/src/mage/cards/h/HarborSerpent.java +++ b/Mage.Sets/src/mage/cards/h/HarborSerpent.java @@ -73,6 +73,6 @@ class HarborSerpentEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { return permanent.getId().equals(source.getSourceId()) && - game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) < 5; + game.getBattlefield().count(filter, source.getControllerId(), source, game) < 5; } } diff --git a/Mage.Sets/src/mage/cards/d/DustinGadgetGenius.java b/Mage.Sets/src/mage/cards/h/HargildeKindlyRunechanter.java similarity index 64% rename from Mage.Sets/src/mage/cards/d/DustinGadgetGenius.java rename to Mage.Sets/src/mage/cards/h/HargildeKindlyRunechanter.java index 941e12a70f3..1b4e99a4c26 100644 --- a/Mage.Sets/src/mage/cards/d/DustinGadgetGenius.java +++ b/Mage.Sets/src/mage/cards/h/HargildeKindlyRunechanter.java @@ -1,4 +1,4 @@ -package mage.cards.d; +package mage.cards.h; import mage.ConditionalMana; import mage.MageInt; @@ -22,9 +22,9 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class DustinGadgetGenius extends CardImpl { +public final class HargildeKindlyRunechanter extends CardImpl { - public DustinGadgetGenius(UUID ownerId, CardSetInfo setInfo) { + public HargildeKindlyRunechanter(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}"); this.addSuperType(SuperType.LEGENDARY); @@ -34,28 +34,28 @@ public final class DustinGadgetGenius extends CardImpl { // {T}: Add {C}{C}. Spend this mana only to cast artifact spells or activate abilities of artifacts. this.addAbility(new ConditionalColorlessManaAbility( - new TapSourceCost(), 2, new DustinGadgetGeniusManaBuilder() + new TapSourceCost(), 2, new HargildeKindlyRunechanterManaBuilder() )); // Friends forever this.addAbility(FriendsForeverAbility.getInstance()); } - private DustinGadgetGenius(final DustinGadgetGenius card) { + private HargildeKindlyRunechanter(final HargildeKindlyRunechanter card) { super(card); } @Override - public DustinGadgetGenius copy() { - return new DustinGadgetGenius(this); + public HargildeKindlyRunechanter copy() { + return new HargildeKindlyRunechanter(this); } } -class DustinGadgetGeniusManaBuilder extends ConditionalManaBuilder { +class HargildeKindlyRunechanterManaBuilder extends ConditionalManaBuilder { @Override public ConditionalMana build(Object... options) { - return new DustinGadgetGeniusConditionalMana(this.mana); + return new HargildeKindlyRunechanterConditionalMana(this.mana); } @Override @@ -64,20 +64,20 @@ class DustinGadgetGeniusManaBuilder extends ConditionalManaBuilder { } } -class DustinGadgetGeniusConditionalMana extends ConditionalMana { +class HargildeKindlyRunechanterConditionalMana extends ConditionalMana { - DustinGadgetGeniusConditionalMana(Mana mana) { + HargildeKindlyRunechanterConditionalMana(Mana mana) { super(mana); - addCondition(DustinGadgetGeniusCondition.instance); + addCondition(HargildeKindlyRunechanterCondition.instance); } } -enum DustinGadgetGeniusCondition implements Condition { +enum HargildeKindlyRunechanterCondition implements Condition { instance; @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && object.isArtifact(game); } } diff --git a/Mage.Sets/src/mage/cards/h/HarmonicConvergence.java b/Mage.Sets/src/mage/cards/h/HarmonicConvergence.java index 95dccfa4bcd..77c94ecc327 100644 --- a/Mage.Sets/src/mage/cards/h/HarmonicConvergence.java +++ b/Mage.Sets/src/mage/cards/h/HarmonicConvergence.java @@ -64,7 +64,7 @@ class HarmonicConvergenceEffect extends OneShotEffect { FilterEnchantmentPermanent filter = new FilterEnchantmentPermanent(); filter.add(new OwnerIdPredicate(player.getId())); Cards toLib = new CardsImpl(); - for(Permanent enchantment: game.getBattlefield().getActivePermanents(filter, playerId, source.getSourceId(), game)) { + for(Permanent enchantment: game.getBattlefield().getActivePermanents(filter, playerId, source, game)) { toLib.add(enchantment); } player.putCardsOnTopOfLibrary(toLib, game, source, true); diff --git a/Mage.Sets/src/mage/cards/h/HarmoniousEmergence.java b/Mage.Sets/src/mage/cards/h/HarmoniousEmergence.java new file mode 100644 index 00000000000..6da9ed6861b --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HarmoniousEmergence.java @@ -0,0 +1,115 @@ +package mage.cards.h; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BecomesCreatureAttachedEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.IndestructibleAbility; +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.SubType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.custom.CreatureToken; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HarmoniousEmergence extends CardImpl { + + public HarmoniousEmergence(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); + + this.subtype.add(SubType.AURA); + + // Enchant land you control + TargetPermanent auraTarget = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // Enchanted land is a 4/5 green Spirit creature with vigilance and haste. It's still a land. + this.addAbility(new SimpleStaticAbility(new BecomesCreatureAttachedEffect( + new CreatureToken(4, 5) + .withColor("G") + .withSubType(SubType.SPIRIT) + .withAbility(VigilanceAbility.getInstance()) + .withAbility(HasteAbility.getInstance()), + "enchanted land is a 4/5 green Spirit creature with vigilance and haste. It's still a land", + Duration.WhileOnBattlefield, BecomesCreatureAttachedEffect.LoseType.COLOR + ))); + + // If enchanted land would be destroyed, instead sacrifice Harmonious Emergence and that land gains indestructible until end of turn. + this.addAbility(new SimpleStaticAbility(new HarmoniousEmergenceEffect())); + } + + private HarmoniousEmergence(final HarmoniousEmergence card) { + super(card); + } + + @Override + public HarmoniousEmergence copy() { + return new HarmoniousEmergence(this); + } +} + +class HarmoniousEmergenceEffect extends ReplacementEffectImpl { + + HarmoniousEmergenceEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "if enchanted land would be destroyed, instead sacrifice " + + "{this} and that land gains indestructible until end of turn"; + } + + private HarmoniousEmergenceEffect(final HarmoniousEmergenceEffect effect) { + super(effect); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + Permanent enchantedPermanent = game.getPermanent(event.getTargetId()); + if (sourcePermanent == null || enchantedPermanent == null) { + return false; + } + sourcePermanent.sacrifice(source, game); + game.addEffect(new GainAbilityTargetEffect(IndestructibleAbility.getInstance()) + .setTargetPointer(new FixedTarget(enchantedPermanent, game)), source); + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DESTROY_PERMANENT; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + return sourcePermanent != null && event.getTargetId().equals(sourcePermanent.getAttachedTo()); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public HarmoniousEmergenceEffect copy() { + return new HarmoniousEmergenceEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HarmonyOfNature.java b/Mage.Sets/src/mage/cards/h/HarmonyOfNature.java index 8b65230b2e2..35480f08b4d 100644 --- a/Mage.Sets/src/mage/cards/h/HarmonyOfNature.java +++ b/Mage.Sets/src/mage/cards/h/HarmonyOfNature.java @@ -66,7 +66,7 @@ class HarmonyOfNatureEffect extends OneShotEffect { } TargetPermanent target = new TargetControlledPermanent(0, Integer.MAX_VALUE, HarmonyOfNature.filter, true); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); if (target.getTargets().isEmpty()) { return false; } diff --git a/Mage.Sets/src/mage/cards/h/HarmsWay.java b/Mage.Sets/src/mage/cards/h/HarmsWay.java index fc6ce082e3e..2925c2d5d46 100644 --- a/Mage.Sets/src/mage/cards/h/HarmsWay.java +++ b/Mage.Sets/src/mage/cards/h/HarmsWay.java @@ -63,7 +63,7 @@ class HarmsWayPreventDamageTargetEffect extends RedirectionEffect { @Override public void init(Ability source, Game game) { - this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); super.init(source, game); } diff --git a/Mage.Sets/src/mage/cards/h/HarshJustice.java b/Mage.Sets/src/mage/cards/h/HarshJustice.java index bfe5fc9d6ed..e708178119c 100644 --- a/Mage.Sets/src/mage/cards/h/HarshJustice.java +++ b/Mage.Sets/src/mage/cards/h/HarshJustice.java @@ -122,7 +122,7 @@ class HarshJusticeEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { int damage = (Integer) this.getValue("damage"); UUID sourceId = (UUID) this.getValue("sourceId"); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && damage > 0 && sourceId != null) { Permanent targetObject = game.getPermanentOrLKIBattlefield(sourceId); if (targetObject != null) { diff --git a/Mage.Sets/src/mage/cards/h/HarshMercy.java b/Mage.Sets/src/mage/cards/h/HarshMercy.java index d953e915ce1..6b92aab46b3 100644 --- a/Mage.Sets/src/mage/cards/h/HarshMercy.java +++ b/Mage.Sets/src/mage/cards/h/HarshMercy.java @@ -63,7 +63,7 @@ class HarshMercyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { Set chosenTypes = new HashSet<>(); PlayerIteration: diff --git a/Mage.Sets/src/mage/cards/h/HatcherySpider.java b/Mage.Sets/src/mage/cards/h/HatcherySpider.java index 350c6ef753a..93e9e7591ff 100644 --- a/Mage.Sets/src/mage/cards/h/HatcherySpider.java +++ b/Mage.Sets/src/mage/cards/h/HatcherySpider.java @@ -1,35 +1,26 @@ package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CastSourceTriggeredAbility; -import mage.constants.SubType; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.effects.common.RevealLibraryPickControllerEffect; import mage.abilities.keyword.ReachAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.FilterCard; +import mage.constants.*; import mage.filter.StaticFilters; import mage.filter.common.FilterPermanentCard; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class HatcherySpider extends CardImpl { @@ -45,10 +36,7 @@ public final class HatcherySpider extends CardImpl { this.addAbility(ReachAbility.getInstance()); // Undergrowth — When you cast this spell, reveal the top X cards of your library, where X is the number of creature cards in your graveyard. You may put a green permanent card with converted mana cost X or less from among them onto the battlefield. Put the rest on the bottom of your library in a random order. - this.addAbility(new CastSourceTriggeredAbility( - new HatcherySpiderEffect(), false, - "Undergrowth — " - )); + this.addAbility(new CastSourceTriggeredAbility(new HatcherySpiderEffect()).setAbilityWord(AbilityWord.UNDERGROWTH)); } private HatcherySpider(final HatcherySpider card) { @@ -64,7 +52,7 @@ public final class HatcherySpider extends CardImpl { class HatcherySpiderEffect extends OneShotEffect { public HatcherySpiderEffect() { - super(Outcome.Benefit); + super(Outcome.PutCardInPlay); this.staticText = "reveal the top X cards of your library, " + "where X is the number of creature cards in your graveyard. " + "You may put a green permanent card with mana value " @@ -88,34 +76,10 @@ class HatcherySpiderEffect extends OneShotEffect { if (player == null) { return false; } - int xValue = new CardsInControllerGraveyardCount( - StaticFilters.FILTER_CARD_CREATURE - ).calculate(game, source, this); - FilterCard filter = new FilterPermanentCard( - "green permanent card with mana value " - + xValue + " or less" - ); + int xValue = player.getGraveyard().count(StaticFilters.FILTER_CARD_CREATURE, game); + FilterPermanentCard filter = new FilterPermanentCard("green permanent card with mana value " + xValue + " or less"); filter.add(new ColorPredicate(ObjectColor.GREEN)); - filter.add(new ManaValuePredicate( - ComparisonType.FEWER_THAN, xValue + 1 - )); - TargetCard target = new TargetCardInLibrary(filter); - Cards cards = new CardsImpl( - player.getLibrary().getTopCards(game, xValue) - ); - if (player.chooseUse(outcome, "Put a card onto the battlefield?", source, game) - && player.choose(outcome, cards, target, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null - && player.moveCards(card, Zone.BATTLEFIELD, source, game)) { - cards.remove(card); - } - } - while (!cards.isEmpty()) { - Card card = cards.getRandom(game); - player.getLibrary().putOnBottom(card, game); - cards.remove(card); - } - return true; + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, xValue + 1)); + return new RevealLibraryPickControllerEffect(xValue, 1, filter, PutCards.BATTLEFIELD, PutCards.BOTTOM_RANDOM).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/h/HauntedCadaver.java b/Mage.Sets/src/mage/cards/h/HauntedCadaver.java index 55fd95ff84c..a5c089ec90f 100644 --- a/Mage.Sets/src/mage/cards/h/HauntedCadaver.java +++ b/Mage.Sets/src/mage/cards/h/HauntedCadaver.java @@ -31,7 +31,7 @@ public final class HauntedCadaver extends CardImpl { ability.addEffect( new DiscardTargetEffect(3)); this.addAbility(ability); // Morph {1}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{B}"))); } private HauntedCadaver(final HauntedCadaver card) { diff --git a/Mage.Sets/src/mage/cards/h/HauntedDead.java b/Mage.Sets/src/mage/cards/h/HauntedDead.java index 66e36020724..63e94133207 100644 --- a/Mage.Sets/src/mage/cards/h/HauntedDead.java +++ b/Mage.Sets/src/mage/cards/h/HauntedDead.java @@ -35,7 +35,7 @@ public final class HauntedDead extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new SpiritWhiteToken()))); // {1}{B}, Discard two cards: Return Haunted Dead from your graveyard to the battlefield tapped. - Ability ability = new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(true), new ManaCostsImpl("{1}{B}")); + Ability ability = new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(true, false), new ManaCostsImpl("{1}{B}")); ability.addCost(new DiscardTargetCost(new TargetCardInHand(2, new FilterCard("two cards")))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HavenOfTheSpiritDragon.java b/Mage.Sets/src/mage/cards/h/HavenOfTheSpiritDragon.java index 5dc1de2f5ce..f7ad7b3c6a1 100644 --- a/Mage.Sets/src/mage/cards/h/HavenOfTheSpiritDragon.java +++ b/Mage.Sets/src/mage/cards/h/HavenOfTheSpiritDragon.java @@ -96,7 +96,7 @@ class HavenOfTheSpiritManaCondition extends CreatureCastManaCondition { @Override public boolean apply(Game game, Ability source, UUID manaProducer, Cost costToPay) { if (super.apply(game, source)) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object != null && object.hasSubtype(SubType.DRAGON, game) && object.isCreature(game)) { return true; diff --git a/Mage.Sets/src/mage/cards/h/HawkinsNationalLaboratory.java b/Mage.Sets/src/mage/cards/h/HavengulLaboratory.java similarity index 76% rename from Mage.Sets/src/mage/cards/h/HawkinsNationalLaboratory.java rename to Mage.Sets/src/mage/cards/h/HavengulLaboratory.java index caa4a6ecc65..014a8e29650 100644 --- a/Mage.Sets/src/mage/cards/h/HawkinsNationalLaboratory.java +++ b/Mage.Sets/src/mage/cards/h/HavengulLaboratory.java @@ -26,13 +26,13 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class HawkinsNationalLaboratory extends CardImpl { +public final class HavengulLaboratory extends CardImpl { - public HawkinsNationalLaboratory(UUID ownerId, CardSetInfo setInfo) { + public HavengulLaboratory(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.addSuperType(SuperType.LEGENDARY); - this.secondSideCardClazz = mage.cards.t.TheUpsideDown.class; + this.secondSideCardClazz = mage.cards.h.HavengulMystery.class; // {T}: Add {C}. this.addAbility(new ColorlessManaAbility()); @@ -46,26 +46,26 @@ public final class HawkinsNationalLaboratory extends CardImpl { this.addAbility(new TransformAbility()); this.addAbility(new BeginningOfEndStepTriggeredAbility( Zone.BATTLEFIELD, new TransformSourceEffect(), - TargetController.YOU, HawkinsNationalLaboratoryCondition.instance, false - ), new HawkinsNationalLaboratoryWatcher()); + TargetController.YOU, HavengulLaboratoryCondition.instance, false + ), new HavengulLaboratoryWatcher()); } - private HawkinsNationalLaboratory(final HawkinsNationalLaboratory card) { + private HavengulLaboratory(final HavengulLaboratory card) { super(card); } @Override - public HawkinsNationalLaboratory copy() { - return new HawkinsNationalLaboratory(this); + public HavengulLaboratory copy() { + return new HavengulLaboratory(this); } } -enum HawkinsNationalLaboratoryCondition implements Condition { +enum HavengulLaboratoryCondition implements Condition { instance; @Override public boolean apply(Game game, Ability source) { - return HawkinsNationalLaboratoryWatcher.checkPlayer(source.getControllerId(), game); + return HavengulLaboratoryWatcher.checkPlayer(source.getControllerId(), game); } @Override @@ -74,11 +74,11 @@ enum HawkinsNationalLaboratoryCondition implements Condition { } } -class HawkinsNationalLaboratoryWatcher extends Watcher { +class HavengulLaboratoryWatcher extends Watcher { private final Map playerMap = new HashMap<>(); - HawkinsNationalLaboratoryWatcher() { + HavengulLaboratoryWatcher() { super(WatcherScope.GAME); } @@ -103,7 +103,7 @@ class HawkinsNationalLaboratoryWatcher extends Watcher { static boolean checkPlayer(UUID playerId, Game game) { return game .getState() - .getWatcher(HawkinsNationalLaboratoryWatcher.class) + .getWatcher(HavengulLaboratoryWatcher.class) .playerMap .getOrDefault(playerId, 0) >= 3; } diff --git a/Mage.Sets/src/mage/cards/t/TheUpsideDown.java b/Mage.Sets/src/mage/cards/h/HavengulMystery.java similarity index 72% rename from Mage.Sets/src/mage/cards/t/TheUpsideDown.java rename to Mage.Sets/src/mage/cards/h/HavengulMystery.java index cdaed4dd00d..b63a0aa5ff2 100644 --- a/Mage.Sets/src/mage/cards/t/TheUpsideDown.java +++ b/Mage.Sets/src/mage/cards/h/HavengulMystery.java @@ -1,4 +1,4 @@ -package mage.cards.t; +package mage.cards.h; import mage.MageObjectReference; import mage.abilities.Ability; @@ -29,19 +29,19 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class TheUpsideDown extends CardImpl { +public final class HavengulMystery extends CardImpl { - public TheUpsideDown(UUID ownerId, CardSetInfo setInfo) { + public HavengulMystery(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.addSuperType(SuperType.LEGENDARY); this.nightCard = true; // When this land transforms into The Upside Down, return target creature card from your graveyard to the battlefield. - this.addAbility(new TheUpsideDownTransformAbility()); + this.addAbility(new HavengulMysteryTransformAbility()); // When the creature put onto the battlefield with The Upside Down leaves the battlefield, transform The Upside Down. - this.addAbility(new TheUpsideDownLeavesAbility()); + this.addAbility(new HavengulMysteryLeavesAbility()); // {T}, Pay 1 life: Add {B}. Ability ability = new BlackManaAbility(); @@ -49,34 +49,34 @@ public final class TheUpsideDown extends CardImpl { this.addAbility(ability); } - private TheUpsideDown(final TheUpsideDown card) { + private HavengulMystery(final HavengulMystery card) { super(card); } @Override - public TheUpsideDown copy() { - return new TheUpsideDown(this); + public HavengulMystery copy() { + return new HavengulMystery(this); } static String makeKey(Ability source, Game game) { - return "TheUpsideDown_" + source.getSourceId() + '_' + source.getSourceObjectZoneChangeCounter(); + return "HavengulMystery_" + source.getSourceId() + '_' + source.getSourceObjectZoneChangeCounter(); } } -class TheUpsideDownTransformAbility extends TriggeredAbilityImpl { +class HavengulMysteryTransformAbility extends TriggeredAbilityImpl { - public TheUpsideDownTransformAbility() { - super(Zone.BATTLEFIELD, new TheUpsideDownEffect(), false); + public HavengulMysteryTransformAbility() { + super(Zone.BATTLEFIELD, new HavengulMysteryEffect(), false); this.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } - public TheUpsideDownTransformAbility(final TheUpsideDownTransformAbility ability) { + public HavengulMysteryTransformAbility(final HavengulMysteryTransformAbility ability) { super(ability); } @Override - public TheUpsideDownTransformAbility copy() { - return new TheUpsideDownTransformAbility(this); + public HavengulMysteryTransformAbility copy() { + return new HavengulMysteryTransformAbility(this); } @Override @@ -100,19 +100,19 @@ class TheUpsideDownTransformAbility extends TriggeredAbilityImpl { } } -class TheUpsideDownEffect extends OneShotEffect { +class HavengulMysteryEffect extends OneShotEffect { - TheUpsideDownEffect() { + HavengulMysteryEffect() { super(Outcome.Benefit); } - private TheUpsideDownEffect(final TheUpsideDownEffect effect) { + private HavengulMysteryEffect(final HavengulMysteryEffect effect) { super(effect); } @Override - public TheUpsideDownEffect copy() { - return new TheUpsideDownEffect(this); + public HavengulMysteryEffect copy() { + return new HavengulMysteryEffect(this); } @Override @@ -127,7 +127,7 @@ class TheUpsideDownEffect extends OneShotEffect { if (permanent == null) { return false; } - String key = TheUpsideDown.makeKey(source, game); + String key = HavengulMystery.makeKey(source, game); Set morSet; if (game.getState().getValue(key) != null) { morSet = (Set) game.getState().getValue(key); @@ -140,19 +140,19 @@ class TheUpsideDownEffect extends OneShotEffect { } } -class TheUpsideDownLeavesAbility extends TriggeredAbilityImpl { +class HavengulMysteryLeavesAbility extends TriggeredAbilityImpl { - TheUpsideDownLeavesAbility() { + HavengulMysteryLeavesAbility() { super(Zone.BATTLEFIELD, new TransformSourceEffect()); } - private TheUpsideDownLeavesAbility(final TheUpsideDownLeavesAbility ability) { + private HavengulMysteryLeavesAbility(final HavengulMysteryLeavesAbility ability) { super(ability); } @Override - public TheUpsideDownLeavesAbility copy() { - return new TheUpsideDownLeavesAbility(this); + public HavengulMysteryLeavesAbility copy() { + return new HavengulMysteryLeavesAbility(this); } @Override @@ -163,7 +163,7 @@ class TheUpsideDownLeavesAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - Set morSet = (Set) game.getState().getValue(TheUpsideDown.makeKey(this, game)); + Set morSet = (Set) game.getState().getValue(HavengulMystery.makeKey(this, game)); return morSet != null && !morSet.isEmpty() && morSet.stream().anyMatch(mor -> mor.refersTo(zEvent.getTarget(), game)); diff --git a/Mage.Sets/src/mage/cards/h/HazardousConditions.java b/Mage.Sets/src/mage/cards/h/HazardousConditions.java index 88395f599d7..505857f9c9b 100644 --- a/Mage.Sets/src/mage/cards/h/HazardousConditions.java +++ b/Mage.Sets/src/mage/cards/h/HazardousConditions.java @@ -1,4 +1,3 @@ - package mage.cards.h; import mage.abilities.effects.common.continuous.BoostAllEffect; @@ -17,7 +16,7 @@ import java.util.UUID; */ public final class HazardousConditions extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures with no counter"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures with no counters on them"); static { filter.add(Predicates.not(CounterAnyPredicate.instance)); diff --git a/Mage.Sets/src/mage/cards/h/HazduhrTheAbbot.java b/Mage.Sets/src/mage/cards/h/HazduhrTheAbbot.java index 6cebc5701eb..e4e72630d2c 100644 --- a/Mage.Sets/src/mage/cards/h/HazduhrTheAbbot.java +++ b/Mage.Sets/src/mage/cards/h/HazduhrTheAbbot.java @@ -88,7 +88,7 @@ class HazduhrTheAbbotRedirectDamageEffect extends RedirectionEffect { 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 (filter.match(permanent, permanent.getControllerId(), source, game)) { if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) { if (event.getTargetId() != null) { TargetPermanent target = new TargetPermanent(); diff --git a/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java b/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java index 8a4fe475afc..99614eb7291 100644 --- a/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java +++ b/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java @@ -1,41 +1,44 @@ package mage.cards.h; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DontUntapInControllersUntapStepAllEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.*; import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledLandPermanent; -import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ManaValuePredicate; -import mage.game.ExileZone; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; +import mage.util.CardUtil; import java.util.UUID; -import mage.ApprovingObject; /** * @author ciaccona007 */ public final class HazoretsUndyingFury extends CardImpl { + private static final FilterPermanent filter = new FilterControlledLandPermanent("Lands you control"); + public HazoretsUndyingFury(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}{R}"); //Shuffle your library, then exile the top four cards. //You may cast any number of nonland cards with converted mana //cost 5 or less from among them without paying their mana costs. - getSpellAbility().addEffect(new HazoretsUndyingFuryEffect()); + this.getSpellAbility().addEffect(new HazoretsUndyingFuryEffect()); //Land you control don't untap during your next untap step. this.getSpellAbility().addEffect(new DontUntapInControllersUntapStepAllEffect( Duration.UntilYourNextTurn, TargetController.YOU, - new FilterControlledLandPermanent("Lands you control")) - .setText("Lands you control don't untap during your next untap phase")); + StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND + ).setText("Lands you control don't untap during your next untap phase")); } private HazoretsUndyingFury(final HazoretsUndyingFury card) { @@ -50,19 +53,17 @@ public final class HazoretsUndyingFury extends CardImpl { class HazoretsUndyingFuryEffect extends OneShotEffect { - private static final FilterCard filter = new FilterCard( - "nonland cards with mana value 5 or less"); + private static final FilterCard filter = new FilterCard(); static { - filter.add(Predicates.not(CardType.LAND.getPredicate())); filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 6)); } public HazoretsUndyingFuryEffect() { super(Outcome.PlayForFree); - this.staticText = "Shuffle your library, then exile the top four cards. " - + "You may cast any number of nonland cards with mana value " - + "5 or less from among them without paying their mana costs"; + this.staticText = "Shuffle your library, then exile the top four cards. " + + "You may cast any number of spells with mana value " + + "5 or less from among them without paying their mana costs"; } public HazoretsUndyingFuryEffect(final HazoretsUndyingFuryEffect effect) { @@ -77,46 +78,15 @@ class HazoretsUndyingFuryEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (controller != null - && sourceObject != null) { - controller.shuffleLibrary(source, game); - // move cards from library to exile - controller.moveCardsToExile(controller.getLibrary().getTopCards(game, 4), - source, game, true, source.getSourceId(), sourceObject.getIdName()); - // cast the possible cards without paying the mana - ExileZone hazoretsUndyingFuryExileZone = game.getExile().getExileZone(source.getSourceId()); - Cards cardsToCast = new CardsImpl(); - if (hazoretsUndyingFuryExileZone == null) { - return true; - } - cardsToCast.addAll(hazoretsUndyingFuryExileZone.getCards(filter, - source.getSourceId(), source.getControllerId(), game)); - while (controller.canRespond() && !cardsToCast.isEmpty()) { - if (!controller.chooseUse(Outcome.PlayForFree, - "Cast (another) a card exiled with " - + sourceObject.getLogName() + " without paying its mana cost?", source, game)) { - break; - } - TargetCard targetCard = new TargetCard(1, Zone.EXILED, - new FilterCard("nonland card to cast for free")); - if (controller.choose(Outcome.PlayForFree, cardsToCast, targetCard, game)) { - Card card = game.getCard(targetCard.getFirstTarget()); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - cardsToCast.remove(card); - if (!cardWasCast) { - game.informPlayer(controller, "You're not able to cast " - + card.getIdName() + " or you canceled the casting."); - } - } - } - } - return true; + if (controller == null) { + return false; } - return false; + controller.shuffleLibrary(source, game); + // move cards from library to exile + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 4)); + controller.moveCards(cards, Zone.EXILED, source, game); + // cast the possible cards without paying the mana + CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, filter); + return true; } } diff --git a/Mage.Sets/src/mage/cards/h/Headhunter.java b/Mage.Sets/src/mage/cards/h/Headhunter.java index 382a69b6691..6a9237a2297 100644 --- a/Mage.Sets/src/mage/cards/h/Headhunter.java +++ b/Mage.Sets/src/mage/cards/h/Headhunter.java @@ -31,7 +31,7 @@ public final class Headhunter extends CardImpl { this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DiscardTargetEffect(1), false, true)); // Morph {B} (You may cast this face down as a 2/2 creature for {3}. Turn it face up any time for its morph cost.) - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{B}"))); } diff --git a/Mage.Sets/src/mage/cards/h/HealingGrace.java b/Mage.Sets/src/mage/cards/h/HealingGrace.java index e692b74283f..beb6f4e7eda 100644 --- a/Mage.Sets/src/mage/cards/h/HealingGrace.java +++ b/Mage.Sets/src/mage/cards/h/HealingGrace.java @@ -62,7 +62,7 @@ class HealingGraceEffect extends PreventionEffectImpl { @Override public void init(Ability source, Game game) { - this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/h/HealingLeaves.java b/Mage.Sets/src/mage/cards/h/HealingLeaves.java index 6cc03b6d798..d8318673cd9 100644 --- a/Mage.Sets/src/mage/cards/h/HealingLeaves.java +++ b/Mage.Sets/src/mage/cards/h/HealingLeaves.java @@ -24,8 +24,7 @@ public final class HealingLeaves extends CardImpl { // Choose one - Target player gains 3 life; or prevent the next 3 damage that would be dealt to any target this turn. this.getSpellAbility().addEffect(new GainLifeTargetEffect(3)); this.getSpellAbility().addTarget(new TargetPlayer()); - Mode mode = new Mode(); - mode.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, 3)); + Mode mode = new Mode(new PreventDamageToTargetEffect(Duration.EndOfTurn, 3)); mode.addTarget(new TargetAnyTarget()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/h/HealingSalve.java b/Mage.Sets/src/mage/cards/h/HealingSalve.java index d155ac831c4..87b84238ad1 100644 --- a/Mage.Sets/src/mage/cards/h/HealingSalve.java +++ b/Mage.Sets/src/mage/cards/h/HealingSalve.java @@ -26,8 +26,7 @@ public final class HealingSalve extends CardImpl { this.getSpellAbility().addEffect(new GainLifeTargetEffect(3)); this.getSpellAbility().addTarget(new TargetPlayer()); - Mode mode = new Mode(); - mode.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, 3)); + Mode mode = new Mode(new PreventDamageToTargetEffect(Duration.EndOfTurn, 3)); mode.addTarget(new TargetAnyTarget()); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/h/HeartOfKiran.java b/Mage.Sets/src/mage/cards/h/HeartOfKiran.java index 3bdcfa81c9f..f95b06761b1 100644 --- a/Mage.Sets/src/mage/cards/h/HeartOfKiran.java +++ b/Mage.Sets/src/mage/cards/h/HeartOfKiran.java @@ -1,28 +1,21 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.Cost; -import mage.abilities.costs.CostImpl; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect; +import mage.abilities.costs.common.RemoveCounterCost; import mage.abilities.keyword.CrewAbility; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.counters.CounterType; -import mage.filter.common.FilterControlledPlaneswalkerPermanent; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.target.Target; +import mage.filter.StaticFilters; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** * @author JRHerlehy */ @@ -43,13 +36,13 @@ public final class HeartOfKiran extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // Crew 3 - this.addAbility(new CrewAbility(3)); - // You may remove a loyalty counter from a planeswalker you control rather than pay Heart of Kiran's crew cost. - Cost cost = new HeartOfKiranAlternateCrewCost(CounterType.LOYALTY, 1); - Effect effect = new AddCardTypeSourceEffect(Duration.EndOfTurn, CardType.CREATURE); - effect.setText("You may remove a loyalty counter from a planeswalker you control rather than pay {this}'s crew cost"); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, cost)); + this.addAbility(new CrewAbility( + 3, + new RemoveCounterCost(new TargetControlledPermanent( + StaticFilters.FILTER_CONTROLLED_PERMANENT_PLANESWALKER + ), CounterType.LOYALTY) + )); } private HeartOfKiran(final HeartOfKiran card) { @@ -61,58 +54,3 @@ public final class HeartOfKiran extends CardImpl { return new HeartOfKiran(this); } } - -class HeartOfKiranAlternateCrewCost extends CostImpl { - - private final CounterType counterTypeToRemove; - private final int countersToRemove; - - private static final FilterControlledPlaneswalkerPermanent filter = new FilterControlledPlaneswalkerPermanent("planeswalker you control"); - - public HeartOfKiranAlternateCrewCost(CounterType counterTypeToRemove, int countersToRemove) { - this.counterTypeToRemove = counterTypeToRemove; - this.countersToRemove = countersToRemove; - } - - public HeartOfKiranAlternateCrewCost(final HeartOfKiranAlternateCrewCost cost) { - super(cost); - this.counterTypeToRemove = cost.counterTypeToRemove; - this.countersToRemove = cost.countersToRemove; - } - - @Override - public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - paid = false; - - Target target = new TargetControlledPermanent(1, 1, filter, true); - - if (target.choose(Outcome.Benefit, controllerId, source.getSourceId(), game)) { - Permanent permanent = game.getPermanent(target.getFirstTarget()); - int originalLoyalty = permanent.getCounters(game).getCount(counterTypeToRemove); - - GameEvent event = new GameEvent(GameEvent.EventType.CREW_VEHICLE, target.getFirstTarget(), source, controllerId); - if (!game.replaceEvent(event)) { - permanent.removeCounters(counterTypeToRemove.createInstance(), source, game); - } - - paid = permanent.getCounters(game).getCount(counterTypeToRemove) < originalLoyalty; - - if (paid) { - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREWED_VEHICLE, target.getFirstTarget(), source, controllerId)); - } - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.VEHICLE_CREWED, source.getSourceId(), source, controllerId)); - } - - return paid; - } - - @Override - public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return !game.getBattlefield().getAllActivePermanents(filter, game).isEmpty(); - } - - @Override - public HeartOfKiranAlternateCrewCost copy() { - return new HeartOfKiranAlternateCrewCost(this); - } -} diff --git a/Mage.Sets/src/mage/cards/h/HeartPiercerManticore.java b/Mage.Sets/src/mage/cards/h/HeartPiercerManticore.java index 0adb9947c01..4d7f1ac9977 100644 --- a/Mage.Sets/src/mage/cards/h/HeartPiercerManticore.java +++ b/Mage.Sets/src/mage/cards/h/HeartPiercerManticore.java @@ -78,7 +78,7 @@ class HeartPiercerManticoreSacrificeEffect extends OneShotEffect { Target target = new TargetControlledCreaturePermanent( 1, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, true ); - if (!controller.choose(outcome, target, source.getSourceId(), game)) { + if (!controller.choose(outcome, target, source, game)) { return false; } Permanent toSacrifice = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/h/HeartSliver.java b/Mage.Sets/src/mage/cards/h/HeartSliver.java index 47c4e1fd6a9..4427e8a7ff1 100644 --- a/Mage.Sets/src/mage/cards/h/HeartSliver.java +++ b/Mage.Sets/src/mage/cards/h/HeartSliver.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; @@ -11,27 +9,25 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; /** * @author Loki */ public final class HeartSliver extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("All sliver creatures"); - - static { - filter.add(SubType.SLIVER.getPredicate()); - } - public HeartSliver(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); this.subtype.add(SubType.SLIVER); this.power = new MageInt(1); this.toughness = new MageInt(1); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield, filter, false))); + this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( + HasteAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_ALL_SLIVERS, false + ))); } private HeartSliver(final HeartSliver card) { diff --git a/Mage.Sets/src/mage/cards/h/HearthCharm.java b/Mage.Sets/src/mage/cards/h/HearthCharm.java index 6d034e1b9b7..427b8409585 100644 --- a/Mage.Sets/src/mage/cards/h/HearthCharm.java +++ b/Mage.Sets/src/mage/cards/h/HearthCharm.java @@ -34,12 +34,10 @@ public final class HearthCharm extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE)); // or attacking creatures get +1/+0 until end of turn - Mode mode = new Mode(); - mode.addEffect(new BoostAllEffect(1, 0, Duration.EndOfTurn, StaticFilters.FILTER_ATTACKING_CREATURES, false)); + Mode mode = new Mode(new BoostAllEffect(1, 0, Duration.EndOfTurn, StaticFilters.FILTER_ATTACKING_CREATURES, false)); this.getSpellAbility().addMode(mode); // or target creature with power 2 or less is unblockable this turn. - mode = new Mode(); - mode.addEffect(new CantBeBlockedTargetEffect()); + mode = new Mode(new CantBeBlockedTargetEffect()); mode.addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/h/HearthcageGiant.java b/Mage.Sets/src/mage/cards/h/HearthcageGiant.java index 08970c78af5..94eb0488f69 100644 --- a/Mage.Sets/src/mage/cards/h/HearthcageGiant.java +++ b/Mage.Sets/src/mage/cards/h/HearthcageGiant.java @@ -28,7 +28,7 @@ import mage.target.common.TargetCreaturePermanent; public final class HearthcageGiant extends CardImpl { private static final FilterControlledPermanent filterElemental = new FilterControlledPermanent("Elemental"); - private static final FilterCreaturePermanent filterGiant = new FilterCreaturePermanent("Giant"); + private static final FilterCreaturePermanent filterGiant = new FilterCreaturePermanent("Giant creature"); static { filterElemental.add(SubType.ELEMENTAL.getPredicate()); diff --git a/Mage.Sets/src/mage/cards/h/HeartlashCinder.java b/Mage.Sets/src/mage/cards/h/HeartlashCinder.java index 3fb8fd9d7be..bb2577dea9d 100644 --- a/Mage.Sets/src/mage/cards/h/HeartlashCinder.java +++ b/Mage.Sets/src/mage/cards/h/HeartlashCinder.java @@ -11,10 +11,7 @@ import mage.abilities.hint.ValueHint; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.ManaType; -import mage.constants.SubType; +import mage.constants.*; import java.util.UUID; @@ -40,7 +37,7 @@ public final class HeartlashCinder extends CardImpl { effect.setText("it gets +X/+0 until end of turn, where X is the number of red mana symbols in the mana costs of permanents you control"); this.addAbility(new EntersBattlefieldTriggeredAbility( effect, false) - .withFlavorWord("Chroma") + .setAbilityWord(AbilityWord.CHROMA) .addHint(new ValueHint("Red mana symbols in your permanents", xValue)) ); } diff --git a/Mage.Sets/src/mage/cards/h/HeartwoodShard.java b/Mage.Sets/src/mage/cards/h/HeartwoodShard.java index 84475daa40d..78afe2682d7 100644 --- a/Mage.Sets/src/mage/cards/h/HeartwoodShard.java +++ b/Mage.Sets/src/mage/cards/h/HeartwoodShard.java @@ -29,9 +29,8 @@ public final class HeartwoodShard extends CardImpl { Ability ability = new SimpleActivatedAbility( new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn), new OrCost( - new CompositeCost(new GenericManaCost(3), new TapSourceCost(), "{3}, {T}"), - new CompositeCost(new ManaCostsImpl<>("{G}"), new TapSourceCost(), "{G}, {T}"), - "{3}, {T} or {G}, {T}" + "{3}, {T} or {G}, {T}", new CompositeCost(new GenericManaCost(3), new TapSourceCost(), "{3}, {T}"), + new CompositeCost(new ManaCostsImpl<>("{G}"), new TapSourceCost(), "{G}, {T}") ) ); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/h/HeatStroke.java b/Mage.Sets/src/mage/cards/h/HeatStroke.java index a24d538a28c..ee6d08fbd46 100644 --- a/Mage.Sets/src/mage/cards/h/HeatStroke.java +++ b/Mage.Sets/src/mage/cards/h/HeatStroke.java @@ -60,7 +60,7 @@ class HeatStrokeEffect extends OneShotEffect { BlockedThisTurnWatcher blockedWatcher = game.getState().getWatcher(BlockedThisTurnWatcher.class); WasBlockedThisTurnWatcher wasBlockedThisTurnWatcher = game.getState().getWatcher(WasBlockedThisTurnWatcher.class); - Set inROI = new HashSet<>(game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)); + Set inROI = new HashSet<>(game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)); boolean toRet = false; Set toDestroy = new HashSet<>(); diff --git a/Mage.Sets/src/mage/cards/h/HeavenlyBlademaster.java b/Mage.Sets/src/mage/cards/h/HeavenlyBlademaster.java index 6f480568238..6c2063e8871 100644 --- a/Mage.Sets/src/mage/cards/h/HeavenlyBlademaster.java +++ b/Mage.Sets/src/mage/cards/h/HeavenlyBlademaster.java @@ -108,7 +108,7 @@ class HeavenlyBlademasterEffect extends OneShotEffect { return false; } Target target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); - if (!player.choose(outcome, target, source.getSourceId(), game)) { + if (!player.choose(outcome, target, source, game)) { return false; } target.getTargets().stream().map( diff --git a/Mage.Sets/src/mage/cards/h/HedronAlignment.java b/Mage.Sets/src/mage/cards/h/HedronAlignment.java index 35ff43f0a60..2d2ed094628 100644 --- a/Mage.Sets/src/mage/cards/h/HedronAlignment.java +++ b/Mage.Sets/src/mage/cards/h/HedronAlignment.java @@ -87,15 +87,15 @@ class HedronAlignmentEffect extends OneShotEffect { if (!game.getBattlefield().contains(filterPermanent, source, game, 1)) { return true; } - if (controller.getHand().getCards(filterCard, source.getSourceId(), controller.getId(), game).isEmpty()) { + if (controller.getHand().getCards(filterCard, controller.getId(), source, game).isEmpty()) { return true; } - if (controller.getGraveyard().getCards(filterCard, source.getSourceId(), controller.getId(), game).isEmpty()) { + if (controller.getGraveyard().getCards(filterCard, controller.getId(), source, game).isEmpty()) { return true; } Cards cardsToCheck = new CardsImpl(); cardsToCheck.addAll(game.getExile().getAllCards(game)); - if (cardsToCheck.count(filterCard, source.getSourceId(), controller.getId(), game) == 0) { + if (cardsToCheck.count(filterCard, controller.getId(), source, game) == 0) { return true; } controller.won(game); diff --git a/Mage.Sets/src/mage/cards/h/HeikoYamazakiTheGeneral.java b/Mage.Sets/src/mage/cards/h/HeikoYamazakiTheGeneral.java index 451914f9bf5..d741c40fc2e 100644 --- a/Mage.Sets/src/mage/cards/h/HeikoYamazakiTheGeneral.java +++ b/Mage.Sets/src/mage/cards/h/HeikoYamazakiTheGeneral.java @@ -1,27 +1,26 @@ package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksAloneControlledTriggeredAbility; import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; -import mage.constants.*; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.filter.common.FilterArtifactCard; +import mage.constants.*; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class HeikoYamazakiTheGeneral extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("a Samurai or Warrior you control"); - private static final FilterArtifactCard filter2 = new FilterArtifactCard("artifact card from your graveyard"); static { filter.add(Predicates.or(SubType.SAMURAI.getPredicate(), SubType.WARRIOR.getPredicate())); @@ -45,7 +44,7 @@ public final class HeikoYamazakiTheGeneral extends CardImpl { .setText("you may cast target artifact card from your graveyard this turn"), filter, false, false ); - ability.addTarget(new TargetCardInYourGraveyard(filter2)); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HellMongrel.java b/Mage.Sets/src/mage/cards/h/HellMongrel.java index 334b84710b5..eab3ccfa64b 100644 --- a/Mage.Sets/src/mage/cards/h/HellMongrel.java +++ b/Mage.Sets/src/mage/cards/h/HellMongrel.java @@ -33,7 +33,7 @@ public final class HellMongrel extends CardImpl { )); // Madness {2}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{2}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{2}{B}"))); } private HellMongrel(final HellMongrel card) { diff --git a/Mage.Sets/src/mage/cards/h/HellcarverDemon.java b/Mage.Sets/src/mage/cards/h/HellcarverDemon.java index e3f7d05bcae..3dc14d8aae0 100644 --- a/Mage.Sets/src/mage/cards/h/HellcarverDemon.java +++ b/Mage.Sets/src/mage/cards/h/HellcarverDemon.java @@ -1,26 +1,24 @@ package mage.cards.h; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlyingAbility; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterNonlandCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.TargetCard; +import mage.util.CardUtil; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; import java.util.UUID; -import mage.ApprovingObject; /** * @author jeffwadsworth & L_J @@ -58,7 +56,7 @@ class HellcarverDemonEffect extends OneShotEffect { super(Outcome.PlayForFree); staticText = "sacrifice all other permanents you control and discard your hand. " + "Exile the top six cards of your library. You may cast any number of " - + "nonland cards exiled this way without paying their mana costs."; + + "spells from among cards exiled this way without paying their mana costs"; } public HellcarverDemonEffect(final HellcarverDemonEffect effect) { @@ -68,54 +66,25 @@ class HellcarverDemonEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (controller != null && sourceObject != null) { - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) { - if (!Objects.equals(permanent, sourceObject)) { - permanent.sacrifice(source, game); - } - } - if (!controller.getHand().isEmpty()) { - int cardsInHand = controller.getHand().size(); - controller.discard(cardsInHand, false, false, source, game); - } - // move cards from library to exile - Set currentExiledCards = new HashSet<>(); - currentExiledCards.addAll(controller.getLibrary().getTopCards(game, 6)); - controller.moveCardsToExile(currentExiledCards, source, game, true, - source.getSourceId(), sourceObject.getIdName()); - - // cast the possible cards without paying the mana - Cards cardsToCast = new CardsImpl(); - cardsToCast.addAll(currentExiledCards); - boolean alreadyCast = false; - while (controller.canRespond() && !cardsToCast.isEmpty()) { - if (!controller.chooseUse(outcome, "Cast a" + (alreadyCast ? "another" : "") - + " card exiled with " + sourceObject.getLogName() - + " without paying its mana cost?", source, game)) { - break; - } - TargetCard targetCard = new TargetCard(1, Zone.EXILED, - new FilterNonlandCard("nonland card to cast for free")); - if (controller.choose(Outcome.PlayForFree, cardsToCast, targetCard, game)) { - alreadyCast = true; - Card card = game.getCard(targetCard.getFirstTarget()); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - cardsToCast.remove(card); - if (!cardWasCast) { - game.informPlayer(controller, "You're not able to cast " - + card.getIdName() + " or you canceled the casting."); - } - } - } - } - return true; + if (controller == null) { + return false; } - return false; + MageObjectReference sourceMor = new MageObjectReference(source); + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_PERMANENT, + source.getControllerId(), source, game + )) { + if (!sourceMor.refersTo(permanent, game)) { + permanent.sacrifice(source, game); + } + } + controller.discard(controller.getHand(), false, source, game); + CardUtil.castMultipleWithAttributeForFree( + controller, source, game, new CardsImpl( + controller.getLibrary().getTopCards(game, 6) + ), StaticFilters.FILTER_CARD + ); + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/h/HellkiteCourser.java b/Mage.Sets/src/mage/cards/h/HellkiteCourser.java index a0948290de0..1a67fd84e3b 100644 --- a/Mage.Sets/src/mage/cards/h/HellkiteCourser.java +++ b/Mage.Sets/src/mage/cards/h/HellkiteCourser.java @@ -84,7 +84,7 @@ class HellkiteCourserEffect extends OneShotEffect { } TargetCard target = new TargetCard(0, 1, Zone.COMMAND, filter); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card == null) { return false; diff --git a/Mage.Sets/src/mage/cards/h/HellkiteHatchling.java b/Mage.Sets/src/mage/cards/h/HellkiteHatchling.java index 002e39e98e2..a840b2155c1 100644 --- a/Mage.Sets/src/mage/cards/h/HellkiteHatchling.java +++ b/Mage.Sets/src/mage/cards/h/HellkiteHatchling.java @@ -1,9 +1,9 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.DevouredCreaturesCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.DevourEffect.DevourFactor; @@ -14,18 +14,20 @@ import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class HellkiteHatchling extends CardImpl { + private static final Condition condition = new DevouredCreaturesCondition(ComparisonType.MORE_THAN, 0); + public HellkiteHatchling(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}"); this.subtype.add(SubType.DRAGON); this.power = new MageInt(2); @@ -35,14 +37,15 @@ public final class HellkiteHatchling extends CardImpl { this.addAbility(new DevourAbility(DevourFactor.Devour1)); // Hellkite Hatchling has flying and trample if it devoured a creature. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( new GainAbilitySourceEffect(FlyingAbility.getInstance()), - new DevouredCreaturesCondition(ComparisonType.MORE_THAN, 0), - "{this} has flying if it devoured a creature"))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + condition, "{this} has flying" + )); + ability.addEffect(new ConditionalContinuousEffect( new GainAbilitySourceEffect(TrampleAbility.getInstance()), - new DevouredCreaturesCondition(ComparisonType.MORE_THAN, 0), - "{this} has trample if it devoured a creature"))); + condition, "and trample if it devoured a creature" + )); + this.addAbility(ability); } private HellkiteHatchling(final HellkiteHatchling card) { diff --git a/Mage.Sets/src/mage/cards/h/HellraiserGoblin.java b/Mage.Sets/src/mage/cards/h/HellraiserGoblin.java index 4a94d00f5d6..42b346f4033 100644 --- a/Mage.Sets/src/mage/cards/h/HellraiserGoblin.java +++ b/Mage.Sets/src/mage/cards/h/HellraiserGoblin.java @@ -3,10 +3,8 @@ package mage.cards.h; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.Mode; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.Effect; -import mage.abilities.effects.RequirementEffect; +import mage.abilities.effects.common.combat.AttacksIfAbleAllEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; @@ -16,9 +14,6 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.game.Game; -import mage.game.permanent.Permanent; /** * @@ -35,10 +30,12 @@ public final class HellraiserGoblin extends CardImpl { this.toughness = new MageInt(2); // Creatures you control have haste and attack each combat if able. - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES)); - Effect effect = new AttacksIfAbleAllEffect(Duration.WhileOnBattlefield); - effect.setText("and attack each combat if able"); - ability.addEffect(effect); + Ability ability = new SimpleStaticAbility(new GainAbilityControlledEffect( + HasteAbility.getInstance(), + Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_CREATURES + )); + ability.addEffect(new AttacksIfAbleAllEffect(StaticFilters.FILTER_CONTROLLED_CREATURES).setText("and attack each combat if able")); this.addAbility(ability); } @@ -51,51 +48,3 @@ public final class HellraiserGoblin extends CardImpl { return new HellraiserGoblin(this); } } - -class AttacksIfAbleAllEffect extends RequirementEffect { - - private FilterControlledCreaturePermanent filter; - - public AttacksIfAbleAllEffect(Duration duration) { - this(duration, new FilterControlledCreaturePermanent()); - } - - public AttacksIfAbleAllEffect(Duration duration, FilterControlledCreaturePermanent filter) { - super(duration); - this.filter = filter; - } - - public AttacksIfAbleAllEffect(final AttacksIfAbleAllEffect effect) { - super(effect); - this.filter = effect.filter; - } - - @Override - public AttacksIfAbleAllEffect copy() { - return new AttacksIfAbleAllEffect(this); - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); - } - - @Override - public boolean mustAttack(Game game) { - return true; - } - - @Override - public boolean mustBlock(Game game) { - return false; - } - - @Override - public String getText(Mode mode) { - if (!staticText.isEmpty()) { - return staticText; - } - return filter.getMessage() + " attack each combat if able"; - } - -} diff --git a/Mage.Sets/src/mage/cards/h/HelmOfKaldra.java b/Mage.Sets/src/mage/cards/h/HelmOfKaldra.java index 9c4cdde8abd..2ffa400bfaa 100644 --- a/Mage.Sets/src/mage/cards/h/HelmOfKaldra.java +++ b/Mage.Sets/src/mage/cards/h/HelmOfKaldra.java @@ -80,13 +80,13 @@ class HelmOfKaldraCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - if (game.getBattlefield().count(HelmOfKaldra.filterHelm, source.getSourceId(), source.getControllerId(), game) < 1) { + if (game.getBattlefield().count(HelmOfKaldra.filterHelm, source.getControllerId(), source, game) < 1) { return false; } - if (game.getBattlefield().count(HelmOfKaldra.filterSword, source.getSourceId(), source.getControllerId(), game) < 1) { + if (game.getBattlefield().count(HelmOfKaldra.filterSword, source.getControllerId(), source, game) < 1) { return false; } - return game.getBattlefield().count(HelmOfKaldra.filterShield, source.getSourceId(), source.getControllerId(), game) >= 1; + return game.getBattlefield().count(HelmOfKaldra.filterShield, source.getControllerId(), source, game) >= 1; } } diff --git a/Mage.Sets/src/mage/cards/h/HeraldOfAnguish.java b/Mage.Sets/src/mage/cards/h/HeraldOfAnguish.java index ca30a58bf73..ebd207e12fb 100644 --- a/Mage.Sets/src/mage/cards/h/HeraldOfAnguish.java +++ b/Mage.Sets/src/mage/cards/h/HeraldOfAnguish.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfYourEndStepTriggeredAbility; @@ -14,17 +12,14 @@ import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.ImproviseAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.TargetController; -import mage.constants.Zone; -import mage.filter.common.FilterControlledArtifactPermanent; +import mage.constants.*; +import mage.filter.StaticFilters; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class HeraldOfAnguish extends CardImpl { @@ -47,7 +42,7 @@ public final class HeraldOfAnguish extends CardImpl { // {1}{B}, Sacrifice an artifact: Target creature gets -2/-2 until end of turn. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(-2, -2, Duration.EndOfTurn), new ManaCostsImpl("{1}{B}")); - ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledArtifactPermanent()))); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_AN))); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HeraldOfLeshrac.java b/Mage.Sets/src/mage/cards/h/HeraldOfLeshrac.java index 703f309f677..549d0b57c1e 100644 --- a/Mage.Sets/src/mage/cards/h/HeraldOfLeshrac.java +++ b/Mage.Sets/src/mage/cards/h/HeraldOfLeshrac.java @@ -89,7 +89,7 @@ class HeraldOfLeshracCumulativeCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Target target = new TargetPermanent(filter); - if (target.choose(Outcome.GainControl, controllerId, source.getSourceId(), game)) { + if (target.choose(Outcome.GainControl, controllerId, source.getSourceId(), source, game)) { ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfGame); effect.setTargetPointer(new FixedTarget(target.getFirstTarget(), game)); game.addEffect(effect, ability); @@ -101,7 +101,7 @@ class HeraldOfLeshracCumulativeCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return game.getBattlefield().contains(filter, source.getSourceId(), controllerId, game, 1); + return game.getBattlefield().contains(filter, source.getSourceId(), controllerId, source, game, 1); } @Override @@ -135,7 +135,7 @@ class HeraldOfLeshracLeavesEffect extends OneShotEffect { FilterPermanent filter = new FilterLandPermanent(); filter.add(new OwnerIdPredicate(playerId)); filter.add(new ControllerIdPredicate(source.getControllerId())); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfGame, playerId); effect.setTargetPointer(new FixedTarget(permanent, game)); game.addEffect(effect, source); diff --git a/Mage.Sets/src/mage/cards/h/HeraldicBanner.java b/Mage.Sets/src/mage/cards/h/HeraldicBanner.java index 4171169e3f8..07ea12d1f92 100644 --- a/Mage.Sets/src/mage/cards/h/HeraldicBanner.java +++ b/Mage.Sets/src/mage/cards/h/HeraldicBanner.java @@ -74,7 +74,7 @@ class HeraldicBannerEffect extends ContinuousEffectImpl { return false; } for (Permanent perm : game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_CONTROLLED_CREATURE, source.getControllerId(), source.getSourceId(), game + StaticFilters.FILTER_CONTROLLED_CREATURE, source.getControllerId(), source, game )) { if (perm.getColor(game).contains(color)) { perm.addPower(1); diff --git a/Mage.Sets/src/mage/cards/h/HeraldsHorn.java b/Mage.Sets/src/mage/cards/h/HeraldsHorn.java index 6ecea121edd..2a41716f9e2 100644 --- a/Mage.Sets/src/mage/cards/h/HeraldsHorn.java +++ b/Mage.Sets/src/mage/cards/h/HeraldsHorn.java @@ -69,7 +69,7 @@ class HeraldsHornEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); // Look at the top card of your library. if (controller != null && controller.getLibrary().hasCards() && sourceObject != null) { diff --git a/Mage.Sets/src/mage/cards/h/HerdchaserDragon.java b/Mage.Sets/src/mage/cards/h/HerdchaserDragon.java index 7378bfdfeba..c61cbc3d0f2 100644 --- a/Mage.Sets/src/mage/cards/h/HerdchaserDragon.java +++ b/Mage.Sets/src/mage/cards/h/HerdchaserDragon.java @@ -43,7 +43,7 @@ public final class HerdchaserDragon extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Megamorph {5}{G}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{5}{G}{G}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{5}{G}{G}"), true)); // When Herdchaser Dragon is turned face up, put a +1/+1 counter on each other Dragon creature you control. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter), false, false)); diff --git a/Mage.Sets/src/mage/cards/h/HeritageDruid.java b/Mage.Sets/src/mage/cards/h/HeritageDruid.java index 7f60c77c1a2..168bce74b79 100644 --- a/Mage.Sets/src/mage/cards/h/HeritageDruid.java +++ b/Mage.Sets/src/mage/cards/h/HeritageDruid.java @@ -75,7 +75,7 @@ class HeritageDruidManaEffect extends BasicManaEffect { @Override public List getNetMana(Game game, Ability source) { if (game != null && game.inCheckPlayableState()) { - int count = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) / 3; + int count = game.getBattlefield().count(filter, source.getControllerId(), source, game) / 3; List netMana = new ArrayList<>(); if (count > 0) { netMana.add(Mana.GreenMana(count * 3)); diff --git a/Mage.Sets/src/mage/cards/h/HeroesPodium.java b/Mage.Sets/src/mage/cards/h/HeroesPodium.java index 1caa0258eca..7895ad60f50 100644 --- a/Mage.Sets/src/mage/cards/h/HeroesPodium.java +++ b/Mage.Sets/src/mage/cards/h/HeroesPodium.java @@ -1,25 +1,26 @@ - package mage.cards.h; import java.util.UUID; -import mage.MageObject; 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.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.cards.*; -import mage.constants.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SuperType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; /** * @@ -27,10 +28,12 @@ import mage.target.TargetCard; */ public final class HeroesPodium extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Each legendary creature you control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("each legendary creature"); + private static final FilterCreatureCard filter2 = new FilterCreatureCard("a legendary creature card"); static { filter.add(SuperType.LEGENDARY.getPredicate()); + filter2.add(SuperType.LEGENDARY.getPredicate()); } public HeroesPodium(UUID ownerId, CardSetInfo setInfo) { @@ -38,15 +41,16 @@ public final class HeroesPodium extends CardImpl { addSuperType(SuperType.LEGENDARY); // Each legendary creature you control gets +1/+1 for each other legendary creature you control. - DynamicValue xValue = new HeroesPodiumLegendaryCount(); - Effect effect = new BoostControlledEffect(xValue, xValue, Duration.WhileOnBattlefield, filter, false); - effect.setText("Each legendary creature you control gets +1/+1 for each other legendary creature you control"); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); - // {X}, {T}: Look at the top X cards of your library. You may reveal a legendary creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new HeroesPodiumEffect(), new ManaCostsImpl("{X}")); + this.addAbility(new SimpleStaticAbility( + new BoostControlledEffect(HeroesPodiumValue.instance, HeroesPodiumValue.instance, Duration.WhileOnBattlefield, filter, false))); + // {X}, {T}: Look at the top X cards of your library. + // You may reveal a legendary creature card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. + Ability ability = new SimpleActivatedAbility( + new LookLibraryAndPickControllerEffect(ManacostVariableValue.REGULAR, 1, filter2, PutCards.HAND, PutCards.BOTTOM_RANDOM), + new ManaCostsImpl("{X}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); - } private HeroesPodium(final HeroesPodium card) { @@ -59,7 +63,8 @@ public final class HeroesPodium extends CardImpl { } } -class HeroesPodiumLegendaryCount implements DynamicValue { +enum HeroesPodiumValue implements DynamicValue { + instance; private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("other legendary creature you control"); @@ -69,16 +74,12 @@ class HeroesPodiumLegendaryCount implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - int value = game.getBattlefield().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); - if (value > 0) { - value--; - } - return value; + return Math.max(game.getBattlefield().count(filter, sourceAbility.getControllerId(), sourceAbility, game) - 1, 0); } @Override public String toString() { - return "X"; + return "1"; } @Override @@ -87,64 +88,7 @@ class HeroesPodiumLegendaryCount implements DynamicValue { } @Override - public HeroesPodiumLegendaryCount copy() { - return new HeroesPodiumLegendaryCount(); - } -} - -class HeroesPodiumEffect extends OneShotEffect { - - private static final FilterCreatureCard filter = new FilterCreatureCard("a legendary creature card"); - - static { - filter.add(SuperType.LEGENDARY.getPredicate()); - } - - public HeroesPodiumEffect() { - super(Outcome.DrawCard); - this.staticText = "Look at the top X cards of your library. You may reveal a legendary creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order"; - } - - public HeroesPodiumEffect(final HeroesPodiumEffect effect) { - super(effect); - } - - @Override - public HeroesPodiumEffect copy() { - return new HeroesPodiumEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (controller == null || sourceObject == null) { - return false; - } - - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, source.getManaCostsToPay().getX())); - boolean legendaryIncluded = cards.count(filter, game) > 0; - controller.lookAtCards(sourceObject.getIdName(), cards, game); - - // You may reveal a legendary creature card from among them and put it into your hand. - if (!cards.isEmpty() && legendaryIncluded && controller.chooseUse(outcome, "Put a legendary creature card into your hand?", source, game)) { - if (cards.size() == 1) { - controller.moveCards(cards, Zone.HAND, source, game); - return true; - } else { - TargetCard target = new TargetCard(Zone.LIBRARY, filter); - if (controller.choose(outcome, cards, target, game)) { - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - controller.moveCards(card, Zone.HAND, source, game); - } - } - } - } - - // Put the rest on the bottom of your library in a random order - controller.putCardsOnBottomOfLibrary(cards, game, source, false); - return true; + public HeroesPodiumValue copy() { + return instance; } } diff --git a/Mage.Sets/src/mage/cards/h/HiddenDragonslayer.java b/Mage.Sets/src/mage/cards/h/HiddenDragonslayer.java index 8f46cc6c240..315ff5b1932 100644 --- a/Mage.Sets/src/mage/cards/h/HiddenDragonslayer.java +++ b/Mage.Sets/src/mage/cards/h/HiddenDragonslayer.java @@ -43,7 +43,7 @@ public final class HiddenDragonslayer extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // Megamorph {2}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{W}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{W}"), true)); // When Hidden Dragonslayer is turned face up, destroy target creature with power 4 or greater an opponent controls. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new DestroyTargetEffect(), false, false); diff --git a/Mage.Sets/src/mage/cards/h/HiddenStockpile.java b/Mage.Sets/src/mage/cards/h/HiddenStockpile.java index a7e9e6ade66..5708f76fab6 100644 --- a/Mage.Sets/src/mage/cards/h/HiddenStockpile.java +++ b/Mage.Sets/src/mage/cards/h/HiddenStockpile.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfYourEndStepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -15,14 +13,15 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.Zone; -import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; import mage.game.permanent.token.ServoToken; import mage.target.common.TargetControlledCreaturePermanent; import mage.watchers.common.RevoltWatcher; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; + /** - * * @author LevelX2 */ public final class HiddenStockpile extends CardImpl { @@ -31,14 +30,14 @@ public final class HiddenStockpile extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}{B}"); // Revolt — At the beginning of your end step, if a permanent you controlled left the battlefield this turn, create a 1/1 colorless Servo artifact creature token. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new BeginningOfYourEndStepTriggeredAbility(new CreateTokenEffect(new ServoToken()), false), RevoltCondition.instance, - "Revolt — At the beginning of your end step, if a permanent you controlled left the battlefield this turn, create a 1/1 colorless Servo artifact creature token."); - ability.setAbilityWord(AbilityWord.REVOLT); - ability.addWatcher(new RevoltWatcher()); - this.addAbility(ability); + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new BeginningOfYourEndStepTriggeredAbility(new CreateTokenEffect(new ServoToken()), false), + RevoltCondition.instance, "At the beginning of your end step, if a permanent you controlled " + + "left the battlefield this turn, create a 1/1 colorless Servo artifact creature token." + ).setAbilityWord(AbilityWord.REVOLT), new RevoltWatcher()); // {1}, Sacrifice a creature: Scry 1. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ScryEffect(1, false), new GenericManaCost(1)); + Ability ability = new SimpleActivatedAbility(new ScryEffect(1, false), new GenericManaCost(1)); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HideSeek.java b/Mage.Sets/src/mage/cards/h/HideSeek.java index 632d508671b..3a54072136b 100644 --- a/Mage.Sets/src/mage/cards/h/HideSeek.java +++ b/Mage.Sets/src/mage/cards/h/HideSeek.java @@ -1,4 +1,3 @@ - package mage.cards.h; import mage.abilities.Ability; @@ -21,7 +20,6 @@ import mage.target.common.TargetOpponent; import java.util.UUID; /** - * * @author LevelX2 */ public final class HideSeek extends SplitCard { @@ -31,14 +29,13 @@ public final class HideSeek extends SplitCard { // Hide // Put target artifact or enchantment on the bottom of its owner's library. - getLeftHalfCard().getSpellAbility().addEffect(new PutOnLibraryTargetEffect(false)); - getLeftHalfCard().getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); + this.getLeftHalfCard().getSpellAbility().addEffect(new PutOnLibraryTargetEffect(false)); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); // Seek // Search target opponent's library for a card and exile it. You gain life equal to its converted mana cost. Then that player shuffles their library.. - getRightHalfCard().getSpellAbility().addEffect(new SeekEffect()); - getRightHalfCard().getSpellAbility().addTarget(new TargetOpponent()); - + this.getRightHalfCard().getSpellAbility().addEffect(new SeekEffect()); + this.getRightHalfCard().getSpellAbility().addTarget(new TargetOpponent()); } private HideSeek(final HideSeek card) { @@ -71,24 +68,17 @@ class SeekEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player opponent = game.getPlayer(source.getFirstTarget()); Player player = game.getPlayer(source.getControllerId()); - if (player != null && opponent != null) { - if (opponent.getLibrary().hasCards()) { - TargetCardInLibrary target = new TargetCardInLibrary(); - if (player.searchLibrary(target, source, game, opponent.getId())) { - UUID targetId = target.getFirstTarget(); - Card card = opponent.getLibrary().remove(targetId, game); - if (card != null) { - player.moveCardToExileWithInfo(card, null, null, source, game, Zone.LIBRARY, true); - int cmc = card.getManaValue(); - if (cmc > 0) { - player.gainLife(cmc, game, source); - } - } - } - } - opponent.shuffleLibrary(source, game); - return true; + if (player == null || opponent == null) { + return false; } - return false; + TargetCardInLibrary target = new TargetCardInLibrary(); + player.searchLibrary(target, source, game, opponent.getId()); + Card card = opponent.getLibrary().getCard(target.getFirstTarget(), game); + if (card != null) { + player.moveCards(card, Zone.EXILED, source, game); + player.gainLife(card.getManaValue(), game, source); + } + opponent.shuffleLibrary(source, game); + return true; } } diff --git a/Mage.Sets/src/mage/cards/h/HideousVisage.java b/Mage.Sets/src/mage/cards/h/HideousVisage.java index babcd2c50d1..f67f7fa44c9 100644 --- a/Mage.Sets/src/mage/cards/h/HideousVisage.java +++ b/Mage.Sets/src/mage/cards/h/HideousVisage.java @@ -8,7 +8,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.StaticFilters; /** * @@ -16,11 +16,17 @@ import mage.filter.common.FilterControlledCreaturePermanent; */ public final class HideousVisage extends CardImpl { + private static final String rule = "creatures you control gain intimidate until end of turn. " + + "(Each of those creatures can't be blocked except by artifact creatures and/or " + + "creatures that share a color with it.)"; + public HideousVisage(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{B}"); - - this.getSpellAbility().addEffect(new GainAbilityControlledEffect(IntimidateAbility.getInstance(), Duration.EndOfTurn, new FilterControlledCreaturePermanent("Creatures"))); + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + IntimidateAbility.getInstance(), + Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURES).setText(rule)); } private HideousVisage(final HideousVisage card) { diff --git a/Mage.Sets/src/mage/cards/h/HidetsuguConsumesAll.java b/Mage.Sets/src/mage/cards/h/HidetsuguConsumesAll.java new file mode 100644 index 00000000000..16e6ba35dc0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HidetsuguConsumesAll.java @@ -0,0 +1,62 @@ +package mage.cards.h; + +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.common.DestroyAllEffect; +import mage.abilities.effects.common.ExileGraveyardAllPlayersEffect; +import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SagaChapter; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.mageobject.ManaValuePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HidetsuguConsumesAll extends CardImpl { + + private static final FilterPermanent filter = new FilterNonlandPermanent(); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 2)); + } + + public HidetsuguConsumesAll(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{R}"); + + this.subtype.add(SubType.SAGA); + this.secondSideCardClazz = mage.cards.v.VesselOfTheAllConsuming.class; + + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I — Destroy each nonland permanent with mana value 1 or less. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new DestroyAllEffect(filter) + .setText("destroy each nonland permanent with mana value 1 or less")); + + // II — Exile all graveyards. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new ExileGraveyardAllPlayersEffect()); + + // III — Exile this Saga, then return it to the battlefield transformed under your control. + this.addAbility(new TransformAbility()); + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + + this.addAbility(sagaAbility, mage.cards.v.VesselOfTheAllConsuming.makeWatcher()); + } + + private HidetsuguConsumesAll(final HidetsuguConsumesAll card) { + super(card); + } + + @Override + public HidetsuguConsumesAll copy() { + return new HidetsuguConsumesAll(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HighRiseSawjack.java b/Mage.Sets/src/mage/cards/h/HighRiseSawjack.java new file mode 100644 index 00000000000..5e35ae1eaec --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HighRiseSawjack.java @@ -0,0 +1,52 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.common.BlocksCreatureTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; + +import java.util.UUID; + +/** + * @author Hiddevb + */ +public final class HighRiseSawjack extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public HighRiseSawjack(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Whenever High-Rise Sawjack blocks a creature with flying, High-Rise Sawjack gets +2/+0 until end of turn. + this.addAbility(new BlocksCreatureTriggeredAbility(new BoostSourceEffect(2, 0, Duration.EndOfTurn), filter, false)); + } + + private HighRiseSawjack(final HighRiseSawjack card) { + super(card); + } + + @Override + public HighRiseSawjack copy() { + return new HighRiseSawjack(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HighcliffFelidar.java b/Mage.Sets/src/mage/cards/h/HighcliffFelidar.java index 50873c7db5b..2c5298546d1 100644 --- a/Mage.Sets/src/mage/cards/h/HighcliffFelidar.java +++ b/Mage.Sets/src/mage/cards/h/HighcliffFelidar.java @@ -101,7 +101,7 @@ class HighcliffFelidarEffect extends OneShotEffect { filter.add(new PowerPredicate(ComparisonType.EQUAL_TO, maxPower)); TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); - if (controller.choose(outcome, target, source.getSourceId(), game)) { + if (controller.choose(outcome, target, source, game)) { toDestroy.add(target.getFirstTarget()); } } diff --git a/Mage.Sets/src/mage/cards/h/HighlandBerserker.java b/Mage.Sets/src/mage/cards/h/HighlandBerserker.java index b535564f1b3..8b857dbbe60 100644 --- a/Mage.Sets/src/mage/cards/h/HighlandBerserker.java +++ b/Mage.Sets/src/mage/cards/h/HighlandBerserker.java @@ -40,7 +40,7 @@ public final class HighlandBerserker extends CardImpl { // Whenever Highland Berserker or another Ally enters the battlefield under your control, you may have Ally creatures you control gain first strike until end of turn. Effect effect = new GainAbilityAllEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn, filter); effect.setText("you may have Ally creatures you control gain first strike until end of turn"); - this.addAbility(new AllyEntersBattlefieldTriggeredAbility(effect, true)); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility(effect, true).setAbilityWord(null)); } private HighlandBerserker(final HighlandBerserker card) { diff --git a/Mage.Sets/src/mage/cards/h/HikariTwilightGuardian.java b/Mage.Sets/src/mage/cards/h/HikariTwilightGuardian.java index 116f61bd0c9..ac55282303b 100644 --- a/Mage.Sets/src/mage/cards/h/HikariTwilightGuardian.java +++ b/Mage.Sets/src/mage/cards/h/HikariTwilightGuardian.java @@ -31,7 +31,7 @@ public final class HikariTwilightGuardian extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever you cast a Spirit or Arcane spell, you may exile Hikari, Twilight Guardian. If you do, return it to the battlefield under its owner's control at the beginning of the next end step. - Effect effect = new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true); + Effect effect = new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(); effect.setText("you may exile {this}. If you do, return it to the battlefield under its owner's control at the beginning of the next end step"); this.addAbility(new SpellCastControllerTriggeredAbility(effect, StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true)); } diff --git a/Mage.Sets/src/mage/cards/h/HinataDawnCrowned.java b/Mage.Sets/src/mage/cards/h/HinataDawnCrowned.java index a657e97f230..16f8bf56ceb 100644 --- a/Mage.Sets/src/mage/cards/h/HinataDawnCrowned.java +++ b/Mage.Sets/src/mage/cards/h/HinataDawnCrowned.java @@ -13,6 +13,7 @@ import mage.constants.*; import mage.game.Game; import mage.util.CardUtil; +import java.util.Optional; import java.util.Set; import java.util.UUID; @@ -115,8 +116,13 @@ final class HinataDawnCrownedEffectUtility { public static int getTargetCount(Game game, Ability abilityToModify) { - return (int)(game.inCheckPlayableState() ? - CardUtil.getAllPossibleTargets(abilityToModify, game).stream().count(): - CardUtil.getAllSelectedTargets(abilityToModify, game).stream().count()); + if (game.inCheckPlayableState()) { + Optional max = abilityToModify.getTargets().stream().map(x -> x.getMaxNumberOfTargets()).max(Integer::compare); + int allPossibleSize = CardUtil.getAllPossibleTargets(abilityToModify, game).size(); + return max.isPresent() ? + Math.min(allPossibleSize, max.get()) : + allPossibleSize; + } else + return CardUtil.getAllSelectedTargets(abilityToModify, game).size(); } } diff --git a/Mage.Sets/src/mage/cards/h/HinderingLight.java b/Mage.Sets/src/mage/cards/h/HinderingLight.java index f0589a07876..072b5ae81df 100644 --- a/Mage.Sets/src/mage/cards/h/HinderingLight.java +++ b/Mage.Sets/src/mage/cards/h/HinderingLight.java @@ -36,7 +36,7 @@ public final class HinderingLight extends CardImpl { this.getSpellAbility().addEffect(new CounterTargetEffect()); this.getSpellAbility().addTarget(new TargetSpell(filter)); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private HinderingLight(final HinderingLight card) { diff --git a/Mage.Sets/src/mage/cards/h/HinterlandDrake.java b/Mage.Sets/src/mage/cards/h/HinterlandDrake.java index df9ac61ec05..dc136208efc 100644 --- a/Mage.Sets/src/mage/cards/h/HinterlandDrake.java +++ b/Mage.Sets/src/mage/cards/h/HinterlandDrake.java @@ -32,7 +32,7 @@ public final class HinterlandDrake extends CardImpl { // Hinterland Drake can't block artifact creatures. Effect effect = new CantBlockCreaturesSourceEffect(StaticFilters.FILTER_PERMANENT_ARTIFACT_CREATURE); - effect.setText("{this} can't block artifact creatures"); + effect.setText("{this} can't block artifact creatures"); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); } diff --git a/Mage.Sets/src/mage/cards/h/HisokaMinamoSensei.java b/Mage.Sets/src/mage/cards/h/HisokaMinamoSensei.java index 013d99f54d2..84d856df425 100644 --- a/Mage.Sets/src/mage/cards/h/HisokaMinamoSensei.java +++ b/Mage.Sets/src/mage/cards/h/HisokaMinamoSensei.java @@ -73,7 +73,7 @@ class HisokaMinamoSenseiDiscardTargetCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - if (targets.choose(Outcome.Discard, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.Discard, controllerId, source.getSourceId(), source, game)) { Player player = game.getPlayer(controllerId); if(player != null) { for (UUID targetId : targets.get(0).getTargets()) { @@ -91,7 +91,7 @@ class HisokaMinamoSenseiDiscardTargetCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/h/HissingIguanar.java b/Mage.Sets/src/mage/cards/h/HissingIguanar.java index f4bb0963e3e..7d4abd7a880 100644 --- a/Mage.Sets/src/mage/cards/h/HissingIguanar.java +++ b/Mage.Sets/src/mage/cards/h/HissingIguanar.java @@ -25,7 +25,7 @@ public final class HissingIguanar extends CardImpl { this.toughness = new MageInt(1); // Whenever another creature dies, you may have Hissing Iguanar deal 1 damage to target player. - DiesCreatureTriggeredAbility ability = new DiesCreatureTriggeredAbility(new DamageTargetEffect(1), true, true); + DiesCreatureTriggeredAbility ability = new DiesCreatureTriggeredAbility(new DamageTargetEffect(1).setText("you may have {this} deal 1 damage to target player or planeswalker"), true, true); ability.addTarget(new TargetPlayerOrPlaneswalker()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HistoriansWisdom.java b/Mage.Sets/src/mage/cards/h/HistoriansWisdom.java index 540838ad4eb..263e8b5bd6b 100644 --- a/Mage.Sets/src/mage/cards/h/HistoriansWisdom.java +++ b/Mage.Sets/src/mage/cards/h/HistoriansWisdom.java @@ -89,6 +89,6 @@ enum HistoriansWisdomCondition implements Condition { } FilterCreaturePermanent filter = new FilterCreaturePermanent(); filter.add(new PowerPredicate(ComparisonType.MORE_THAN, creature.getPower().getValue())); - return game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game).isEmpty(); + return game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game).isEmpty(); } } diff --git a/Mage.Sets/src/mage/cards/h/HitRun.java b/Mage.Sets/src/mage/cards/h/HitRun.java index 33924e502d9..c6ec92b5745 100644 --- a/Mage.Sets/src/mage/cards/h/HitRun.java +++ b/Mage.Sets/src/mage/cards/h/HitRun.java @@ -77,8 +77,8 @@ class HitEffect extends OneShotEffect { CardType.CREATURE.getPredicate())); TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), targetPlayer.getId(), game)) { - targetPlayer.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + if (target.canChoose(targetPlayer.getId(), source, game)) { + targetPlayer.choose(Outcome.Sacrifice, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.sacrifice(source, game); @@ -113,7 +113,7 @@ class RunEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - int attackingCreatures = game.getBattlefield().count(new FilterAttackingCreature(), controller.getId(), controller.getId(), game); + int attackingCreatures = game.getBattlefield().count(new FilterAttackingCreature(), controller.getId(), source, game); if (attackingCreatures > 1) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterAttackingCreature(), controller.getId(), game)) { ContinuousEffect effect = new BoostTargetEffect(attackingCreatures - 1, 0, Duration.EndOfTurn); diff --git a/Mage.Sets/src/mage/cards/h/HiveheartShaman.java b/Mage.Sets/src/mage/cards/h/HiveheartShaman.java index 35f5f608a75..f0190fa0308 100644 --- a/Mage.Sets/src/mage/cards/h/HiveheartShaman.java +++ b/Mage.Sets/src/mage/cards/h/HiveheartShaman.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.DomainValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; @@ -83,7 +82,7 @@ enum HiveheartShamanPredicate implements ObjectSourcePlayerPredicate { return game.getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, - input.getPlayerId(), input.getSourceId(), game + input.getPlayerId(), input.getSource(), game ) .stream() .map(permanent -> permanent.getSubtype(game)) @@ -95,8 +94,6 @@ enum HiveheartShamanPredicate implements ObjectSourcePlayerPredicate { class HiveheartShamanEffect extends OneShotEffect { - private static final DynamicValue xValue = new DomainValue(); - HiveheartShamanEffect() { super(Outcome.Benefit); staticText = "create a 1/1 green Insect creature token. Put X +1/+1 counters on it, " + @@ -116,7 +113,7 @@ class HiveheartShamanEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Token token = new InsectToken(); token.putOntoBattlefield(1, game, source); - int domainCount = xValue.calculate(game, source, this); + int domainCount = DomainValue.REGULAR.calculate(game, source, this); if (domainCount < 1) { return true; } diff --git a/Mage.Sets/src/mage/cards/h/HoardHauler.java b/Mage.Sets/src/mage/cards/h/HoardHauler.java new file mode 100644 index 00000000000..2aa3d339969 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HoardHauler.java @@ -0,0 +1,75 @@ +package mage.cards.h; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.constants.SubType; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.CrewAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.token.TreasureToken; + +/** + * + * @author weirddan455 + */ +public final class HoardHauler extends CardImpl { + + public HoardHauler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}{R}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever Hoard Hauler deals combat damage to a player, create a Treasure token for each artifact they control. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new CreateTokenEffect(new TreasureToken(), HoardHaulerValue.instance), false, true)); + + // Crew 3 + this.addAbility(new CrewAbility(3)); + } + + private HoardHauler(final HoardHauler card) { + super(card); + } + + @Override + public HoardHauler copy() { + return new HoardHauler(this); + } +} + +enum HoardHaulerValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_ARTIFACT, effect.getTargetPointer().getFirst(game, sourceAbility), game); + } + + @Override + public HoardHaulerValue copy() { + return this; + } + + @Override + public String toString() { + return "1"; + } + + @Override + public String getMessage() { + return "artifact they control"; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HoldForRansom.java b/Mage.Sets/src/mage/cards/h/HoldForRansom.java new file mode 100644 index 00000000000..512dd93aff9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HoldForRansom.java @@ -0,0 +1,109 @@ +package mage.cards.h; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.combat.CantAttackBlockAttachedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.effects.common.AttachEffect; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author weirddan455 + */ +public final class HoldForRansom extends CardImpl { + + public HoldForRansom(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Removal)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // Enchanted creature can't attack or block and has "{7}: Hold for Ransom's controller sacrifices it and draws a card. Activate only as a sorcery." + Ability ability = new SimpleStaticAbility(new CantAttackBlockAttachedEffect(AttachmentType.AURA)); + ability.addEffect(new HoldForRansomGainEffect()); + this.addAbility(ability); + } + + private HoldForRansom(final HoldForRansom card) { + super(card); + } + + @Override + public HoldForRansom copy() { + return new HoldForRansom(this); + } +} + +class HoldForRansomGainEffect extends GainAbilityAttachedEffect { + + public HoldForRansomGainEffect() { + super(new ActivateAsSorceryActivatedAbility(new HoldForRansomSacrificeEffect(), new GenericManaCost(7)), AttachmentType.AURA); + this.staticText = "and has \"" + ability.getRule() + '"'; + } + + private HoldForRansomGainEffect(final HoldForRansomGainEffect effect) { + super(effect); + } + + @Override + public HoldForRansomGainEffect copy() { + return new HoldForRansomGainEffect(this); + } + + @Override + public void afterGain(Game game, Ability source, Permanent permanent, Ability addedAbility) { + Permanent aura = game.getPermanent(source.getSourceId()); + addedAbility.getEffects().setTargetPointer(new FixedTarget(aura == null ? null : aura.getId(), game)); + } +} + +class HoldForRansomSacrificeEffect extends OneShotEffect { + + public HoldForRansomSacrificeEffect() { + super(Outcome.Sacrifice); + this.staticText = "Hold for Ransom's controller sacrifices it and draws a card"; + } + + private HoldForRansomSacrificeEffect(final HoldForRansomSacrificeEffect effect) { + super(effect); + } + + @Override + public HoldForRansomSacrificeEffect copy() { + return new HoldForRansomSacrificeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent aura = game.getPermanent(targetPointer.getFirst(game, source)); + if (aura == null) { + return false; + } + Player auraController = game.getPlayer(aura.getControllerId()); + aura.sacrifice(source, game); + if (auraController != null) { + auraController.drawCards(1, source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HollowheadSliver.java b/Mage.Sets/src/mage/cards/h/HollowheadSliver.java index 33003fb3629..aace31bb7d8 100644 --- a/Mage.Sets/src/mage/cards/h/HollowheadSliver.java +++ b/Mage.Sets/src/mage/cards/h/HollowheadSliver.java @@ -36,7 +36,7 @@ public final class HollowheadSliver extends CardImpl { ability.addCost(new DiscardCardCost()); this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( ability, Duration.WhileOnBattlefield, - StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS + StaticFilters.FILTER_PERMANENT_SLIVERS ))); } diff --git a/Mage.Sets/src/mage/cards/h/HoodedAssassin.java b/Mage.Sets/src/mage/cards/h/HoodedAssassin.java index 8d774d0c14f..cb6f2002fa8 100644 --- a/Mage.Sets/src/mage/cards/h/HoodedAssassin.java +++ b/Mage.Sets/src/mage/cards/h/HoodedAssassin.java @@ -40,8 +40,7 @@ public final class HoodedAssassin extends CardImpl { // * Put a +1/+1 counter on Hooded Assassin. Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false); // * Destroy target creature that was dealt damage this turn. - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetCreaturePermanent(filter)); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/h/HoodedBlightfang.java b/Mage.Sets/src/mage/cards/h/HoodedBlightfang.java index f0dc0bfeeed..175fb6c960c 100644 --- a/Mage.Sets/src/mage/cards/h/HoodedBlightfang.java +++ b/Mage.Sets/src/mage/cards/h/HoodedBlightfang.java @@ -88,7 +88,7 @@ class HoodedBlightfangTriggeredAbility extends TriggeredAbilityImpl { if (permanent == null || damaged == null || !StaticFilters.FILTER_PERMANENT_PLANESWALKER.match(damaged, game) - || !HoodedBlightfang.filter.match(permanent, this.getSourceId(), this.getControllerId(), game)) { + || !HoodedBlightfang.filter.match(permanent, this.getControllerId(), this, game)) { return false; } this.getEffects().setTargetPointer(new FixedTarget(damaged.getId(), damaged.getZoneChangeCounter(game))); diff --git a/Mage.Sets/src/mage/cards/h/HoodedHydra.java b/Mage.Sets/src/mage/cards/h/HoodedHydra.java index 514b447d9b6..48c6bf1d413 100644 --- a/Mage.Sets/src/mage/cards/h/HoodedHydra.java +++ b/Mage.Sets/src/mage/cards/h/HoodedHydra.java @@ -44,7 +44,7 @@ public final class HoodedHydra extends CardImpl { this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new SnakeToken(), new CountersSourceCount(CounterType.P1P1)), false)); // Morph {3}{G}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{G}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{G}{G}"))); // As Hooded Hydra is turned face up, put five +1/+1 counters on it. Effect effect = new AddCountersSourceEffect(CounterType.P1P1.createInstance(5)); diff --git a/Mage.Sets/src/mage/cards/h/HopeCharm.java b/Mage.Sets/src/mage/cards/h/HopeCharm.java index aeca2296f4c..dc569ed682e 100644 --- a/Mage.Sets/src/mage/cards/h/HopeCharm.java +++ b/Mage.Sets/src/mage/cards/h/HopeCharm.java @@ -36,13 +36,11 @@ public final class HopeCharm extends CardImpl { this.getSpellAbility().addEffect(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // or target player gains 2 life - Mode mode = new Mode(); - mode.addEffect(new GainLifeTargetEffect(2)); + Mode mode = new Mode(new GainLifeTargetEffect(2)); mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); // or destroy target Aura. - mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetPermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/h/HordeAmbusher.java b/Mage.Sets/src/mage/cards/h/HordeAmbusher.java index 258a57d61fa..ca49ae33106 100644 --- a/Mage.Sets/src/mage/cards/h/HordeAmbusher.java +++ b/Mage.Sets/src/mage/cards/h/HordeAmbusher.java @@ -1,4 +1,3 @@ - package mage.cards.h; import java.util.UUID; @@ -8,7 +7,6 @@ import mage.abilities.Ability; import mage.abilities.common.BlocksSourceTriggeredAbility; import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility; import mage.abilities.costs.common.RevealTargetFromHandCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageControllerEffect; import mage.abilities.effects.common.combat.CantBlockTargetEffect; import mage.abilities.keyword.MorphAbility; @@ -42,15 +40,13 @@ public final class HordeAmbusher extends CardImpl { this.toughness = new MageInt(2); // Whenever Horde Ambusher blocks, it deals 1 damage to you. - this.addAbility(new BlocksSourceTriggeredAbility(new DamageControllerEffect(1, "it"), false)); - + this.addAbility(new BlocksSourceTriggeredAbility(new DamageControllerEffect(1, "it"))); + // Morph - Reveal a red card in your hand. - this.addAbility(new MorphAbility(this, new RevealTargetFromHandCost(new TargetCardInHand(filter)))); - + this.addAbility(new MorphAbility(new RevealTargetFromHandCost(new TargetCardInHand(filter)))); + // When Horde Ambusher is turned face up, target creature can't block this turn. - Effect effect = new CantBlockTargetEffect(Duration.EndOfTurn); - effect.setText("target creature can't block this turn"); - Ability ability = new TurnedFaceUpSourceTriggeredAbility(effect); + Ability ability = new TurnedFaceUpSourceTriggeredAbility(new CantBlockTargetEffect(Duration.EndOfTurn)); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HornetNest.java b/Mage.Sets/src/mage/cards/h/HornetNest.java index 83b448036e2..87c4f6a2699 100644 --- a/Mage.Sets/src/mage/cards/h/HornetNest.java +++ b/Mage.Sets/src/mage/cards/h/HornetNest.java @@ -1,19 +1,15 @@ package mage.cards.h; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealtDamageToSourceTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.DefenderAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.game.Game; import mage.game.permanent.token.InsectDeathToken; -import mage.players.Player; import java.util.UUID; @@ -33,7 +29,8 @@ public final class HornetNest extends CardImpl { this.addAbility(DefenderAbility.getInstance()); // Whenever Hornet Nest is dealt damage, create that many 1/1 green Insect creature tokens with flying and deathtouch. - this.addAbility(new DealtDamageToSourceTriggeredAbility(new HornetNestDealDamageEffect(), false, false)); + this.addAbility(new DealtDamageToSourceTriggeredAbility( + new CreateTokenEffect(new InsectDeathToken(), SavedDamageValue.MANY), false)); } private HornetNest(final HornetNest card) { @@ -45,32 +42,3 @@ public final class HornetNest extends CardImpl { return new HornetNest(this); } } - -class HornetNestDealDamageEffect extends OneShotEffect { - - public HornetNestDealDamageEffect() { - super(Outcome.Damage); - this.staticText = "create that many 1/1 green Insect creature tokens with flying and deathtouch"; - } - - public HornetNestDealDamageEffect(final HornetNestDealDamageEffect effect) { - super(effect); - } - - @Override - public HornetNestDealDamageEffect copy() { - return new HornetNestDealDamageEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - int amount = (Integer) getValue("damage"); - if (amount > 0) { - return new CreateTokenEffect(new InsectDeathToken(), amount).apply(game, source); - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/h/HostileTakeover.java b/Mage.Sets/src/mage/cards/h/HostileTakeover.java new file mode 100644 index 00000000000..961813d690c --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HostileTakeover.java @@ -0,0 +1,57 @@ +package mage.cards.h; + +import java.util.UUID; + +import mage.abilities.effects.common.DamageAllEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.other.AnotherTargetPredicate; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; + +/** + * + * @author weirddan455 + */ +public final class HostileTakeover extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other target creature"); + + static { + filter.add(new AnotherTargetPredicate(2)); + } + + public HostileTakeover(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}{B}{R}"); + + // Up to one target creature has base power and toughness 1/1 until end of turn. Up to one other target creature has base power and toughness 4/4 until end of turn. Then Hostile Takeover deals 3 damage to each creature. + this.getSpellAbility().addEffect(new SetPowerToughnessTargetEffect(1, 1, Duration.EndOfTurn)); + TargetCreaturePermanent target1 = new TargetCreaturePermanent(0, 1); + target1.setTargetTag(1); + this.getSpellAbility().addTarget(target1.withChooseHint("1/1")); + + this.getSpellAbility().addEffect(new SetPowerToughnessTargetEffect(4, 4, Duration.EndOfTurn) + .setTargetPointer(new SecondTargetPointer()) + .setText("up to one other target creature has base power and toughness 4/4 until end of turn")); + TargetCreaturePermanent target2 = new TargetCreaturePermanent(0, 1, filter, false); + target2.setTargetTag(2); + this.getSpellAbility().addTarget(target2.withChooseHint("4/4")); + + this.getSpellAbility().addEffect(new DamageAllEffect(3, StaticFilters.FILTER_PERMANENT_CREATURE) + .concatBy("Then")); + } + + private HostileTakeover(final HostileTakeover card) { + super(card); + } + + @Override + public HostileTakeover copy() { + return new HostileTakeover(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HotheadedGiant.java b/Mage.Sets/src/mage/cards/h/HotheadedGiant.java index db25c00639f..91ba66f331a 100644 --- a/Mage.Sets/src/mage/cards/h/HotheadedGiant.java +++ b/Mage.Sets/src/mage/cards/h/HotheadedGiant.java @@ -1,14 +1,9 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; -import mage.ObjectColor; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.condition.Condition; -import mage.abilities.condition.InvertCondition; -import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; @@ -17,22 +12,21 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.WatcherScope; import mage.counters.CounterType; -import mage.filter.FilterSpell; -import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.stack.Spell; import mage.watchers.Watcher; +import java.util.*; + /** - * - * @author jeffwadsworth + * @author TheElk801 */ public final class HotheadedGiant extends CardImpl { public HotheadedGiant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.subtype.add(SubType.GIANT); this.subtype.add(SubType.WARRIOR); @@ -43,9 +37,11 @@ public final class HotheadedGiant extends CardImpl { this.addAbility(HasteAbility.getInstance()); // Hotheaded Giant enters the battlefield with two -1/-1 counters on it unless you've cast another red spell this turn. - Condition condition = new CastRedSpellThisTurnCondition(); - this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect(new AddCountersSourceEffect(CounterType.M1M1.createInstance(2)), new InvertCondition(condition), ""), "with two -1/-1 counters on it unless you've cast another red spell this turn"), new HotHeadedGiantWatcher(this.getId())); - + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.M1M1.createInstance(2)), + HotheadedGiantWatcher::checkSpell, null, + "with two -1/-1 counters on it unless you've cast another red spell this turn" + ), new HotheadedGiantWatcher()); } private HotheadedGiant(final HotheadedGiant card) { @@ -58,50 +54,39 @@ public final class HotheadedGiant extends CardImpl { } } -class CastRedSpellThisTurnCondition implements Condition { +class HotheadedGiantWatcher extends Watcher { - @Override - public boolean apply(Game game, Ability source) { - HotHeadedGiantWatcher watcher = game.getState().getWatcher(HotHeadedGiantWatcher.class, source.getControllerId()); - if (watcher != null) { - return watcher.conditionMet(); - } - return false; - } -} + private final Map> spellMap = new HashMap<>(); + private static final List emptyList = new ArrayList<>(); -class HotHeadedGiantWatcher extends Watcher { - - private static final FilterSpell filter = new FilterSpell(); - - static { - filter.add(new ColorPredicate(ObjectColor.RED)); - } - - private UUID cardId; - - public HotHeadedGiantWatcher(UUID cardId) { - super(WatcherScope.PLAYER); - this.cardId = cardId; + HotheadedGiantWatcher() { + super(WatcherScope.GAME); } @Override public void watch(GameEvent event, Game game) { - if (condition == true) { //no need to check - condition has already occured + if (event.getType() != EventType.SPELL_CAST) { return; } - if (event.getType() == GameEvent.EventType.SPELL_CAST - && controllerId.equals(event.getPlayerId())) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (!spell.getSourceId().equals(cardId) && filter.match(spell, game)) { - condition = true; - } + Spell spell = game.getSpell(event.getSourceId()); + if (spell != null && spell.getColor(game).isRed()) { + spellMap.computeIfAbsent(event.getPlayerId(), x -> new ArrayList<>()) + .add(new MageObjectReference(event.getSourceId(), game)); } } @Override public void reset() { super.reset(); - condition = false; + spellMap.clear(); + } + + static boolean checkSpell(Game game, Ability source) { + return game.getState() + .getWatcher(HotheadedGiantWatcher.class) + .spellMap + .getOrDefault(source.getControllerId(), emptyList) + .stream() + .noneMatch(mor -> !mor.refersTo(source, game)); } } diff --git a/Mage.Sets/src/mage/cards/h/HowlOfTheNightPack.java b/Mage.Sets/src/mage/cards/h/HowlOfTheNightPack.java index 596101e4949..0c815d50574 100644 --- a/Mage.Sets/src/mage/cards/h/HowlOfTheNightPack.java +++ b/Mage.Sets/src/mage/cards/h/HowlOfTheNightPack.java @@ -17,7 +17,7 @@ import mage.game.permanent.token.WolfToken; */ public final class HowlOfTheNightPack extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("for each Forest you control"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("Forest you control"); static { filter.add(SubType.FOREST.getPredicate()); diff --git a/Mage.Sets/src/mage/cards/h/HowlingMoon.java b/Mage.Sets/src/mage/cards/h/HowlingMoon.java index c272a645863..1a489ce69b3 100644 --- a/Mage.Sets/src/mage/cards/h/HowlingMoon.java +++ b/Mage.Sets/src/mage/cards/h/HowlingMoon.java @@ -1,25 +1,24 @@ package mage.cards.h; -import java.util.UUID; - import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.common.CastSecondSpellTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.token.WolfToken; import mage.target.common.TargetControlledPermanent; -import mage.watchers.common.CastSpellLastTurnWatcher; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class HowlingMoon extends CardImpl { @@ -42,7 +41,9 @@ public final class HowlingMoon extends CardImpl { this.addAbility(ability); // Whenever an opponent casts their second spell each turn, create a 2/2 green Wolf creature token. - this.addAbility(new HowlingMoonTriggeredAbility(), new CastSpellLastTurnWatcher()); + this.addAbility(new CastSecondSpellTriggeredAbility( + new CreateTokenEffect(new WolfToken()), TargetController.OPPONENT + )); } private HowlingMoon(final HowlingMoon card) { @@ -54,38 +55,3 @@ public final class HowlingMoon extends CardImpl { return new HowlingMoon(this); } } - -class HowlingMoonTriggeredAbility extends TriggeredAbilityImpl { - - public HowlingMoonTriggeredAbility() { - super(Zone.BATTLEFIELD, new CreateTokenEffect(new WolfToken())); - } - - private HowlingMoonTriggeredAbility(final HowlingMoonTriggeredAbility ability) { - super(ability); - } - - @Override - public HowlingMoonTriggeredAbility copy() { - return new HowlingMoonTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SPELL_CAST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (game.getOpponents(controllerId).contains(event.getPlayerId())) { - CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); - return watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) == 2; - } - return false; - } - - @Override - public String getTriggerPhrase() { - return "Whenever an opponent casts their second spell each turn, "; - } -} diff --git a/Mage.Sets/src/mage/cards/h/HowlpackAvenger.java b/Mage.Sets/src/mage/cards/h/HowlpackAvenger.java index 047490e4b73..77d011f0586 100644 --- a/Mage.Sets/src/mage/cards/h/HowlpackAvenger.java +++ b/Mage.Sets/src/mage/cards/h/HowlpackAvenger.java @@ -60,7 +60,7 @@ public final class HowlpackAvenger extends CardImpl { class HowlpackAvengerTriggeredAbility extends TriggeredAbilityImpl { HowlpackAvengerTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(SavedDamageValue.instance)); + super(Zone.BATTLEFIELD, new DamageTargetEffect(SavedDamageValue.MUCH)); this.addTarget(new TargetAnyTarget()); } @@ -91,11 +91,11 @@ class HowlpackAvengerTriggeredAbility extends TriggeredAbilityImpl { return false; } this.getEffects().setValue("damage", damage); - return false; + return true; } @Override - public String getRule() { - return "Whenever a permanent you control is dealt damage, {this} deals that much damage to any target."; + public String getTriggerPhrase() { + return "Whenever a permanent you control is dealt damage, "; } } diff --git a/Mage.Sets/src/mage/cards/h/HowltoothHollow.java b/Mage.Sets/src/mage/cards/h/HowltoothHollow.java index 183bd2b9ca5..adf9b5c9f2d 100644 --- a/Mage.Sets/src/mage/cards/h/HowltoothHollow.java +++ b/Mage.Sets/src/mage/cards/h/HowltoothHollow.java @@ -1,6 +1,7 @@ package mage.cards.h; import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInHandCondition; @@ -30,7 +31,8 @@ public final class HowltoothHollow extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // Hideaway - this.addAbility(new HideawayAbility()); + this.addAbility(new HideawayAbility(4)); + this.addAbility(new EntersBattlefieldTappedAbility()); // {tap}: Add {B}. this.addAbility(new BlackManaAbility()); diff --git a/Mage.Sets/src/mage/cards/h/HuatliDinosaurKnight.java b/Mage.Sets/src/mage/cards/h/HuatliDinosaurKnight.java index 6129e2ed0a2..0969ef69d8d 100644 --- a/Mage.Sets/src/mage/cards/h/HuatliDinosaurKnight.java +++ b/Mage.Sets/src/mage/cards/h/HuatliDinosaurKnight.java @@ -2,7 +2,6 @@ package mage.cards.h; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DamageWithPowerFromOneToAnotherTargetEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; @@ -36,7 +35,7 @@ public final class HuatliDinosaurKnight extends CardImpl { addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.HUATLI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +2: Put two +1/+1 counters on up to one target Dinosaur you control. Ability ability = new LoyaltyAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)) diff --git a/Mage.Sets/src/mage/cards/h/HuatliRadiantChampion.java b/Mage.Sets/src/mage/cards/h/HuatliRadiantChampion.java index 8879c3524f9..1e2730baed3 100644 --- a/Mage.Sets/src/mage/cards/h/HuatliRadiantChampion.java +++ b/Mage.Sets/src/mage/cards/h/HuatliRadiantChampion.java @@ -1,7 +1,6 @@ package mage.cards.h; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -30,7 +29,7 @@ public final class HuatliRadiantChampion extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.HUATLI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Put a loyalty counter on Huatli, Radiant Champion for each creature you control. this.addAbility(new LoyaltyAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(0), diff --git a/Mage.Sets/src/mage/cards/h/HuatliTheSunsHeart.java b/Mage.Sets/src/mage/cards/h/HuatliTheSunsHeart.java index f6e0b0a5a7f..ec58e07e7ea 100644 --- a/Mage.Sets/src/mage/cards/h/HuatliTheSunsHeart.java +++ b/Mage.Sets/src/mage/cards/h/HuatliTheSunsHeart.java @@ -1,7 +1,6 @@ package mage.cards.h; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.GreatestToughnessAmongControlledCreaturesValue; import mage.abilities.effects.common.GainLifeEffect; @@ -25,7 +24,7 @@ public final class HuatliTheSunsHeart extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.HUATLI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(7)); + this.setStartingLoyalty(7); // Each creature you control assigns combat damage equal to its toughness rather than its power. this.addAbility(new SimpleStaticAbility(new CombatDamageByToughnessEffect( diff --git a/Mage.Sets/src/mage/cards/h/HuatliWarriorPoet.java b/Mage.Sets/src/mage/cards/h/HuatliWarriorPoet.java index 9f436f45bd7..3bc125fbce6 100644 --- a/Mage.Sets/src/mage/cards/h/HuatliWarriorPoet.java +++ b/Mage.Sets/src/mage/cards/h/HuatliWarriorPoet.java @@ -3,7 +3,6 @@ package mage.cards.h; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.Mode; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.GetXLoyaltyValue; import mage.abilities.dynamicvalue.common.GreatestPowerAmongControlledCreaturesValue; import mage.abilities.effects.ContinuousEffect; @@ -34,7 +33,7 @@ public final class HuatliWarriorPoet extends CardImpl { addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.HUATLI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +2: You gain life equal to the greatest power among creatures you control. this.addAbility(new LoyaltyAbility(new GainLifeEffect( diff --git a/Mage.Sets/src/mage/cards/h/HullBreach.java b/Mage.Sets/src/mage/cards/h/HullBreach.java index 0863c17c2dc..d8f0706a6e6 100644 --- a/Mage.Sets/src/mage/cards/h/HullBreach.java +++ b/Mage.Sets/src/mage/cards/h/HullBreach.java @@ -26,16 +26,14 @@ public final class HullBreach extends CardImpl { Target target = new TargetArtifactPermanent(); this.getSpellAbility().addTarget(target); // or destroy target enchantment; - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + Mode mode = new Mode(new DestroyTargetEffect()); target = new TargetEnchantmentPermanent(); mode.addTarget(target); this.getSpellAbility().addMode(mode); // or destroy target artifact and target enchantment. - mode = new Mode(); Effect effect = new DestroyTargetEffect(false, true); effect.setText("destroy target artifact and target enchantment"); - mode.addEffect(effect); + mode = new Mode(effect); mode.addTarget(new TargetArtifactPermanent()); mode.addTarget(new TargetEnchantmentPermanent()); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/h/HumOfTheRadix.java b/Mage.Sets/src/mage/cards/h/HumOfTheRadix.java index adb93334408..fe028e533f9 100644 --- a/Mage.Sets/src/mage/cards/h/HumOfTheRadix.java +++ b/Mage.Sets/src/mage/cards/h/HumOfTheRadix.java @@ -54,7 +54,7 @@ class HumOfTheRadixCostIncreaseEffect extends CostModificationEffectImpl { public boolean apply(Game game, Ability source, Ability abilityToModify) { CardUtil.increaseCost(abilityToModify, game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, - abilityToModify.getControllerId(), source.getSourceId(), game + abilityToModify.getControllerId(), source, game ).size()); return true; } diff --git a/Mage.Sets/src/mage/cards/h/Humiliate.java b/Mage.Sets/src/mage/cards/h/Humiliate.java index b372d5f2302..4e0730d49d0 100644 --- a/Mage.Sets/src/mage/cards/h/Humiliate.java +++ b/Mage.Sets/src/mage/cards/h/Humiliate.java @@ -66,14 +66,14 @@ class HumiliateEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player == null || game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getSourceId(), source.getControllerId(), game + source.getControllerId(), source, game ) < 1) { return false; } TargetPermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); target.withChooseHint("+1/+1 counter"); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); return permanent != null && permanent.addCounters( CounterType.P1P1.createInstance(), source.getControllerId(), source, game diff --git a/Mage.Sets/src/mage/cards/h/Humility.java b/Mage.Sets/src/mage/cards/h/Humility.java index f936d256fd6..5018b6122f5 100644 --- a/Mage.Sets/src/mage/cards/h/Humility.java +++ b/Mage.Sets/src/mage/cards/h/Humility.java @@ -62,7 +62,7 @@ public final class Humility extends CardImpl { Player player = game.getPlayer(source.getControllerId()); if (player != null) { for (Permanent permanent : game.getBattlefield().getActivePermanents( - new FilterCreaturePermanent(), source.getControllerId(), source.getSourceId(), game)) { + new FilterCreaturePermanent(), source.getControllerId(), source, game)) { switch (layer) { case AbilityAddingRemovingEffects_6: permanent.removeAllAbilities(source.getSourceId(), game); diff --git a/Mage.Sets/src/mage/cards/h/HungrySpriggan.java b/Mage.Sets/src/mage/cards/h/HungrySpriggan.java index d5e49e56c4c..adb7d064f23 100644 --- a/Mage.Sets/src/mage/cards/h/HungrySpriggan.java +++ b/Mage.Sets/src/mage/cards/h/HungrySpriggan.java @@ -27,7 +27,7 @@ public final class HungrySpriggan extends CardImpl { this.toughness = new MageInt(1); this.addAbility(TrampleAbility.getInstance()); - this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(3, 3, Duration.EndOfTurn), false)); + this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(3, 3, Duration.EndOfTurn).setText("it gets +3/+3 until end of turn"), false)); } private HungrySpriggan(final HungrySpriggan card) { diff --git a/Mage.Sets/src/mage/cards/h/HuntedNightmare.java b/Mage.Sets/src/mage/cards/h/HuntedNightmare.java index ab2e8d9a12f..726a64e530e 100644 --- a/Mage.Sets/src/mage/cards/h/HuntedNightmare.java +++ b/Mage.Sets/src/mage/cards/h/HuntedNightmare.java @@ -78,7 +78,7 @@ class HuntedNightmareEffect extends OneShotEffect { } Target target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); return permanent != null && permanent.addCounters(CounterType.DEATHTOUCH.createInstance(), player.getId(), source, game); } diff --git a/Mage.Sets/src/mage/cards/h/HunterSliver.java b/Mage.Sets/src/mage/cards/h/HunterSliver.java index e271ba88afe..34243ca8a0b 100644 --- a/Mage.Sets/src/mage/cards/h/HunterSliver.java +++ b/Mage.Sets/src/mage/cards/h/HunterSliver.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; @@ -9,13 +7,13 @@ import mage.abilities.keyword.ProvokeAbility; 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.constants.SubType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author cbt33 */ public final class HunterSliver extends CardImpl { @@ -28,8 +26,10 @@ public final class HunterSliver extends CardImpl { this.toughness = new MageInt(1); // All Sliver creatures have provoke. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(new ProvokeAbility(), - Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS))); + this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( + new ProvokeAbility(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_ALL_SLIVERS + ).setText("all Sliver creatures have provoke"))); } private HunterSliver(final HunterSliver card) { diff --git a/Mage.Sets/src/mage/cards/h/HuntersProwess.java b/Mage.Sets/src/mage/cards/h/HuntersProwess.java index 8f9c39f9cb7..40ef45fdc4e 100644 --- a/Mage.Sets/src/mage/cards/h/HuntersProwess.java +++ b/Mage.Sets/src/mage/cards/h/HuntersProwess.java @@ -1,11 +1,11 @@ - package mage.cards.h; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.TrampleAbility; @@ -13,9 +13,6 @@ 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.players.Player; import mage.target.common.TargetCreaturePermanent; /** @@ -27,15 +24,15 @@ public final class HuntersProwess extends CardImpl { public HuntersProwess(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{G}"); - // Until end of turn, target creature gets +3/+3 and gains trample and "Whenever this creature deals combat damage to a player, draw that many cards." - Effect effect = new BoostTargetEffect(3,3, Duration.EndOfTurn); - effect.setText("Until end of turn, target creature gets +3/+3"); + Effect effect = new BoostTargetEffect(3, 3, Duration.EndOfTurn); + effect.setText("Until end of turn, target creature gets +3/+3"); this.getSpellAbility().addEffect(effect); effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); - effect.setText("and gains trample"); - this.getSpellAbility().addEffect(effect); - Ability grantedAbility = new DealsCombatDamageToAPlayerTriggeredAbility(new HuntersProwessDrawEffect(), false, true); + effect.setText("and gains trample"); + this.getSpellAbility().addEffect(effect); + Ability grantedAbility = new DealsCombatDamageToAPlayerTriggeredAbility( + new DrawCardSourceControllerEffect(SavedDamageValue.MANY), false, true); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(grantedAbility, Duration.EndOfTurn, "and \"Whenever this creature deals combat damage to a player, draw that many cards.\"")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); @@ -50,35 +47,3 @@ public final class HuntersProwess extends CardImpl { return new HuntersProwess(this); } } - -class HuntersProwessDrawEffect extends OneShotEffect { - - public HuntersProwessDrawEffect() { - super(Outcome.Benefit); - this.staticText = "draw that many cards"; - } - - public HuntersProwessDrawEffect(final HuntersProwessDrawEffect effect) { - super(effect); - } - - @Override - public HuntersProwessDrawEffect copy() { - return new HuntersProwessDrawEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - int damage = (Integer) this.getValue("damage"); - if (damage > 0) { - controller.drawCards(damage, source, game); - } - return true; - } - - - return false; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/h/HuntmasterLiger.java b/Mage.Sets/src/mage/cards/h/HuntmasterLiger.java index 3524529dd90..14dd6f51a18 100644 --- a/Mage.Sets/src/mage/cards/h/HuntmasterLiger.java +++ b/Mage.Sets/src/mage/cards/h/HuntmasterLiger.java @@ -32,7 +32,7 @@ public final class HuntmasterLiger extends CardImpl { // Whenever this creature mutates, other creatures you control get +X/+X until end of turn, where X is the number of times this creature has mutated. this.addAbility(new MutatesSourceTriggeredAbility(new BoostControlledEffect( SourceMutatedCount.instance, SourceMutatedCount.instance, Duration.EndOfTurn, - StaticFilters.FILTER_PERMANENT_CREATURE, true, true + StaticFilters.FILTER_PERMANENT_CREATURES, true, true ))); } diff --git a/Mage.Sets/src/mage/cards/h/HurlyBurly.java b/Mage.Sets/src/mage/cards/h/HurlyBurly.java index da4243c7a7b..b78d98fd474 100644 --- a/Mage.Sets/src/mage/cards/h/HurlyBurly.java +++ b/Mage.Sets/src/mage/cards/h/HurlyBurly.java @@ -30,8 +30,7 @@ public final class HurlyBurly extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{R}"); this.getSpellAbility().addEffect(new DamageAllEffect(1, filterWithFlying)); - Mode mode = new Mode(); - mode.addEffect(new DamageAllEffect(1, filterWithoutFlying)); + Mode mode = new Mode(new DamageAllEffect(1, filterWithoutFlying)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/h/Hushbringer.java b/Mage.Sets/src/mage/cards/h/Hushbringer.java index 868fbef763c..db685204da7 100644 --- a/Mage.Sets/src/mage/cards/h/Hushbringer.java +++ b/Mage.Sets/src/mage/cards/h/Hushbringer.java @@ -99,7 +99,7 @@ class HushbringerEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { MageObject enteringObject = game.getObject(event.getSourceId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Ability ability = (Ability) getValue("targetAbility"); if (enteringObject == null || sourceObject == null || ability == null) { return null; diff --git a/Mage.Sets/src/mage/cards/h/HushwingGryff.java b/Mage.Sets/src/mage/cards/h/HushwingGryff.java index 6dacad7ea24..8b3bc1ca75b 100644 --- a/Mage.Sets/src/mage/cards/h/HushwingGryff.java +++ b/Mage.Sets/src/mage/cards/h/HushwingGryff.java @@ -68,7 +68,7 @@ class HushwingGryffEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { MageObject enteringObject = game.getObject(event.getSourceId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Ability ability = (Ability) getValue("targetAbility"); if (enteringObject != null && sourceObject != null && ability != null) { MageObject abilitObject = game.getObject(ability.getSourceId()); diff --git a/Mage.Sets/src/mage/cards/h/HydraOmnivore.java b/Mage.Sets/src/mage/cards/h/HydraOmnivore.java index 4042b708962..fa7ad52ecfd 100644 --- a/Mage.Sets/src/mage/cards/h/HydraOmnivore.java +++ b/Mage.Sets/src/mage/cards/h/HydraOmnivore.java @@ -62,7 +62,7 @@ class HydraOmnivoreEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { UUID damagedOpponent = this.getTargetPointer().getFirst(game, source); int amount = (Integer) getValue("damage"); - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object != null && amount > 0 && damagedOpponent != null) { for (UUID playerId : game.getOpponents(source.getControllerId())) { if (!Objects.equals(playerId, damagedOpponent)) { diff --git a/Mage.Sets/src/mage/cards/h/Hydroblast.java b/Mage.Sets/src/mage/cards/h/Hydroblast.java index 2b9fc1feff8..5c47c2e9204 100644 --- a/Mage.Sets/src/mage/cards/h/Hydroblast.java +++ b/Mage.Sets/src/mage/cards/h/Hydroblast.java @@ -29,8 +29,7 @@ public final class Hydroblast extends CardImpl { this.getSpellAbility().addTarget(new TargetSpell()); // or destroy target permanent if it's red. - Mode mode = new Mode(); - mode.addEffect(new HydroblastDestroyEffect()); + Mode mode = new Mode(new HydroblastDestroyEffect()); mode.addTarget(new TargetPermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/h/HyenaUmbra.java b/Mage.Sets/src/mage/cards/h/HyenaUmbra.java index 1edc60af013..f85d2b92bb8 100644 --- a/Mage.Sets/src/mage/cards/h/HyenaUmbra.java +++ b/Mage.Sets/src/mage/cards/h/HyenaUmbra.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; @@ -16,26 +14,32 @@ import mage.constants.*; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class HyenaUmbra extends CardImpl { public HyenaUmbra(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); this.subtype.add(SubType.AURA); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // Enchanted creature gets +1/+1 and has first strike. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 1, Duration.WhileOnBattlefield))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.AURA))); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect( + 1, 1, Duration.WhileOnBattlefield + )); + ability.addEffect(new GainAbilityAttachedEffect( + FirstStrikeAbility.getInstance(), AttachmentType.AURA + ).setText("and has first strike")); + this.addAbility(ability); + // Totem armor this.addAbility(new TotemArmorAbility()); } diff --git a/Mage.Sets/src/mage/cards/h/Hypergenesis.java b/Mage.Sets/src/mage/cards/h/Hypergenesis.java index c687e3fcbee..ef05c0ad68a 100644 --- a/Mage.Sets/src/mage/cards/h/Hypergenesis.java +++ b/Mage.Sets/src/mage/cards/h/Hypergenesis.java @@ -88,7 +88,7 @@ class HypergenesisEffect extends OneShotEffect { firstInactivePlayer = currentPlayer.getId(); } target.clearChosen(); - if (target.canChoose(source.getSourceId(), currentPlayer.getId(), game) + if (target.canChoose(currentPlayer.getId(), source, game) && currentPlayer.chooseUse(outcome, "Put card from your hand to play?", source, game)) { if (target.chooseTarget(outcome, currentPlayer.getId(), source, game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/h/HypnoticGrifter.java b/Mage.Sets/src/mage/cards/h/HypnoticGrifter.java new file mode 100644 index 00000000000..324854d03f2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HypnoticGrifter.java @@ -0,0 +1,39 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HypnoticGrifter extends CardImpl { + + public HypnoticGrifter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // {3}: Hypnotic Grifter connives. + this.addAbility(new SimpleActivatedAbility(new ConniveSourceEffect("{this}"), new GenericManaCost(3))); + } + + private HypnoticGrifter(final HypnoticGrifter card) { + super(card); + } + + @Override + public HypnoticGrifter copy() { + return new HypnoticGrifter(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HystericalBlindness.java b/Mage.Sets/src/mage/cards/h/HystericalBlindness.java index 89aeafc9e45..346412b6654 100644 --- a/Mage.Sets/src/mage/cards/h/HystericalBlindness.java +++ b/Mage.Sets/src/mage/cards/h/HystericalBlindness.java @@ -1,4 +1,3 @@ - package mage.cards.h; import java.util.UUID; @@ -7,8 +6,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; /** * @@ -16,18 +14,11 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class HystericalBlindness extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public HystericalBlindness(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{U}"); - // Creatures your opponents control get -4/-0 until end of turn. - this.getSpellAbility().addEffect(new BoostAllEffect(-4, 0, Duration.EndOfTurn, filter, false)); + this.getSpellAbility().addEffect(new BoostAllEffect(-4, 0, Duration.EndOfTurn, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, false)); } private HystericalBlindness(final HystericalBlindness card) { diff --git a/Mage.Sets/src/mage/cards/h/Hystrodon.java b/Mage.Sets/src/mage/cards/h/Hystrodon.java index 29a92f6da59..c6222c5b852 100644 --- a/Mage.Sets/src/mage/cards/h/Hystrodon.java +++ b/Mage.Sets/src/mage/cards/h/Hystrodon.java @@ -31,7 +31,7 @@ public final class Hystrodon extends CardImpl { // Whenever Hystrodon deals combat damage to a player, you may draw a card. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DrawCardSourceControllerEffect(1), true)); // Morph {1}{G}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{G}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{G}{G}"))); } private Hystrodon(final Hystrodon card) { diff --git a/Mage.Sets/src/mage/cards/i/IbHalfheartGoblinTactician.java b/Mage.Sets/src/mage/cards/i/IbHalfheartGoblinTactician.java index 6f8cb02d7b4..f69f72839a0 100644 --- a/Mage.Sets/src/mage/cards/i/IbHalfheartGoblinTactician.java +++ b/Mage.Sets/src/mage/cards/i/IbHalfheartGoblinTactician.java @@ -29,7 +29,7 @@ import mage.target.common.TargetControlledPermanent; */ public final class IbHalfheartGoblinTactician extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("two Mountains"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("Mountains"); private static final FilterCreaturePermanent filterGoblin = new FilterCreaturePermanent("another Goblin you control"); static { diff --git a/Mage.Sets/src/mage/cards/i/IceCauldron.java b/Mage.Sets/src/mage/cards/i/IceCauldron.java index 30f5a15f066..7971da9c264 100644 --- a/Mage.Sets/src/mage/cards/i/IceCauldron.java +++ b/Mage.Sets/src/mage/cards/i/IceCauldron.java @@ -98,7 +98,7 @@ class IceCauldronExileEffect extends OneShotEffect { TargetCard target = new TargetCard(Zone.HAND, filter); target.setNotTarget(true); Card chosenCard = null; - if (controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.Benefit, target, source, game)) { chosenCard = controller.getHand().get(target.getFirstTarget(), game); } if (chosenCard != null) { diff --git a/Mage.Sets/src/mage/cards/i/IcebreakerKraken.java b/Mage.Sets/src/mage/cards/i/IcebreakerKraken.java index dcd18091a4b..908536028f4 100644 --- a/Mage.Sets/src/mage/cards/i/IcebreakerKraken.java +++ b/Mage.Sets/src/mage/cards/i/IcebreakerKraken.java @@ -98,7 +98,7 @@ class IcebreakerKrakenEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { for (Permanent permanent : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_OR_CREATURE, - source.getFirstTarget(), source.getControllerId(), game + source.getFirstTarget(), source, game )) { if (permanent == null) { continue; diff --git a/Mage.Sets/src/mage/cards/i/IcefeatherAven.java b/Mage.Sets/src/mage/cards/i/IcefeatherAven.java index 48c07f245fd..206169db7a2 100644 --- a/Mage.Sets/src/mage/cards/i/IcefeatherAven.java +++ b/Mage.Sets/src/mage/cards/i/IcefeatherAven.java @@ -40,7 +40,7 @@ public final class IcefeatherAven extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Morph {1}{G}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{G}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{G}{U}"))); // When Icefeather Aven is turned face up, you may return another target creature to its owner's hand. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new ReturnToHandTargetEffect(), false, true); ability.addTarget(new TargetCreaturePermanent(filter)); diff --git a/Mage.Sets/src/mage/cards/i/IchorSlick.java b/Mage.Sets/src/mage/cards/i/IchorSlick.java index f72717008d1..b5a6a49fafe 100644 --- a/Mage.Sets/src/mage/cards/i/IchorSlick.java +++ b/Mage.Sets/src/mage/cards/i/IchorSlick.java @@ -30,7 +30,7 @@ public final class IchorSlick extends CardImpl { this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); // Madness {3}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{3}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{3}{B}"))); } private IchorSlick(final IchorSlick card) { diff --git a/Mage.Sets/src/mage/cards/i/Ichorid.java b/Mage.Sets/src/mage/cards/i/Ichorid.java index f05c7e7f4b3..da61c6ff2f7 100644 --- a/Mage.Sets/src/mage/cards/i/Ichorid.java +++ b/Mage.Sets/src/mage/cards/i/Ichorid.java @@ -1,10 +1,8 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.ObjectColor; -import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.BeginningOfYourEndStepTriggeredAbility; import mage.abilities.costs.common.ExileFromGraveCost; @@ -20,21 +18,20 @@ import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Plopman */ public final class Ichorid extends CardImpl { public Ichorid(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(3); @@ -42,15 +39,12 @@ public final class Ichorid extends CardImpl { // Haste this.addAbility(HasteAbility.getInstance()); + // At the beginning of the end step, sacrifice Ichorid. this.addAbility(new BeginningOfYourEndStepTriggeredAbility(new SacrificeSourceEffect(), false)); + // At the beginning of your upkeep, if Ichorid is in your graveyard, you may exile a black creature card other than Ichorid from your graveyard. If you do, return Ichorid to the battlefield. - FilterCard filter = new FilterCreatureCard("a black creature card other than Ichorid from your graveyard"); - filter.add(Predicates.not(new CardIdPredicate(this.getId()))); - filter.add(new ColorPredicate(ObjectColor.BLACK)); - Ability ability = new IchoridTriggerdAbility(filter); - this.addAbility(ability); - + this.addAbility(new IchoridTriggerdAbility()); } private Ichorid(final Ichorid card) { @@ -63,16 +57,20 @@ public final class Ichorid extends CardImpl { } } -class IchoridTriggerdAbility extends BeginningOfUpkeepTriggeredAbility{ +class IchoridTriggerdAbility extends BeginningOfUpkeepTriggeredAbility { - public IchoridTriggerdAbility(FilterCard filter){ - super(Zone.GRAVEYARD, - new DoIfCostPaid(new ReturnSourceFromGraveyardToBattlefieldEffect(), - new ExileFromGraveCost( - new TargetCardInYourGraveyard(1, 1, filter, true) - ) - ), - TargetController.YOU, false); + private static final FilterCard filter = new FilterCreatureCard("another black creature card"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(new ColorPredicate(ObjectColor.BLACK)); + } + + public IchoridTriggerdAbility() { + super(Zone.GRAVEYARD, new DoIfCostPaid( + new ReturnSourceFromGraveyardToBattlefieldEffect(), + new ExileFromGraveCost(new TargetCardInYourGraveyard(filter)) + ), TargetController.YOU, false); } public IchoridTriggerdAbility(IchoridTriggerdAbility ability) { @@ -83,19 +81,17 @@ class IchoridTriggerdAbility extends BeginningOfUpkeepTriggeredAbility{ public BeginningOfUpkeepTriggeredAbility copy() { return new IchoridTriggerdAbility(this); } - + @Override public boolean checkInterveningIfClause(Game game) { - Player controller = game.getPlayer(controllerId); - if(controller != null && controller.getGraveyard().contains(sourceId)){ - return super.checkInterveningIfClause(game); - } - return false; + MageObject sourceObject = getSourceObjectIfItStillExists(game); + return sourceObject != null && game.getState().getZone(getSourceId()) == Zone.GRAVEYARD; } @Override public String getRule() { - return "At the beginning of your upkeep, if {this} is in your graveyard, you may exile a black creature card other than {this} from your graveyard. If you do, return {this} to the battlefield."; + return "At the beginning of your upkeep, if {this} is in your graveyard, " + + "you may exile a black creature card other than {this} from your graveyard. " + + "If you do, return {this} to the battlefield."; } - } diff --git a/Mage.Sets/src/mage/cards/i/Ichthyomorphosis.java b/Mage.Sets/src/mage/cards/i/Ichthyomorphosis.java index d0411d87da8..37493941782 100644 --- a/Mage.Sets/src/mage/cards/i/Ichthyomorphosis.java +++ b/Mage.Sets/src/mage/cards/i/Ichthyomorphosis.java @@ -38,7 +38,7 @@ public final class Ichthyomorphosis extends CardImpl { // Enchanted creature loses all abilities and is a blue Fish with base power and toughness 0/1. Effect effect = new BecomesCreatureAttachedEffect( new CreatureToken(0, 1, "", SubType.FISH).withColor("U"), - "Enchanted creature loses all abilities and is a blue Fish creature with base power and toughness 0/1", + "Enchanted creature loses all abilities and is a blue Fish with base power and toughness 0/1", Duration.WhileOnBattlefield, BecomesCreatureAttachedEffect.LoseType.ALL ); effect.setOutcome(Outcome.Detriment); diff --git a/Mage.Sets/src/mage/cards/i/IconOfAncestry.java b/Mage.Sets/src/mage/cards/i/IconOfAncestry.java index ac44440de24..57ff868cd12 100644 --- a/Mage.Sets/src/mage/cards/i/IconOfAncestry.java +++ b/Mage.Sets/src/mage/cards/i/IconOfAncestry.java @@ -6,9 +6,10 @@ 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.dynamicvalue.common.StaticValue; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -61,15 +62,10 @@ public final class IconOfAncestry extends CardImpl { } } -class IconOfAncestryEffect extends LookLibraryAndPickControllerEffect { +class IconOfAncestryEffect extends OneShotEffect { public IconOfAncestryEffect() { - super(StaticValue.get(3), false, StaticValue.get(1), new FilterCreatureCard( - "creature card that matches the chosen subtype" - ), Zone.LIBRARY, false, true, false, - Zone.HAND, true, false, false); - this.setOutcome(Outcome.AIDontUseIt); - this.setBackInRandomOrder(true); + super(Outcome.AIDontUseIt); staticText = "look at the top three cards of your library. " + "You may reveal a creature card of the chosen type from among them and put it into your hand. " + "Put the rest on the bottom of your library in a random order"; @@ -77,13 +73,13 @@ class IconOfAncestryEffect extends LookLibraryAndPickControllerEffect { @Override public boolean apply(Game game, Ability source) { - SubType subtype = (SubType) game.getState().getValue(source.getSourceId() + "_type"); + SubType subtype = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game); if (subtype == null) { return false; } + FilterCreatureCard filter = new FilterCreatureCard(subtype.toString() + " creature card"); filter.add(subtype.getPredicate()); - filter.setMessage(subtype.toString() + " creature card"); - return super.apply(game, source); + return new LookLibraryAndPickControllerEffect(3, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM).apply(game, source); } public IconOfAncestryEffect(final IconOfAncestryEffect effect) { diff --git a/Mage.Sets/src/mage/cards/i/IdolOfEndurance.java b/Mage.Sets/src/mage/cards/i/IdolOfEndurance.java index 8bf959f3576..6a38e31fe36 100644 --- a/Mage.Sets/src/mage/cards/i/IdolOfEndurance.java +++ b/Mage.Sets/src/mage/cards/i/IdolOfEndurance.java @@ -14,6 +14,7 @@ import mage.constants.*; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.ExileZone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; @@ -22,8 +23,9 @@ import mage.players.Player; import mage.util.CardUtil; import mage.watchers.Watcher; -import java.util.*; -import java.util.stream.Collectors; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; /** * @author TheElk801 @@ -84,28 +86,16 @@ class IdolOfEnduranceExileEffect extends OneShotEffect { return false; } Cards cards = new CardsImpl(player.getGraveyard().getCards(filter, game)); - MageObjectReference mor = new MageObjectReference(permanent, game); - player.moveCards(cards, Zone.EXILED, source, game); - Set morSet = cards - .getCards(game) - .stream() - .filter(Objects::nonNull) - .map(card -> new MageObjectReference(card, game)) - .collect(Collectors.toSet()); - String exileId = "idolOfEndurance_" + mor.getSourceId() + mor.getZoneChangeCounter(); - if (game.getState().getValue(exileId) == null) { - game.getState().setValue(exileId, new HashSet()); - } - ((Set) game.getState().getValue(exileId)).addAll(morSet); - game.addDelayedTriggeredAbility(new IdolOfEnduranceDelayedTrigger(exileId), source); + player.moveCardsToExile(cards.getCards(game), source, game, true, CardUtil.getExileZoneId(game, source), CardUtil.getSourceName(game, source)); + game.addDelayedTriggeredAbility(new IdolOfEnduranceDelayedTrigger(), source); return true; } } class IdolOfEnduranceDelayedTrigger extends DelayedTriggeredAbility { - IdolOfEnduranceDelayedTrigger(String exileId) { - super(new IdolOfEnduranceLeaveEffect(exileId), Duration.Custom, true, false); + IdolOfEnduranceDelayedTrigger() { + super(new IdolOfEnduranceLeaveEffect(), Duration.Custom, true, false); this.usesStack = false; this.setRuleVisible(false); } @@ -138,16 +128,12 @@ class IdolOfEnduranceDelayedTrigger extends DelayedTriggeredAbility { class IdolOfEnduranceLeaveEffect extends OneShotEffect { - private final String exileId; - - IdolOfEnduranceLeaveEffect(String exileId) { + IdolOfEnduranceLeaveEffect() { super(Outcome.Benefit); - this.exileId = exileId; } private IdolOfEnduranceLeaveEffect(final IdolOfEnduranceLeaveEffect effect) { super(effect); - this.exileId = effect.exileId; } @Override @@ -161,17 +147,11 @@ class IdolOfEnduranceLeaveEffect extends OneShotEffect { if (player == null) { return false; } - Object object = game.getState().getValue(exileId); - if (!(object instanceof Set)) { - return false; - } - Set morSet = (Set) object; - return player != null && player.moveCards( - morSet.stream() - .map(mor -> mor.getCard(game)) - .filter(Objects::nonNull) - .collect(Collectors.toSet()), - Zone.GRAVEYARD, source, game + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + return exileZone != null + && !exileZone.isEmpty() + && player.moveCards( + exileZone, Zone.GRAVEYARD, source, game ); } } @@ -200,28 +180,16 @@ class IdolOfEnduranceCastFromExileEffect extends AsThoughEffectImpl { @Override public void init(Ability source, Game game) { super.init(source, game); - IdolOfEnduranceWatcher watcher = game.getState().getWatcher(IdolOfEnduranceWatcher.class); - if (watcher != null) { - watcher.addPlayable(source, game); - } + IdolOfEnduranceWatcher.addPlayable(source, game); } @Override public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { - IdolOfEnduranceWatcher watcher = game.getState().getWatcher(IdolOfEnduranceWatcher.class); - if (watcher == null || !watcher.checkPermission(affectedControllerId, source, game)) { + if (!IdolOfEnduranceWatcher.checkPermission(affectedControllerId, source, game)) { return false; } - Object value = game.getState().getValue( - "idolOfEndurance_" + source.getSourceId() + source.getSourceObjectZoneChangeCounter() - ); - if (!(value instanceof Set)) { - discard(); - return false; - } - Set morSet = (Set) value; - if (game.getState().getZone(sourceId) != Zone.EXILED - || morSet.stream().noneMatch(mor -> mor.refersTo(sourceId, game))) { + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + if (exileZone == null || !exileZone.contains(sourceId)) { return false; } Card card = game.getCard(sourceId); @@ -248,7 +216,6 @@ class IdolOfEnduranceWatcher extends Watcher { } morMap.computeIfAbsent(event.getAdditionalReference().getApprovingMageObjectReference(), m -> new HashMap<>()) .compute(event.getPlayerId(), (u, i) -> i == null ? 0 : Integer.sum(i, -1)); - return; } } @@ -258,24 +225,27 @@ class IdolOfEnduranceWatcher extends Watcher { super.reset(); } - boolean checkPermission(UUID playerId, Ability source, Game game) { + static boolean checkPermission(UUID playerId, Ability source, Game game) { if (!playerId.equals(source.getControllerId())) { return false; } - MageObjectReference mor = new MageObjectReference( - source.getSourceId(), source.getSourceObjectZoneChangeCounter(), game - ); - if (!morMap.containsKey(mor)) { - return false; - } - return morMap.get(mor).getOrDefault(playerId, 0) > 0; + IdolOfEnduranceWatcher watcher = game.getState().getWatcher(IdolOfEnduranceWatcher.class); + MageObjectReference mor = new MageObjectReference(source); + return watcher + .morMap + .containsKey(mor) + && watcher + .morMap + .get(mor) + .getOrDefault(playerId, 0) > 0; } - void addPlayable(Ability source, Game game) { - MageObjectReference mor = new MageObjectReference( - source.getSourceId(), source.getSourceObjectZoneChangeCounter(), game - ); - morMap.computeIfAbsent(mor, m -> new HashMap<>()) + static void addPlayable(Ability source, Game game) { + MageObjectReference mor = new MageObjectReference(source); + game.getState() + .getWatcher(IdolOfEnduranceWatcher.class) + .morMap + .computeIfAbsent(mor, m -> new HashMap<>()) .compute(source.getControllerId(), CardUtil::setOrIncrementValue); } } diff --git a/Mage.Sets/src/mage/cards/i/IdolOfOblivion.java b/Mage.Sets/src/mage/cards/i/IdolOfOblivion.java index 3e7b2931594..2dba9b17035 100644 --- a/Mage.Sets/src/mage/cards/i/IdolOfOblivion.java +++ b/Mage.Sets/src/mage/cards/i/IdolOfOblivion.java @@ -3,7 +3,7 @@ package mage.cards.i; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CreatedTokenThisTurnCondition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; @@ -12,17 +12,10 @@ import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.WatcherScope; import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.game.permanent.PermanentToken; import mage.game.permanent.token.EldraziToken; -import mage.watchers.Watcher; +import mage.watchers.common.CreatedTokenWatcher; -import java.util.HashSet; -import java.util.Set; import java.util.UUID; /** @@ -36,8 +29,8 @@ public final class IdolOfOblivion extends CardImpl { // {T}: Draw a card. Activate this ability only if you created a token this turn. this.addAbility(new ActivateIfConditionActivatedAbility( Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), - new TapSourceCost(), IdolOfOblivionCondition.instance - )); + new TapSourceCost(), CreatedTokenThisTurnCondition.instance + ).addHint(CreatedTokenThisTurnCondition.getHint()), new CreatedTokenWatcher()); // {8}, {T}, Sacrifice Idol of Oblivion: Create 10/10 colorless Eldrazi creature token. Ability ability = new SimpleActivatedAbility( @@ -45,7 +38,7 @@ public final class IdolOfOblivion extends CardImpl { ); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); - this.addAbility(ability, new IdolOfOblivionWatcher()); + this.addAbility(ability); } private IdolOfOblivion(final IdolOfOblivion card) { @@ -57,47 +50,3 @@ public final class IdolOfOblivion extends CardImpl { return new IdolOfOblivion(this); } } - -enum IdolOfOblivionCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - IdolOfOblivionWatcher watcher = game.getState().getWatcher(IdolOfOblivionWatcher.class); - return watcher != null && watcher.tokenEntered(source.getControllerId()); - } - - @Override - public String toString() { - return "if you created a token this turn"; - } -} - -class IdolOfOblivionWatcher extends Watcher { - - private final Set playerIds = new HashSet<>(); - - IdolOfOblivionWatcher() { - super(WatcherScope.GAME); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() != GameEvent.EventType.ENTERS_THE_BATTLEFIELD) { - return; - } - Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent instanceof PermanentToken) { - playerIds.add(permanent.getControllerId()); - } - } - - @Override - public void reset() { - playerIds.clear(); - } - - boolean tokenEntered(UUID playerId) { - return playerIds.contains(playerId); - } -} diff --git a/Mage.Sets/src/mage/cards/i/IgnitionTeam.java b/Mage.Sets/src/mage/cards/i/IgnitionTeam.java index 7714d69baa2..9027cf29265 100644 --- a/Mage.Sets/src/mage/cards/i/IgnitionTeam.java +++ b/Mage.Sets/src/mage/cards/i/IgnitionTeam.java @@ -72,7 +72,7 @@ class TappedLandsCount implements DynamicValue { if (sourceAbility != null) { FilterLandPermanent filter = new FilterLandPermanent("tapped lands on the battlefield"); filter.add(TappedPredicate.TAPPED); - return game.getBattlefield().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + return game.getBattlefield().count(filter, sourceAbility.getControllerId(), sourceAbility, game); } return 0; } diff --git a/Mage.Sets/src/mage/cards/i/IllGottenGains.java b/Mage.Sets/src/mage/cards/i/IllGottenGains.java index 707325a27c7..fbd2081849c 100644 --- a/Mage.Sets/src/mage/cards/i/IllGottenGains.java +++ b/Mage.Sets/src/mage/cards/i/IllGottenGains.java @@ -71,7 +71,7 @@ class IllGottenGainsEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null) { Target target = new TargetCardInYourGraveyard(0, 3, new FilterCard()); - if (target.choose(Outcome.ReturnToHand, player.getId(), source.getSourceId(), game)) { + if (target.choose(Outcome.ReturnToHand, player.getId(), source.getSourceId(), source, game)) { player.moveCards(new CardsImpl(target.getTargets()), Zone.HAND, source, game); } } diff --git a/Mage.Sets/src/mage/cards/i/IllTemperedLoner.java b/Mage.Sets/src/mage/cards/i/IllTemperedLoner.java index 0381d939033..08b861d29d1 100644 --- a/Mage.Sets/src/mage/cards/i/IllTemperedLoner.java +++ b/Mage.Sets/src/mage/cards/i/IllTemperedLoner.java @@ -33,8 +33,8 @@ public final class IllTemperedLoner extends CardImpl { this.secondSideCardClazz = mage.cards.h.HowlpackAvenger.class; // Whenever Ill-Tempered Loner is dealt damage, it deals that much damage to any target. - Ability ability = new DealtDamageToSourceTriggeredAbility(new DamageTargetEffect(SavedDamageValue.instance) - .setText("it deals that much damage to any target"), false, false); + Ability ability = new DealtDamageToSourceTriggeredAbility( + new DamageTargetEffect(SavedDamageValue.MUCH, "it"), false); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/i/IllicitShipment.java b/Mage.Sets/src/mage/cards/i/IllicitShipment.java new file mode 100644 index 00000000000..aa92d727e9b --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IllicitShipment.java @@ -0,0 +1,35 @@ +package mage.cards.i; + +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.abilities.keyword.CasualtyAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IllicitShipment extends CardImpl { + + public IllicitShipment(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}{B}"); + + // Casualty 3 + this.addAbility(new CasualtyAbility(this, 3)); + + // Search your library for a card, put that card into your hand, then shuffle. + this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary())); + } + + private IllicitShipment(final IllicitShipment card) { + super(card); + } + + @Override + public IllicitShipment copy() { + return new IllicitShipment(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IlluminatedFolio.java b/Mage.Sets/src/mage/cards/i/IlluminatedFolio.java index 8a1073e8ad8..53337be7ab0 100644 --- a/Mage.Sets/src/mage/cards/i/IlluminatedFolio.java +++ b/Mage.Sets/src/mage/cards/i/IlluminatedFolio.java @@ -11,7 +11,6 @@ import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; import mage.constants.CardType; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; @@ -68,14 +67,14 @@ class IlluminatedFolioTarget extends TargetCardInHand { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - return super.canChoose(sourceId, sourceControllerId, game) - && !possibleTargets(sourceId,sourceControllerId, game).isEmpty(); + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + return super.canChoose(sourceControllerId, source, game) + && !possibleTargets(sourceControllerId, source, game).isEmpty(); } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set possibleTargets = super.possibleTargets(sourceId,sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); if (this.getTargets().size() == 1) { Card card = game.getCard(this.getTargets().get(0)); possibleTargets.removeIf( diff --git a/Mage.Sets/src/mage/cards/i/IlluminatorVirtuoso.java b/Mage.Sets/src/mage/cards/i/IlluminatorVirtuoso.java new file mode 100644 index 00000000000..af14525d6ca --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IlluminatorVirtuoso.java @@ -0,0 +1,52 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.common.BecomesTargetTriggeredAbility; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IlluminatorVirtuoso extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a spell you control"); + + static { + filter.add(TargetController.YOU.getControllerPredicate()); + } + + public IlluminatorVirtuoso(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Double strike + this.addAbility(DoubleStrikeAbility.getInstance()); + + // Whenever Illuminator Virtuoso becomes the target of a spell you control, it connives. + this.addAbility(new BecomesTargetTriggeredAbility( + new ConniveSourceEffect(), filter + ).setTriggerPhrase("Whenever {this} becomes the target of a spell you control, ")); + } + + private IlluminatorVirtuoso(final IlluminatorVirtuoso card) { + super(card); + } + + @Override + public IlluminatorVirtuoso copy() { + return new IlluminatorVirtuoso(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IllusionaryPresence.java b/Mage.Sets/src/mage/cards/i/IllusionaryPresence.java index cd3b943c7f9..6f47376227d 100644 --- a/Mage.Sets/src/mage/cards/i/IllusionaryPresence.java +++ b/Mage.Sets/src/mage/cards/i/IllusionaryPresence.java @@ -78,7 +78,7 @@ class IllusionaryPresenceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { SubType landTypeChoice = SubType.byDescription((String) game.getState().getValue(mageObject.getId().toString() + "BasicLandType")); if (landTypeChoice != null) { diff --git a/Mage.Sets/src/mage/cards/i/IllusionaryServant.java b/Mage.Sets/src/mage/cards/i/IllusionaryServant.java index b3ed6aef636..9addb333775 100644 --- a/Mage.Sets/src/mage/cards/i/IllusionaryServant.java +++ b/Mage.Sets/src/mage/cards/i/IllusionaryServant.java @@ -25,7 +25,7 @@ public final class IllusionaryServant extends CardImpl { this.toughness = new MageInt(4); this.addAbility(FlyingAbility.getInstance()); - this.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect())); + this.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect().setText("sacrifice it"))); } private IllusionaryServant(final IllusionaryServant card) { diff --git a/Mage.Sets/src/mage/cards/i/IllusionaryTerrain.java b/Mage.Sets/src/mage/cards/i/IllusionaryTerrain.java index ef07e66981f..88cd2c1d18e 100644 --- a/Mage.Sets/src/mage/cards/i/IllusionaryTerrain.java +++ b/Mage.Sets/src/mage/cards/i/IllusionaryTerrain.java @@ -155,7 +155,7 @@ class ChooseTwoBasicLandTypesEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } if (controller != null && mageObject != null) { diff --git a/Mage.Sets/src/mage/cards/i/IllusionistsStratagem.java b/Mage.Sets/src/mage/cards/i/IllusionistsStratagem.java index 9b2de6deafd..179ced6e00a 100644 --- a/Mage.Sets/src/mage/cards/i/IllusionistsStratagem.java +++ b/Mage.Sets/src/mage/cards/i/IllusionistsStratagem.java @@ -27,7 +27,7 @@ public final class IllusionistsStratagem extends CardImpl { StaticFilters.FILTER_CONTROLLED_CREATURES, false)); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private IllusionistsStratagem(final IllusionistsStratagem card) { diff --git a/Mage.Sets/src/mage/cards/i/IllusoryAmbusher.java b/Mage.Sets/src/mage/cards/i/IllusoryAmbusher.java index b6142aaab42..6dfabd1fbd9 100644 --- a/Mage.Sets/src/mage/cards/i/IllusoryAmbusher.java +++ b/Mage.Sets/src/mage/cards/i/IllusoryAmbusher.java @@ -1,19 +1,15 @@ - package mage.cards.i; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealtDamageToSourceTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.FlashAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Outcome; -import mage.game.Game; -import mage.players.Player; /** * @@ -32,7 +28,8 @@ public final class IllusoryAmbusher extends CardImpl { this.addAbility(FlashAbility.getInstance()); // Whenever Illusory Ambusher is dealt damage, draw that many cards. - this.addAbility(new DealtDamageToSourceTriggeredAbility(new IllusoryAmbusherDealtDamageEffect(), false, false)); + this.addAbility(new DealtDamageToSourceTriggeredAbility( + new DrawCardSourceControllerEffect(SavedDamageValue.MANY), false)); } private IllusoryAmbusher(final IllusoryAmbusher card) { @@ -44,33 +41,3 @@ public final class IllusoryAmbusher extends CardImpl { return new IllusoryAmbusher(this); } } - -class IllusoryAmbusherDealtDamageEffect extends OneShotEffect { - - public IllusoryAmbusherDealtDamageEffect() { - super(Outcome.Damage); - this.staticText = "draw that many cards"; - } - - public IllusoryAmbusherDealtDamageEffect(final IllusoryAmbusherDealtDamageEffect effect) { - super(effect); - } - - @Override - public IllusoryAmbusherDealtDamageEffect copy() { - return new IllusoryAmbusherDealtDamageEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - int amount = (Integer) getValue("damage"); - if (amount > 0) { - player.drawCards(amount, source, game); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/i/IllusoryDemon.java b/Mage.Sets/src/mage/cards/i/IllusoryDemon.java index 15e7a57f693..8961523d49b 100644 --- a/Mage.Sets/src/mage/cards/i/IllusoryDemon.java +++ b/Mage.Sets/src/mage/cards/i/IllusoryDemon.java @@ -1,7 +1,5 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.common.SacrificeSourceEffect; @@ -11,27 +9,25 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class IllusoryDemon extends CardImpl { public IllusoryDemon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}"); this.subtype.add(SubType.DEMON); this.subtype.add(SubType.ILLUSION); - - - this.power = new MageInt(4); this.toughness = new MageInt(3); // Flying this.addAbility(FlyingAbility.getInstance()); - + // When you cast a spell, sacrifice Illusory Demon. - this.addAbility(new SpellCastControllerTriggeredAbility(new SacrificeSourceEffect(), false)); + this.addAbility(new SpellCastControllerTriggeredAbility(new SacrificeSourceEffect(), false).setTriggerPhrase("When you cast a spell, ")); } private IllusoryDemon(final IllusoryDemon card) { diff --git a/Mage.Sets/src/mage/cards/i/ImmaculateMagistrate.java b/Mage.Sets/src/mage/cards/i/ImmaculateMagistrate.java index 682dbb69c20..cb5500d50f9 100644 --- a/Mage.Sets/src/mage/cards/i/ImmaculateMagistrate.java +++ b/Mage.Sets/src/mage/cards/i/ImmaculateMagistrate.java @@ -74,7 +74,7 @@ class ImmaculateMagistrateEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); if (permanent != null) { - int count = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int count = game.getBattlefield().count(filter, source.getControllerId(), source, game); if (count > 0) { permanent.addCounters(CounterType.P1P1.createInstance(count), source.getControllerId(), source, game); return true; diff --git a/Mage.Sets/src/mage/cards/i/ImmolatingSouleater.java b/Mage.Sets/src/mage/cards/i/ImmolatingSouleater.java index c795d8e54ec..465997d5d68 100644 --- a/Mage.Sets/src/mage/cards/i/ImmolatingSouleater.java +++ b/Mage.Sets/src/mage/cards/i/ImmolatingSouleater.java @@ -1,36 +1,33 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.PhyrexianManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.ColoredManaSymbol; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author North */ public final class ImmolatingSouleater extends CardImpl { public ImmolatingSouleater(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DOG); this.power = new MageInt(1); this.toughness = new MageInt(1); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new BoostSourceEffect(1, 0, Duration.EndOfTurn), - new PhyrexianManaCost(ColoredManaSymbol.R))); + this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect( + 1, 0, Duration.EndOfTurn + ), new ManaCostsImpl<>("{R/P}"))); } private ImmolatingSouleater(final ImmolatingSouleater card) { diff --git a/Mage.Sets/src/mage/cards/i/ImmortalCoil.java b/Mage.Sets/src/mage/cards/i/ImmortalCoil.java index d8e9fb6086b..6f9cb5623c7 100644 --- a/Mage.Sets/src/mage/cards/i/ImmortalCoil.java +++ b/Mage.Sets/src/mage/cards/i/ImmortalCoil.java @@ -79,7 +79,7 @@ class ImmortalCoilAbility extends StateTriggeredAbility { @Override public String getRule() { - return "When there are no cards in your graveyard, you lose the game"; + return "When there are no cards in your graveyard, you lose the game."; } } @@ -118,7 +118,7 @@ class ImmortalCoilPreventionEffect extends PreventionEffectImpl { if (player != null) { TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(Math.min(damage, player.getGraveyard().size()), StaticFilters.FILTER_CARD); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); player.moveCards(new CardsImpl(target.getTargets()), Zone.EXILED, source, game); } event.setAmount(0); diff --git a/Mage.Sets/src/mage/cards/i/ImpelledGiant.java b/Mage.Sets/src/mage/cards/i/ImpelledGiant.java index a6d6885dd09..11772f68b11 100644 --- a/Mage.Sets/src/mage/cards/i/ImpelledGiant.java +++ b/Mage.Sets/src/mage/cards/i/ImpelledGiant.java @@ -83,7 +83,7 @@ class ImpelledGiantCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - if (target.choose(Outcome.Tap, controllerId, source.getSourceId(), game)) { + if (target.choose(Outcome.Tap, controllerId, source.getSourceId(), source, game)) { for (UUID targetId : target.getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent == null) { @@ -100,7 +100,7 @@ class ImpelledGiantCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return target.canChoose(source.getSourceId(), controllerId, game); + return target.canChoose(controllerId, source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/i/ImpendingDisaster.java b/Mage.Sets/src/mage/cards/i/ImpendingDisaster.java index 60eef97cc75..cd3ef30dec0 100644 --- a/Mage.Sets/src/mage/cards/i/ImpendingDisaster.java +++ b/Mage.Sets/src/mage/cards/i/ImpendingDisaster.java @@ -48,7 +48,7 @@ public final class ImpendingDisaster extends CardImpl { @Override public boolean apply(Game game, Ability source) { - return game.getBattlefield().count(new FilterLandPermanent(), source.getSourceId(), source.getControllerId(), game) >= 7; + return game.getBattlefield().count(new FilterLandPermanent(), source.getControllerId(), source, game) >= 7; } } } diff --git a/Mage.Sets/src/mage/cards/i/ImperialEdict.java b/Mage.Sets/src/mage/cards/i/ImperialEdict.java index a0385149646..4380a201a29 100644 --- a/Mage.Sets/src/mage/cards/i/ImperialEdict.java +++ b/Mage.Sets/src/mage/cards/i/ImperialEdict.java @@ -66,8 +66,8 @@ class ImperialEdictEffect extends OneShotEffect { FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); filter.add(new ControllerIdPredicate(player.getId())); Target target = new TargetPermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { - while (!target.isChosen() && target.canChoose(source.getSourceId(), player.getId(), game) && player.canRespond()) { + if (target.canChoose(player.getId(), source, game)) { + while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) { player.chooseTarget(Outcome.DestroyPermanent, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/i/ImperialHellkite.java b/Mage.Sets/src/mage/cards/i/ImperialHellkite.java index 5302c3337b1..2c634f30835 100644 --- a/Mage.Sets/src/mage/cards/i/ImperialHellkite.java +++ b/Mage.Sets/src/mage/cards/i/ImperialHellkite.java @@ -32,7 +32,7 @@ public final class ImperialHellkite extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Morph {6}{R}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{6}{R}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{6}{R}{R}"))); // When Imperial Hellkite is turned face up, you may search your library for a Dragon card, reveal it, and put it into your hand. If you do, shuffle your library. Effect effect = new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0, 1, new FilterBySubtypeCard(SubType.DRAGON)), true, true); diff --git a/Mage.Sets/src/mage/cards/i/ImperialMask.java b/Mage.Sets/src/mage/cards/i/ImperialMask.java index 540d044feda..dd7d8e79140 100644 --- a/Mage.Sets/src/mage/cards/i/ImperialMask.java +++ b/Mage.Sets/src/mage/cards/i/ImperialMask.java @@ -1,7 +1,5 @@ - package mage.cards.i; -import java.util.UUID; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.SourceMatchesFilterCondition; @@ -16,8 +14,9 @@ import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.permanent.TokenPredicate; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class ImperialMask extends CardImpl { @@ -34,10 +33,10 @@ public final class ImperialMask extends CardImpl { // When Imperial Mask enters the battlefield, if it's not a token, each of your teammates puts a token that's a copy of Imperial Mask onto the battlefield. // No implementation of teammates currently, so no effect needed this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new InfoEffect("each of your teammates puts a token that's a copy of {this} onto the battlefield"), false), + new EntersBattlefieldTriggeredAbility(new InfoEffect(""), false), new SourceMatchesFilterCondition(filter), "When {this} enters the battlefield, if it's not a token, " - + "each of your teammates puts a token that's a copy of {this} onto the battlefield" + + "each of your teammates creates a token that's a copy of {this}" )); // You have hexproof. diff --git a/Mage.Sets/src/mage/cards/i/ImpetuousProtege.java b/Mage.Sets/src/mage/cards/i/ImpetuousProtege.java index 5a33ae46571..e7059b86a70 100644 --- a/Mage.Sets/src/mage/cards/i/ImpetuousProtege.java +++ b/Mage.Sets/src/mage/cards/i/ImpetuousProtege.java @@ -77,7 +77,7 @@ class ImpetuousProtegeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int maxPower = 0; - for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { maxPower = Math.max(maxPower, creature.getPower().getValue()); } game.addEffect(new BoostSourceEffect(maxPower, 0, Duration.EndOfTurn), source); diff --git a/Mage.Sets/src/mage/cards/i/ImposterMech.java b/Mage.Sets/src/mage/cards/i/ImposterMech.java new file mode 100644 index 00000000000..9db40b903ab --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/ImposterMech.java @@ -0,0 +1,61 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.common.CopyPermanentEffect; +import mage.abilities.keyword.CrewAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.util.functions.CopyApplier; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ImposterMech extends CardImpl { + + private static final CopyApplier applier = new CopyApplier() { + @Override + public boolean apply(Game game, MageObject blueprint, Ability source, UUID targetObjectId) { + blueprint.removeAllCardTypes(); + blueprint.addCardType(CardType.ARTIFACT); + blueprint.addSubType(SubType.VEHICLE); + blueprint.getAbilities().add(new CrewAbility(3)); + return true; + } + }; + + public ImposterMech(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{U}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // You may have Imposter Mech enter the battlefield as a copy of a creature an opponent controls, except its a Vehicle artifact with crew 3 and it loses all other card types. + this.addAbility(new EntersBattlefieldAbility( + new CopyPermanentEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_A_CREATURE, applier), + null, "You may have {this} enter the battlefield as a copy of a creature " + + "an opponent controls, except its a Vehicle artifact with crew 3 and it loses all other card types.", null + )); + + // Crew 3 + this.addAbility(new CrewAbility(3)); + } + + private ImposterMech(final ImposterMech card) { + super(card); + } + + @Override + public ImposterMech copy() { + return new ImposterMech(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/Imprison.java b/Mage.Sets/src/mage/cards/i/Imprison.java index bfa0a0a1d0f..3c7ac354825 100644 --- a/Mage.Sets/src/mage/cards/i/Imprison.java +++ b/Mage.Sets/src/mage/cards/i/Imprison.java @@ -50,7 +50,7 @@ public final class Imprison extends CardImpl { this.addAbility(new ImprisonTriggeredAbility()); // Whenever enchanted creature attacks or blocks, you may pay {1}. If you do, tap the creature, remove it from combat, and creatures it was blocking that had become blocked by only that creature this combat become unblocked. If you don't, destroy Imprison. - this.addAbility(new AttacksOrBlocksAttachedTriggeredAbility(new DoIfCostPaid(new ImprisonUnblockEffect(), new DestroySourceEffect(), new ManaCostsImpl("1")), AttachmentType.AURA)); + this.addAbility(new AttacksOrBlocksAttachedTriggeredAbility(new DoIfCostPaid(new ImprisonUnblockEffect(), new DestroySourceEffect(), new ManaCostsImpl<>("{1}")), AttachmentType.AURA)); } private Imprison(final Imprison card) { @@ -66,7 +66,7 @@ public final class Imprison extends CardImpl { class ImprisonTriggeredAbility extends TriggeredAbilityImpl { ImprisonTriggeredAbility() { - super(Zone.BATTLEFIELD, new DoIfCostPaid(new CounterTargetEffect().setText("counter that ability"), new DestroySourceEffect(), new ManaCostsImpl("1"))); + super(Zone.BATTLEFIELD, new DoIfCostPaid(new CounterTargetEffect().setText("counter that ability"), new DestroySourceEffect(), new ManaCostsImpl<>("{1}"))); } ImprisonTriggeredAbility(final ImprisonTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/i/ImpromptuRaid.java b/Mage.Sets/src/mage/cards/i/ImpromptuRaid.java index eac63ee6692..f99d57e6bb1 100644 --- a/Mage.Sets/src/mage/cards/i/ImpromptuRaid.java +++ b/Mage.Sets/src/mage/cards/i/ImpromptuRaid.java @@ -78,14 +78,14 @@ class ImpromptuRaidEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && controller != null) { Card card = controller.getLibrary().getFromTop(game); if (card != null) { Cards cards = new CardsImpl(); cards.add(card); controller.revealCards(sourceObject.getName(), cards, game); - if (filterPutInGraveyard.match(card, source.getSourceId(), source.getControllerId(), game)) { + if (filterPutInGraveyard.match(card, source.getControllerId(), source, game)) { controller.moveCards(card, Zone.GRAVEYARD, source, game); return true; } diff --git a/Mage.Sets/src/mage/cards/i/Impulse.java b/Mage.Sets/src/mage/cards/i/Impulse.java index 3bc1465fd98..23a5e015893 100644 --- a/Mage.Sets/src/mage/cards/i/Impulse.java +++ b/Mage.Sets/src/mage/cards/i/Impulse.java @@ -1,14 +1,11 @@ - package mage.cards.i; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.FilterCard; /** * @@ -20,8 +17,7 @@ public final class Impulse extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); // Look at the top four cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(4), false, StaticValue.get(1), new FilterCard(), Zone.LIBRARY, false, false)); - + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(4, 1, PutCards.HAND, PutCards.BOTTOM_ANY)); } private Impulse(final Impulse card) { diff --git a/Mage.Sets/src/mage/cards/i/InSearchOfGreatness.java b/Mage.Sets/src/mage/cards/i/InSearchOfGreatness.java index 66b78be6045..178d92eb694 100644 --- a/Mage.Sets/src/mage/cards/i/InSearchOfGreatness.java +++ b/Mage.Sets/src/mage/cards/i/InSearchOfGreatness.java @@ -1,25 +1,28 @@ package mage.cards.i; -import java.util.UUID; - -import mage.ApprovingObject; +import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.common.FilterPermanentCard; -import mage.filter.predicate.Predicates; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCardInHand; +import mage.util.CardUtil; + +import java.util.Objects; +import java.util.UUID; /** - * * @author weirddan455 */ public final class InSearchOfGreatness extends CardImpl { @@ -30,8 +33,8 @@ public final class InSearchOfGreatness extends CardImpl { // At the beginning of your upkeep, you may cast a permanent spell from your hand with converted mana cost // equal to 1 plus the highest converted mana cost among other permanents you control // without paying its mana cost. If you don't, scry 1. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new InSearchOfGreatnessEffect(), - TargetController.YOU, false, false + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new InSearchOfGreatnessEffect(), TargetController.YOU, false )); } @@ -69,35 +72,19 @@ class InSearchOfGreatnessEffect extends OneShotEffect { if (controller == null) { return false; } - int cmc = 0; - UUID permId = source.getSourceId(); - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(controller.getId())) { - if (permanent != null && !permanent.getId().equals(permId)) { - int permCmc = permanent.getManaValue(); - if (permCmc > cmc) { - cmc = permCmc; - } - } - } - if (controller.chooseUse(outcome, "Cast a permanent spell from your hand with CMC equal to " - + ++cmc + "?", source, game)) { - FilterPermanentCard filter = new FilterPermanentCard("permanent spell from your hand"); - filter.add(Predicates.not(CardType.LAND.getPredicate())); - filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, cmc)); - TargetCardInHand target = new TargetCardInHand(filter); - if (controller.chooseTarget(outcome, target, source, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - if (cardWasCast) { - return true; - } - } - } - } - return controller.scry(1, source, game); + MageObjectReference sourceRef = new MageObjectReference(source); + int manaValue = game + .getBattlefield() + .getActivePermanents(StaticFilters.FILTER_CONTROLLED_PERMANENT, controller.getId(), game) + .stream() + .filter(Objects::nonNull) + .filter(permanent -> !sourceRef.refersTo(permanent, game)) + .mapToInt(MageObject::getManaValue) + .sum(); + FilterCard filter = new FilterCard(); + filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, manaValue + 1)); + return CardUtil.castSpellWithAttributesForFree( + controller, source, game, new CardsImpl(controller.getHand()), filter + ) || controller.scry(1, source, game); } } diff --git a/Mage.Sets/src/mage/cards/i/InTooDeep.java b/Mage.Sets/src/mage/cards/i/InTooDeep.java new file mode 100644 index 00000000000..c1c14b4a725 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InTooDeep.java @@ -0,0 +1,66 @@ +package mage.cards.i; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BecomesCreatureAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.SplitSecondAbility; +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.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.game.permanent.token.ClueArtifactToken; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InTooDeep extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("creature, planeswalker, or Clue"); + + static { + filter.add(Predicates.or( + CardType.CREATURE.getPredicate(), + CardType.PLANESWALKER.getPredicate(), + SubType.CLUE.getPredicate() + )); + } + + public InTooDeep(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}{U}"); + + this.subtype.add(SubType.AURA); + + // Split second + this.addAbility(new SplitSecondAbility()); + + // Enchant creature, planeswalker, or Clue + TargetPermanent auraTarget = new TargetPermanent(filter); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // Enchanted permanent is a colorless Clue artifact with "{2}, Sacrifice this artifact: Draw a card" and loses all other abilities. + this.addAbility(new SimpleStaticAbility(new BecomesCreatureAttachedEffect( + new ClueArtifactToken(), "enchanted permanent is a colorless Clue artifact with " + + "\"{2}, Sacrifice this artifact: Draw a card\" and loses all other abilities", + Duration.WhileOnBattlefield, BecomesCreatureAttachedEffect.LoseType.ALL + ))); + } + + private InTooDeep(final InTooDeep card) { + super(card); + } + + @Override + public InTooDeep copy() { + return new InTooDeep(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InallaArchmageRitualist.java b/Mage.Sets/src/mage/cards/i/InallaArchmageRitualist.java index b162446354b..3a3e7ec8b21 100644 --- a/Mage.Sets/src/mage/cards/i/InallaArchmageRitualist.java +++ b/Mage.Sets/src/mage/cards/i/InallaArchmageRitualist.java @@ -68,7 +68,7 @@ public final class InallaArchmageRitualist extends CardImpl { new InallaArchmageRitualistEffect(), new ManaCostsImpl("{1}"), "Pay {1} to create a token copy?"), filter, false, SetTargetPointer.PERMANENT, ""), SourceOnBattlefieldOrCommandZoneCondition.instance, - "Eminence — Whenever another nontoken Wizard enters the battlefield under your control, " + "Whenever another nontoken Wizard enters the battlefield under your control, " + "{this} is in the command zone or on the battlefield, " + "you may pay {1}. If you do, create a token that's a copy of that Wizard. " + "That token gains haste. Exile it at the beginning of the next end step"); diff --git a/Mage.Sets/src/mage/cards/i/InameAsOne.java b/Mage.Sets/src/mage/cards/i/InameAsOne.java index 9df76aa7fdf..534465cba2b 100644 --- a/Mage.Sets/src/mage/cards/i/InameAsOne.java +++ b/Mage.Sets/src/mage/cards/i/InameAsOne.java @@ -90,7 +90,7 @@ class InameAsOneEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Card targetCard = game.getCard(getTargetPointer().getFirst(game, source)); if (controller != null && sourceObject != null && targetCard != null) { if (controller.chooseUse(outcome, "Exile " + sourceObject.getLogName() + " to return Spirit card?", source, game)) { diff --git a/Mage.Sets/src/mage/cards/i/InameLifeAspect.java b/Mage.Sets/src/mage/cards/i/InameLifeAspect.java index e5450bcb15c..79e7c52b9f1 100644 --- a/Mage.Sets/src/mage/cards/i/InameLifeAspect.java +++ b/Mage.Sets/src/mage/cards/i/InameLifeAspect.java @@ -76,7 +76,7 @@ class InameLifeAspectEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { if (controller.chooseUse(outcome, "Exile " + sourceObject.getLogName() + " to return Spirit cards?", source, game)) { Effect effect = new ReturnToHandTargetEffect(); diff --git a/Mage.Sets/src/mage/cards/i/IncandescentAria.java b/Mage.Sets/src/mage/cards/i/IncandescentAria.java new file mode 100644 index 00000000000..7105d48dbd2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IncandescentAria.java @@ -0,0 +1,39 @@ +package mage.cards.i; + +import mage.abilities.effects.common.DamageAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.TokenPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IncandescentAria extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("nontoken creature"); + + static { + filter.add(TokenPredicate.FALSE); + } + + public IncandescentAria(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R}{G}{W}"); + + // Incandescent Aria deals 3 damage to each nontoken creature. + this.getSpellAbility().addEffect(new DamageAllEffect(3, filter)); + } + + private IncandescentAria(final IncandescentAria card) { + super(card); + } + + @Override + public IncandescentAria copy() { + return new IncandescentAria(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IncandescentSoulstoke.java b/Mage.Sets/src/mage/cards/i/IncandescentSoulstoke.java index 2aa5999d909..eb03b377ad9 100644 --- a/Mage.Sets/src/mage/cards/i/IncandescentSoulstoke.java +++ b/Mage.Sets/src/mage/cards/i/IncandescentSoulstoke.java @@ -93,7 +93,7 @@ class IncandescentSoulstokeEffect extends OneShotEffect { FilterCard filter = new FilterCreatureCard(); filter.add(SubType.ELEMENTAL.getPredicate()); TargetCardInHand target = new TargetCardInHand(filter); - if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCreatureInPlay, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { diff --git a/Mage.Sets/src/mage/cards/i/IncarnationTechnique.java b/Mage.Sets/src/mage/cards/i/IncarnationTechnique.java index 3834d8b8aa6..20cf455002f 100644 --- a/Mage.Sets/src/mage/cards/i/IncarnationTechnique.java +++ b/Mage.Sets/src/mage/cards/i/IncarnationTechnique.java @@ -67,10 +67,10 @@ class IncarnationTechniqueEffect extends OneShotEffect { player.millCards(5, source, game); TargetCard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (!target.canChoose(source.getControllerId(), source, game)) { return true; } - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card != null) { player.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/i/IncendiaryCommand.java b/Mage.Sets/src/mage/cards/i/IncendiaryCommand.java index 4f9f78e2beb..da9233c3e28 100644 --- a/Mage.Sets/src/mage/cards/i/IncendiaryCommand.java +++ b/Mage.Sets/src/mage/cards/i/IncendiaryCommand.java @@ -36,17 +36,14 @@ public final class IncendiaryCommand extends CardImpl { this.getSpellAbility().addEffect(new DamageTargetEffect(4)); this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); // or Incendiary Command deals 2 damage to each creature; - Mode mode = new Mode(); - mode.addEffect(new DamageAllEffect(2, new FilterCreaturePermanent())); + Mode mode = new Mode(new DamageAllEffect(2, new FilterCreaturePermanent())); this.getSpellAbility().getModes().addMode(mode); // or destroy target nonbasic land; - mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetNonBasicLandPermanent()); this.getSpellAbility().getModes().addMode(mode); // or each player discards all the cards in their hand, then draws that many cards. - mode = new Mode(); - mode.addEffect(new IncendiaryCommandDrawEffect()); + mode = new Mode(new IncendiaryCommandDrawEffect()); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/i/InciteHysteria.java b/Mage.Sets/src/mage/cards/i/InciteHysteria.java index c8458ed25ee..faa103baec5 100644 --- a/Mage.Sets/src/mage/cards/i/InciteHysteria.java +++ b/Mage.Sets/src/mage/cards/i/InciteHysteria.java @@ -69,7 +69,7 @@ class InciteHysteriaEffect extends OneShotEffect { Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source)); if (target != null) { ObjectColor color = target.getColor(game); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { if (permanent.getColor(game).shares(color)) { ContinuousEffect effect = new GainAbilityTargetEffect(new CantBlockAbility(), Duration.EndOfTurn); effect.setTargetPointer(new FixedTarget(permanent, game)); diff --git a/Mage.Sets/src/mage/cards/i/InciteWar.java b/Mage.Sets/src/mage/cards/i/InciteWar.java index e6790395e38..c10ec8bce35 100644 --- a/Mage.Sets/src/mage/cards/i/InciteWar.java +++ b/Mage.Sets/src/mage/cards/i/InciteWar.java @@ -44,8 +44,7 @@ public final class InciteWar extends CardImpl { this.getSpellAbility().addWatcher(new AttackedThisTurnWatcher()); // or creatures you control gain first strike until end of turn. - Mode mode = new Mode(); - mode.addEffect(new GainAbilityAllEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn, filter)); + Mode mode = new Mode(new GainAbilityAllEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn, filter)); this.getSpellAbility().getModes().addMode(mode); // Entwine {2} diff --git a/Mage.Sets/src/mage/cards/i/IncorrigibleYouths.java b/Mage.Sets/src/mage/cards/i/IncorrigibleYouths.java index 4ea10666aee..216e55f723c 100644 --- a/Mage.Sets/src/mage/cards/i/IncorrigibleYouths.java +++ b/Mage.Sets/src/mage/cards/i/IncorrigibleYouths.java @@ -26,7 +26,7 @@ public final class IncorrigibleYouths extends CardImpl { // Haste this.addAbility(HasteAbility.getInstance()); // Madness {2}{R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{2}{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{2}{R}"))); } private IncorrigibleYouths(final IncorrigibleYouths card) { diff --git a/Mage.Sets/src/mage/cards/i/Incriminate.java b/Mage.Sets/src/mage/cards/i/Incriminate.java new file mode 100644 index 00000000000..c0a0a783b40 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/Incriminate.java @@ -0,0 +1,101 @@ +package mage.cards.i; + +import mage.MageItem; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanentSameController; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class Incriminate extends CardImpl { + + public Incriminate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); + + // Choose two target creatures controlled by the same player. That player sacrifices one of them. + this.getSpellAbility().addEffect(new IncriminateEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanentSameController(2)); + } + + private Incriminate(final Incriminate card) { + super(card); + } + + @Override + public Incriminate copy() { + return new Incriminate(this); + } +} + +class IncriminateEffect extends OneShotEffect { + + IncriminateEffect() { + super(Outcome.Benefit); + staticText = "choose two target creatures controlled by the same player. That player sacrifices one of them"; + } + + private IncriminateEffect(final IncriminateEffect effect) { + super(effect); + } + + @Override + public IncriminateEffect copy() { + return new IncriminateEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + List permanents = this + .getTargetPointer() + .getTargets(game, source) + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + Permanent permanent; + switch (permanents.size()) { + case 0: + return false; + case 1: + permanent = permanents.get(0); + break; + case 2: + Player player = game.getPlayer(permanents.get(0).getControllerId()); + if (player == null) { + return false; + } + FilterPermanent filter = new FilterPermanent("creature to sacrifice"); + filter.add(Predicates.or( + permanents + .stream() + .map(MageItem::getId) + .map(ControllerIdPredicate::new) + .collect(Collectors.toList()) + )); + TargetPermanent target = new TargetPermanent(filter); + target.setNotTarget(true); + player.choose(Outcome.Sacrifice, target, source, game); + permanent = game.getPermanent(target.getFirstTarget()); + default: + throw new UnsupportedOperationException("This shouldn't have happened"); + } + return permanent != null && permanent.sacrifice(source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IncubationDruid.java b/Mage.Sets/src/mage/cards/i/IncubationDruid.java index 9fbb7f8f404..0bc69a192da 100644 --- a/Mage.Sets/src/mage/cards/i/IncubationDruid.java +++ b/Mage.Sets/src/mage/cards/i/IncubationDruid.java @@ -195,7 +195,7 @@ class AnyColorLandsProduceManaEffect extends ManaEffect { return types; } inManaTypeCalculation = true; - List lands = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, source.getControllerId(), source.getSourceId(), game); + List lands = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, source.getControllerId(), source, game); for (Permanent land : lands) { Abilities mana = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD); for (ActivatedManaAbilityImpl ability : mana) { diff --git a/Mage.Sets/src/mage/cards/i/IncubationIncongruity.java b/Mage.Sets/src/mage/cards/i/IncubationIncongruity.java index 3d035fe3e61..5ef822d0757 100644 --- a/Mage.Sets/src/mage/cards/i/IncubationIncongruity.java +++ b/Mage.Sets/src/mage/cards/i/IncubationIncongruity.java @@ -1,16 +1,15 @@ package mage.cards.i; import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardSetInfo; import mage.cards.SplitCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SpellAbilityType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; @@ -28,13 +27,10 @@ public final class IncubationIncongruity extends SplitCard { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, new CardType[]{CardType.INSTANT}, "{G/U}", "{1}{G}{U}", SpellAbilityType.SPLIT); // Incubation - // Look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. + // Look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. this.getLeftHalfCard().getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, - StaticValue.get(1), StaticFilters.FILTER_CARD_CREATURE_A, - Zone.LIBRARY, false, true, false, - Zone.HAND, false, false, false - ).setBackInRandomOrder(true)); + 5, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_RANDOM)); // Incongruity // Exile target creature. That creature's controller creates a 3/3 green Frog Lizard creature token. diff --git a/Mage.Sets/src/mage/cards/i/IndathaTriome.java b/Mage.Sets/src/mage/cards/i/IndathaTriome.java index 22d2d1572fe..b6f2baad954 100644 --- a/Mage.Sets/src/mage/cards/i/IndathaTriome.java +++ b/Mage.Sets/src/mage/cards/i/IndathaTriome.java @@ -1,7 +1,7 @@ package mage.cards.i; import mage.abilities.common.EntersBattlefieldTappedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.keyword.CyclingAbility; import mage.abilities.mana.BlackManaAbility; import mage.abilities.mana.GreenManaAbility; @@ -34,7 +34,7 @@ public final class IndathaTriome extends CardImpl { this.addAbility(new EntersBattlefieldTappedAbility()); // Cycling {3} - this.addAbility(new CyclingAbility(new ManaCostsImpl("{3}"))); + this.addAbility(new CyclingAbility(new GenericManaCost(3))); } private IndathaTriome(final IndathaTriome card) { diff --git a/Mage.Sets/src/mage/cards/i/Indestructibility.java b/Mage.Sets/src/mage/cards/i/Indestructibility.java index b94a289101f..7a91e6e81d9 100644 --- a/Mage.Sets/src/mage/cards/i/Indestructibility.java +++ b/Mage.Sets/src/mage/cards/i/Indestructibility.java @@ -1,43 +1,37 @@ - package mage.cards.i; -import java.util.UUID; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.IndestructibleAbility; 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.constants.*; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author North */ public final class Indestructibility extends CardImpl { public Indestructibility(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); this.subtype.add(SubType.AURA); - // Enchant permanent TargetPermanent auraTarget = new TargetPermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Benefit)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // Enchanted permanent is indestructible. - Effect effect = new GainAbilityAttachedEffect(IndestructibleAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield); - effect.setText("Enchanted permanent is indestructible"); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( + IndestructibleAbility.getInstance(), AttachmentType.AURA, + Duration.WhileOnBattlefield, null, "permanent" + ))); } private Indestructibility(final Indestructibility card) { diff --git a/Mage.Sets/src/mage/cards/i/IndomitableCreativity.java b/Mage.Sets/src/mage/cards/i/IndomitableCreativity.java index 679e186ad3d..b0c9866c237 100644 --- a/Mage.Sets/src/mage/cards/i/IndomitableCreativity.java +++ b/Mage.Sets/src/mage/cards/i/IndomitableCreativity.java @@ -71,7 +71,7 @@ class IndomitableCreativityEffect extends OneShotEffect { "For each permanent destroyed this way, " + "its controller reveals cards from the top of their library" + " until an artifact or creature card is revealed and exiles that card. " + - "Those players put the exiled card onto the battlefield, then shuffle"; + "Those players put the exiled cards onto the battlefield, then shuffle"; } public IndomitableCreativityEffect(final IndomitableCreativityEffect effect) { diff --git a/Mage.Sets/src/mage/cards/i/InduceDespair.java b/Mage.Sets/src/mage/cards/i/InduceDespair.java index 2b87a2c8ed6..9985b23a42a 100644 --- a/Mage.Sets/src/mage/cards/i/InduceDespair.java +++ b/Mage.Sets/src/mage/cards/i/InduceDespair.java @@ -25,7 +25,7 @@ import mage.target.targetpointer.FixedTarget; */ public final class InduceDespair extends CardImpl { - private static final FilterCreatureCard filter = new FilterCreatureCard("creature card from your hand"); + private static final FilterCreatureCard filter = new FilterCreatureCard("a creature card from your hand"); public InduceDespair(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{B}"); diff --git a/Mage.Sets/src/mage/cards/i/IndulgeExcess.java b/Mage.Sets/src/mage/cards/i/IndulgeExcess.java new file mode 100644 index 00000000000..6ae13ad047c --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IndulgeExcess.java @@ -0,0 +1,158 @@ +package mage.cards.i; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.AftermathAbility; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SpellAbilityType; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.DamagedEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.CitizenGreenWhiteToken; +import mage.game.permanent.token.TreasureToken; +import mage.watchers.Watcher; + +import java.util.*; + +/** + * @author TheElk801 + */ +public final class IndulgeExcess extends SplitCard { + + public IndulgeExcess(UUID ownerId, CardSetInfo setInfo) { + super( + ownerId, setInfo, + new CardType[]{CardType.SORCERY}, new CardType[]{CardType.SORCERY}, + "{2}{R}", "{1}{R}", SpellAbilityType.SPLIT_AFTERMATH + ); + + // Indulge + // Whenever a creature you control attacks this turn, create a 1/1 green and white Citizen creature token that's tapped and attacking. + this.getLeftHalfCard().getSpellAbility().addEffect( + new CreateDelayedTriggeredAbilityEffect(new IndulgeTriggeredAbility()) + ); + + // Excess + // Aftermath + // Create a Treasure token for each creature you controlled that dealt combat damage to a player this turn. + this.getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); + this.getRightHalfCard().getSpellAbility().addEffect( + new CreateTokenEffect(new TreasureToken(), ExcessValue.instance) + ); + this.getRightHalfCard().getSpellAbility().addWatcher(new ExcessWatcher()); + } + + private IndulgeExcess(final IndulgeExcess card) { + super(card); + } + + @Override + public IndulgeExcess copy() { + return new IndulgeExcess(this); + } +} + +class IndulgeTriggeredAbility extends DelayedTriggeredAbility { + + IndulgeTriggeredAbility() { + super(new CreateTokenEffect( + new CitizenGreenWhiteToken(), 1, true, true + ), Duration.EndOfTurn, false, false); + } + + private IndulgeTriggeredAbility(final IndulgeTriggeredAbility ability) { + super(ability); + } + + @Override + public IndulgeTriggeredAbility copy() { + return new IndulgeTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ATTACKER_DECLARED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return isControlledBy(game.getControllerId(event.getSourceId())); + } + + @Override + public String getTriggerPhrase() { + return "Whenever a creature you control attacks this turn, "; + } +} + +enum ExcessValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return ExcessWatcher.getCount(sourceAbility.getControllerId(), game); + } + + @Override + public ExcessValue copy() { + return this; + } + + @Override + public String getMessage() { + return "creature you controlled that dealt combat damage to a player this turn"; + } + + @Override + public String toString() { + return "1"; + } +} + +class ExcessWatcher extends Watcher { + + private final Map> map = new HashMap<>(); + + ExcessWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.DAMAGED_PLAYER || !((DamagedEvent) event).isCombatDamage()) { + return; + } + Permanent permanent = game.getPermanent(event.getSourceId()); + if (permanent == null) { + return; + } + map.computeIfAbsent( + permanent.getControllerId(), x -> new HashSet<>() + ).add(new MageObjectReference(permanent, game)); + } + + @Override + public void reset() { + super.reset(); + map.clear(); + } + + static int getCount(UUID playerId, Game game) { + return game + .getState() + .getWatcher(ExcessWatcher.class) + .map + .getOrDefault(playerId, Collections.emptySet()) + .size(); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IndustrialAdvancement.java b/Mage.Sets/src/mage/cards/i/IndustrialAdvancement.java new file mode 100644 index 00000000000..4483f7805d9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IndustrialAdvancement.java @@ -0,0 +1,93 @@ +package mage.cards.i; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IndustrialAdvancement extends CardImpl { + + public IndustrialAdvancement(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); + + // At the beginning of your end step, you may sacrifice a creature. If you do, look at the top X cards of your library, when X is that creature's mana value. You may put a creature card from among them onto the battlefield. Put the rest on the bottom of your library in a random order. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new IndustrialAdvancementEffect(), TargetController.YOU, false + )); + } + + private IndustrialAdvancement(final IndustrialAdvancement card) { + super(card); + } + + @Override + public IndustrialAdvancement copy() { + return new IndustrialAdvancement(this); + } +} + +class IndustrialAdvancementEffect extends OneShotEffect { + + IndustrialAdvancementEffect() { + super(Outcome.Benefit); + staticText = "you may sacrifice a creature. If you do, look at the top X cards of your library, " + + "where X is that creature's mana value. You may put a creature card from among them " + + "onto the battlefield. Put the rest on the bottom of your library in a random order"; + } + + private IndustrialAdvancementEffect(final IndustrialAdvancementEffect effect) { + super(effect); + } + + @Override + public IndustrialAdvancementEffect copy() { + return new IndustrialAdvancementEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetPermanent target = new TargetControlledCreaturePermanent(0, 1); + target.setNotTarget(true); + player.choose(outcome, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null || !permanent.sacrifice(source, game)) { + return false; + } + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, permanent.getManaValue())); + if (cards.isEmpty()) { + return true; + } + TargetCard targetCard = new TargetCardInLibrary( + 0, 1, StaticFilters.FILTER_CARD_CREATURE + ); + player.choose(outcome, cards, targetCard, game); + player.moveCards(game.getCard(targetCard.getFirstTarget()), Zone.BATTLEFIELD, source, game); + cards.retainZone(Zone.LIBRARY, game); + player.putCardsOnBottomOfLibrary(cards, game, source, false); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/i/InfernalCaretaker.java b/Mage.Sets/src/mage/cards/i/InfernalCaretaker.java index d02b7a99cd8..12fdda32ad2 100644 --- a/Mage.Sets/src/mage/cards/i/InfernalCaretaker.java +++ b/Mage.Sets/src/mage/cards/i/InfernalCaretaker.java @@ -31,7 +31,7 @@ public final class InfernalCaretaker extends CardImpl { this.toughness = new MageInt(2); // Morph {3}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{B}"))); // When Infernal Caretaker is turned face up, return all Zombie cards from all graveyards to their owners' hands. Effect effect = new ReturnToHandFromGraveyardAllEffect(zombieCard); diff --git a/Mage.Sets/src/mage/cards/i/InfernalDenizen.java b/Mage.Sets/src/mage/cards/i/InfernalDenizen.java index c5d0fd92572..55af6908f0c 100644 --- a/Mage.Sets/src/mage/cards/i/InfernalDenizen.java +++ b/Mage.Sets/src/mage/cards/i/InfernalDenizen.java @@ -108,15 +108,15 @@ class InfernalDenizenEffect extends OneShotEffect { creature.tap(source, game); } TargetOpponent targetOpp = new TargetOpponent(true); - if (targetOpp.canChoose(source.getSourceId(), player.getId(), game) - && targetOpp.choose(Outcome.Detriment, player.getId(), source.getSourceId(), game)) { + if (targetOpp.canChoose(player.getId(), source, game) + && targetOpp.choose(Outcome.Detriment, player.getId(), source.getSourceId(), source, game)) { Player opponent = game.getPlayer(targetOpp.getFirstTarget()); if (opponent != null) { FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creature controlled by " + player.getLogName()); filter2.add(new ControllerIdPredicate(player.getId())); TargetCreaturePermanent targetCreature = new TargetCreaturePermanent(1, 1, filter2, true); targetCreature.setTargetController(opponent.getId()); - if (targetCreature.canChoose(source.getSourceId(), id, game) + if (targetCreature.canChoose(id, source, game) && opponent.chooseUse(Outcome.GainControl, "Gain control of a creature?", source, game) && opponent.chooseTarget(Outcome.GainControl, targetCreature, source, game)) { ConditionalContinuousEffect giveEffect = new ConditionalContinuousEffect( diff --git a/Mage.Sets/src/mage/cards/i/InfernalHarvest.java b/Mage.Sets/src/mage/cards/i/InfernalHarvest.java index 28a3e0ce38a..2133d76aeac 100644 --- a/Mage.Sets/src/mage/cards/i/InfernalHarvest.java +++ b/Mage.Sets/src/mage/cards/i/InfernalHarvest.java @@ -106,7 +106,7 @@ class InfernalHarvestAdditionalCost extends VariableCostImpl { return false; } Player player = game.getPlayer(controllerId); - if (player == null || !targets.choose(Outcome.ReturnToHand, controllerId, source.getSourceId(), game)) { + if (player == null || !targets.choose(Outcome.ReturnToHand, controllerId, source.getSourceId(), source, game)) { return false; } return paid = player.moveCards( diff --git a/Mage.Sets/src/mage/cards/i/InfernalMedusa.java b/Mage.Sets/src/mage/cards/i/InfernalMedusa.java index da01ada6b0a..d3f730dfa94 100644 --- a/Mage.Sets/src/mage/cards/i/InfernalMedusa.java +++ b/Mage.Sets/src/mage/cards/i/InfernalMedusa.java @@ -4,7 +4,7 @@ package mage.cards.i; import java.util.UUID; import mage.MageInt; import mage.abilities.common.BecomesBlockedByCreatureTriggeredAbility; -import mage.abilities.common.BlocksSourceTriggeredAbility; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; @@ -37,7 +37,7 @@ public final class InfernalMedusa extends CardImpl { // Whenever Infernal Medusa blocks a creature, destroy that creature at end of combat. Effect effect = new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(new DestroyTargetEffect()), true); effect.setText("destroy that creature at end of combat"); - this.addAbility(new BlocksSourceTriggeredAbility(effect, false, true)); + this.addAbility(new BlocksCreatureTriggeredAbility(effect)); // Whenever Infernal Medusa becomes blocked by a non-Wall creature, destroy that creature at end of combat. this.addAbility(new BecomesBlockedByCreatureTriggeredAbility(effect, filter, false)); } diff --git a/Mage.Sets/src/mage/cards/i/InfernalOffering.java b/Mage.Sets/src/mage/cards/i/InfernalOffering.java index 210eb5926ea..57b779d2c1a 100644 --- a/Mage.Sets/src/mage/cards/i/InfernalOffering.java +++ b/Mage.Sets/src/mage/cards/i/InfernalOffering.java @@ -72,7 +72,7 @@ class InfernalOfferingSacrificeEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null) { Target target = new TargetOpponent(true); - target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), game); + target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), source, game); Player opponent = game.getPlayer(target.getFirstTarget()); if (opponent != null) { //Choose creatures to sacrifice @@ -80,7 +80,7 @@ class InfernalOfferingSacrificeEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(player.getId(), game)) { if (playerId.equals(player.getId()) || playerId.equals(opponent.getId())) { target = new TargetControlledCreaturePermanent(1, 1, new FilterControlledCreaturePermanent(), true); - if (target.choose(Outcome.Sacrifice, playerId, source.getControllerId(), game)) { + if (target.choose(Outcome.Sacrifice, playerId, source.getControllerId(), source, game)) { toSacrifice.put(playerId, target.getFirstTarget()); } } @@ -130,10 +130,10 @@ class InfernalOfferingReturnEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Target target = new TargetOpponent(true); - target.choose(Outcome.PutCreatureInPlay, source.getControllerId(), source.getSourceId(), game); + target.choose(Outcome.PutCreatureInPlay, source.getControllerId(), source.getSourceId(), source, game); Player opponent = game.getPlayer(target.getFirstTarget()); target = new TargetCardInYourGraveyard(new FilterCreatureCard("creature card in your graveyard")); - if (target.choose(Outcome.PutCreatureInPlay, controller.getId(), source.getSourceId(), game)) { + if (target.choose(Outcome.PutCreatureInPlay, controller.getId(), source.getSourceId(), source, game)) { Card card = controller.getGraveyard().get(target.getFirstTarget(), game); if (card != null) { controller.moveCards(card, Zone.BATTLEFIELD, source, game); @@ -141,7 +141,7 @@ class InfernalOfferingReturnEffect extends OneShotEffect { } if (opponent != null) { target = new TargetCardInYourGraveyard(new FilterCreatureCard("creature card in your graveyard")); - if (target.choose(Outcome.PutCreatureInPlay, opponent.getId(), source.getSourceId(), game)) { + if (target.choose(Outcome.PutCreatureInPlay, opponent.getId(), source.getSourceId(), source, game)) { Card card = opponent.getGraveyard().get(target.getFirstTarget(), game); if (card != null) { opponent.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/i/InfernalTutor.java b/Mage.Sets/src/mage/cards/i/InfernalTutor.java index 489b25114ad..1b7f4d8d2b9 100644 --- a/Mage.Sets/src/mage/cards/i/InfernalTutor.java +++ b/Mage.Sets/src/mage/cards/i/InfernalTutor.java @@ -73,7 +73,7 @@ class InfernalTutorEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { if (!controller.getHand().isEmpty()) { Card cardToReveal = null; diff --git a/Mage.Sets/src/mage/cards/i/InfiltratorsMagemark.java b/Mage.Sets/src/mage/cards/i/InfiltratorsMagemark.java index 7fb640f4b0d..f97afd7e261 100644 --- a/Mage.Sets/src/mage/cards/i/InfiltratorsMagemark.java +++ b/Mage.Sets/src/mage/cards/i/InfiltratorsMagemark.java @@ -88,6 +88,6 @@ class InfiltratorsMagemarkCantBeBlockedAllEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filter.match(permanent, source.getControllerId(), source, game); } } diff --git a/Mage.Sets/src/mage/cards/i/InfusedArrows.java b/Mage.Sets/src/mage/cards/i/InfusedArrows.java index 08f74eb8730..79998c242dc 100644 --- a/Mage.Sets/src/mage/cards/i/InfusedArrows.java +++ b/Mage.Sets/src/mage/cards/i/InfusedArrows.java @@ -1,4 +1,3 @@ - package mage.cards.i; import java.util.UUID; @@ -9,14 +8,12 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.RemovedCountersForCostValue; import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.keyword.SunburstAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Zone; import mage.counters.CounterType; import mage.target.common.TargetCreaturePermanent; @@ -26,16 +23,15 @@ import mage.target.common.TargetCreaturePermanent; */ public final class InfusedArrows extends CardImpl { + private static final DynamicValue xValue = new SignInversionDynamicValue(RemovedCountersForCostValue.instance); + public InfusedArrows(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); // Sunburst this.addAbility(new SunburstAbility(this)); // {tap}, Remove X charge counters from Infused Arrows: Target creature gets -X/-X until end of turn. - DynamicValue value = new SignInversionDynamicValue(RemovedCountersForCostValue.instance); - Effect effect = new BoostTargetEffect(value, value, Duration.EndOfTurn); - effect.setText("Target creature gets -X/-X until end of turn"); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn), new TapSourceCost()); ability.addCost(new RemoveVariableCountersSourceCost(CounterType.CHARGE.createInstance())); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/i/IngeniousSmith.java b/Mage.Sets/src/mage/cards/i/IngeniousSmith.java index 8fd5859aad8..a2cb43b3d2b 100644 --- a/Mage.Sets/src/mage/cards/i/IngeniousSmith.java +++ b/Mage.Sets/src/mage/cards/i/IngeniousSmith.java @@ -4,14 +4,13 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.filter.common.FilterArtifactPermanent; @@ -36,10 +35,7 @@ public final class IngeniousSmith extends CardImpl { // You may reveal an artifact card from among them and put it into your hand. // Put the rest on the bottom of your library in a random order. this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(1), StaticFilters.FILTER_CARD_ARTIFACT_AN, - Zone.LIBRARY, false, true, false, Zone.HAND, - true, false, false).setBackInRandomOrder(true) - )); + 4, 1, StaticFilters.FILTER_CARD_ARTIFACT_AN, PutCards.HAND, PutCards.BOTTOM_RANDOM))); // Whenever one or more artifacts enter the battlefield under your control, put a +1/+1 counter on Ingenious Smith. // This ability triggers only once each turn. diff --git a/Mage.Sets/src/mage/cards/i/InkTreaderNephilim.java b/Mage.Sets/src/mage/cards/i/InkTreaderNephilim.java index ff0a225da3b..9f584c8820d 100644 --- a/Mage.Sets/src/mage/cards/i/InkTreaderNephilim.java +++ b/Mage.Sets/src/mage/cards/i/InkTreaderNephilim.java @@ -138,7 +138,7 @@ class InkTreaderNephilimEffect extends CopySpellForEachItCouldTargetEffect { return game.getBattlefield() .getActivePermanents( StaticFilters.FILTER_PERMANENT_CREATURE, - player.getId(), source.getSourceId(), game + player.getId(), source, game ).stream() .filter(Objects::nonNull) .filter(p -> !p.equals(permanent)) diff --git a/Mage.Sets/src/mage/cards/i/InnerFlameAcolyte.java b/Mage.Sets/src/mage/cards/i/InnerFlameAcolyte.java index 6f45e6c334b..f065920893b 100644 --- a/Mage.Sets/src/mage/cards/i/InnerFlameAcolyte.java +++ b/Mage.Sets/src/mage/cards/i/InnerFlameAcolyte.java @@ -1,7 +1,5 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -12,12 +10,13 @@ import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class InnerFlameAcolyte extends CardImpl { @@ -31,9 +30,12 @@ public final class InnerFlameAcolyte extends CardImpl { this.toughness = new MageInt(2); // When Inner-Flame Acolyte enters the battlefield, target creature gets +2/+0 and gains haste until end of turn. - Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(2, 0, Duration.EndOfTurn)); - ability.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn) - .setText("and gains haste until end of turn")); + Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect( + 2, 0, Duration.EndOfTurn + ).setText("target creature gets +2/+0")); + ability.addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains haste until end of turn")); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/i/InniazTheGaleForce.java b/Mage.Sets/src/mage/cards/i/InniazTheGaleForce.java index 3562ec3dc75..c4bb03519b6 100644 --- a/Mage.Sets/src/mage/cards/i/InniazTheGaleForce.java +++ b/Mage.Sets/src/mage/cards/i/InniazTheGaleForce.java @@ -107,8 +107,8 @@ class InniazTheGaleForceEffect extends OneShotEffect { } private void chooseTargets(Player controller, Game game, Ability source) { - if (game.getBattlefield().count(this.filter, source.getSourceId(), source.getControllerId(), game) > 0) { - controller.choose(Outcome.Neutral, this.target, source.getSourceId(), game); + if (game.getBattlefield().count(this.filter, source.getControllerId(), source, game) > 0) { + controller.choose(Outcome.Neutral, this.target, source, game); } } diff --git a/Mage.Sets/src/mage/cards/i/InnocentTraveler.java b/Mage.Sets/src/mage/cards/i/InnocentTraveler.java index 8e6d2edf044..aa66ac6579a 100644 --- a/Mage.Sets/src/mage/cards/i/InnocentTraveler.java +++ b/Mage.Sets/src/mage/cards/i/InnocentTraveler.java @@ -79,9 +79,9 @@ class InnocentTravelerEffect extends OneShotEffect { TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), opponent.getId(), game) + if (!target.canChoose(opponent.getId(), source, game) || !opponent.chooseUse(Outcome.AIDontUseIt, "Sacrifice a creature?", source, game) - || !opponent.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) { + || !opponent.choose(Outcome.Sacrifice, target, source, game)) { continue; } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/i/Inquisition.java b/Mage.Sets/src/mage/cards/i/Inquisition.java index 4808dec5034..be89d3d9ba0 100644 --- a/Mage.Sets/src/mage/cards/i/Inquisition.java +++ b/Mage.Sets/src/mage/cards/i/Inquisition.java @@ -60,7 +60,7 @@ class InquisitionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && controller != null) { Player targetPlayer = game.getPlayer(source.getFirstTarget()); if (targetPlayer != null) { diff --git a/Mage.Sets/src/mage/cards/i/InquisitorExarch.java b/Mage.Sets/src/mage/cards/i/InquisitorExarch.java index c2ac1e11f29..b484c0aac50 100644 --- a/Mage.Sets/src/mage/cards/i/InquisitorExarch.java +++ b/Mage.Sets/src/mage/cards/i/InquisitorExarch.java @@ -29,8 +29,7 @@ public final class InquisitorExarch extends CardImpl { this.toughness = new MageInt(2); Ability ability = new EntersBattlefieldTriggeredAbility(new GainLifeEffect(2)); - Mode mode = new Mode(); - mode.addEffect(new LoseLifeTargetEffect(2)); + Mode mode = new Mode(new LoseLifeTargetEffect(2)); mode.addTarget(new TargetPlayer()); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/i/InsatiableGorgers.java b/Mage.Sets/src/mage/cards/i/InsatiableGorgers.java index ee73f9ed7a6..a8af08653c7 100644 --- a/Mage.Sets/src/mage/cards/i/InsatiableGorgers.java +++ b/Mage.Sets/src/mage/cards/i/InsatiableGorgers.java @@ -28,7 +28,7 @@ public final class InsatiableGorgers extends CardImpl { this.addAbility(new AttacksEachCombatStaticAbility()); // Madness {3}{R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{3}{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{3}{R}"))); } private InsatiableGorgers(final InsatiableGorgers card) { diff --git a/Mage.Sets/src/mage/cards/i/InsatiableSouleater.java b/Mage.Sets/src/mage/cards/i/InsatiableSouleater.java index b6e2d3b19c9..31bdf5df35a 100644 --- a/Mage.Sets/src/mage/cards/i/InsatiableSouleater.java +++ b/Mage.Sets/src/mage/cards/i/InsatiableSouleater.java @@ -1,37 +1,34 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.PhyrexianManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.ColoredManaSymbol; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author North */ public final class InsatiableSouleater extends CardImpl { public InsatiableSouleater(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BEAST); this.power = new MageInt(5); this.toughness = new MageInt(1); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new GainAbilitySourceEffect(TrampleAbility.getInstance(), Duration.EndOfTurn), - new PhyrexianManaCost(ColoredManaSymbol.G))); + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl<>("{G/P}"))); } private InsatiableSouleater(final InsatiableSouleater card) { diff --git a/Mage.Sets/src/mage/cards/i/InscriptionOfAbundance.java b/Mage.Sets/src/mage/cards/i/InscriptionOfAbundance.java index 017823e60f2..2a3c340f495 100644 --- a/Mage.Sets/src/mage/cards/i/InscriptionOfAbundance.java +++ b/Mage.Sets/src/mage/cards/i/InscriptionOfAbundance.java @@ -89,7 +89,7 @@ class InscriptionOfAbundanceEffect extends OneShotEffect { .getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getFirstTarget(), source.getSourceId(), game + source.getFirstTarget(), source, game ).stream() .filter(Objects::nonNull) .map(MageObject::getPower) diff --git a/Mage.Sets/src/mage/cards/i/InsideOut.java b/Mage.Sets/src/mage/cards/i/InsideOut.java index a998d479b1a..840c1849b95 100644 --- a/Mage.Sets/src/mage/cards/i/InsideOut.java +++ b/Mage.Sets/src/mage/cards/i/InsideOut.java @@ -26,7 +26,7 @@ public final class InsideOut extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } diff --git a/Mage.Sets/src/mage/cards/i/InsidiousDreams.java b/Mage.Sets/src/mage/cards/i/InsidiousDreams.java index af18bb4ef80..afe920eacf8 100644 --- a/Mage.Sets/src/mage/cards/i/InsidiousDreams.java +++ b/Mage.Sets/src/mage/cards/i/InsidiousDreams.java @@ -1,18 +1,18 @@ package mage.cards.i; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.costs.common.DiscardXTargetCost; import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.FilterCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; import java.util.UUID; @@ -26,11 +26,10 @@ public final class InsidiousDreams extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}"); // As an additional cost to cast Insidious Dreams, discard X cards. - this.getSpellAbility().addCost(new DiscardXTargetCost(new FilterCard("cards"), true)); + this.getSpellAbility().addCost(new DiscardXTargetCost(StaticFilters.FILTER_CARD_CARDS, true)); // Search your library for X cards. Then shuffle your library and put those cards on top of it in any order. this.getSpellAbility().addEffect(new InsidiousDreamsEffect()); - } private InsidiousDreams(final InsidiousDreams card) { @@ -45,8 +44,6 @@ public final class InsidiousDreams extends CardImpl { class InsidiousDreamsEffect extends OneShotEffect { - static final private String textTop = "card to put on your library (last chosen will be on top)"; - public InsidiousDreamsEffect() { super(Outcome.Benefit); this.staticText = "Search your library for up to X cards. Then shuffle and put those cards on top of it in any order"; @@ -64,39 +61,17 @@ class InsidiousDreamsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - int amount = GetXValue.instance.calculate(game, source, this); - - if (controller != null && sourceObject != null) { - TargetCardInLibrary target = new TargetCardInLibrary(0, amount, new FilterCard()); - if (controller.searchLibrary(target, source, game)) { - Cards chosen = new CardsImpl(); - for (UUID cardId : target.getTargets()) { - Card card = controller.getLibrary().remove(cardId, game); - chosen.add(card); - } - controller.shuffleLibrary(source, game); - - TargetCard targetToLib = new TargetCard(Zone.LIBRARY, new FilterCard(textTop)); - - while (chosen.size() > 1 && controller.canRespond()) { - controller.choose(Outcome.Neutral, chosen, targetToLib, game); - Card card = chosen.get(targetToLib.getFirstTarget(), game); - if (card != null) { - chosen.remove(card); - controller.moveCardToLibraryWithInfo(card, source, game, Zone.LIBRARY, true, false); - - } - targetToLib.clearChosen(); - } - - if (chosen.size() == 1) { - Card card = chosen.get(chosen.iterator().next(), game); - controller.moveCardToLibraryWithInfo(card, source, game, Zone.LIBRARY, true, false); - } - } - return true; + if (controller == null) { + return false; } - return false; + TargetCardInLibrary target = new TargetCardInLibrary( + 0, GetXValue.instance.calculate(game, source, this), StaticFilters.FILTER_CARD_CARDS + ); + controller.searchLibrary(target, source, game); + Cards chosen = new CardsImpl(); + target.getTargets().stream().forEach(cardId -> controller.getLibrary().getCard(cardId, game)); + controller.shuffleLibrary(source, game); + controller.putCardsOnTopOfLibrary(chosen, game, source, true); + return true; } } diff --git a/Mage.Sets/src/mage/cards/i/InsidiousWill.java b/Mage.Sets/src/mage/cards/i/InsidiousWill.java index fd1b6a5a0d3..b80eb11e458 100644 --- a/Mage.Sets/src/mage/cards/i/InsidiousWill.java +++ b/Mage.Sets/src/mage/cards/i/InsidiousWill.java @@ -30,14 +30,12 @@ public final class InsidiousWill extends CardImpl { getSpellAbility().addTarget(new TargetSpell()); // You may choose new targets for target spell.; - Mode mode = new Mode(); - mode.addEffect(new ChooseNewTargetsTargetEffect()); + Mode mode = new Mode(new ChooseNewTargetsTargetEffect()); mode.addTarget(new TargetSpell()); this.getSpellAbility().addMode(mode); // Copy target instant or sorcery spell. You may choose new targets for the copy. - mode = new Mode(); - mode.addEffect(new CopyTargetSpellEffect()); + mode = new Mode(new CopyTargetSpellEffect()); mode.addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/i/Insist.java b/Mage.Sets/src/mage/cards/i/Insist.java index 68bc2c45084..4be52a9113d 100644 --- a/Mage.Sets/src/mage/cards/i/Insist.java +++ b/Mage.Sets/src/mage/cards/i/Insist.java @@ -78,7 +78,7 @@ class InsistEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null) { return "This spell can't be countered (" + sourceObject.getName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/i/InspireAwe.java b/Mage.Sets/src/mage/cards/i/InspireAwe.java index 483b60114aa..1887efa7d50 100644 --- a/Mage.Sets/src/mage/cards/i/InspireAwe.java +++ b/Mage.Sets/src/mage/cards/i/InspireAwe.java @@ -29,8 +29,8 @@ public final class InspireAwe extends CardImpl { // Prevent all combat damage that would be dealt this turn except by enchanted creatures and enchantment creatures. Scry 2. this.getSpellAbility().addEffect(new PreventAllDamageByAllPermanentsEffect( filter, Duration.EndOfTurn, true - ).setText("Prevent all combat damage that would be dealt this turn " + - "except by enchanted creatures and enchantment creatures.")); + ).setText("prevent all combat damage that would be dealt this turn except combat damage " + + "that would be dealt by enchanted creatures and enchantment creatures")); this.getSpellAbility().addEffect(new ScryEffect(2)); } diff --git a/Mage.Sets/src/mage/cards/i/InspiredSprite.java b/Mage.Sets/src/mage/cards/i/InspiredSprite.java index be6fdb24fac..1363a2fd650 100644 --- a/Mage.Sets/src/mage/cards/i/InspiredSprite.java +++ b/Mage.Sets/src/mage/cards/i/InspiredSprite.java @@ -23,7 +23,7 @@ import mage.filter.FilterSpell; */ public final class InspiredSprite extends CardImpl { - private static final FilterSpell filter = new FilterSpell("Wizard"); + private static final FilterSpell filter = new FilterSpell("a Wizard spell"); static { filter.add(SubType.WIZARD.getPredicate()); diff --git a/Mage.Sets/src/mage/cards/i/InspiringOverseer.java b/Mage.Sets/src/mage/cards/i/InspiringOverseer.java new file mode 100644 index 00000000000..31e3b0a5d27 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InspiringOverseer.java @@ -0,0 +1,46 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InspiringOverseer extends CardImpl { + + public InspiringOverseer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.ANGEL); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Inspiring Overseer enters the battlefield, you gain 1 life and draw a card. + Ability ability = new EntersBattlefieldTriggeredAbility(new GainLifeEffect(1)); + ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); + this.addAbility(ability); + } + + private InspiringOverseer(final InspiringOverseer card) { + super(card); + } + + @Override + public InspiringOverseer copy() { + return new InspiringOverseer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InspiringStatuary.java b/Mage.Sets/src/mage/cards/i/InspiringStatuary.java index 12e8bcda085..33270464a97 100644 --- a/Mage.Sets/src/mage/cards/i/InspiringStatuary.java +++ b/Mage.Sets/src/mage/cards/i/InspiringStatuary.java @@ -17,7 +17,7 @@ import java.util.UUID; */ public final class InspiringStatuary extends CardImpl { - private static final FilterCard filter = new FilterCard("non-artifact spells you cast"); + private static final FilterCard filter = new FilterCard("nonartifact spells"); static { filter.add(Predicates.not(CardType.ARTIFACT.getPredicate())); diff --git a/Mage.Sets/src/mage/cards/i/IntellectualOffering.java b/Mage.Sets/src/mage/cards/i/IntellectualOffering.java index 4bb7af53ada..3be2950e05d 100644 --- a/Mage.Sets/src/mage/cards/i/IntellectualOffering.java +++ b/Mage.Sets/src/mage/cards/i/IntellectualOffering.java @@ -63,7 +63,7 @@ class IntellectualOfferingDrawEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null) { Target target = new TargetOpponent(true); - target.choose(Outcome.DrawCard, source.getControllerId(), source.getSourceId(), game); + target.choose(Outcome.DrawCard, source.getControllerId(), source.getSourceId(), source, game); player.drawCards(3, source, game); Player opponent = game.getPlayer(target.getFirstTarget()); if (opponent != null) { @@ -96,7 +96,7 @@ class IntellectualOfferingUntapEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null) { Target target = new TargetOpponent(true); - target.choose(Outcome.Untap, source.getControllerId(), source.getSourceId(), game); + target.choose(Outcome.Untap, source.getControllerId(), source.getSourceId(), source, game); for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterNonlandPermanent(), player.getId(), game)) { permanent.untap(game); } diff --git a/Mage.Sets/src/mage/cards/i/IntrusivePackbeast.java b/Mage.Sets/src/mage/cards/i/IntrusivePackbeast.java index 9221a1d3050..72d5cb9d373 100644 --- a/Mage.Sets/src/mage/cards/i/IntrusivePackbeast.java +++ b/Mage.Sets/src/mage/cards/i/IntrusivePackbeast.java @@ -29,7 +29,7 @@ public final class IntrusivePackbeast extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // When Intrusive Packbeast enters the battlefield, tap up to two target creatures your opponents control. - Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect().setText("tap up to two target creatures your opponents control")); + Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); ability.addTarget(new TargetOpponentsCreaturePermanent(0, 2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/InventorsGoggles.java b/Mage.Sets/src/mage/cards/i/InventorsGoggles.java index 0f0b6fb10df..345b171287c 100644 --- a/Mage.Sets/src/mage/cards/i/InventorsGoggles.java +++ b/Mage.Sets/src/mage/cards/i/InventorsGoggles.java @@ -1,7 +1,5 @@ - package mage.cards.i; -import java.util.UUID; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; @@ -13,27 +11,27 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterPermanent; +import java.util.UUID; + /** - * * @author emerald000 */ public final class InventorsGoggles extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent(SubType.ARTIFICER, "an Artificer"); + public InventorsGoggles(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +1/+2. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(1, 2, Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 2, Duration.WhileOnBattlefield))); // Whenever an Artificer enters the battlefield under your control, you may attach Inventor's Goggles to it. this.addAbility(new EntersBattlefieldControlledTriggeredAbility( - Zone.BATTLEFIELD, - new AttachEffect(Outcome.BoostCreature, "attach {this} to it"), - new FilterPermanent(SubType.ARTIFICER, "Artificer"), - true, - SetTargetPointer.PERMANENT, - null)); + Zone.BATTLEFIELD, new AttachEffect(Outcome.BoostCreature, "attach {this} to it"), + filter, true, SetTargetPointer.PERMANENT, null + )); // Equip {2} this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2))); diff --git a/Mage.Sets/src/mage/cards/i/InvertTheSkies.java b/Mage.Sets/src/mage/cards/i/InvertTheSkies.java index a738dce64fe..4d484900c98 100644 --- a/Mage.Sets/src/mage/cards/i/InvertTheSkies.java +++ b/Mage.Sets/src/mage/cards/i/InvertTheSkies.java @@ -45,7 +45,7 @@ public final class InvertTheSkies extends CardImpl { this.getSpellAbility().addEffect(new ConditionalContinuousEffect( new GainAbilityControlledEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), new LockedInCondition(new ManaWasSpentCondition(ColoredManaSymbol.U)), - "and creatures you control gain flying until end of turn if {U} was spent to cast it")); + "and creatures you control gain flying until end of turn if {U} was spent to cast this spell")); this.getSpellAbility().addEffect(new InfoEffect("(Do both if {G}{U} was spent.)")); diff --git a/Mage.Sets/src/mage/cards/i/InvigoratedRampage.java b/Mage.Sets/src/mage/cards/i/InvigoratedRampage.java index c4763a2e359..303332f0ace 100644 --- a/Mage.Sets/src/mage/cards/i/InvigoratedRampage.java +++ b/Mage.Sets/src/mage/cards/i/InvigoratedRampage.java @@ -33,10 +33,9 @@ public final class InvigoratedRampage extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Two target creatures each get +2/+0 and gain trample until end of turn. - Mode mode = new Mode(); effect = new BoostTargetEffect(2, 0, Duration.EndOfTurn); effect.setText("Two target creatures each get +2/+0"); - mode.addEffect(effect); + Mode mode = new Mode(effect); effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); effect.setText("and gain trample until end of turn"); mode.addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/i/InvigoratingHotSpring.java b/Mage.Sets/src/mage/cards/i/InvigoratingHotSpring.java index 6876dfb0cfd..25d44dca879 100644 --- a/Mage.Sets/src/mage/cards/i/InvigoratingHotSpring.java +++ b/Mage.Sets/src/mage/cards/i/InvigoratingHotSpring.java @@ -39,7 +39,7 @@ public final class InvigoratingHotSpring extends CardImpl { // Invigorating Hot Spring enters the battlefield with four +1/+1 counters on it. this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect( - CounterType.M1M1.createInstance(4) + CounterType.P1P1.createInstance(4) ), "with four +1/+1 counters on it")); // Modified creatures you control have haste. diff --git a/Mage.Sets/src/mage/cards/i/InvokeCalamity.java b/Mage.Sets/src/mage/cards/i/InvokeCalamity.java new file mode 100644 index 00000000000..fa16d546995 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InvokeCalamity.java @@ -0,0 +1,135 @@ +package mage.cards.i; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.ExileSpellEffect; +import mage.cards.*; +import mage.constants.CardType; +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.events.ZoneChangeEvent; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InvokeCalamity extends CardImpl { + + public InvokeCalamity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}{R}{R}{R}"); + + // You may cast up to two instant and/or sorcery spells with total mana value 6 or less from your graveyard and/or hand without paying their mana costs. If those spells would be put into your graveyard, exile them instead. Exile Invoke Calamity. + this.getSpellAbility().addEffect(new InvokeCalamityEffect()); + this.getSpellAbility().addEffect(new ExileSpellEffect()); + } + + private InvokeCalamity(final InvokeCalamity card) { + super(card); + } + + @Override + public InvokeCalamity copy() { + return new InvokeCalamity(this); + } +} + +class InvokeCalamityEffect extends OneShotEffect { + + InvokeCalamityEffect() { + super(Outcome.Benefit); + staticText = "you may cast up to two instant and/or sorcery spells " + + "with total mana value 6 or less from your graveyard and/or hand without paying their mana costs. " + + "If those spells would be put into your graveyard, exile them instead"; + } + + private InvokeCalamityEffect(final InvokeCalamityEffect effect) { + super(effect); + } + + @Override + public InvokeCalamityEffect copy() { + return new InvokeCalamityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(player.getHand()); + cards.addAll(player.getGraveyard()); + CardUtil.castMultipleWithAttributeForFree( + player, source, game, cards, + StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, + 2, new InvokeCalamityTracker() + ); + return true; + } +} + +class InvokeCalamityTracker implements CardUtil.SpellCastTracker { + + private int totalManaValue = 0; + + @Override + public boolean checkCard(Card card, Game game) { + return card.getManaValue() + totalManaValue <= 6; + } + + @Override + public void addCard(Card card, Ability source, Game game) { + totalManaValue += card.getManaValue(); + game.addEffect(new InvokeCalamityReplacementEffect(card, game), source); + } +} + +class InvokeCalamityReplacementEffect extends ReplacementEffectImpl { + + private final MageObjectReference mor; + + InvokeCalamityReplacementEffect(Card card, Game game) { + super(Duration.EndOfTurn, Outcome.Exile); + this.mor = new MageObjectReference(card.getMainCard(), game); + } + + private InvokeCalamityReplacementEffect(final InvokeCalamityReplacementEffect effect) { + super(effect); + this.mor = effect.mor; + } + + @Override + public InvokeCalamityReplacementEffect copy() { + return new InvokeCalamityReplacementEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + Card card = mor.getCard(game); + return controller != null + && card != null + && controller.moveCards(card, Zone.EXILED, source, game); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + return zEvent.getToZone() == Zone.GRAVEYARD + && zEvent.getTargetId().equals(mor.getSourceId()); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvokeDespair.java b/Mage.Sets/src/mage/cards/i/InvokeDespair.java index edfc786b31c..99ca02842ac 100644 --- a/Mage.Sets/src/mage/cards/i/InvokeDespair.java +++ b/Mage.Sets/src/mage/cards/i/InvokeDespair.java @@ -69,7 +69,7 @@ class InvokeDespairEffect extends OneShotEffect { } Target target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - opponent.choose(outcome, target, source.getSourceId(), game); + opponent.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); boolean sacrificed = false; if (permanent != null) { @@ -81,7 +81,7 @@ class InvokeDespairEffect extends OneShotEffect { } target = new TargetControlledPermanent(enchantmentFilter); target.setNotTarget(true); - opponent.choose(outcome, target, source.getSourceId(), game); + opponent.choose(outcome, target, source, game); permanent = game.getPermanent(target.getFirstTarget()); sacrificed = false; if (permanent != null) { @@ -93,7 +93,7 @@ class InvokeDespairEffect extends OneShotEffect { } target = new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_PLANESWALKER); target.setNotTarget(true); - opponent.choose(outcome, target, source.getSourceId(), game); + opponent.choose(outcome, target, source, game); permanent = game.getPermanent(target.getFirstTarget()); sacrificed = false; if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/i/InvokeJustice.java b/Mage.Sets/src/mage/cards/i/InvokeJustice.java new file mode 100644 index 00000000000..9662a047a43 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InvokeJustice.java @@ -0,0 +1,96 @@ +package mage.cards.i; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetAmount; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetPermanentAmount; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InvokeJustice extends CardImpl { + + private static final FilterCard filter = new FilterPermanentCard("permanent card from your graveyard"); + + public InvokeJustice(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{W}{W}{W}{W}"); + + // Return target permanent card from your graveyard to the battlefield, then distribute four +1/+1 counters among any number of creatures and/or Vehicles target player controls. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); + this.getSpellAbility().addEffect(new InvokeJusticeEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); + this.getSpellAbility().addTarget(new TargetPlayer()); + } + + private InvokeJustice(final InvokeJustice card) { + super(card); + } + + @Override + public InvokeJustice copy() { + return new InvokeJustice(this); + } +} + +class InvokeJusticeEffect extends OneShotEffect { + + InvokeJusticeEffect() { + super(Outcome.Benefit); + staticText = ", then distribute four +1/+1 counters among " + + "any number of creatures and/or Vehicles target player controls"; + this.setTargetPointer(new SecondTargetPointer()); + } + + private InvokeJusticeEffect(final InvokeJusticeEffect effect) { + super(effect); + } + + @Override + public InvokeJusticeEffect copy() { + return new InvokeJusticeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (controller == null || player == null) { + return false; + } + FilterPermanent filter = new FilterPermanent( + "creatures and/or Vehicles controlled by " + player.getName() + ); + filter.add(new ControllerIdPredicate(player.getId())); + if (!game.getBattlefield().contains(filter, source, game, 1)) { + return false; + } + TargetAmount target = new TargetPermanentAmount(4, filter); + target.setNotTarget(true); + controller.choose(outcome, target, source, game); + for (UUID targetId : target.getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + permanent.addCounters(CounterType.P1P1.createInstance(target.getTargetAmount(targetId)), source, game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvokeTheAncients.java b/Mage.Sets/src/mage/cards/i/InvokeTheAncients.java index 1fe3454c314..0ea1288588f 100644 --- a/Mage.Sets/src/mage/cards/i/InvokeTheAncients.java +++ b/Mage.Sets/src/mage/cards/i/InvokeTheAncients.java @@ -71,7 +71,7 @@ class InvokeTheAncientsEffect extends OneShotEffect { if (player == null) { return false; } - token.putOntoBattlefield(1, game, source, source.getControllerId()); + token.putOntoBattlefield(2, game, source, source.getControllerId()); for (UUID tokenId : token.getLastAddedTokenIds()) { Permanent permanent = game.getPermanent(tokenId); if (permanent == null) { diff --git a/Mage.Sets/src/mage/cards/i/InvokeTheFiremind.java b/Mage.Sets/src/mage/cards/i/InvokeTheFiremind.java index 923a95958c6..6cebbb512ec 100644 --- a/Mage.Sets/src/mage/cards/i/InvokeTheFiremind.java +++ b/Mage.Sets/src/mage/cards/i/InvokeTheFiremind.java @@ -22,8 +22,7 @@ public final class InvokeTheFiremind extends CardImpl { this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(ManacostVariableValue.REGULAR)); - Mode mode = new Mode(); - mode.addEffect(new DamageTargetEffect(ManacostVariableValue.REGULAR)); + Mode mode = new Mode(new DamageTargetEffect(ManacostVariableValue.REGULAR)); mode.addTarget(new TargetAnyTarget()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/i/InvoluntaryEmployment.java b/Mage.Sets/src/mage/cards/i/InvoluntaryEmployment.java new file mode 100644 index 00000000000..c750977e792 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InvoluntaryEmployment.java @@ -0,0 +1,42 @@ +package mage.cards.i; + +import java.util.UUID; + +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.game.permanent.token.TreasureToken; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author weirddan455 + */ +public final class InvoluntaryEmployment extends CardImpl { + + public InvoluntaryEmployment(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); + + // Gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn. Create a Treasure token. + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new UntapTargetEffect().setText("Untap that creature")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn).setText("It gains haste until end of turn.")); + this.getSpellAbility().addEffect(new CreateTokenEffect(new TreasureToken())); + } + + private InvoluntaryEmployment(final InvoluntaryEmployment card) { + super(card); + } + + @Override + public InvoluntaryEmployment copy() { + return new InvoluntaryEmployment(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IonStorm.java b/Mage.Sets/src/mage/cards/i/IonStorm.java index 527456f63c7..be134304d2b 100644 --- a/Mage.Sets/src/mage/cards/i/IonStorm.java +++ b/Mage.Sets/src/mage/cards/i/IonStorm.java @@ -28,7 +28,7 @@ public final class IonStorm extends CardImpl { // {1}{R}, Remove a +1/+1 counter or a charge counter from a permanent you control: Ion Storm deals 2 damage to any target. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new ManaCostsImpl("{1}{R}")); - ability.addCost(new OrCost(new RemoveCounterCost(new TargetControlledPermanent(), CounterType.P1P1), new RemoveCounterCost(new TargetControlledPermanent(), CounterType.CHARGE), " Remove a +1/+1 counter or a charge counter from a permanent you control")); + ability.addCost(new OrCost(" Remove a +1/+1 counter or a charge counter from a permanent you control", new RemoveCounterCost(new TargetControlledPermanent(), CounterType.P1P1), new RemoveCounterCost(new TargetControlledPermanent(), CounterType.CHARGE))); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/IonaShieldOfEmeria.java b/Mage.Sets/src/mage/cards/i/IonaShieldOfEmeria.java index 34c419fefaa..5866ece3a74 100644 --- a/Mage.Sets/src/mage/cards/i/IonaShieldOfEmeria.java +++ b/Mage.Sets/src/mage/cards/i/IonaShieldOfEmeria.java @@ -67,7 +67,7 @@ class IonaShieldOfEmeriaReplacementEffect extends ContinuousRuleModifyingEffectI @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { ObjectColor chosenColor = (ObjectColor) game.getState().getValue(source.getSourceId() + "_color"); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null && chosenColor != null) { return "You can't cast " + chosenColor.toString() + " spells (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/i/IreShaman.java b/Mage.Sets/src/mage/cards/i/IreShaman.java index eca51966108..980fc8b7f5c 100644 --- a/Mage.Sets/src/mage/cards/i/IreShaman.java +++ b/Mage.Sets/src/mage/cards/i/IreShaman.java @@ -30,7 +30,7 @@ public final class IreShaman extends CardImpl { this.addAbility(new MenaceAbility()); // Megamorph {R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{R}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{R}"), true)); // When Ire Shaman is turned face up, exile the top card of your library. Until end of turn, you may play that card. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new ExileTopXMayPlayUntilEndOfTurnEffect(1), false)); diff --git a/Mage.Sets/src/mage/cards/i/IronApprentice.java b/Mage.Sets/src/mage/cards/i/IronApprentice.java new file mode 100644 index 00000000000..fbc8996e263 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IronApprentice.java @@ -0,0 +1,105 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.counters.Counter; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IronApprentice extends CardImpl { + + public IronApprentice(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}"); + + this.subtype.add(SubType.CONSTRUCT); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Iron Apprentice enters the battlefield with a +1/+1 counter on it. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect( + CounterType.P1P1.createInstance(1) + ), "with a +1/+1 counter on it")); + + // When Iron Apprentice dies, if it had counters on it, put those counters on target creature you control. + Ability ability = new ConditionalTriggeredAbility( + new DiesSourceTriggeredAbility(new IronApprenticeEffect()), IronApprenticeCondition.instance, + "When {this} dies, if it had counters on it, put those counters on target creature you control." + ); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private IronApprentice(final IronApprentice card) { + super(card); + } + + @Override + public IronApprentice copy() { + return new IronApprentice(this); + } +} + +enum IronApprenticeCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentOrLKI(game); + return permanent != null && permanent + .getCounters(game) + .values() + .stream() + .mapToInt(Counter::getCount) + .anyMatch(x -> x > 0); + } +} + +class IronApprenticeEffect extends OneShotEffect { + + IronApprenticeEffect() { + super(Outcome.Benefit); + } + + private IronApprenticeEffect(final IronApprenticeEffect effect) { + super(effect); + } + + @Override + public IronApprenticeEffect copy() { + return new IronApprenticeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentOrLKI(game); + Permanent creature = game.getPermanent(source.getFirstTarget()); + if (permanent == null || creature == null) { + return false; + } + permanent + .getCounters(game) + .copy() + .values() + .stream() + .forEach(counter -> creature.addCounters(counter, source, game)); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/i/IronfistCrusher.java b/Mage.Sets/src/mage/cards/i/IronfistCrusher.java index be50747fe9f..db6f71dec3d 100644 --- a/Mage.Sets/src/mage/cards/i/IronfistCrusher.java +++ b/Mage.Sets/src/mage/cards/i/IronfistCrusher.java @@ -30,7 +30,7 @@ public final class IronfistCrusher extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CanBlockAdditionalCreatureEffect(0))); // Morph {3}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{W}"))); } private IronfistCrusher(final IronfistCrusher card) { diff --git a/Mage.Sets/src/mage/cards/i/IronsoulEnforcer.java b/Mage.Sets/src/mage/cards/i/IronsoulEnforcer.java new file mode 100644 index 00000000000..d73969abf96 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IronsoulEnforcer.java @@ -0,0 +1,69 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksAloneControlledTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.filter.predicate.mageobject.CommanderPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IronsoulEnforcer extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledPermanent("{this} or a commander you control"); + + static { + filter.add(IronsoulEnforcerPredicate.instance); + } + + public IronsoulEnforcer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SAMURAI); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever Ironsoul Enforcer or a commander you control attacks alone, return target artifact card from your graveyard to the battlefield. + Ability ability = new AttacksAloneControlledTriggeredAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect(), filter, false, false + ); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); + this.addAbility(ability); + } + + private IronsoulEnforcer(final IronsoulEnforcer card) { + super(card); + } + + @Override + public IronsoulEnforcer copy() { + return new IronsoulEnforcer(this); + } +} + +enum IronsoulEnforcerPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return input.getObject().getId().equals(input.getSourceId()) + || CommanderPredicate.instance.apply(input.getObject(), game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/i/IrresistiblePrey.java b/Mage.Sets/src/mage/cards/i/IrresistiblePrey.java index dd7304c09f3..a1448b907f0 100644 --- a/Mage.Sets/src/mage/cards/i/IrresistiblePrey.java +++ b/Mage.Sets/src/mage/cards/i/IrresistiblePrey.java @@ -24,7 +24,7 @@ public final class IrresistiblePrey extends CardImpl { // Draw a card. this.getSpellAbility().addEffect(new MustBeBlockedByAtLeastOneTargetEffect(Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private IrresistiblePrey(final IrresistiblePrey card) { diff --git a/Mage.Sets/src/mage/cards/i/IshkanahBroodmother.java b/Mage.Sets/src/mage/cards/i/IshkanahBroodmother.java new file mode 100644 index 00000000000..22a9c2fdcf6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IshkanahBroodmother.java @@ -0,0 +1,85 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.ExileFromGraveCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DraftFromSpellbookEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.keyword.ReachAbility; +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.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IshkanahBroodmother extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.SPIDER, "Spiders"); + private static final List spellbook = Collections.unmodifiableList(Arrays.asList( + "Arachnoform", + "Brood Weaver", + "Drider", + // "Glowstone Recluse", mutate card + "Gnottvold Recluse", + "Hatchery Spider", + "Mammoth Spider", + "Netcaster Spider", + "Prey Upon", + "Sentinel Spider", + "Snarespinner", + "Spider Spawning", + "Spidery Grasp", + "Sporecap Spider", + "Twin-Silk Spider" + )); + + public IshkanahBroodmother(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SPIDER); + this.power = new MageInt(3); + this.toughness = new MageInt(5); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Other Spiders you control get +1/+2. + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 2, Duration.WhileOnBattlefield, filter, true + ))); + + // {1}{B/G}, Exile two cards from your graveyard: Draft a card from Ishkanah, Broodmother's spellbook. + Ability ability = new SimpleActivatedAbility( + new DraftFromSpellbookEffect(spellbook), new ManaCostsImpl<>("{1}{B/G}") + ); + ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard( + 2, StaticFilters.FILTER_CARD_CARDS + ))); + this.addAbility(ability); + } + + private IshkanahBroodmother(final IshkanahBroodmother card) { + super(card); + } + + @Override + public IshkanahBroodmother copy() { + return new IshkanahBroodmother(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IsochronScepter.java b/Mage.Sets/src/mage/cards/i/IsochronScepter.java index b52f68e325d..dc454a3b565 100644 --- a/Mage.Sets/src/mage/cards/i/IsochronScepter.java +++ b/Mage.Sets/src/mage/cards/i/IsochronScepter.java @@ -11,10 +11,7 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; @@ -36,7 +33,7 @@ public final class IsochronScepter extends CardImpl { // Imprint - When Isochron Scepter enters the battlefield, you may exile an instant card with converted mana cost 2 or less from your hand. this.addAbility(new EntersBattlefieldTriggeredAbility( new IsochronScepterImprintEffect(),true) - .withFlavorWord("Imprint") + .setAbilityWord(AbilityWord.IMPRINT) ); // {2}, {T}: You may copy the exiled card. If you do, you may cast the copy without paying its mana cost. @@ -83,7 +80,7 @@ class IsochronScepterImprintEffect extends OneShotEffect { if (controller != null) { if (!controller.getHand().isEmpty()) { TargetCard target = new TargetCard(Zone.HAND, filter); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + if (target.canChoose(source.getControllerId(), source, game) && controller.choose(Outcome.Benefit, controller.getHand(), target, game)) { Card card = controller.getHand().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/i/ItThatBetrays.java b/Mage.Sets/src/mage/cards/i/ItThatBetrays.java index 1ae54306a7e..866c8b2165c 100644 --- a/Mage.Sets/src/mage/cards/i/ItThatBetrays.java +++ b/Mage.Sets/src/mage/cards/i/ItThatBetrays.java @@ -1,7 +1,5 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.OpponentSacrificesNonTokenPermanentTriggeredAbility; import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlTargetEffect; @@ -13,8 +11,9 @@ import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.predicate.permanent.TokenPredicate; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class ItThatBetrays extends CardImpl { @@ -26,7 +25,7 @@ public final class ItThatBetrays extends CardImpl { } public ItThatBetrays(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{12}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{12}"); this.subtype.add(SubType.ELDRAZI); this.power = new MageInt(11); @@ -36,7 +35,10 @@ public final class ItThatBetrays extends CardImpl { this.addAbility(new AnnihilatorAbility(2)); // Whenever an opponent sacrifices a nontoken permanent, put that card onto the battlefield under your control. - this.addAbility(new OpponentSacrificesNonTokenPermanentTriggeredAbility(new ReturnToBattlefieldUnderYourControlTargetEffect())); + this.addAbility(new OpponentSacrificesNonTokenPermanentTriggeredAbility( + new ReturnToBattlefieldUnderYourControlTargetEffect() + .setText("put that card onto the battlefield under your control") + )); } private ItThatBetrays(final ItThatBetrays card) { @@ -47,5 +49,4 @@ public final class ItThatBetrays extends CardImpl { public ItThatBetrays copy() { return new ItThatBetrays(this); } - } diff --git a/Mage.Sets/src/mage/cards/i/IvoryCharm.java b/Mage.Sets/src/mage/cards/i/IvoryCharm.java index 823b16b2d66..9abfe3b9a57 100644 --- a/Mage.Sets/src/mage/cards/i/IvoryCharm.java +++ b/Mage.Sets/src/mage/cards/i/IvoryCharm.java @@ -25,13 +25,11 @@ public final class IvoryCharm extends CardImpl { // Choose one - All creatures get -2/-0 until end of turn this.getSpellAbility().addEffect(new BoostAllEffect(-2, 0, Duration.EndOfTurn)); // or tap target creature - Mode mode = new Mode(); - mode.addEffect(new TapTargetEffect()); + Mode mode = new Mode(new TapTargetEffect()); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or prevent the next 1 damage that would be dealt to any target this turn. - mode = new Mode(); - mode.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, 1)); + mode = new Mode(new PreventDamageToTargetEffect(Duration.EndOfTurn, 1)); mode.addTarget(new TargetAnyTarget()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/i/IvoryGiant.java b/Mage.Sets/src/mage/cards/i/IvoryGiant.java index 9b7908cddba..e56336a73df 100644 --- a/Mage.Sets/src/mage/cards/i/IvoryGiant.java +++ b/Mage.Sets/src/mage/cards/i/IvoryGiant.java @@ -37,7 +37,7 @@ public final class IvoryGiant extends CardImpl { // When Ivory Giant enters the battlefield, tap all nonwhite creatures. this.addAbility(new EntersBattlefieldTriggeredAbility(new TapAllEffect(filter))); // Suspend 5-{W} - this.addAbility(new SuspendAbility(5, new ManaCostsImpl("{W"), this)); + this.addAbility(new SuspendAbility(5, new ManaCostsImpl("{W}"), this)); } private IvoryGiant(final IvoryGiant card) { diff --git a/Mage.Sets/src/mage/cards/i/IwamoriOfTheOpenFist.java b/Mage.Sets/src/mage/cards/i/IwamoriOfTheOpenFist.java index d20131802f3..b4d0ed82e34 100644 --- a/Mage.Sets/src/mage/cards/i/IwamoriOfTheOpenFist.java +++ b/Mage.Sets/src/mage/cards/i/IwamoriOfTheOpenFist.java @@ -81,7 +81,7 @@ class IwamoriOfTheOpenFistEffect extends OneShotEffect { for (UUID playerId : game.getOpponents(controller.getId())) { Player opponent = game.getPlayer(playerId); Target target = new TargetCardInHand(filter); - if (opponent != null && target.canChoose(source.getSourceId(), opponent.getId(), game)) { + if (opponent != null && target.canChoose(opponent.getId(), source, game)) { if (opponent.chooseUse(Outcome.PutCreatureInPlay, "Put a legendary creature card from your hand onto the battlefield?", source, game)) { if (target.chooseTarget(Outcome.PutCreatureInPlay, opponent.getId(), source, game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/i/Ixidron.java b/Mage.Sets/src/mage/cards/i/Ixidron.java index 59698198cc2..276024aaff8 100644 --- a/Mage.Sets/src/mage/cards/i/Ixidron.java +++ b/Mage.Sets/src/mage/cards/i/Ixidron.java @@ -3,6 +3,7 @@ package mage.cards.i; import java.util.UUID; import mage.MageInt; +import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; @@ -43,7 +44,7 @@ public final class Ixidron extends CardImpl { this.toughness = new MageInt(0); // As Ixidron enters the battlefield, turn all other nontoken creatures face down. - this.addAbility(new EntersBattlefieldAbility(new BecomesFaceDownCreatureAllEffect(filterTurnFaceDown))); + this.addAbility(new AsEntersBattlefieldAbility(new BecomesFaceDownCreatureAllEffect(filterTurnFaceDown))); // Ixidron's power and toughness are each equal to the number of face-down creatures on the battlefield. this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new PermanentsOnBattlefieldCount(filter), Duration.EndOfGame))); diff --git a/Mage.Sets/src/mage/cards/i/IzoniThousandEyed.java b/Mage.Sets/src/mage/cards/i/IzoniThousandEyed.java index 7d5b792d5ad..507a92a3eb1 100644 --- a/Mage.Sets/src/mage/cards/i/IzoniThousandEyed.java +++ b/Mage.Sets/src/mage/cards/i/IzoniThousandEyed.java @@ -11,12 +11,9 @@ import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GainLifeEffect; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.constants.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.permanent.token.IzoniInsectToken; import mage.target.common.TargetControlledPermanent; @@ -44,7 +41,7 @@ public final class IzoniThousandEyed extends CardImpl { StaticFilters.FILTER_CARD_CREATURE ) ), false) - .withFlavorWord("Undergrowth") + .setAbilityWord(AbilityWord.UNDERGROWTH) ); // {B}{G}, Sacrifice another creature: You gain 1 life and draw a card. diff --git a/Mage.Sets/src/mage/cards/i/IzzetCharm.java b/Mage.Sets/src/mage/cards/i/IzzetCharm.java index 3f65a58a442..603d6f1d69c 100644 --- a/Mage.Sets/src/mage/cards/i/IzzetCharm.java +++ b/Mage.Sets/src/mage/cards/i/IzzetCharm.java @@ -28,14 +28,12 @@ public final class IzzetCharm extends CardImpl { this.getSpellAbility().getTargets().add(new TargetSpell(StaticFilters.FILTER_SPELL_NON_CREATURE)); // or Izzet Charm deals 2 damage to target creature; - Mode mode = new Mode(); - mode.addEffect(new DamageTargetEffect(2)); + Mode mode = new Mode(new DamageTargetEffect(2)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or draw two cards, then discard two cards. - mode = new Mode(); - mode.addEffect(new DrawDiscardControllerEffect(2, 2)); + mode = new Mode(new DrawDiscardControllerEffect(2, 2)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/i/IzzetChemister.java b/Mage.Sets/src/mage/cards/i/IzzetChemister.java index eaf33025caf..82df45de737 100644 --- a/Mage.Sets/src/mage/cards/i/IzzetChemister.java +++ b/Mage.Sets/src/mage/cards/i/IzzetChemister.java @@ -9,37 +9,26 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.keyword.HasteAbility; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.common.FilterOwnedCard; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; import mage.game.ExileZone; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInExile; +import mage.target.common.TargetCardInGraveyard; +import mage.util.CardUtil; import java.util.UUID; -import mage.ApprovingObject; /** * @author TheElk801 */ public final class IzzetChemister extends CardImpl { - private static final FilterCard filter = new FilterOwnedCard("instant or sorcery card from your graveyard"); - - static { - filter.add(Predicates.or( - CardType.INSTANT.getPredicate(), - CardType.SORCERY.getPredicate()) - ); - } - public IzzetChemister(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); @@ -51,15 +40,16 @@ public final class IzzetChemister extends CardImpl { // Haste this.addAbility(HasteAbility.getInstance()); - // R, T: Exile target instant or sorcery card from your graveyard. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(this.getId(), this.getIdName()), new ManaCostsImpl("{R}")); + // {R}, {T}: Exile target instant or sorcery card from your graveyard. + Ability ability = new SimpleActivatedAbility( + new ExileTargetEffect().setToSourceExileZone(true), new ManaCostsImpl<>("{R}") + ); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCard(Zone.GRAVEYARD, filter)); + ability.addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); - // 1R, T: Sacrifice Izzet Chemister: Cast any number of cards exiled with Izzet Chemister without paying their mana costs. - IzzetChemisterCastFromExileEffect returnFromExileEffect = new IzzetChemisterCastFromExileEffect(this.getId(), "Cast any number of cards exiled with {this} without paying their mana costs."); - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, returnFromExileEffect, new ManaCostsImpl("{1}{R}")); + // {1}{R}, {T}: Sacrifice Izzet Chemister: Cast any number of cards exiled with Izzet Chemister without paying their mana costs. + ability = new SimpleActivatedAbility(new IzzetChemisterCastFromExileEffect(), new ManaCostsImpl<>("{1}{R}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); @@ -77,17 +67,13 @@ public final class IzzetChemister extends CardImpl { class IzzetChemisterCastFromExileEffect extends OneShotEffect { - private final UUID exileId; - - public IzzetChemisterCastFromExileEffect(UUID exileId, String description) { + public IzzetChemisterCastFromExileEffect() { super(Outcome.PlayForFree); - this.exileId = exileId; - this.setText(description); + staticText = "cast any number of cards exiled with {this} without paying their mana costs"; } public IzzetChemisterCastFromExileEffect(final IzzetChemisterCastFromExileEffect effect) { super(effect); - this.exileId = effect.exileId; } @Override @@ -97,38 +83,15 @@ class IzzetChemisterCastFromExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - ExileZone exile = game.getExile().getExileZone(exileId); Player controller = game.getPlayer(source.getControllerId()); - FilterCard filter = new FilterCard(); - if (controller != null - && exile != null) { - Cards cardsToExile = new CardsImpl(); - cardsToExile.addAll(exile.getCards(game)); - OuterLoop: - while (cardsToExile.count(filter, game) > 0) { - if (!controller.canRespond()) { - return false; - } - TargetCardInExile target = new TargetCardInExile(0, 1, filter, exileId, false); - target.setNotTarget(true); - while (controller.canRespond() - && cardsToExile.count(filter, game) > 0 - && controller.choose(Outcome.PlayForFree, cardsToExile, target, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(card, game, true), game, true, - new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - cardsToExile.remove(card); - } else { - break OuterLoop; - } - target.clearChosen(); - } - } - return true; + ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + if (controller == null || exile == null || exile.isEmpty()) { + return false; } - return false; + CardUtil.castMultipleWithAttributeForFree( + controller, source, game, new CardsImpl(exile), + StaticFilters.FILTER_CARD + ); + return true; } } diff --git a/Mage.Sets/src/mage/cards/i/IzzetChronarch.java b/Mage.Sets/src/mage/cards/i/IzzetChronarch.java index 11187f5bfae..5f9864506d5 100644 --- a/Mage.Sets/src/mage/cards/i/IzzetChronarch.java +++ b/Mage.Sets/src/mage/cards/i/IzzetChronarch.java @@ -1,11 +1,9 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -14,8 +12,9 @@ import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Loki */ public final class IzzetChronarch extends CardImpl { @@ -29,14 +28,14 @@ public final class IzzetChronarch extends CardImpl { } public IzzetChronarch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{R}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(2); this.toughness = new MageInt(2); - Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), false); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/IzzetStaticaster.java b/Mage.Sets/src/mage/cards/i/IzzetStaticaster.java index 163a71b6350..65a4ff8fe6b 100644 --- a/Mage.Sets/src/mage/cards/i/IzzetStaticaster.java +++ b/Mage.Sets/src/mage/cards/i/IzzetStaticaster.java @@ -84,7 +84,7 @@ class IzzetStaticasterDamageEffect extends OneShotEffect { } else { filter.add(new NamePredicate(targetPermanent.getName())); } - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanent.damage(1, source.getSourceId(), source, game, false, true); } return true; diff --git a/Mage.Sets/src/mage/cards/j/JabbaTheHutt.java b/Mage.Sets/src/mage/cards/j/JabbaTheHutt.java index 0c289d72f73..c4924dc03ee 100644 --- a/Mage.Sets/src/mage/cards/j/JabbaTheHutt.java +++ b/Mage.Sets/src/mage/cards/j/JabbaTheHutt.java @@ -21,13 +21,14 @@ import mage.constants.Outcome; import mage.constants.SuperType; import mage.constants.Zone; import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterOpponentsCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.HunterToken; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; -import mage.target.common.TargetOpponentsCreaturePermanent; /** * @@ -35,7 +36,7 @@ import mage.target.common.TargetOpponentsCreaturePermanent; */ public final class JabbaTheHutt extends CardImpl { - private static final FilterOpponentsCreaturePermanent filter = new FilterOpponentsCreaturePermanent("creature an opponent control with a bounty counter on it"); + private static final FilterPermanent filter = new FilterOpponentsCreaturePermanent("creature an opponent controls with a bounty counter on it"); static { filter.add(CounterType.BOUNTY.getPredicate()); @@ -58,9 +59,9 @@ public final class JabbaTheHutt extends CardImpl { this.addAbility(ability); // {R},{T}: Create a tapped 4/4 red Hunter creature token. It fights another target creature an opponent control with a bounty counter on it. Activate this ability only any time you could cast a sorcery. - ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new JabbaTheHuttEffect(), new ManaCostsImpl("R")); + ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new JabbaTheHuttEffect(), new ManaCostsImpl<>("{R}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetOpponentsCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/j/JaceArcaneStrategist.java b/Mage.Sets/src/mage/cards/j/JaceArcaneStrategist.java index cec4fe502cd..3ed23ece1d1 100644 --- a/Mage.Sets/src/mage/cards/j/JaceArcaneStrategist.java +++ b/Mage.Sets/src/mage/cards/j/JaceArcaneStrategist.java @@ -3,7 +3,6 @@ package mage.cards.j; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.DrawSecondCardTriggeredAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.combat.CantBeBlockedAllEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; @@ -29,7 +28,7 @@ public final class JaceArcaneStrategist extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.JACE); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // Whenever you draw your second card each turn, put a +1/+1 counter on target creature you control. Ability ability = new DrawSecondCardTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java b/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java index 400790cc83b..b14153cddbb 100644 --- a/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java +++ b/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java @@ -3,32 +3,24 @@ package mage.cards.j; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.*; import mage.constants.*; import mage.filter.FilterCard; -import mage.filter.FilterPlayer; -import mage.filter.common.FilterNonlandCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.other.PlayerIdPredicate; -import mage.game.ExileZone; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetCard; -import mage.target.TargetPlayer; -import mage.target.common.TargetCardInExile; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetOpponent; import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; -import java.util.*; -import mage.ApprovingObject; +import java.util.ArrayList; +import java.util.Set; +import java.util.UUID; /** * @author LevelX2 @@ -40,7 +32,7 @@ public final class JaceArchitectOfThought extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.JACE); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Until your next turn, whenever a creature an opponent controls attacks, it gets -1/-0 until end of turn. this.addAbility(new LoyaltyAbility(new JaceArchitectOfThoughtStartEffect1(), 1)); @@ -52,7 +44,6 @@ public final class JaceArchitectOfThought extends CardImpl { // -8: For each player, search that player's library for a nonland card and exile it, // then that player shuffles their library. You may cast those cards without paying their mana costs. this.addAbility(new LoyaltyAbility(new JaceArchitectOfThoughtEffect3(), -8)); - } private JaceArchitectOfThought(final JaceArchitectOfThought card) { @@ -92,7 +83,7 @@ class JaceArchitectOfThoughtStartEffect1 extends OneShotEffect { class JaceArchitectOfThoughtDelayedTriggeredAbility extends DelayedTriggeredAbility { - private int startingTurn; + private final int startingTurn; public JaceArchitectOfThoughtDelayedTriggeredAbility(int startingTurn) { super(new BoostTargetEffect(-1, 0, Duration.EndOfTurn), Duration.Custom, false); @@ -230,83 +221,33 @@ class JaceArchitectOfThoughtEffect3 extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (controller == null || sourcePermanent == null) { + if (controller == null) { return false; } - if (controller.chooseUse(Outcome.Benefit, "Look at all players' libraries before card select?", null, game)) { + if (controller.chooseUse(Outcome.Benefit, "Look at all players' libraries before card select?", source, game)) { game.informPlayers(controller.getLogName() + " is looking at all players' libraries."); controller.lookAtAllLibraries(source, game); } - List playerList = new ArrayList<>(); - playerList.addAll(game.getState().getPlayersInRange(controller.getId(), game)); - Set checkList = new HashSet<>(); - while (!playerList.isEmpty()) { - FilterPlayer filter = new FilterPlayer(); - List playerPredicates = new ArrayList<>(); - playerList.forEach((playerId) -> { - playerPredicates.add(new PlayerIdPredicate(playerId)); - }); - filter.add(Predicates.or(playerPredicates)); - TargetPlayer targetPlayer = new TargetPlayer(1, 1, true, filter); - targetPlayer.setRequired(!checkList.containsAll(playerList)); - if (controller.chooseTarget(outcome, targetPlayer, source, game)) { - UUID playerId = targetPlayer.getFirstTarget(); - Player player = game.getPlayer(playerId); - if (player != null) { - String playerName = player.getLogName() + "'s"; - if (source.isControlledBy(player.getId())) { - playerName = "your"; - } - TargetCardInLibrary target = new TargetCardInLibrary(new FilterNonlandCard("nonland card from " + playerName + " library")); - if (controller.searchLibrary(target, source, game, playerId)) { - checkList.add(playerId); - UUID targetId = target.getFirstTarget(); - Card card = player.getLibrary().remove(targetId, game); - if (card != null) { - controller.moveCardsToExile(card, source, game, true, CardUtil.getCardExileZoneId(game, source), sourcePermanent.getName()); - playerList.remove(playerId); - } - } else { - playerList.remove(playerId); - } - } else { - playerList.remove(playerId); - } - } else { - break; + Cards cards = new CardsImpl(); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player == null) { + continue; } - - // remove disconnected or quit players - playerList.removeIf(playerId -> game.getPlayer(playerId) == null || !game.getPlayer(playerId).canRespond()); - } - checkList.stream().map((playerId) -> game.getPlayer(playerId)).filter((player) -> (player != null)).forEachOrdered((player) -> { + TargetCardInLibrary target = new TargetCardInLibrary( + 0, 1, StaticFilters.FILTER_CARD_A_NON_LAND + ); + controller.searchLibrary(target, source, game, playerId); + Card card = player.getLibrary().getCard(target.getFirstTarget(), game); + if (card == null) { + continue; + } + cards.add(card); + controller.moveCards(card, Zone.EXILED, source, game); player.shuffleLibrary(source, game); - }); - ExileZone jaceExileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); - if (jaceExileZone == null) { - return true; - } - FilterCard filter = new FilterCard("card to cast without mana costs"); - TargetCardInExile target = new TargetCardInExile(filter, source.getSourceId()); - Cards cardsToChoose = new CardsImpl(jaceExileZone.getCards(game)); - while (controller.canRespond() - && cardsToChoose.count(filter, game) > 0 - && controller.chooseUse(Outcome.Benefit, "Cast another spell from exile zone for free?", source, game)) { - controller.choose(Outcome.PlayForFree, cardsToChoose, target, game); - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - cardsToChoose.remove(card); - if (cardWasCast) { - game.getExile().removeCard(card, game); - } - } - target.clearChosen(); } + cards.retainZone(Zone.EXILED, game); + CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, StaticFilters.FILTER_CARD); return true; } } diff --git a/Mage.Sets/src/mage/cards/j/JaceBeleren.java b/Mage.Sets/src/mage/cards/j/JaceBeleren.java index 27a93f560b1..7ea444b8510 100644 --- a/Mage.Sets/src/mage/cards/j/JaceBeleren.java +++ b/Mage.Sets/src/mage/cards/j/JaceBeleren.java @@ -3,7 +3,6 @@ package mage.cards.j; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DrawCardAllEffect; import mage.abilities.effects.common.DrawCardTargetEffect; import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect; @@ -25,7 +24,7 @@ public final class JaceBeleren extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.JACE); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +2: Each player draws a card. this.addAbility(new LoyaltyAbility(new DrawCardAllEffect(1), 2)); diff --git a/Mage.Sets/src/mage/cards/j/JaceCunningCastaway.java b/Mage.Sets/src/mage/cards/j/JaceCunningCastaway.java index ec38cad3e7d..7b83bde8d7c 100644 --- a/Mage.Sets/src/mage/cards/j/JaceCunningCastaway.java +++ b/Mage.Sets/src/mage/cards/j/JaceCunningCastaway.java @@ -4,7 +4,6 @@ package mage.cards.j; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.effects.common.CreateTokenEffect; @@ -34,7 +33,7 @@ public final class JaceCunningCastaway extends CardImpl { addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.JACE); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Whenever one or more creatures you control deal combat damage to a player this turn, draw a card, then discard a card. this.addAbility(new LoyaltyAbility(new JaceCunningCastawayEffect1(), 1)); diff --git a/Mage.Sets/src/mage/cards/j/JaceIngeniousMindMage.java b/Mage.Sets/src/mage/cards/j/JaceIngeniousMindMage.java index 686cdc5f704..dc7a2f301d7 100644 --- a/Mage.Sets/src/mage/cards/j/JaceIngeniousMindMage.java +++ b/Mage.Sets/src/mage/cards/j/JaceIngeniousMindMage.java @@ -4,7 +4,6 @@ package mage.cards.j; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.UntapAllControllerEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; @@ -29,7 +28,7 @@ public final class JaceIngeniousMindMage extends CardImpl { addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.JACE); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Draw a card. this.addAbility(new LoyaltyAbility(new DrawCardSourceControllerEffect(1), 1)); diff --git a/Mage.Sets/src/mage/cards/j/JaceMemoryAdept.java b/Mage.Sets/src/mage/cards/j/JaceMemoryAdept.java index 1d15ffea264..04ab1c419a2 100644 --- a/Mage.Sets/src/mage/cards/j/JaceMemoryAdept.java +++ b/Mage.Sets/src/mage/cards/j/JaceMemoryAdept.java @@ -5,7 +5,6 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.Mode; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawCardTargetEffect; import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect; @@ -28,7 +27,7 @@ public final class JaceMemoryAdept extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.JACE); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Draw a card. Target player puts the top card of their library into their graveyard. LoyaltyAbility ability1 = new LoyaltyAbility(new DrawCardSourceControllerEffect(1), 1); diff --git a/Mage.Sets/src/mage/cards/j/JaceMirrorMage.java b/Mage.Sets/src/mage/cards/j/JaceMirrorMage.java index faabc94065e..f16da18f0b7 100644 --- a/Mage.Sets/src/mage/cards/j/JaceMirrorMage.java +++ b/Mage.Sets/src/mage/cards/j/JaceMirrorMage.java @@ -3,7 +3,6 @@ package mage.cards.j; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.condition.common.KickedCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -36,7 +35,7 @@ public final class JaceMirrorMage extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.JACE); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // Kicker {2} this.addAbility(new KickerAbility("{2}")); diff --git a/Mage.Sets/src/mage/cards/j/JaceTelepathUnbound.java b/Mage.Sets/src/mage/cards/j/JaceTelepathUnbound.java index 2ae3ad22e52..bc67fa20ea3 100644 --- a/Mage.Sets/src/mage/cards/j/JaceTelepathUnbound.java +++ b/Mage.Sets/src/mage/cards/j/JaceTelepathUnbound.java @@ -3,7 +3,6 @@ package mage.cards.j; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.*; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -32,7 +31,7 @@ public final class JaceTelepathUnbound extends CardImpl { this.color.setBlue(true); this.nightCard = true; - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Up to one target creature gets -2/-0 until your next turn. Effect effect = new BoostTargetEffect(-2, 0, Duration.UntilYourNextTurn); diff --git a/Mage.Sets/src/mage/cards/j/JaceTheLivingGuildpact.java b/Mage.Sets/src/mage/cards/j/JaceTheLivingGuildpact.java index c905f3cacc5..f79268e9ec2 100644 --- a/Mage.Sets/src/mage/cards/j/JaceTheLivingGuildpact.java +++ b/Mage.Sets/src/mage/cards/j/JaceTheLivingGuildpact.java @@ -2,11 +2,9 @@ package mage.cards.j; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.effects.common.ShuffleHandGraveyardAllEffect; import mage.cards.CardImpl; @@ -14,8 +12,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; -import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.common.FilterNonlandPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; @@ -38,13 +34,10 @@ public final class JaceTheLivingGuildpact extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.JACE); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Look at the top two cards of your library. Put one of them into your graveyard. - Effect effect = new LookLibraryAndPickControllerEffect( - StaticValue.get(2), false, StaticValue.get(1), new FilterCard(), Zone.LIBRARY, true, false, false, Zone.GRAVEYARD, false); - effect.setText("Look at the top two cards of your library. Put one of them into your graveyard"); - this.addAbility(new LoyaltyAbility(effect, 1)); + this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect(2, 1, PutCards.GRAVEYARD, PutCards.TOP_ANY), 1)); // -3: Return another target nonland permanent to its owner's hand. LoyaltyAbility ability = new LoyaltyAbility(new ReturnToHandTargetEffect(), -3); @@ -53,9 +46,8 @@ public final class JaceTheLivingGuildpact extends CardImpl { // -8: Each player shuffles their hand and graveyard into their library. You draw seven cards. ability = new LoyaltyAbility(new ShuffleHandGraveyardAllEffect(), -8); - ability.addEffect(new DrawCardSourceControllerEffect(7).setText("You draw seven cards")); + ability.addEffect(new DrawCardSourceControllerEffect(7, "you")); this.addAbility(ability); - } private JaceTheLivingGuildpact(final JaceTheLivingGuildpact card) { diff --git a/Mage.Sets/src/mage/cards/j/JaceTheMindSculptor.java b/Mage.Sets/src/mage/cards/j/JaceTheMindSculptor.java index b4ae3b8e6cf..15755998437 100644 --- a/Mage.Sets/src/mage/cards/j/JaceTheMindSculptor.java +++ b/Mage.Sets/src/mage/cards/j/JaceTheMindSculptor.java @@ -4,7 +4,6 @@ package mage.cards.j; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.BrainstormEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; @@ -33,7 +32,7 @@ public final class JaceTheMindSculptor extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.JACE); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +2: Look at the top card of target player's library. You may put that card on the bottom of that player's library. LoyaltyAbility ability1 = new LoyaltyAbility(new JaceTheMindSculptorEffect1(), 2); diff --git a/Mage.Sets/src/mage/cards/j/JaceUnravelerOfSecrets.java b/Mage.Sets/src/mage/cards/j/JaceUnravelerOfSecrets.java index c7354d62bfc..4d9c3b5ed9b 100644 --- a/Mage.Sets/src/mage/cards/j/JaceUnravelerOfSecrets.java +++ b/Mage.Sets/src/mage/cards/j/JaceUnravelerOfSecrets.java @@ -4,7 +4,6 @@ package mage.cards.j; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -31,7 +30,7 @@ public final class JaceUnravelerOfSecrets extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.JACE); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Scry 1, then draw a card. Ability ability = new LoyaltyAbility(new ScryEffect(1, false), 1); diff --git a/Mage.Sets/src/mage/cards/j/JaceWielderOfMysteries.java b/Mage.Sets/src/mage/cards/j/JaceWielderOfMysteries.java index dcb6ec7f37a..e08bf8945b0 100644 --- a/Mage.Sets/src/mage/cards/j/JaceWielderOfMysteries.java +++ b/Mage.Sets/src/mage/cards/j/JaceWielderOfMysteries.java @@ -2,7 +2,6 @@ package mage.cards.j; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.ReplacementEffectImpl; @@ -33,7 +32,7 @@ public final class JaceWielderOfMysteries extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.JACE); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // If you would draw a card while your library has no cards in it, you win the game instead. this.addAbility(new SimpleStaticAbility(new JaceWielderOfMysteriesContinuousEffect())); diff --git a/Mage.Sets/src/mage/cards/j/JacesDefeat.java b/Mage.Sets/src/mage/cards/j/JacesDefeat.java index 007bdbb1f09..4de69688399 100644 --- a/Mage.Sets/src/mage/cards/j/JacesDefeat.java +++ b/Mage.Sets/src/mage/cards/j/JacesDefeat.java @@ -73,7 +73,7 @@ class JacesDefeatEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null) { for (UUID targetId : getTargetPointer().getTargets(game, source) ) { Spell spell = game.getStack().getSpell(targetId); diff --git a/Mage.Sets/src/mage/cards/j/JacesMindseeker.java b/Mage.Sets/src/mage/cards/j/JacesMindseeker.java index 9832c9717d5..ca4873ebab2 100644 --- a/Mage.Sets/src/mage/cards/j/JacesMindseeker.java +++ b/Mage.Sets/src/mage/cards/j/JacesMindseeker.java @@ -5,21 +5,20 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlyingAbility; -import mage.cards.*; +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.StaticFilters; import mage.filter.common.FilterInstantOrSorceryCard; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; import mage.target.common.TargetOpponent; +import mage.util.CardUtil; -import java.util.Set; import java.util.UUID; -import mage.ApprovingObject; /** * @author LevelX2 @@ -75,44 +74,15 @@ class JaceMindseekerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Cards cardsToCast = new CardsImpl(); - Player targetOpponent = game.getPlayer(targetPointer.getFirst(game, source)); - if (targetOpponent != null) { - Set allCards = targetOpponent.millCards(5, source, game).getCards(game); - for (Card card : allCards) { - if (filter.match(card, game)) { - Zone zone = game.getState().getZone(card.getId()); - // If the five cards are put into a public zone such as exile instead - // of a graveyard (perhaps due to the ability of Rest in Peace), - // you can cast one of those instant or sorcery cards from that zone. - if (zone == Zone.GRAVEYARD - || zone == Zone.EXILED) { - cardsToCast.add(card); - } - } - } - - // cast an instant or sorcery for free - if (!cardsToCast.isEmpty()) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - TargetCard target = new TargetCard(Zone.GRAVEYARD, filter); // zone should be ignored here - target.setNotTarget(true); - if (controller.chooseUse(outcome, "Cast an instant or sorcery card from among them for free?", source, game) - && controller.choose(Outcome.PlayForFree, cardsToCast, target, game)) { - Card card = cardsToCast.get(target.getFirstTarget(), game); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - } - } - } - - } - return true; + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(source.getFirstTarget()); + if (controller == null || opponent == null) { + return false; } - return false; + return CardUtil.castSpellWithAttributesForFree( + controller, source, game, + opponent.millCards(5, source, game), + StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY + ); } } diff --git a/Mage.Sets/src/mage/cards/j/JackInTheMox.java b/Mage.Sets/src/mage/cards/j/JackInTheMox.java index 2780d404507..ac2d54947ca 100644 --- a/Mage.Sets/src/mage/cards/j/JackInTheMox.java +++ b/Mage.Sets/src/mage/cards/j/JackInTheMox.java @@ -51,12 +51,13 @@ class JackInTheMoxManaEffect extends ManaEffect { JackInTheMoxManaEffect() { super(); - staticText = "Roll a six-sided die for {this}. On a 1, sacrifice {this} and lose 5 life. Otherwise, {this} has one of the following effects. Treat this ability as a mana source." - + "
2 Add {W}.\n" - + "
3 Add {U}.\n" - + "
4 Add {B}.\n" - + "
5 Add {R}.\n" - + "
6 Add {G}."; + staticText = "roll a six-sided die. This ability has the indicated effect." + + "
1 - Sacrifice {this} and you lose 5 life." + + "
2 - Add {W}." + + "
3 - Add {U}." + + "
4 - Add {B}." + + "
5 - Add {R}." + + "
6 - Add {G}."; } JackInTheMoxManaEffect(final JackInTheMoxManaEffect effect) { diff --git a/Mage.Sets/src/mage/cards/j/JackalPup.java b/Mage.Sets/src/mage/cards/j/JackalPup.java index 24c7fa97eec..d72970a9363 100644 --- a/Mage.Sets/src/mage/cards/j/JackalPup.java +++ b/Mage.Sets/src/mage/cards/j/JackalPup.java @@ -1,16 +1,13 @@ package mage.cards.j; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealtDamageToSourceTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.DamageControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.game.Game; -import mage.players.Player; import java.util.UUID; @@ -27,8 +24,8 @@ public final class JackalPup extends CardImpl { this.toughness = new MageInt(1); // Whenever Jackal Pup is dealt damage, it deals that much damage to you. - this.addAbility(new DealtDamageToSourceTriggeredAbility(new JackalPupEffect(), false, false)); - + this.addAbility(new DealtDamageToSourceTriggeredAbility( + new DamageControllerEffect(SavedDamageValue.MUCH, "it"), false)); } private JackalPup(final JackalPup card) { @@ -40,30 +37,3 @@ public final class JackalPup extends CardImpl { return new JackalPup(this); } } - -class JackalPupEffect extends OneShotEffect { - - public JackalPupEffect() { - super(Outcome.Damage); - staticText = "it deals that much damage to you"; - } - - public JackalPupEffect(final JackalPupEffect effect) { - super(effect); - } - - @Override - public JackalPupEffect copy() { - return new JackalPupEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player you = game.getPlayer(source.getControllerId()); - if (you != null) { - you.damage((Integer) this.getValue("damage"), source.getSourceId(), source, game); - } - return true; - } - -} diff --git a/Mage.Sets/src/mage/cards/j/Jackhammer.java b/Mage.Sets/src/mage/cards/j/Jackhammer.java new file mode 100644 index 00000000000..db185bac9f7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/Jackhammer.java @@ -0,0 +1,44 @@ +package mage.cards.j; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.DrawSecondCardTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.combat.CantBeBlockedAllEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author Hiddevb + */ +public final class Jackhammer extends CardImpl { + + public Jackhammer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}{R}"); + this.subtype.add(SubType.EQUIPMENT); + + + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(2, 0))); + this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2))); + } + + private Jackhammer(final Jackhammer card) { + super(card); + } + + @Override + public Jackhammer copy() { + return new Jackhammer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JaddiLifestrider.java b/Mage.Sets/src/mage/cards/j/JaddiLifestrider.java index 9a361e3ca1e..2c8b16ac3f7 100644 --- a/Mage.Sets/src/mage/cards/j/JaddiLifestrider.java +++ b/Mage.Sets/src/mage/cards/j/JaddiLifestrider.java @@ -68,7 +68,7 @@ class JaddiLifestriderEffect extends OneShotEffect { int tappedAmount = 0; Player you = game.getPlayer(source.getControllerId()); TargetCreaturePermanent target = new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) && target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), game)) { + if (target.canChoose(source.getControllerId(), source, game) && target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), source, game)) { for (UUID creatureId : target.getTargets()) { Permanent creature = game.getPermanent(creatureId); if (creature != null) { diff --git a/Mage.Sets/src/mage/cards/j/JadeMonolith.java b/Mage.Sets/src/mage/cards/j/JadeMonolith.java index 51fa65d4bc4..b3aa82be4a3 100644 --- a/Mage.Sets/src/mage/cards/j/JadeMonolith.java +++ b/Mage.Sets/src/mage/cards/j/JadeMonolith.java @@ -70,14 +70,14 @@ class JadeMonolithRedirectionEffect extends ReplacementEffectImpl { @Override public void init(Ability source, Game game) { - this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); } @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); Permanent targetCreature = game.getPermanent(source.getFirstTarget()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); DamageEvent damageEvent = (DamageEvent) event; if (controller != null && targetCreature != null && sourceObject != null) { controller.damage(damageEvent.getAmount(), damageEvent.getSourceId(), source, game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), damageEvent.getAppliedEffects()); diff --git a/Mage.Sets/src/mage/cards/j/JadziOracleOfArcavios.java b/Mage.Sets/src/mage/cards/j/JadziOracleOfArcavios.java index bcada6b0520..c613a9c8d51 100644 --- a/Mage.Sets/src/mage/cards/j/JadziOracleOfArcavios.java +++ b/Mage.Sets/src/mage/cards/j/JadziOracleOfArcavios.java @@ -240,7 +240,7 @@ class JourneyToTheOracleEffect extends OneShotEffect { TargetCardInHand target = new TargetCardInHand( 0, Integer.MAX_VALUE, StaticFilters.FILTER_CARD_LANDS ); - player.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game); + player.choose(Outcome.PutCardInPlay, target, source, game); return player.moveCards(new CardsImpl(target.getTargets()), Zone.BATTLEFIELD, source, game); } } diff --git a/Mage.Sets/src/mage/cards/j/JaggedPoppet.java b/Mage.Sets/src/mage/cards/j/JaggedPoppet.java index 1e98da1ec05..ce1ca657e24 100644 --- a/Mage.Sets/src/mage/cards/j/JaggedPoppet.java +++ b/Mage.Sets/src/mage/cards/j/JaggedPoppet.java @@ -1,4 +1,3 @@ - package mage.cards.j; import java.util.UUID; @@ -8,15 +7,14 @@ import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.DealtDamageToSourceTriggeredAbility; import mage.abilities.condition.common.HellbentCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.game.Game; -import mage.players.Player; /** * @@ -33,16 +31,15 @@ public final class JaggedPoppet extends CardImpl { this.toughness = new MageInt(4); // Whenever Jagged Poppet is dealt damage, discard that many cards. - this.addAbility(new DealtDamageToSourceTriggeredAbility(new JaggedPoppetDealtDamageEffect(), false, false)); + this.addAbility(new DealtDamageToSourceTriggeredAbility(new DiscardControllerEffect(SavedDamageValue.MANY), false)); // Hellbent - Whenever Jagged Poppet deals combat damage to a player, if you have no cards in hand, that player discards cards equal to the damage. Ability hellbentAbility = new ConditionalInterveningIfTriggeredAbility( - new DealsCombatDamageToAPlayerTriggeredAbility(new JaggedPoppetDealsDamageEffect(), false, true), + new DealsCombatDamageToAPlayerTriggeredAbility(new DiscardTargetEffect(SavedDamageValue.MANY), false, true), HellbentCondition.instance, - "Hellbent — Whenever {this} deals combat damage to a player, if you have no cards in hand, that player discards cards equal to the damage."); + "Whenever {this} deals combat damage to a player, if you have no cards in hand, that player discards cards equal to the damage."); hellbentAbility.setAbilityWord(AbilityWord.HELLBENT); this.addAbility(hellbentAbility); - } private JaggedPoppet(final JaggedPoppet card) { @@ -54,73 +51,3 @@ public final class JaggedPoppet extends CardImpl { return new JaggedPoppet(this); } } - -class JaggedPoppetDealsDamageEffect extends OneShotEffect { - - public JaggedPoppetDealsDamageEffect() { - super(Outcome.Discard); - //staticText = "it deals that much damage to each creature that player controls"; - } - - public JaggedPoppetDealsDamageEffect(final JaggedPoppetDealsDamageEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - //According to the Balefire Dragon code, This statement gets the player that was dealt the combat damage - Player player = game.getPlayer(targetPointer.getFirst(game, source)); - if (player != null) { - //Call the getValue method of the Effect class to retrieve the amount of damage - int amount = (Integer) getValue("damage"); - - if (amount > 0) { - //Call the player discard function discarding cards equal to damage - player.discard(amount, false, false, source, game); - } - return true; - } - return false; - } - - @Override - public JaggedPoppetDealsDamageEffect copy() { - return new JaggedPoppetDealsDamageEffect(this); - } -} - -class JaggedPoppetDealtDamageEffect extends OneShotEffect { - - public JaggedPoppetDealtDamageEffect() { - super(Outcome.Discard); - staticText = "discard that many cards"; - } - - public JaggedPoppetDealtDamageEffect(final JaggedPoppetDealtDamageEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - - //According to the Firedrinker Satyr code, This statement gets the player that controls Jagged Poppet - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - //Call the getValue method of the Effect class to retrieve the amount of damage - int amount = (Integer) getValue("damage"); - - if (amount > 0) { - //Call the player discard function discarding cards equal to damage - player.discard(amount, false, false, source, game); - } - return true; - } - return false; - - } - - @Override - public JaggedPoppetDealtDamageEffect copy() { - return new JaggedPoppetDealtDamageEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/j/JaggedScarArchers.java b/Mage.Sets/src/mage/cards/j/JaggedScarArchers.java index 9c883b75b4c..8c71bdc4b70 100644 --- a/Mage.Sets/src/mage/cards/j/JaggedScarArchers.java +++ b/Mage.Sets/src/mage/cards/j/JaggedScarArchers.java @@ -47,7 +47,7 @@ public final class JaggedScarArchers extends CardImpl { // Jagged-Scar Archers's power and toughness are each equal to the number of Elves you control. this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new PermanentsOnBattlefieldCount(controlledElvesFilter), Duration.EndOfGame))); // {tap}: Jagged-Scar Archers deals damage equal to its power to target creature with flying. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new SourcePermanentPowerCount()), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new SourcePermanentPowerCount()).setText("{this} deals damage equal to its power to target creature with flying"), new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent(flyingCreatureFilter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/j/JalumGrifter.java b/Mage.Sets/src/mage/cards/j/JalumGrifter.java index c54f86e9966..03fc79a70df 100644 --- a/Mage.Sets/src/mage/cards/j/JalumGrifter.java +++ b/Mage.Sets/src/mage/cards/j/JalumGrifter.java @@ -94,8 +94,8 @@ class JalumGrifterEffect extends OneShotEffect { } Target target = new TargetControlledPermanent(2, 2, new FilterControlledLandPermanent(), true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - while (!target.isChosen() && target.canChoose(source.getSourceId(), controller.getId(), game) && controller.canRespond()) { + if (target.canChoose(controller.getId(), source, game)) { + while (!target.isChosen() && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target, source, game); } } diff --git a/Mage.Sets/src/mage/cards/j/JanglingAutomaton.java b/Mage.Sets/src/mage/cards/j/JanglingAutomaton.java index 7d179ab9af0..7bcaa9c9f26 100644 --- a/Mage.Sets/src/mage/cards/j/JanglingAutomaton.java +++ b/Mage.Sets/src/mage/cards/j/JanglingAutomaton.java @@ -62,7 +62,7 @@ class JanglingAutomatonEffect extends OneShotEffect { if (defenderId != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent(); filter.add(new ControllerIdPredicate(defenderId)); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanent.untap(game); } return true; diff --git a/Mage.Sets/src/mage/cards/j/JarJarBinks.java b/Mage.Sets/src/mage/cards/j/JarJarBinks.java index c32f09b2485..ba0b5207421 100644 --- a/Mage.Sets/src/mage/cards/j/JarJarBinks.java +++ b/Mage.Sets/src/mage/cards/j/JarJarBinks.java @@ -156,8 +156,8 @@ class JarJarBinksTapEffect extends OneShotEffect { filter.add(new PowerPredicate(ComparisonType.EQUAL_TO, highestPower)); Target target = new TargetPermanent(filter); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { - if (controller.choose(outcome, target, source.getSourceId(), game)) { + if (target.canChoose(source.getControllerId(), source, game)) { + if (controller.choose(outcome, target, source, game)) { permanentToTap = game.getPermanent(target.getFirstTarget()); } } diff --git a/Mage.Sets/src/mage/cards/j/JarOfEyeballs.java b/Mage.Sets/src/mage/cards/j/JarOfEyeballs.java index 880fd0e703c..9bceed2e19d 100644 --- a/Mage.Sets/src/mage/cards/j/JarOfEyeballs.java +++ b/Mage.Sets/src/mage/cards/j/JarOfEyeballs.java @@ -7,26 +7,22 @@ import mage.abilities.costs.Cost; import mage.abilities.costs.common.RemoveAllCountersSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -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.StaticFilters; import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; import java.util.UUID; /** - * @author North + * @author awjackson */ public final class JarOfEyeballs extends CardImpl { @@ -42,7 +38,9 @@ public final class JarOfEyeballs extends CardImpl { // {3}, {tap}, Remove all eyeball counters from Jar of Eyeballs: // Look at the top X cards of your library, where X is the number of eyeball counters removed this way. // Put one of them into your hand and the rest on the bottom of your library in any order. - SimpleActivatedAbility ability = new SimpleActivatedAbility(new JarOfEyeballsEffect(), new GenericManaCost(3)); + SimpleActivatedAbility ability = new SimpleActivatedAbility( + new LookLibraryAndPickControllerEffect(JarOfEyeballsValue.instance, 1, PutCards.HAND, PutCards.BOTTOM_ANY), + new GenericManaCost(3)); ability.addCost(new TapSourceCost()); ability.addCost(new RemoveAllCountersSourceCost(CounterType.EYEBALL)); this.addAbility(ability); @@ -58,43 +56,32 @@ public final class JarOfEyeballs extends CardImpl { } } -class JarOfEyeballsEffect extends OneShotEffect { - - public JarOfEyeballsEffect() { - super(Outcome.DrawCard); - this.staticText = "Look at the top X cards of your library, where X is the number of eyeball counters removed this way. Put one of them into your hand and the rest on the bottom of your library in any order"; - } - - public JarOfEyeballsEffect(final JarOfEyeballsEffect effect) { - super(effect); - } +enum JarOfEyeballsValue implements DynamicValue { + instance; @Override - public JarOfEyeballsEffect copy() { - return new JarOfEyeballsEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } + public int calculate(Game game, Ability sourceAbility, Effect effect) { int countersRemoved = 0; - for (Cost cost : source.getCosts()) { + for (Cost cost : sourceAbility.getCosts()) { if (cost instanceof RemoveAllCountersSourceCost) { countersRemoved = ((RemoveAllCountersSourceCost) cost).getRemovedCounters(); } } - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, countersRemoved)); - controller.lookAtCards(source, null, cards, game); - TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into your hand")); - if (controller.choose(Outcome.DrawCard, cards, target, game)) { - Cards targetCards = new CardsImpl(target.getTargets()); - controller.moveCards(targetCards, Zone.HAND, source, game); - cards.removeAll(targetCards); - } - controller.putCardsOnBottomOfLibrary(cards, game, source, true); - return true; + return countersRemoved; + } + + @Override + public JarOfEyeballsValue copy() { + return instance; + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return "the number of eyeball counters removed this way"; } } diff --git a/Mage.Sets/src/mage/cards/j/JarethLeonineTitan.java b/Mage.Sets/src/mage/cards/j/JarethLeonineTitan.java index 37a1af48dab..2e48e362b41 100644 --- a/Mage.Sets/src/mage/cards/j/JarethLeonineTitan.java +++ b/Mage.Sets/src/mage/cards/j/JarethLeonineTitan.java @@ -3,19 +3,14 @@ package mage.cards.j; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.BlocksSourceTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.ColoredManaCost; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainProtectionFromColorSourceEffect; 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.constants.*; /** * @@ -33,11 +28,14 @@ public final class JarethLeonineTitan extends CardImpl { this.toughness = new MageInt(7); // Whenever Jareth, Leonine Titan blocks, it gets +7/+7 until end of turn. - this.addAbility(new BlocksSourceTriggeredAbility(new BoostSourceEffect(7,7,Duration.EndOfTurn), false)); + this.addAbility(new BlocksSourceTriggeredAbility( + new BoostSourceEffect(7, 7, Duration.EndOfTurn, "it") + )); // {W}: Jareth gains protection from the color of your choice until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainProtectionFromColorSourceEffect(Duration.EndOfTurn), new ManaCostsImpl("{W}")); - this.addAbility(ability); - + this.addAbility(new SimpleActivatedAbility( + new GainProtectionFromColorSourceEffect(Duration.EndOfTurn), + new ColoredManaCost(ColoredManaSymbol.W) + )); } private JarethLeonineTitan(final JarethLeonineTitan card) { diff --git a/Mage.Sets/src/mage/cards/j/JaxisTheTroublemaker.java b/Mage.Sets/src/mage/cards/j/JaxisTheTroublemaker.java new file mode 100644 index 00000000000..256d9da78e4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JaxisTheTroublemaker.java @@ -0,0 +1,94 @@ +package mage.cards.j; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.BlitzAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JaxisTheTroublemaker extends CardImpl { + + public JaxisTheTroublemaker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // {R}, {T}, Discard a card: Create a token that's a copy of another target creature you control. It gains haste and "When this creature dies, draw a card." Sacrifice it at the beginning of the next end step. Activate only as a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + new JaxisTheTroublemakerEffect(), new ManaCostsImpl<>("{R}") + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new DiscardCardCost()); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); + this.addAbility(ability); + + // Blitz {1}{R} + this.addAbility(new BlitzAbility(this, "{1}{R}")); + } + + private JaxisTheTroublemaker(final JaxisTheTroublemaker card) { + super(card); + } + + @Override + public JaxisTheTroublemaker copy() { + return new JaxisTheTroublemaker(this); + } +} + +class JaxisTheTroublemakerEffect extends OneShotEffect { + + JaxisTheTroublemakerEffect() { + super(Outcome.Benefit); + staticText = "create a token that's a copy of another target creature you control. It gains haste and " + + "\"When this creature dies, draw a card.\" Sacrifice it at the beginning of the next end step"; + } + + private JaxisTheTroublemakerEffect(final JaxisTheTroublemakerEffect effect) { + super(effect); + } + + @Override + public JaxisTheTroublemakerEffect copy() { + return new JaxisTheTroublemakerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(); + effect.addAdditionalAbilities( + HasteAbility.getInstance(), + new DiesSourceTriggeredAbility( + new DrawCardSourceControllerEffect(1) + ).setTriggerPhrase("When this creature dies, ") + ); + effect.apply(game, source); + effect.sacrificeTokensCreatedAtNextEndStep(game, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/j/JayaBallard.java b/Mage.Sets/src/mage/cards/j/JayaBallard.java index 5a1e88a84a3..bf01d7cfe46 100644 --- a/Mage.Sets/src/mage/cards/j/JayaBallard.java +++ b/Mage.Sets/src/mage/cards/j/JayaBallard.java @@ -2,7 +2,6 @@ package mage.cards.j; import mage.Mana; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.discard.DiscardAndDrawThatManyEffect; import mage.abilities.effects.mana.AddConditionalManaEffect; @@ -27,7 +26,7 @@ public final class JayaBallard extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.JAYA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Add {R}{R}{R}. Spend this mana only to cast instant or sorcery spells. this.addAbility(new LoyaltyAbility(new AddConditionalManaEffect( diff --git a/Mage.Sets/src/mage/cards/j/JayaVeneratedFiremage.java b/Mage.Sets/src/mage/cards/j/JayaVeneratedFiremage.java index f124de4b778..1f451a78153 100644 --- a/Mage.Sets/src/mage/cards/j/JayaVeneratedFiremage.java +++ b/Mage.Sets/src/mage/cards/j/JayaVeneratedFiremage.java @@ -3,7 +3,6 @@ package mage.cards.j; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.DamageTargetEffect; @@ -28,7 +27,7 @@ public final class JayaVeneratedFiremage extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.JAYA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // If another red source you control would deal damage to a permanent or player, it deals that much damage plus 1 to that permanent or player instead. this.addAbility(new SimpleStaticAbility(new JayaVeneratedFiremageEffect())); diff --git a/Mage.Sets/src/mage/cards/j/JeeringInstigator.java b/Mage.Sets/src/mage/cards/j/JeeringInstigator.java index 61beb4fa0ec..0801a0884f6 100644 --- a/Mage.Sets/src/mage/cards/j/JeeringInstigator.java +++ b/Mage.Sets/src/mage/cards/j/JeeringInstigator.java @@ -44,7 +44,7 @@ public final class JeeringInstigator extends CardImpl { this.toughness = new MageInt(1); // Morph {2}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{2}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl<>("{2}{R}"))); // When Jeering Instigator is turned face up, if it's your turn, gain control of another target creature until end of turn. Untap it. That creature gains haste until end of turn. Ability ability = new ConditionalInterveningIfTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/j/JeganthaTheWellspring.java b/Mage.Sets/src/mage/cards/j/JeganthaTheWellspring.java index fc7a5cf1b95..dfe2e13a7be 100644 --- a/Mage.Sets/src/mage/cards/j/JeganthaTheWellspring.java +++ b/Mage.Sets/src/mage/cards/j/JeganthaTheWellspring.java @@ -6,12 +6,8 @@ import mage.Mana; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCost; -import mage.abilities.costs.mana.ManaCosts; -import mage.abilities.effects.mana.ManaEffect; import mage.abilities.keyword.CompanionAbility; import mage.abilities.keyword.CompanionCondition; -import mage.abilities.mana.SimpleManaAbility; import mage.abilities.mana.conditional.ManaCondition; import mage.cards.Card; import mage.cards.CardImpl; @@ -20,6 +16,8 @@ import mage.constants.*; import mage.game.Game; import java.util.*; +import mage.abilities.mana.ConditionalColoredManaAbility; +import mage.abilities.mana.builder.ConditionalManaBuilder; /** * @author TheElk801 @@ -39,8 +37,8 @@ public final class JeganthaTheWellspring extends CardImpl { this.addAbility(new CompanionAbility(JeganthaTheWellspringCompanionCondition.instance)); // {T}: Add {W}{U}{B}{R}{G}. This mana can't be spent to pay generic mana costs. - this.addAbility(new SimpleManaAbility( - Zone.BATTLEFIELD, new JeganthaTheWellspringManaEffect(), new TapSourceCost() + this.addAbility(new ConditionalColoredManaAbility( + new TapSourceCost(), new Mana(1, 1, 1, 1, 1, 0, 0, 0), new JeganthaManaBuilder() )); } @@ -72,65 +70,38 @@ enum JeganthaTheWellspringCompanionCondition implements CompanionCondition { return card.getManaCostSymbols() .stream() .anyMatch(s -> symbolMap.compute( - s, (str, i) -> (i == null) ? 1 : i + 1 - ) > 1); + s, (str, i) -> (i == null) ? 1 : i + 1 + ) > 1); } } -class JeganthaTheWellspringManaEffect extends ManaEffect { +class JeganthaManaBuilder extends ConditionalManaBuilder { - JeganthaTheWellspringManaEffect() { - super(); - staticText = "Add {W}{U}{B}{R}{G}. This mana can't be spent to pay generic mana costs."; - } - - private JeganthaTheWellspringManaEffect(final JeganthaTheWellspringManaEffect effect) { - super(effect); + @Override + public ConditionalMana build(Object... options) { + return new JeganthaConditionalMana(this.mana); } @Override - public Mana produceMana(Game game, Ability source) { - Mana mana = new Mana(); - mana.add(new JeganthaTheWellspringConditionalMana("W")); - mana.add(new JeganthaTheWellspringConditionalMana("U")); - mana.add(new JeganthaTheWellspringConditionalMana("B")); - mana.add(new JeganthaTheWellspringConditionalMana("R")); - mana.add(new JeganthaTheWellspringConditionalMana("G")); - return mana; + public String getRule() { + return "This mana can't be spent to pay generic mana costs"; } +} + +class JeganthaConditionalMana extends ConditionalMana { + + JeganthaConditionalMana(Mana mana) { + super(mana); + staticText = "This mana can't be spent to pay generic mana costs"; + addCondition(new JeganthaManaCondition()); + } +} + +class JeganthaManaCondition extends ManaCondition { @Override - public JeganthaTheWellspringManaEffect copy() { - return new JeganthaTheWellspringManaEffect(this); - } -} - -class JeganthaTheWellspringConditionalMana extends ConditionalMana { - - JeganthaTheWellspringConditionalMana(String manaSymbol) { - super(new Mana(ColoredManaSymbol.valueOf(manaSymbol))); - addCondition(new JeganthaTheWellspringManaCondition(manaSymbol)); - } -} - -class JeganthaTheWellspringManaCondition extends ManaCondition { - - private final String manaSymbol; - - JeganthaTheWellspringManaCondition(String manaSymbol) { - this.manaSymbol = manaSymbol.toLowerCase(Locale.ENGLISH); - } - - @Override - public boolean apply(Game game, Ability source, UUID originalId, Cost costToPay) { - if (!(costToPay instanceof ManaCosts)) { - return false; - } - return Arrays.stream( - ((ManaCosts) costToPay) - .getUnpaid() - .getText() - .split("[\\}\\{]") - ).map(s -> s.toLowerCase(Locale.ENGLISH)).anyMatch(s -> s.contains(manaSymbol)); + public boolean apply(Game game, Ability source, UUID originalId, Cost costsToPay) { + // TODO find a better method. this one forces the user to pay off the generic mana before continuing. + return source.getManaCostsToPay().getUnpaid().getMana().getGeneric() == 0; } } diff --git a/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java b/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java index 72d48113490..2f3a3b78d9a 100644 --- a/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java +++ b/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java @@ -1,9 +1,5 @@ package mage.cards.j; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import mage.ApprovingObject; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -11,27 +7,25 @@ import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlyingAbility; -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.SuperType; -import mage.constants.WatcherScope; -import mage.filter.common.FilterInstantOrSorceryCard; -import mage.game.ExileZone; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.*; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.game.stack.StackObject; import mage.players.Player; -import mage.target.common.TargetCardInExile; import mage.util.CardUtil; import mage.watchers.Watcher; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class JelevaNephaliasScourge extends CardImpl { @@ -112,8 +106,8 @@ class JelevaNephaliasCastEffect extends OneShotEffect { public JelevaNephaliasCastEffect() { super(Outcome.PlayForFree); - this.staticText = "you may cast an instant or sorcery card " - + "exiled with it without paying its mana cost"; + this.staticText = "you may cast an instant or sorcery spell " + + "from among cards exiled with {this} without paying its mana cost"; } public JelevaNephaliasCastEffect(final JelevaNephaliasCastEffect effect) { @@ -128,29 +122,14 @@ class JelevaNephaliasCastEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - ExileZone exileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); - if (exileZone != null - && exileZone.count(new FilterInstantOrSorceryCard(), game) > 0) { - if (controller.chooseUse(outcome, "Cast an instant or sorcery card from " - + "exile without paying its mana cost?", source, game)) { - TargetCardInExile target = new TargetCardInExile( - new FilterInstantOrSorceryCard(), CardUtil.getCardExileZoneId(game, source)); - if (controller.choose(Outcome.PlayForFree, exileZone, target, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - return cardWasCast; - } - } - } - } - return true; + if (controller == null) { + return false; } - return false; + Cards cards = new CardsImpl(game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source))); + return CardUtil.castSpellWithAttributesForFree( + controller, source, game, cards, + StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY + ); } } @@ -170,8 +149,8 @@ class JelevaNephaliasWatcher extends Watcher { for (StackObject stackObject : game.getStack()) { if (stackObject instanceof Spell) { Spell spell = (Spell) stackObject; - manaSpendToCast.putIfAbsent(spell.getSourceId().toString() - + spell.getCard().getZoneChangeCounter(game), + manaSpendToCast.putIfAbsent(spell.getSourceId().toString() + + spell.getCard().getZoneChangeCounter(game), spell.getSpellAbility().getManaCostsToPay().manaValue()); } } diff --git a/Mage.Sets/src/mage/cards/j/JerrenCorruptedBishop.java b/Mage.Sets/src/mage/cards/j/JerrenCorruptedBishop.java index 36eb28f00ad..a4414029fca 100644 --- a/Mage.Sets/src/mage/cards/j/JerrenCorruptedBishop.java +++ b/Mage.Sets/src/mage/cards/j/JerrenCorruptedBishop.java @@ -115,7 +115,7 @@ class JerrenCorruptedBishopTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { switch (event.getType()) { case ENTERS_THE_BATTLEFIELD: - return event.getSourceId().equals(getSourceId()); + return event.getTargetId().equals(getSourceId()); case ZONE_CHANGE: ZoneChangeEvent zEvent = (ZoneChangeEvent) event; return zEvent.isDiesEvent() diff --git a/Mage.Sets/src/mage/cards/j/JeskaThriceReborn.java b/Mage.Sets/src/mage/cards/j/JeskaThriceReborn.java index 34aba889bd8..bfe7a8e07de 100644 --- a/Mage.Sets/src/mage/cards/j/JeskaThriceReborn.java +++ b/Mage.Sets/src/mage/cards/j/JeskaThriceReborn.java @@ -38,6 +38,7 @@ public final class JeskaThriceReborn extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.JESKA); + this.setStartingLoyalty(0); // Jeska, Thrice Reborn enters the battlefield with a loyalty counter on it for each time you've cast a commander from the command zone this game. this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect( diff --git a/Mage.Sets/src/mage/cards/j/JeskaiCharm.java b/Mage.Sets/src/mage/cards/j/JeskaiCharm.java index ad04741fffe..ed4c88c3320 100644 --- a/Mage.Sets/src/mage/cards/j/JeskaiCharm.java +++ b/Mage.Sets/src/mage/cards/j/JeskaiCharm.java @@ -31,15 +31,13 @@ public final class JeskaiCharm extends CardImpl { this.getSpellAbility().addEffect(new PutOnLibraryTargetEffect(true)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // - Jeskai Charm deals 4 damage to target opponent. - Mode mode = new Mode(); - mode.addEffect(new DamageTargetEffect(4)); + Mode mode = new Mode(new DamageTargetEffect(4)); mode.addTarget(new TargetOpponentOrPlaneswalker()); this.getSpellAbility().addMode(mode); // - Creatures you control get +1/+1 and gain lifelink until end of turn. - mode = new Mode(); Effect effect = new BoostControlledEffect(1, 1, Duration.EndOfTurn); effect.setText("Creatures you control get +1/+1"); - mode.addEffect(effect); + mode = new Mode(effect); effect = new GainAbilityControlledEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn, new FilterControlledCreaturePermanent()); effect.setText("and gain lifelink until end of turn"); mode.addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/j/JestersCap.java b/Mage.Sets/src/mage/cards/j/JestersCap.java index 07a5ed3ba8f..0b06e5973e8 100644 --- a/Mage.Sets/src/mage/cards/j/JestersCap.java +++ b/Mage.Sets/src/mage/cards/j/JestersCap.java @@ -1,36 +1,30 @@ - package mage.cards.j; -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.OneShotEffect; -import mage.cards.Card; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.search.SearchLibraryAndExileTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.game.Game; -import mage.players.Player; import mage.target.TargetPlayer; -import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; /** - * * @author fireshoes */ public final class JestersCap extends CardImpl { public JestersCap(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // {2}, {tap}, Sacrifice Jester's Cap: Search target player's library for three cards and exile them. Then that player shuffles their library. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new JestersCapEffect(), new ManaCostsImpl("{2}")); + Ability ability = new SimpleActivatedAbility( + new SearchLibraryAndExileTargetEffect(3, false), new GenericManaCost(2) + ); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetPlayer()); @@ -46,39 +40,3 @@ public final class JestersCap extends CardImpl { return new JestersCap(this); } } - -class JestersCapEffect extends OneShotEffect { - - public JestersCapEffect() { - super(Outcome.Benefit); - this.staticText = "Search target player's library for three cards and exile them. Then that player shuffles"; - } - - public JestersCapEffect(final JestersCapEffect effect) { - super(effect); - } - - @Override - public JestersCapEffect copy() { - return new JestersCapEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - boolean applied = false; - Player targetPlayer = game.getPlayer(source.getFirstTarget()); - Player player = game.getPlayer(source.getControllerId()); - if (player != null && targetPlayer != null) { - TargetCardInLibrary target = new TargetCardInLibrary(3, 3, new FilterCard()); - player.searchLibrary(target, source, game, targetPlayer.getId()); - for (UUID cardId : target.getTargets()) { - final Card targetCard = game.getCard(cardId); - if (targetCard != null) { - applied |= player.moveCardToExileWithInfo(targetCard, null, null, source, game, Zone.LIBRARY, true); - } - } - targetPlayer.shuffleLibrary(source, game); - } - return applied; - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/j/JestersScepter.java b/Mage.Sets/src/mage/cards/j/JestersScepter.java index 32d8e747810..d56fba15e63 100644 --- a/Mage.Sets/src/mage/cards/j/JestersScepter.java +++ b/Mage.Sets/src/mage/cards/j/JestersScepter.java @@ -76,7 +76,7 @@ class JestersScepterEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Player targetedPlayer = game.getPlayer(source.getFirstTarget()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && targetedPlayer != null && sourceObject != null) { @@ -125,7 +125,7 @@ class JestersScepterLookAtCardEffect extends AsThoughEffectImpl { if (affectedControllerId.equals(source.getControllerId())) { Card card = game.getCard(objectId); if (card != null) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/j/JetmirNexusOfRevels.java b/Mage.Sets/src/mage/cards/j/JetmirNexusOfRevels.java new file mode 100644 index 00000000000..c6efad14104 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JetmirNexusOfRevels.java @@ -0,0 +1,111 @@ +package mage.cards.j; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JetmirNexusOfRevels extends CardImpl { + + public JetmirNexusOfRevels(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{G}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.DEMON); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Creatures you control get +1/+0 and have vigilance as long as you control three or more creatures. + // Creatures you control also get +1/+0 and have trample as long as you control six or more creatures. + // Creatures you control also get +1/+0 and have double strike as long as you control nine or more creatures. + this.addAbility(new SimpleStaticAbility(new JetmirNexusOfRevelsEffect())); + } + + private JetmirNexusOfRevels(final JetmirNexusOfRevels card) { + super(card); + } + + @Override + public JetmirNexusOfRevels copy() { + return new JetmirNexusOfRevels(this); + } +} + +class JetmirNexusOfRevelsEffect extends ContinuousEffectImpl { + + JetmirNexusOfRevelsEffect() { + super(Duration.WhileOnBattlefield, Outcome.BoostCreature); + staticText = "Creatures you control get +1/+0 and have vigilance as long as you control three or more creatures.
" + + "Creatures you control also get +1/+0 and have trample as long as you control six or more creatures.
" + + "Creatures you control also get +1/+0 and have double strike as long as you control nine or more creatures."; + } + + private JetmirNexusOfRevelsEffect(final JetmirNexusOfRevelsEffect effect) { + super(effect); + } + + @Override + public JetmirNexusOfRevelsEffect copy() { + return new JetmirNexusOfRevelsEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + List permanents = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, + source.getControllerId(), source, game + ); + int level = Math.min(permanents.size() / 3, 3); + if (level < 1) { + return false; + } + for (Permanent permanent : permanents) { + switch (layer) { + case AbilityAddingRemovingEffects_6: + permanent.addAbility(VigilanceAbility.getInstance(), source.getSourceId(), game); + if (level > 1) { + permanent.addAbility(TrampleAbility.getInstance(), source.getSourceId(), game); + } + if (level > 2) { + permanent.addAbility(DoubleStrikeAbility.getInstance(), source.getSourceId(), game); + } + continue; + case PTChangingEffects_7: + if (sublayer == SubLayer.ModifyPT_7c) { + permanent.addPower(level); + } + continue; + } + } + return true; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.PTChangingEffects_7 + || layer == Layer.AbilityAddingRemovingEffects_6; + } +} diff --git a/Mage.Sets/src/mage/cards/j/JetmirsFixer.java b/Mage.Sets/src/mage/cards/j/JetmirsFixer.java new file mode 100644 index 00000000000..10a0bd5506e --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JetmirsFixer.java @@ -0,0 +1,75 @@ +package mage.cards.j; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +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.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.watchers.common.ManaPaidSourceWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JetmirsFixer extends CardImpl { + + public JetmirsFixer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{G}"); + + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {R}{G}: Jetmir's Fixer gets +1/+1 until end of turn. If mana from a Treasure was spent to activate this ability, put a +1/+1 counter on Jetmir's Fixer instead. + this.addAbility(new SimpleActivatedAbility(new JetmirsFixerEffect(), new ManaCostsImpl<>("{R}{G}"))); + } + + private JetmirsFixer(final JetmirsFixer card) { + super(card); + } + + @Override + public JetmirsFixer copy() { + return new JetmirsFixer(this); + } +} + +class JetmirsFixerEffect extends OneShotEffect { + + JetmirsFixerEffect() { + super(Outcome.Benefit); + staticText = "{this} gets +1/+1 until end of turn. If mana from a Treasure " + + "was spent to activate this ability, put a +1/+1 counter on {this} instead"; + } + + private JetmirsFixerEffect(final JetmirsFixerEffect effect) { + super(effect); + } + + @Override + public JetmirsFixerEffect copy() { + return new JetmirsFixerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (ManaPaidSourceWatcher.getTreasurePaid(source.getId(), game) < 1) { + game.addEffect(new BoostSourceEffect(1, 1, Duration.EndOfTurn), source); + return true; + } + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + return permanent != null && permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JetmirsGarden.java b/Mage.Sets/src/mage/cards/j/JetmirsGarden.java new file mode 100644 index 00000000000..e90f8878f97 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JetmirsGarden.java @@ -0,0 +1,48 @@ +package mage.cards.j; + +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.keyword.CyclingAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JetmirsGarden extends CardImpl { + + public JetmirsGarden(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + this.subtype.add(SubType.MOUNTAIN); + this.subtype.add(SubType.FOREST); + this.subtype.add(SubType.PLAINS); + + // ({T}: Add {R}, {G}, or {W}.) + this.addAbility(new RedManaAbility()); + this.addAbility(new GreenManaAbility()); + this.addAbility(new WhiteManaAbility()); + + // Jetmir's Garden enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // Cycling {3} + this.addAbility(new CyclingAbility(new GenericManaCost(3))); + } + + private JetmirsGarden(final JetmirsGarden card) { + super(card); + } + + @Override + public JetmirsGarden copy() { + return new JetmirsGarden(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JewelThief.java b/Mage.Sets/src/mage/cards/j/JewelThief.java new file mode 100644 index 00000000000..b9d2a94a7ce --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JewelThief.java @@ -0,0 +1,47 @@ +package mage.cards.j; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +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.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JewelThief extends CardImpl { + + public JewelThief(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When Jewel Thief enters the battlefield, create a Treasure token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new TreasureToken()))); + } + + private JewelThief(final JewelThief card) { + super(card); + } + + @Override + public JewelThief copy() { + return new JewelThief(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JeweledTorque.java b/Mage.Sets/src/mage/cards/j/JeweledTorque.java index ad295d7912f..621c971e718 100644 --- a/Mage.Sets/src/mage/cards/j/JeweledTorque.java +++ b/Mage.Sets/src/mage/cards/j/JeweledTorque.java @@ -61,7 +61,7 @@ enum JeweledTorquePredicate implements ObjectSourcePlayerPredicate { @Override public boolean apply(ObjectSourcePlayer input, Game game) { - Permanent permanent = game.getPermanent(input.getSourceId()); + Permanent permanent = input.getSource().getSourcePermanentIfItStillExists(game); if (permanent == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/j/JiangYanggu.java b/Mage.Sets/src/mage/cards/j/JiangYanggu.java index 193e63b41e9..3a390631b1b 100644 --- a/Mage.Sets/src/mage/cards/j/JiangYanggu.java +++ b/Mage.Sets/src/mage/cards/j/JiangYanggu.java @@ -4,7 +4,6 @@ package mage.cards.j; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalOneShotEffect; @@ -43,7 +42,7 @@ public final class JiangYanggu extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.YANGGU); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Target creature gets +2/+2 until end of turn. Ability ability = new LoyaltyAbility(new BoostTargetEffect(2, 2, Duration.EndOfTurn), 1); diff --git a/Mage.Sets/src/mage/cards/j/JiangYangguWildcrafter.java b/Mage.Sets/src/mage/cards/j/JiangYangguWildcrafter.java index 36fea642e1b..63333e9acd9 100644 --- a/Mage.Sets/src/mage/cards/j/JiangYangguWildcrafter.java +++ b/Mage.Sets/src/mage/cards/j/JiangYangguWildcrafter.java @@ -2,9 +2,8 @@ package mage.cards.j; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.mana.AnyColorManaAbility; import mage.cards.CardImpl; @@ -29,10 +28,10 @@ public final class JiangYangguWildcrafter extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.YANGGU); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // Each creature you control with a +1/+1 counter on it has "{T}: Add one mana of any color." - this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( new AnyColorManaAbility(), Duration.WhileOnBattlefield, StaticFilters.FILTER_EACH_CONTROLLED_CREATURE_P1P1 ))); diff --git a/Mage.Sets/src/mage/cards/j/JinGitaxiasProgressTyrant.java b/Mage.Sets/src/mage/cards/j/JinGitaxiasProgressTyrant.java new file mode 100644 index 00000000000..a1bf9b4bd35 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JinGitaxiasProgressTyrant.java @@ -0,0 +1,92 @@ +package mage.cards.j; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.common.SpellCastOpponentTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CopySourceSpellEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterSpell; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.stack.Spell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JinGitaxiasProgressTyrant extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("an artifact, instant, or sorcery spell"); + + static { + filter.add(Predicates.or( + CardType.ARTIFACT.getPredicate(), + CardType.INSTANT.getPredicate(), + CardType.SORCERY.getPredicate() + )); + } + + public JinGitaxiasProgressTyrant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); + this.subtype.add(SubType.PRAETOR); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Whenever you cast an artifact, instant, or sorcery spell, copy that spell. You may choose new targets for the copy. This ability triggers only once each turn. + this.addAbility(new SpellCastControllerTriggeredAbility( + new CopySourceSpellEffect().setText("copy that spell. You may choose new targets for the copy"), + filter, false, true + ).setTriggersOnce(true)); + + // Whenever an opponent casts an artifact, instant, or sorcery spell, counter that spell. This ability triggers only once each turn. + this.addAbility(new SpellCastOpponentTriggeredAbility( + new JinGitaxiasProgressTyrantEffect(), filter, false + ).setTriggersOnce(true)); + } + + private JinGitaxiasProgressTyrant(final JinGitaxiasProgressTyrant card) { + super(card); + } + + @Override + public JinGitaxiasProgressTyrant copy() { + return new JinGitaxiasProgressTyrant(this); + } +} + +class JinGitaxiasProgressTyrantEffect extends OneShotEffect { + + JinGitaxiasProgressTyrantEffect() { + super(Outcome.Benefit); + staticText = "counter that spell"; + } + + private JinGitaxiasProgressTyrantEffect(final JinGitaxiasProgressTyrantEffect effect) { + super(effect); + } + + @Override + public JinGitaxiasProgressTyrantEffect copy() { + return new JinGitaxiasProgressTyrantEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = (Spell) getValue("spellCast"); + if (spell != null) { + game.getStack().counter(spell.getId(), source, game);; + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/j/JinnieFayJetmirsSecond.java b/Mage.Sets/src/mage/cards/j/JinnieFayJetmirsSecond.java new file mode 100644 index 00000000000..3d316994489 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JinnieFayJetmirsSecond.java @@ -0,0 +1,93 @@ +package mage.cards.j; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.CreateTokenEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.token.CatHasteToken; +import mage.game.permanent.token.DogVigilanceToken; +import mage.game.permanent.token.Token; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JinnieFayJetmirsSecond extends CardImpl { + + public JinnieFayJetmirsSecond(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R/G}{G}{G/W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // If you would create one or more tokens, you may instead create that many 2/2 green Cat creature tokens with haste or that many 3/1 green Dog creature tokens with vigilance. + this.addAbility(new SimpleStaticAbility(new JinnieFayJetmirsSecondEffect())); + } + + private JinnieFayJetmirsSecond(final JinnieFayJetmirsSecond card) { + super(card); + } + + @Override + public JinnieFayJetmirsSecond copy() { + return new JinnieFayJetmirsSecond(this); + } +} + +class JinnieFayJetmirsSecondEffect extends ReplacementEffectImpl { + + JinnieFayJetmirsSecondEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit, false); + staticText = "if you would create one or more tokens, you may instead create that many 2/2 green " + + "Cat creature tokens with haste or that many 3/1 green Dog creature tokens with vigilance"; + } + + private JinnieFayJetmirsSecondEffect(final JinnieFayJetmirsSecondEffect effect) { + super(effect); + } + + @Override + public JinnieFayJetmirsSecondEffect copy() { + return new JinnieFayJetmirsSecondEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CREATE_TOKEN; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return source.isControlledBy(event.getPlayerId()); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + CreateTokenEvent tokenEvent = (CreateTokenEvent) event; + Player player = game.getPlayer(source.getControllerId()); + int amount = tokenEvent.getTokens().values().stream().mapToInt(x -> x).sum(); + if (player == null || amount < 1 || !player.chooseUse( + outcome, "Replace this token event?", source, game + )) { + return false; + } + Token token = player.chooseUse( + outcome, "Choose 2/2 Cat or 3/1 Dog", null, + "Cat", "Dog", source, game + ) ? new CatHasteToken() : new DogVigilanceToken(); + tokenEvent.getTokens().clear(); + tokenEvent.getTokens().put(token, amount); + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/j/JoinTheMaestros.java b/Mage.Sets/src/mage/cards/j/JoinTheMaestros.java new file mode 100644 index 00000000000..57768df1432 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JoinTheMaestros.java @@ -0,0 +1,35 @@ +package mage.cards.j; + +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.CasualtyAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.OgreWarriorToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JoinTheMaestros extends CardImpl { + + public JoinTheMaestros(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); + + // Casualty 2 + this.addAbility(new CasualtyAbility(this, 2)); + + // Create a 4/3 black Ogre Warrior creature token. + this.getSpellAbility().addEffect(new CreateTokenEffect(new OgreWarriorToken())); + } + + private JoinTheMaestros(final JoinTheMaestros card) { + super(card); + } + + @Override + public JoinTheMaestros copy() { + return new JoinTheMaestros(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JoragaBard.java b/Mage.Sets/src/mage/cards/j/JoragaBard.java index 2dc81eafb22..65f6d7eb878 100644 --- a/Mage.Sets/src/mage/cards/j/JoragaBard.java +++ b/Mage.Sets/src/mage/cards/j/JoragaBard.java @@ -1,7 +1,5 @@ - package mage.cards.j; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AllyEntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; @@ -14,13 +12,14 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class JoragaBard extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Ally creatures you control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("have Ally creatures you control"); static { filter.add(SubType.ALLY.getPredicate()); @@ -28,7 +27,7 @@ public final class JoragaBard extends CardImpl { } public JoragaBard(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.ROGUE); this.subtype.add(SubType.BARD); @@ -37,7 +36,9 @@ public final class JoragaBard extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(4); - this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new GainAbilityAllEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn, filter), true)); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new GainAbilityAllEffect( + VigilanceAbility.getInstance(), Duration.EndOfTurn, filter + ), true).setAbilityWord(null)); } private JoragaBard(final JoragaBard card) { diff --git a/Mage.Sets/src/mage/cards/j/JotunGrunt.java b/Mage.Sets/src/mage/cards/j/JotunGrunt.java index 1bc87e837b4..bd7ae020c3f 100644 --- a/Mage.Sets/src/mage/cards/j/JotunGrunt.java +++ b/Mage.Sets/src/mage/cards/j/JotunGrunt.java @@ -62,7 +62,7 @@ class JotunGruntCost extends CostImpl { public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { - if (targets.choose(Outcome.Removal, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.Removal, controllerId, source.getSourceId(), source, game)) { for (UUID targetId: targets.get(0).getTargets()) { Card card = game.getCard(targetId); if (card == null || game.getState().getZone(targetId) != Zone.GRAVEYARD) { @@ -78,7 +78,7 @@ class JotunGruntCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/j/JotunOwlKeeper.java b/Mage.Sets/src/mage/cards/j/JotunOwlKeeper.java index bd7d7efeada..bf6a7af4807 100644 --- a/Mage.Sets/src/mage/cards/j/JotunOwlKeeper.java +++ b/Mage.Sets/src/mage/cards/j/JotunOwlKeeper.java @@ -31,9 +31,8 @@ public final class JotunOwlKeeper extends CardImpl { // Cumulative upkeep {W} or {U} this.addAbility(new CumulativeUpkeepAbility(new OrCost( - new ManaCostsImpl("{W}"), - new ManaCostsImpl("{U}"), - "{W} or {U}" + "{W} or {U}", new ManaCostsImpl("{W}"), + new ManaCostsImpl("{U}") ))); // When Jötun Owl Keeper dies, put a 1/1 white Bird creature token with flying onto the battlefield for each age counter on it. diff --git a/Mage.Sets/src/mage/cards/j/JourneyForTheElixir.java b/Mage.Sets/src/mage/cards/j/JourneyForTheElixir.java index 659918ec2b3..9f0ed072089 100644 --- a/Mage.Sets/src/mage/cards/j/JourneyForTheElixir.java +++ b/Mage.Sets/src/mage/cards/j/JourneyForTheElixir.java @@ -70,7 +70,7 @@ class JourneyForTheElixirEffect extends OneShotEffect { player.searchLibrary(targetCardInLibrary, source, game); Cards cards = new CardsImpl(targetCardInLibrary.getTargets()); TargetCard target = new JourneyForTheElixirGraveyardTarget(cards); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); cards.addAll(target.getTargets()); player.revealCards(source, cards, game); player.moveCards(cards, Zone.HAND, source, game); @@ -177,8 +177,8 @@ class JourneyForTheElixirGraveyardTarget extends TargetCardInYourGraveyard { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set possibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); Cards alreadyTargeted = new CardsImpl(this.getTargets()); alreadyTargeted.addAll(cards); boolean hasBasic = alreadyTargeted diff --git a/Mage.Sets/src/mage/cards/j/JourneyOfDiscovery.java b/Mage.Sets/src/mage/cards/j/JourneyOfDiscovery.java index cb24153a7e1..cb742f5ce29 100644 --- a/Mage.Sets/src/mage/cards/j/JourneyOfDiscovery.java +++ b/Mage.Sets/src/mage/cards/j/JourneyOfDiscovery.java @@ -27,8 +27,7 @@ public final class JourneyOfDiscovery extends CardImpl { this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0, 2, StaticFilters.FILTER_CARD_BASIC_LANDS), true)); // or you may play up to two additional lands this turn. - Mode mode = new Mode(); - mode.addEffect(new PlayAdditionalLandsControllerEffect(2, Duration.EndOfTurn)); + Mode mode = new Mode(new PlayAdditionalLandsControllerEffect(2, Duration.EndOfTurn)); this.getSpellAbility().getModes().addMode(mode); // Entwine {2}{G} diff --git a/Mage.Sets/src/mage/cards/j/JovensFerrets.java b/Mage.Sets/src/mage/cards/j/JovensFerrets.java index 1f91fe9a7e8..653aad5159d 100644 --- a/Mage.Sets/src/mage/cards/j/JovensFerrets.java +++ b/Mage.Sets/src/mage/cards/j/JovensFerrets.java @@ -82,7 +82,7 @@ class JovensFerretsEffect extends OneShotEffect { BlockedAttackerWatcher watcher = game.getState().getWatcher(BlockedAttackerWatcher.class); if (watcher != null) { List toTap = new ArrayList<>(); - for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { if (!creature.getId().equals(source.getSourceId())) { if (watcher.creatureHasBlockedAttacker(sourcePermanent, creature, game)) { toTap.add(creature); diff --git a/Mage.Sets/src/mage/cards/j/JuganDefendsTheTemple.java b/Mage.Sets/src/mage/cards/j/JuganDefendsTheTemple.java new file mode 100644 index 00000000000..0ccc1720602 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JuganDefendsTheTemple.java @@ -0,0 +1,59 @@ +package mage.cards.j; + +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SagaChapter; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.HumanMonkToken; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JuganDefendsTheTemple extends CardImpl { + + public JuganDefendsTheTemple(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); + + this.subtype.add(SubType.SAGA); + this.secondSideCardClazz = mage.cards.r.RemnantOfTheRisingStar.class; + + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I — Create a 1/1 green Human Monk creature token with "{T}: Add {G}." + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new CreateTokenEffect(new HumanMonkToken())); + + // II — Put a +1/+1 counter on each of up to two target creatures. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), + new TargetPermanent(0, 2, StaticFilters.FILTER_PERMANENT_CREATURES) + ); + + // III — Exile this Saga, then return it to the battlefield transformed under your control. + this.addAbility(new TransformAbility()); + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + + this.addAbility(sagaAbility); + } + + private JuganDefendsTheTemple(final JuganDefendsTheTemple card) { + super(card); + } + + @Override + public JuganDefendsTheTemple copy() { + return new JuganDefendsTheTemple(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JukaiPreserver.java b/Mage.Sets/src/mage/cards/j/JukaiPreserver.java index 5e6e2d017d6..eaf11012be3 100644 --- a/Mage.Sets/src/mage/cards/j/JukaiPreserver.java +++ b/Mage.Sets/src/mage/cards/j/JukaiPreserver.java @@ -10,6 +10,8 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; @@ -38,7 +40,7 @@ public final class JukaiPreserver extends CardImpl { ability = new ChannelAbility( "{2}{G}", new AddCountersTargetEffect(CounterType.P1P1.createInstance()) ); - ability.addTarget(new TargetControlledCreaturePermanent(0, 2)); + ability.addTarget(new TargetPermanent(0, 2, StaticFilters.FILTER_CONTROLLED_CREATURES)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/j/JukaiTrainee.java b/Mage.Sets/src/mage/cards/j/JukaiTrainee.java index b528e0952bd..147dba078fe 100644 --- a/Mage.Sets/src/mage/cards/j/JukaiTrainee.java +++ b/Mage.Sets/src/mage/cards/j/JukaiTrainee.java @@ -26,7 +26,9 @@ public final class JukaiTrainee extends CardImpl { // Whenever Jukai Trainee blocks or becomes blocked, it gets +1/+1 until end of turn. this.addAbility(new BlocksOrBecomesBlockedSourceTriggeredAbility( - new BoostSourceEffect(1, 1, Duration.EndOfTurn), false + new BoostSourceEffect(1, 1, Duration.EndOfTurn) + .setText("it gets +1/+1 until end of turn"), + false, false )); } diff --git a/Mage.Sets/src/mage/cards/j/JumpTrooper.java b/Mage.Sets/src/mage/cards/j/JumpTrooper.java index 20ed86e9b3e..e168b67cb01 100644 --- a/Mage.Sets/src/mage/cards/j/JumpTrooper.java +++ b/Mage.Sets/src/mage/cards/j/JumpTrooper.java @@ -83,7 +83,7 @@ class JumpTrooperTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (game.getOpponents(this.controllerId).contains(event.getPlayerId())) { Permanent creature = game.getPermanent(event.getTargetId()); - if (creature != null && filter.match(creature, getSourceId(), getControllerId(), game)) { + if (creature != null && filter.match(creature, getControllerId(), this, game)) { this.getTargets().clear(); TargetStackObject target = new TargetStackObject(); target.add(event.getSourceId(), game); diff --git a/Mage.Sets/src/mage/cards/j/JundCharm.java b/Mage.Sets/src/mage/cards/j/JundCharm.java index 00603e86dab..266a2181847 100644 --- a/Mage.Sets/src/mage/cards/j/JundCharm.java +++ b/Mage.Sets/src/mage/cards/j/JundCharm.java @@ -29,12 +29,10 @@ public final class JundCharm extends CardImpl { this.getSpellAbility().addEffect(new ExileGraveyardAllTargetPlayerEffect()); this.getSpellAbility().addTarget(new TargetPlayer()); // or Jund Charm deals 2 damage to each creature; - Mode mode = new Mode(); - mode.addEffect(new DamageAllEffect(2, new FilterCreaturePermanent())); + Mode mode = new Mode(new DamageAllEffect(2, new FilterCreaturePermanent())); this.getSpellAbility().addMode(mode); // or put two +1/+1 counters on target creature. - mode = new Mode(); - mode.addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2), Outcome.BoostCreature)); + mode = new Mode(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2), Outcome.BoostCreature)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/j/JundSojourners.java b/Mage.Sets/src/mage/cards/j/JundSojourners.java index c4497a06f6a..edf88190961 100644 --- a/Mage.Sets/src/mage/cards/j/JundSojourners.java +++ b/Mage.Sets/src/mage/cards/j/JundSojourners.java @@ -1,7 +1,5 @@ - package mage.cards.j; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.CycleTriggeredAbility; @@ -9,39 +7,41 @@ import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.keyword.CyclingAbility; +import mage.abilities.meta.OrTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.Zone; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class JundSojourners extends CardImpl { public JundSojourners(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}{R}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{R}{G}"); this.subtype.add(SubType.VIASHINO); this.subtype.add(SubType.SHAMAN); - - - - this.power = new MageInt(3); this.toughness = new MageInt(2); // When you cycle Jund Sojourners or it dies, you may have it deal 1 damage to any target. - Ability ability1 = new CycleTriggeredAbility(new DamageTargetEffect(1)); - Ability ability2 = new DiesSourceTriggeredAbility(new DamageTargetEffect(1)); - ability1.addTarget(new TargetAnyTarget()); - ability2.addTarget(new TargetAnyTarget()); - this.addAbility(ability1); - this.addAbility(ability2); - + Ability ability = new OrTriggeredAbility(Zone.ALL, + new DamageTargetEffect(1).setText("it deal 1 damage to any target"), + true, + "When you cycle {this} or it dies, ", + new CycleTriggeredAbility(null, true), + new DiesSourceTriggeredAbility(null, true) + ); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + // Cycling {2}{R} - this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}{R}"))); + this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{2}{R}"))); } private JundSojourners(final JundSojourners card) { diff --git a/Mage.Sets/src/mage/cards/j/JunjiTheMidnightSky.java b/Mage.Sets/src/mage/cards/j/JunjiTheMidnightSky.java index 803c73e4056..5c61ba24e6c 100644 --- a/Mage.Sets/src/mage/cards/j/JunjiTheMidnightSky.java +++ b/Mage.Sets/src/mage/cards/j/JunjiTheMidnightSky.java @@ -29,7 +29,7 @@ import java.util.UUID; */ public final class JunjiTheMidnightSky extends CardImpl { - private static final FilterCard filter = new FilterCreatureCard("non-Dragon creature card"); + private static final FilterCard filter = new FilterCreatureCard("non-Dragon creature card from a graveyard"); static { filter.add(Predicates.not(SubType.DRAGON.getPredicate())); @@ -60,7 +60,7 @@ public final class JunjiTheMidnightSky extends CardImpl { // • Put target non-Dragon creature card from a graveyard onto the battlefield under your control. You lose 2 life. Mode mode = new Mode(new ReturnFromGraveyardToBattlefieldTargetEffect()); mode.addEffect(new LoseLifeSourceControllerEffect(2)); - ability.addTarget(new TargetCardInGraveyard(filter)); + mode.addTarget(new TargetCardInGraveyard(filter)); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/j/JunkDiver.java b/Mage.Sets/src/mage/cards/j/JunkDiver.java index 02a416c5f48..48fe6c08d0a 100644 --- a/Mage.Sets/src/mage/cards/j/JunkDiver.java +++ b/Mage.Sets/src/mage/cards/j/JunkDiver.java @@ -13,7 +13,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterArtifactCard; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.common.TargetCardInYourGraveyard; /** @@ -25,7 +25,7 @@ public final class JunkDiver extends CardImpl { private static final FilterArtifactCard filter = new FilterArtifactCard("another target artifact card from your graveyard"); static { - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); } public JunkDiver(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/j/JustTheWind.java b/Mage.Sets/src/mage/cards/j/JustTheWind.java index 07c217b0130..5700435a655 100644 --- a/Mage.Sets/src/mage/cards/j/JustTheWind.java +++ b/Mage.Sets/src/mage/cards/j/JustTheWind.java @@ -24,7 +24,7 @@ public final class JustTheWind extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Madness {U} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{U}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{U}"))); } private JustTheWind(final JustTheWind card) { diff --git a/Mage.Sets/src/mage/cards/k/KaaliaOfTheVast.java b/Mage.Sets/src/mage/cards/k/KaaliaOfTheVast.java index 45880434739..0daa958af2c 100644 --- a/Mage.Sets/src/mage/cards/k/KaaliaOfTheVast.java +++ b/Mage.Sets/src/mage/cards/k/KaaliaOfTheVast.java @@ -13,7 +13,6 @@ import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInHand; @@ -120,7 +119,7 @@ class KaaliaOfTheVastEffect extends OneShotEffect { return false; } TargetCardInHand target = new TargetCardInHand(filter); - if (target.canChoose(source.getSourceId(), controller.getId(), game) && target.choose(outcome, controller.getId(), source.getSourceId(), game)) { + if (target.canChoose(controller.getId(), source, game) && target.choose(outcome, controller.getId(), source.getSourceId(), source, game)) { if (!target.getTargets().isEmpty()) { UUID cardId = target.getFirstTarget(); Card card = game.getCard(cardId); diff --git a/Mage.Sets/src/mage/cards/k/KabiraEvangel.java b/Mage.Sets/src/mage/cards/k/KabiraEvangel.java index 7fe59316bef..549022a84a4 100644 --- a/Mage.Sets/src/mage/cards/k/KabiraEvangel.java +++ b/Mage.Sets/src/mage/cards/k/KabiraEvangel.java @@ -1,36 +1,27 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; -import mage.abilities.effects.Effect; +import mage.abilities.common.AllyEntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.continuous.GainProtectionFromColorAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; +import mage.filter.common.FilterControlledPermanent; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class KabiraEvangel extends CardImpl { - private static final FilterControlledCreaturePermanent FILTER1 = new FilterControlledCreaturePermanent(); - - static { - FILTER1.add(SubType.ALLY.getPredicate()); - } + private static final FilterPermanent FILTER1 = new FilterControlledPermanent(SubType.ALLY, "Ally"); public KabiraEvangel(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.subtype.add(SubType.ALLY); @@ -38,13 +29,13 @@ public final class KabiraEvangel extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(3); - FilterPermanent filter2 = new FilterPermanent(getName() + " or another Ally"); - filter2.add(Predicates.or(new CardIdPredicate(this.getId()), SubType.ALLY.getPredicate())); - // Whenever Kabira Evangel or another Ally enters the battlefield under your control, you may choose a color. If you do, Allies you control gain protection from the chosen color until end of turn. - Effect effect = new GainProtectionFromColorAllEffect(Duration.EndOfTurn, FILTER1); - effect.setText("choose a color. If you do, Allies you control gain protection from the chosen color until end of turn."); - this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, effect, filter2, true)); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility( + new GainProtectionFromColorAllEffect(Duration.EndOfTurn, FILTER1) + .setText("choose a color. If you do, Allies you control gain protection " + + "from the chosen color until end of turn."), + true + ).setAbilityWord(null)); } private KabiraEvangel(final KabiraEvangel card) { diff --git a/Mage.Sets/src/mage/cards/k/KabiraVindicator.java b/Mage.Sets/src/mage/cards/k/KabiraVindicator.java index 40ea1119063..3f714f6aa36 100644 --- a/Mage.Sets/src/mage/cards/k/KabiraVindicator.java +++ b/Mage.Sets/src/mage/cards/k/KabiraVindicator.java @@ -37,10 +37,10 @@ public final class KabiraVindicator extends LevelerCard { this.addAbility(new LevelUpAbility(new ManaCostsImpl("{2}{W}"))); Abilities abilities1 = new AbilitiesImpl<>(); - abilities1.add(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE, true))); + abilities1.add(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES, true))); Abilities abilities2 = new AbilitiesImpl<>(); - abilities2.add(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE, true))); + abilities2.add(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES, true))); this.addAbilities(LevelerCardBuilder.construct( new LevelerCardBuilder.LevelAbility(2, 4, abilities1, 3, 6), diff --git a/Mage.Sets/src/mage/cards/k/KadenasSilencer.java b/Mage.Sets/src/mage/cards/k/KadenasSilencer.java index 662044dfb61..3f3c988ba56 100644 --- a/Mage.Sets/src/mage/cards/k/KadenasSilencer.java +++ b/Mage.Sets/src/mage/cards/k/KadenasSilencer.java @@ -33,7 +33,7 @@ public final class KadenasSilencer extends CardImpl { this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new KadenasSilencerEffect())); // Megamorph {1}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{U}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{U}"), true)); } private KadenasSilencer(final KadenasSilencer card) { @@ -67,7 +67,7 @@ class KadenasSilencerEffect extends OneShotEffect { Set opps = game.getOpponents(source.getControllerId()); game.getStack() .stream() - .filter(stackObject -> stackObject instanceof Ability) + .filter(Ability.class::isInstance) .filter(stackObject -> opps.contains(stackObject.getControllerId())) .forEach(stackObject -> game.getStack().counter(stackObject.getId(), source, game)); return true; diff --git a/Mage.Sets/src/mage/cards/k/KaervekTheMerciless.java b/Mage.Sets/src/mage/cards/k/KaervekTheMerciless.java index 22f1c228534..dbbc4528237 100644 --- a/Mage.Sets/src/mage/cards/k/KaervekTheMerciless.java +++ b/Mage.Sets/src/mage/cards/k/KaervekTheMerciless.java @@ -51,7 +51,7 @@ class KaervekTheMercilessEffect extends OneShotEffect { public KaervekTheMercilessEffect() { super(Outcome.Benefit); - this.staticText = "{this} deals damage to any target equal to that spell's mana value"; + this.staticText = "{this} deals damage equal to that spell's mana value to any target"; } public KaervekTheMercilessEffect(final KaervekTheMercilessEffect effect) { diff --git a/Mage.Sets/src/mage/cards/k/KaheeraTheOrphanguard.java b/Mage.Sets/src/mage/cards/k/KaheeraTheOrphanguard.java index 90a868ddd7b..d9d7611fba8 100644 --- a/Mage.Sets/src/mage/cards/k/KaheeraTheOrphanguard.java +++ b/Mage.Sets/src/mage/cards/k/KaheeraTheOrphanguard.java @@ -80,7 +80,7 @@ enum KaheeraTheOrphanguardCompanionCondition implements CompanionCondition { @Override public String getRule() { - return "Each creature card in your starting deck is a Cat, Elemental, Nightmare, Dinosaur or Beast card."; + return "Each creature card in your starting deck is a Cat, Elemental, Nightmare, Dinosaur, or Beast card."; } private static final List subtypes = Arrays.asList( diff --git a/Mage.Sets/src/mage/cards/k/KahoMinamoHistorian.java b/Mage.Sets/src/mage/cards/k/KahoMinamoHistorian.java index 8217dae71e7..f30d6267dba 100644 --- a/Mage.Sets/src/mage/cards/k/KahoMinamoHistorian.java +++ b/Mage.Sets/src/mage/cards/k/KahoMinamoHistorian.java @@ -1,7 +1,5 @@ package mage.cards.k; -import java.util.UUID; -import mage.ApprovingObject; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -11,23 +9,21 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.SearchEffect; -import mage.cards.*; -import mage.constants.CardType; -import mage.constants.ComparisonType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.players.Player; -import mage.target.common.TargetCardInExile; import mage.target.common.TargetCardInLibrary; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class KahoMinamoHistorian extends CardImpl { @@ -88,7 +84,7 @@ class KahoMinamoHistorianEffect extends SearchEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { if (controller.searchLibrary(target, source, game)) { UUID exileZone = CardUtil.getCardExileZoneId(game, source); @@ -109,8 +105,8 @@ class KahoMinamoHistorianCastEffect extends OneShotEffect { public KahoMinamoHistorianCastEffect() { super(Outcome.PlayForFree); - this.staticText = "you may cast a card with mana value X " - + "exiled with {this} without paying its mana cost"; + this.staticText = "you may cast a spell with mana value X " + + "from among cards exiled with {this} without paying its mana cost"; } public KahoMinamoHistorianCastEffect(final KahoMinamoHistorianCastEffect effect) { @@ -125,24 +121,12 @@ class KahoMinamoHistorianCastEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - FilterCard filter = new FilterCard(); - filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, source.getManaCostsToPay().getX())); - TargetCardInExile target = new TargetCardInExile(filter, CardUtil.getCardExileZoneId(game, source)); - Cards cards = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); - if (cards != null - && !cards.isEmpty() - && controller.choose(Outcome.PlayForFree, cards, target, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - } - } - return true; + Cards cards = new CardsImpl(game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source))); + if (controller == null || cards.isEmpty()) { + return false; } - return false; + FilterCard filter = new FilterCard(); + filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, source.getManaCostsToPay().getX())); + return CardUtil.castSpellWithAttributesForFree(controller, source, game, cards, filter); } } diff --git a/Mage.Sets/src/mage/cards/k/KaijinOfTheVanishingTouch.java b/Mage.Sets/src/mage/cards/k/KaijinOfTheVanishingTouch.java index 88b1f5ac6d4..ed7abd4aaa3 100644 --- a/Mage.Sets/src/mage/cards/k/KaijinOfTheVanishingTouch.java +++ b/Mage.Sets/src/mage/cards/k/KaijinOfTheVanishingTouch.java @@ -1,11 +1,9 @@ - package mage.cards.k; import java.util.UUID; import mage.MageInt; -import mage.abilities.common.BlocksSourceTriggeredAbility; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.DefenderAbility; @@ -31,9 +29,11 @@ public final class KaijinOfTheVanishingTouch extends CardImpl { this.addAbility(DefenderAbility.getInstance()); // Whenever Kaijin of the Vanishing Touch blocks a creature, return that creature to its owner's hand at end of combat. - Effect effect = new ReturnToHandTargetEffect(); - effect.setText("return that creature to its owner's hand at end of combat"); - this.addAbility(new BlocksSourceTriggeredAbility(new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(effect)), false, true)); + this.addAbility(new BlocksCreatureTriggeredAbility( + new CreateDelayedTriggeredAbilityEffect( + new AtTheEndOfCombatDelayedTriggeredAbility(new ReturnToHandTargetEffect()) + ).setText("return that creature to its owner's hand at end of combat") + )); } private KaijinOfTheVanishingTouch(final KaijinOfTheVanishingTouch card) { diff --git a/Mage.Sets/src/mage/cards/k/KaimaTheFracturedCalm.java b/Mage.Sets/src/mage/cards/k/KaimaTheFracturedCalm.java new file mode 100644 index 00000000000..91fcfcefc02 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KaimaTheFracturedCalm.java @@ -0,0 +1,94 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.combat.GoadTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KaimaTheFracturedCalm extends CardImpl { + + public KaimaTheFracturedCalm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // At the beginning of your end step, goad each creature your opponents control that's enchanted by an Aura you control. Put a +1/+1 counter on Kaima, the Fractured Calm for each creature goaded this way. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new KaimaTheFracturedCalmEffect(), TargetController.YOU, false + )); + } + + private KaimaTheFracturedCalm(final KaimaTheFracturedCalm card) { + super(card); + } + + @Override + public KaimaTheFracturedCalm copy() { + return new KaimaTheFracturedCalm(this); + } +} + +class KaimaTheFracturedCalmEffect extends OneShotEffect { + + KaimaTheFracturedCalmEffect() { + super(Outcome.Benefit); + staticText = "goad each creature your opponents control that's enchanted by an Aura you control. " + + "Put a +1/+1 counter on {this} for each creature goaded this way"; + } + + private KaimaTheFracturedCalmEffect(final KaimaTheFracturedCalmEffect effect) { + super(effect); + } + + @Override + public KaimaTheFracturedCalmEffect copy() { + return new KaimaTheFracturedCalmEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int goaded = 0; + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, + source.getControllerId(), source, game + )) { + if (permanent + .getAttachments() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .noneMatch(p -> p.isControlledBy(source.getControllerId()) + && p.hasSubtype(SubType.AURA, game))) { + continue; + } + game.addEffect(new GoadTargetEffect().setTargetPointer(new FixedTarget(permanent, game)), source); + goaded++; + } + if (goaded < 1) { + return false; + } + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent != null) { + permanent.addCounters(CounterType.P1P1.createInstance(goaded), source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KaitoShizuki.java b/Mage.Sets/src/mage/cards/k/KaitoShizuki.java index 55f0322f2c5..b5f45b0770e 100644 --- a/Mage.Sets/src/mage/cards/k/KaitoShizuki.java +++ b/Mage.Sets/src/mage/cards/k/KaitoShizuki.java @@ -3,7 +3,6 @@ package mage.cards.k; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.RaidCondition; @@ -23,6 +22,7 @@ import mage.game.Game; import mage.game.command.emblems.KaitoShizukiEmblem; import mage.game.permanent.Permanent; import mage.game.permanent.token.NinjaToken; +import mage.watchers.common.PlayerAttackedWatcher; import java.util.UUID; @@ -41,7 +41,7 @@ public final class KaitoShizuki extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KAITO); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // At the beginning of your end step, if Kaito Shizuki entered the battlefield this turn, he phases out. this.addAbility(new BeginningOfEndStepTriggeredAbility( @@ -55,7 +55,7 @@ public final class KaitoShizuki extends CardImpl { new DiscardControllerEffect(1), condition, "Then discard a card unless you attacked this turn" )); - this.addAbility(ability.addHint(RaidHint.instance)); + this.addAbility(ability.addHint(RaidHint.instance), new PlayerAttackedWatcher()); // −2: Create a 1/1 blue Ninja creature token with "This creature can't be blocked." this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new NinjaToken()), -2)); diff --git a/Mage.Sets/src/mage/cards/k/KalonianHydra.java b/Mage.Sets/src/mage/cards/k/KalonianHydra.java index c47a872f4e4..9d44e4580ec 100644 --- a/Mage.Sets/src/mage/cards/k/KalonianHydra.java +++ b/Mage.Sets/src/mage/cards/k/KalonianHydra.java @@ -15,10 +15,8 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Outcome; -import mage.constants.TargetController; import mage.counters.CounterType; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -73,7 +71,7 @@ class KalonianHydraEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - List permanents = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_CREATURE_P1P1, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_CREATURE_P1P1, source.getControllerId(), source, game); for (Permanent permanent : permanents) { int existingCounters = permanent.getCounters(game).getCount(CounterType.P1P1); if (existingCounters > 0) { diff --git a/Mage.Sets/src/mage/cards/k/KamahlsSummons.java b/Mage.Sets/src/mage/cards/k/KamahlsSummons.java index cc9c27c89c4..b9d5c50615f 100644 --- a/Mage.Sets/src/mage/cards/k/KamahlsSummons.java +++ b/Mage.Sets/src/mage/cards/k/KamahlsSummons.java @@ -61,7 +61,7 @@ class KamahlsSummonsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { Map revealedCards = new HashMap<>(); for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { @@ -69,7 +69,7 @@ class KamahlsSummonsEffect extends OneShotEffect { if (player != null) { if (player.getHand().count(StaticFilters.FILTER_CARD_CREATURE, game) > 0) { TargetCardInHand target = new TargetCardInHand(0, Integer.MAX_VALUE, StaticFilters.FILTER_CARD_CREATURE); - if (player.choose(outcome, target, source.getSourceId(), game)) { + if (player.choose(outcome, target, source, game)) { Cards cards = new CardsImpl(target.getTargets()); controller.revealCards(sourceObject.getIdName(), cards, game); revealedCards.put(playerId, target.getTargets().size()); diff --git a/Mage.Sets/src/mage/cards/k/KamahlsWill.java b/Mage.Sets/src/mage/cards/k/KamahlsWill.java index 251dacffce0..cd59cb8a5b8 100644 --- a/Mage.Sets/src/mage/cards/k/KamahlsWill.java +++ b/Mage.Sets/src/mage/cards/k/KamahlsWill.java @@ -91,7 +91,7 @@ class KamahlsWillEffect extends OneShotEffect { } for (Permanent creature : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game )) { if (creature == null || creature.getPower().getValue() < 1) { continue; diff --git a/Mage.Sets/src/mage/cards/k/KamiOfCelebration.java b/Mage.Sets/src/mage/cards/k/KamiOfCelebration.java new file mode 100644 index 00000000000..23e1899a516 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KamiOfCelebration.java @@ -0,0 +1,85 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.common.AttacksCreatureYouControlTriggeredAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEndOfTurnEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.ModifiedPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KamiOfCelebration extends CardImpl { + + private static final FilterControlledCreaturePermanent filter + = new FilterControlledCreaturePermanent("a modified creature you control"); + + static { + filter.add(ModifiedPredicate.instance); + } + + public KamiOfCelebration(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever a modified creature you control attacks, exile the top card of your library. You may play that card this turn. + this.addAbility(new AttacksCreatureYouControlTriggeredAbility( + new ExileTopXMayPlayUntilEndOfTurnEffect(1), false, filter + )); + + // Whenever you cast a spell from exile, put a +1/+1 counter on target creature you control. + this.addAbility(new KamiOfCelebrationAbility()); + } + + private KamiOfCelebration(final KamiOfCelebration card) { + super(card); + } + + @Override + public KamiOfCelebration copy() { + return new KamiOfCelebration(this); + } +} + +class KamiOfCelebrationAbility extends SpellCastControllerTriggeredAbility { + + KamiOfCelebrationAbility() { + super(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false); + this.addTarget(new TargetControlledCreaturePermanent()); + } + + private KamiOfCelebrationAbility(final KamiOfCelebrationAbility ability) { + super(ability); + } + + @Override + public KamiOfCelebrationAbility copy() { + return new KamiOfCelebrationAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getZone() == Zone.EXILED && super.checkTrigger(event, game); + } + + @Override + public String getRule() { + return "Whenever you cast a spell from exile, put a +1/+1 counter on target creature you control."; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KamiOfIndustry.java b/Mage.Sets/src/mage/cards/k/KamiOfIndustry.java new file mode 100644 index 00000000000..1aa23bac775 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KamiOfIndustry.java @@ -0,0 +1,97 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.common.FilterArtifactCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KamiOfIndustry extends CardImpl { + + private static final FilterCard filter + = new FilterArtifactCard("artifact card with mana value 3 or less from your graveyard"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); + } + + public KamiOfIndustry(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(3); + this.toughness = new MageInt(6); + + // When Kami of Industry enters the battlefield, return target artifact card with mana value 3 or less from your graveyard to the battlefield. It gains haste. Sacrifice it at the beginning of the next end step. + Ability ability = new EntersBattlefieldTriggeredAbility(new KamiOfIndustryEffect()); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); + } + + private KamiOfIndustry(final KamiOfIndustry card) { + super(card); + } + + @Override + public KamiOfIndustry copy() { + return new KamiOfIndustry(this); + } +} + +class KamiOfIndustryEffect extends OneShotEffect { + + KamiOfIndustryEffect() { + super(Outcome.Benefit); + staticText = "return target artifact card with mana value 3 or less from your graveyard " + + "to the battlefield. It gains haste. Sacrifice it at the beginning of the next end step"; + } + + private KamiOfIndustryEffect(final KamiOfIndustryEffect effect) { + super(effect); + } + + @Override + public KamiOfIndustryEffect copy() { + return new KamiOfIndustryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(source.getFirstTarget()); + if (player == null || card == null) { + return false; + } + player.moveCards(card, Zone.BATTLEFIELD, source, game); + Permanent permanent = game.getPermanent(card.getId()); + if (permanent == null) { + return false; + } + game.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance()) + .setTargetPointer(new FixedTarget(permanent, game)), source); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new SacrificeTargetEffect("sacrifice it").setTargetPointer(new FixedTarget(permanent, game)) + ), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KappaCannoneer.java b/Mage.Sets/src/mage/cards/k/KappaCannoneer.java new file mode 100644 index 00000000000..7ea0c9a5658 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KappaCannoneer.java @@ -0,0 +1,58 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.ImproviseAbility; +import mage.abilities.keyword.WardAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KappaCannoneer extends CardImpl { + + public KappaCannoneer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{5}{U}"); + + this.subtype.add(SubType.TURTLE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Improvise + this.addAbility(new ImproviseAbility()); + + // Ward {4} + this.addAbility(new WardAbility(new ManaCostsImpl<>("{4}"))); + + // Whenever an artifact enters the battlefield under your control, put a +1/+1 counter on Kappa Cannoneer and it can't be blocked this turn. + Ability ability = new EntersBattlefieldControlledTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_AN + ); + ability.addEffect(new CantBeBlockedSourceEffect(Duration.EndOfTurn) + .setText("and it can't be blocked this turn")); + this.addAbility(ability); + } + + private KappaCannoneer(final KappaCannoneer card) { + super(card); + } + + @Override + public KappaCannoneer copy() { + return new KappaCannoneer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KarfellHarbinger.java b/Mage.Sets/src/mage/cards/k/KarfellHarbinger.java index 1130d6edb6f..344118bc279 100644 --- a/Mage.Sets/src/mage/cards/k/KarfellHarbinger.java +++ b/Mage.Sets/src/mage/cards/k/KarfellHarbinger.java @@ -75,7 +75,7 @@ class KarfellHarbingerManaCondition extends ManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { if (source instanceof SpellAbility) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && object.isInstantOrSorcery(game); } return source instanceof ForetellAbility; diff --git a/Mage.Sets/src/mage/cards/k/KariZevSkyshipRaider.java b/Mage.Sets/src/mage/cards/k/KariZevSkyshipRaider.java index da85aef699a..d028250a9f7 100644 --- a/Mage.Sets/src/mage/cards/k/KariZevSkyshipRaider.java +++ b/Mage.Sets/src/mage/cards/k/KariZevSkyshipRaider.java @@ -58,7 +58,7 @@ class KariZevSkyshipRaiderEffect extends OneShotEffect { KariZevSkyshipRaiderEffect() { super(Outcome.PutCreatureInPlay); - staticText = "create Ragaven, a legendary 2/1 red Monkey creature token. Ragavan enters the battlefied tapped and attacking. Exile that token at end of combat"; + staticText = "create Ragavan, a legendary 2/1 red Monkey creature token. Ragavan enters the battlefield tapped and attacking. Exile that token at end of combat"; } KariZevSkyshipRaiderEffect(final KariZevSkyshipRaiderEffect effect) { diff --git a/Mage.Sets/src/mage/cards/k/KariZevsExpertise.java b/Mage.Sets/src/mage/cards/k/KariZevsExpertise.java index 2f2b75f23d8..a92b7571acf 100644 --- a/Mage.Sets/src/mage/cards/k/KariZevsExpertise.java +++ b/Mage.Sets/src/mage/cards/k/KariZevsExpertise.java @@ -1,32 +1,39 @@ package mage.cards.k; -import java.util.UUID; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; -import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect; +import mage.abilities.effects.common.cost.CastFromHandForFreeEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.Duration; import mage.constants.SubType; +import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class KariZevsExpertise extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("creature or Vehicle"); + private static final FilterCard filter2 = new FilterCard("a spell with mana value 2 or less"); static { - filter.add(Predicates.or(CardType.CREATURE.getPredicate(), - SubType.VEHICLE.getPredicate())); + filter.add(Predicates.or( + CardType.CREATURE.getPredicate(), + SubType.VEHICLE.getPredicate() + )); + filter2.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 3)); } public KariZevsExpertise(UUID ownerId, CardSetInfo setInfo) { @@ -36,10 +43,12 @@ public final class KariZevsExpertise extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn)); this.getSpellAbility().addEffect(new UntapTargetEffect().setText("Untap it")); - this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn).setText("It gains haste until end of turn")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("It gains haste until end of turn")); // You may cast a card with converted mana cost 2 or less from your hand without paying its mana cost. - this.getSpellAbility().addEffect(new CastWithoutPayingManaCostEffect(2).concatBy("
")); + this.getSpellAbility().addEffect(new CastFromHandForFreeEffect(filter2).concatBy("
")); } private KariZevsExpertise(final KariZevsExpertise card) { diff --git a/Mage.Sets/src/mage/cards/k/KarnLiberated.java b/Mage.Sets/src/mage/cards/k/KarnLiberated.java index f9fb4e0cfd1..d83d596df4e 100644 --- a/Mage.Sets/src/mage/cards/k/KarnLiberated.java +++ b/Mage.Sets/src/mage/cards/k/KarnLiberated.java @@ -4,7 +4,6 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetForSourceEffect; import mage.cards.*; @@ -35,7 +34,7 @@ public final class KarnLiberated extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{7}"); this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KARN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(6)); + this.setStartingLoyalty(6); // +4: Target player exiles a card from their hand. LoyaltyAbility ability1 = new LoyaltyAbility(new KarnPlayerExileEffect(), 4); @@ -239,7 +238,7 @@ class KarnPlayerExileEffect extends OneShotEffect { return false; } TargetCardInHand target = new TargetCardInHand(); - if (target.canChoose(source.getSourceId(), player.getId(), game) + if (target.canChoose(player.getId(), source, game) && target.chooseTarget(Outcome.Exile, player.getId(), source, game)) { UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); return player.moveCardsToExile(new CardsImpl(target.getTargets()).getCards(game), source, game, true, exileId, sourceObject.getIdName()); diff --git a/Mage.Sets/src/mage/cards/k/KarnScionOfUrza.java b/Mage.Sets/src/mage/cards/k/KarnScionOfUrza.java index ed5784b42a6..0ad22cce20b 100644 --- a/Mage.Sets/src/mage/cards/k/KarnScionOfUrza.java +++ b/Mage.Sets/src/mage/cards/k/KarnScionOfUrza.java @@ -1,9 +1,7 @@ package mage.cards.k; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.common.ArtifactYouControlHint; @@ -11,17 +9,19 @@ import mage.cards.*; import mage.constants.*; import mage.counters.CounterType; import mage.filter.FilterCard; -import mage.game.ExileZone; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.token.KarnConstructToken; import mage.players.Player; import mage.target.Target; import mage.target.TargetCard; +import mage.target.common.TargetCardInExile; import mage.target.common.TargetOpponent; -import java.util.List; +import java.util.Objects; import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; /** * @author spjspj @@ -33,20 +33,18 @@ public final class KarnScionOfUrza extends CardImpl { addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KARN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Reveal the top two cards of your library. An opponent chooses one of them. Put that card into your hand and exile the other with a silver counter on it. - LoyaltyAbility ability1 = new LoyaltyAbility(new KarnPlus1Effect(), 1); - this.addAbility(ability1); + this.addAbility(new LoyaltyAbility(new KarnPlus1Effect(), 1)); // -1: Put a card you own with a silver counter on it from exile into your hand. - LoyaltyAbility ability2 = new LoyaltyAbility(new KarnMinus1Effect(), -1); - this.addAbility(ability2); + this.addAbility(new LoyaltyAbility(new KarnMinus1Effect(), -1)); // -2: Create a 0/0 colorless Construct artifact creature token with "This creature gets +1/+1 for each artifact you control." - LoyaltyAbility ability3 = new LoyaltyAbility(new CreateTokenEffect(new KarnConstructToken(), 1), -2); - ability3.addHint(ArtifactYouControlHint.instance); - this.addAbility(ability3); + this.addAbility(new LoyaltyAbility(new CreateTokenEffect( + new KarnConstructToken(), 1 + ), -2).addHint(ArtifactYouControlHint.instance)); } private KarnScionOfUrza(final KarnScionOfUrza card) { @@ -79,44 +77,47 @@ class KarnPlus1Effect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (sourceObject == null || controller == null) { + if (controller == null) { return false; } Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 2)); - if (cards.isEmpty()) { return true; } - controller.revealCards(staticText, cards, game); + controller.revealCards(source, cards, game); Card cardToHand; - if (cards.size() == 1) { - cardToHand = cards.getRandom(game); - } else { - Player opponent; - Set opponents = game.getOpponents(controller.getId()); - if (opponents.size() == 1) { - opponent = game.getPlayer(opponents.iterator().next()); - } else { - Target target = new TargetOpponent(true); - controller.chooseTarget(Outcome.Detriment, target, source, game); - opponent = game.getPlayer(target.getFirstTarget()); - } - TargetCard target = new TargetCard(1, Zone.LIBRARY, new FilterCard()); - opponent.chooseTarget(outcome, cards, target, source, game); - cardToHand = game.getCard(target.getFirstTarget()); + switch (cards.size()) { + case 0: + return false; + case 1: + cardToHand = cards.getRandom(game); + break; + default: + Player opponent; + Set opponents = game.getOpponents(controller.getId()); + if (opponents.size() == 1) { + opponent = game.getPlayer(opponents.iterator().next()); + } else { + Target target = new TargetOpponent(true); + controller.chooseTarget(Outcome.Detriment, target, source, game); + opponent = game.getPlayer(target.getFirstTarget()); + } + TargetCard target = new TargetCard(1, Zone.LIBRARY, StaticFilters.FILTER_CARD); + opponent.chooseTarget(outcome, cards, target, source, game); + cardToHand = game.getCard(target.getFirstTarget()); } if (cardToHand != null) { controller.moveCards(cardToHand, Zone.HAND, source, game); - cards.remove(cardToHand); } - if (!cards.isEmpty()) { - controller.moveCards(cards, Zone.EXILED, source, game); - for (Card c : cards.getCards(game)) { - c.addCounters(CounterType.SILVER.createInstance(1), source.getControllerId(), source, game); - } + cards.retainZone(Zone.LIBRARY, game); + if (cards.isEmpty()) { + return true; } + controller.moveCards(cards, Zone.EXILED, source, game); + cards.getCards(game) + .stream() + .forEach(card -> card.addCounters(CounterType.SILVER.createInstance(1), source, game)); return true; } } @@ -149,38 +150,29 @@ class KarnMinus1Effect extends OneShotEffect { if (controller == null) { return false; } - ExileZone exZone = game.getExile().getPermanentExile(); // getExileZone(Zone.EXILED); - if (exZone == null) { - return true; - } - Card card = null; - - List exile = game.getExile().getAllCards(game); - boolean noTargets = exile.isEmpty(); - if (noTargets) { - game.informPlayer(controller, "You have no exiled cards."); - return true; - } - - Cards filteredCards = new CardsImpl(); - - for (Card exileCard : exile) { - if (exileCard.isOwnedBy(source.getControllerId()) && filter.match(exileCard, game)) { - filteredCards.add(exileCard); - } - } - - TargetCard target = new TargetCard(Zone.EXILED, filter); - target.setNotTarget(true); - if (!controller.choose(Outcome.Benefit, filteredCards, target, game)) { - return true; + Cards cards = new CardsImpl(game + .getExile() + .getCards(filter, game) + .stream() + .filter(Objects::nonNull) + .filter(card -> card.isOwnedBy(source.getControllerId())) + .collect(Collectors.toList())); + Card card; + switch (cards.size()) { + case 0: + return false; + case 1: + card = cards.getRandom(game); + break; + default: + TargetCard target = new TargetCardInExile(filter); + target.setNotTarget(true); + controller.choose(outcome, target, source, game); + card = cards.get(target.getFirstTarget(), game); } if (card == null) { - card = game.getCard(target.getFirstTarget()); + return false; } - if (card != null) { - controller.moveCards(card, Zone.HAND, source, game); - } - return true; + return card != null && controller.moveCards(card, Zone.HAND, source, game); } } diff --git a/Mage.Sets/src/mage/cards/k/KarnSilverGolem.java b/Mage.Sets/src/mage/cards/k/KarnSilverGolem.java index 6a92f4ac25f..a121a156d0f 100644 --- a/Mage.Sets/src/mage/cards/k/KarnSilverGolem.java +++ b/Mage.Sets/src/mage/cards/k/KarnSilverGolem.java @@ -41,7 +41,7 @@ public final class KarnSilverGolem extends CardImpl { this.addAbility(new BlocksOrBecomesBlockedSourceTriggeredAbility(new BoostSourceEffect(-4, +4, Duration.EndOfTurn), false)); // {1}: Target noncreature artifact becomes an artifact creature with power and toughness each equal to its converted mana cost until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new KarnSilverGolemEffect(), new ManaCostsImpl("{1")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new KarnSilverGolemEffect(), new ManaCostsImpl("{1}")); ability.addTarget(new TargetPermanent(filterNonCreature)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KarnTheGreatCreator.java b/Mage.Sets/src/mage/cards/k/KarnTheGreatCreator.java index a65402c9012..0c28284bed8 100644 --- a/Mage.Sets/src/mage/cards/k/KarnTheGreatCreator.java +++ b/Mage.Sets/src/mage/cards/k/KarnTheGreatCreator.java @@ -2,7 +2,6 @@ package mage.cards.k; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.RestrictionEffect; @@ -38,7 +37,7 @@ public final class KarnTheGreatCreator extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KARN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Activated abilities of artifacts your opponents control can't be activated. this.addAbility(new SimpleStaticAbility(new KarnTheGreatCreatorCantActivateEffect())); diff --git a/Mage.Sets/src/mage/cards/k/KaronaFalseGod.java b/Mage.Sets/src/mage/cards/k/KaronaFalseGod.java index f4874f657c7..6eeba08e646 100644 --- a/Mage.Sets/src/mage/cards/k/KaronaFalseGod.java +++ b/Mage.Sets/src/mage/cards/k/KaronaFalseGod.java @@ -122,7 +122,7 @@ class KaronaFalseGodEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && controller != null) { Choice typeChoice = new ChoiceCreatureType(sourceObject); if (!controller.choose(Outcome.BoostCreature, typeChoice, game)) { diff --git a/Mage.Sets/src/mage/cards/k/KaronasZealot.java b/Mage.Sets/src/mage/cards/k/KaronasZealot.java index 5f1f804bfc7..5432c1d6b96 100644 --- a/Mage.Sets/src/mage/cards/k/KaronasZealot.java +++ b/Mage.Sets/src/mage/cards/k/KaronasZealot.java @@ -30,7 +30,7 @@ public final class KaronasZealot extends CardImpl { this.toughness = new MageInt(5); // Morph {3}{W}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{W}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{W}{W}"))); // When Karona's Zealot is turned face up, all damage that would be dealt to it this turn is dealt to target creature instead. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new RedirectDamageFromSourceToTargetEffect(Duration.EndOfTurn, Integer.MAX_VALUE, ACCORDING_DURATION) diff --git a/Mage.Sets/src/mage/cards/k/KasminaEnigmaSage.java b/Mage.Sets/src/mage/cards/k/KasminaEnigmaSage.java index 18555194544..73b34aed2ec 100644 --- a/Mage.Sets/src/mage/cards/k/KasminaEnigmaSage.java +++ b/Mage.Sets/src/mage/cards/k/KasminaEnigmaSage.java @@ -3,7 +3,6 @@ package mage.cards.k; import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.GetXLoyaltyValue; import mage.abilities.effects.ContinuousEffectImpl; @@ -37,7 +36,7 @@ public final class KasminaEnigmaSage extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KASMINA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(2)); + this.setStartingLoyalty(2); // Each other planeswalker you control has the loyalty abilities of Kasmina, Enigma Sage. this.addAbility(new SimpleStaticAbility(new KasminaEnigmaSageGainAbilitiesEffect())); @@ -88,7 +87,7 @@ class KasminaEnigmaSageGainAbilitiesEffect extends ContinuousEffectImpl { .collect(Collectors.toList()); for (Permanent permanent : game.getState().getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_PERMANENT_PLANESWALKER, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game )) { if (permanent == null || permanent == perm) { continue; diff --git a/Mage.Sets/src/mage/cards/k/KasminaEnigmaticMentor.java b/Mage.Sets/src/mage/cards/k/KasminaEnigmaticMentor.java index 1d88da9af44..fef968cad21 100644 --- a/Mage.Sets/src/mage/cards/k/KasminaEnigmaticMentor.java +++ b/Mage.Sets/src/mage/cards/k/KasminaEnigmaticMentor.java @@ -3,7 +3,6 @@ package mage.cards.k; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.SpellAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DrawDiscardControllerEffect; @@ -31,7 +30,7 @@ public final class KasminaEnigmaticMentor extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KASMINA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Spells your opponents cast that target a creature or planeswalker you control cost {2} more to cast. this.addAbility(new SimpleStaticAbility(new KasminaEnigmaticMentorCostModificationEffect())); diff --git a/Mage.Sets/src/mage/cards/k/KatabaticWinds.java b/Mage.Sets/src/mage/cards/k/KatabaticWinds.java index c3e29e029d7..8e2d4eba936 100644 --- a/Mage.Sets/src/mage/cards/k/KatabaticWinds.java +++ b/Mage.Sets/src/mage/cards/k/KatabaticWinds.java @@ -84,7 +84,7 @@ class KatabaticWindsRestrictionEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filter.match(permanent, source.getControllerId(), source, game); } } diff --git a/Mage.Sets/src/mage/cards/k/KathariBomber.java b/Mage.Sets/src/mage/cards/k/KathariBomber.java index b5329645d1d..fb766421fc2 100644 --- a/Mage.Sets/src/mage/cards/k/KathariBomber.java +++ b/Mage.Sets/src/mage/cards/k/KathariBomber.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; @@ -16,27 +14,28 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.game.permanent.token.GoblinToken; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class KathariBomber extends CardImpl { public KathariBomber(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{R}"); this.subtype.add(SubType.BIRD); this.subtype.add(SubType.SHAMAN); - - - this.power = new MageInt(2); this.toughness = new MageInt(2); // Flying this.addAbility(FlyingAbility.getInstance()); + // When Kathari Bomber deals combat damage to a player, create two 1/1 red Goblin creature tokens and sacrifice Kathari Bomber. - Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new CreateTokenEffect(new GoblinToken(), 2), false); - ability.addEffect(new SacrificeSourceEffect()); + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility( + new CreateTokenEffect(new GoblinToken(), 2), false + ).setTriggerPhrase("When {this} deals combat damage to a player, "); + ability.addEffect(new SacrificeSourceEffect().concatBy("and")); this.addAbility(ability); // Unearth {3}{B}{R} diff --git a/Mage.Sets/src/mage/cards/k/KathrilAspectWarper.java b/Mage.Sets/src/mage/cards/k/KathrilAspectWarper.java index 02e909f4aae..b91ddaca877 100644 --- a/Mage.Sets/src/mage/cards/k/KathrilAspectWarper.java +++ b/Mage.Sets/src/mage/cards/k/KathrilAspectWarper.java @@ -102,7 +102,7 @@ class KathrilAspectWarperEffect extends OneShotEffect { = new FilterControlledCreaturePermanent("creature to give a " + counterType + " counter"); Target target = new TargetControlledPermanent(filter); target.setNotTarget(true); - if (!player.choose(outcome, target, source.getSourceId(), game)) { + if (!player.choose(outcome, target, source, game)) { continue; } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/k/KatsumasaTheAnimator.java b/Mage.Sets/src/mage/cards/k/KatsumasaTheAnimator.java new file mode 100644 index 00000000000..ecedfaf2196 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KatsumasaTheAnimator.java @@ -0,0 +1,114 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.AddCardTypeTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterArtifactPermanent; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KatsumasaTheAnimator extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledArtifactPermanent("noncreature artifact you control"); + private static final FilterPermanent filter2 + = new FilterArtifactPermanent("noncreature artifacts"); + + static { + filter.add(Predicates.not(CardType.CREATURE.getPredicate())); + filter2.add(Predicates.not(CardType.CREATURE.getPredicate())); + } + + public KatsumasaTheAnimator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.MOONFOLK); + this.subtype.add(SubType.ARTIFICER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {2}{U}: Until end of turn, target noncreature artifact you control becomes an artifact creature and gains flying. If it's not a Vehicle, it has base power and toughness 1/1 until end of turn. + Ability ability = new SimpleActivatedAbility(new KatsumasaTheAnimatorEffect(), new ManaCostsImpl<>("{2}{U}")); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + + // At the beginning of your upkeep, put a +1/+1 counter on each of up to three target noncreature artifacts. + ability = new BeginningOfUpkeepTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), TargetController.YOU, false + ); + ability.addTarget(new TargetPermanent(0, 3, filter2)); + this.addAbility(ability); + } + + private KatsumasaTheAnimator(final KatsumasaTheAnimator card) { + super(card); + } + + @Override + public KatsumasaTheAnimator copy() { + return new KatsumasaTheAnimator(this); + } +} + +class KatsumasaTheAnimatorEffect extends OneShotEffect { + + KatsumasaTheAnimatorEffect() { + super(Outcome.Benefit); + staticText = "until end of turn, target noncreature artifact you control becomes an artifact creature " + + "and gains flying. If it's not a Vehicle, it has base power and toughness 1/1 until end of turn"; + } + + private KatsumasaTheAnimatorEffect(final KatsumasaTheAnimatorEffect effect) { + super(effect); + } + + @Override + public KatsumasaTheAnimatorEffect copy() { + return new KatsumasaTheAnimatorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + game.addEffect(new AddCardTypeTargetEffect( + Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE + ), source); + game.addEffect(new GainAbilityTargetEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ), source); + if (!permanent.hasSubtype(SubType.VEHICLE, game)) { + game.addEffect(new SetPowerToughnessTargetEffect( + 1, 1, Duration.EndOfTurn + ), source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KavuScout.java b/Mage.Sets/src/mage/cards/k/KavuScout.java index 49f0682e841..81778331d5a 100644 --- a/Mage.Sets/src/mage/cards/k/KavuScout.java +++ b/Mage.Sets/src/mage/cards/k/KavuScout.java @@ -32,7 +32,7 @@ public final class KavuScout extends CardImpl { this.toughness = new MageInt(2); // Domain - Kavu Scout gets +1/+0 for each basic land type among lands you control. - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceEffect(new DomainValue(), StaticValue.get(0), Duration.WhileOnBattlefield)); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceEffect(DomainValue.REGULAR, StaticValue.get(0), Duration.WhileOnBattlefield)); ability.setAbilityWord(AbilityWord.DOMAIN); this.addAbility(ability.addHint(DomainHint.instance)); } diff --git a/Mage.Sets/src/mage/cards/k/KayaBaneOfTheDead.java b/Mage.Sets/src/mage/cards/k/KayaBaneOfTheDead.java index 13ab5564c8d..542a24cbce8 100644 --- a/Mage.Sets/src/mage/cards/k/KayaBaneOfTheDead.java +++ b/Mage.Sets/src/mage/cards/k/KayaBaneOfTheDead.java @@ -2,7 +2,6 @@ package mage.cards.k; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.common.ExileTargetEffect; @@ -25,7 +24,7 @@ public final class KayaBaneOfTheDead extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KAYA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(7)); + this.setStartingLoyalty(7); // Your opponents and permanents your opponents control with hexproof can be the target of spells and abilities you control as though they didn't have hexproof. this.addAbility(new SimpleStaticAbility(new KayaBaneOfTheDeadEffect())); @@ -50,7 +49,7 @@ class KayaBaneOfTheDeadEffect extends AsThoughEffectImpl { KayaBaneOfTheDeadEffect() { super(AsThoughEffectType.HEXPROOF, Duration.WhileOnBattlefield, Outcome.Benefit); - staticText = "your opponents and creatures with hexproof they control " + + staticText = "your opponents and permanents your opponents control with hexproof " + "can be the targets of spells and abilities you control as though they didn't have hexproof"; } diff --git a/Mage.Sets/src/mage/cards/k/KayaGeistHunter.java b/Mage.Sets/src/mage/cards/k/KayaGeistHunter.java index e2770582a67..36c28eb247a 100644 --- a/Mage.Sets/src/mage/cards/k/KayaGeistHunter.java +++ b/Mage.Sets/src/mage/cards/k/KayaGeistHunter.java @@ -2,7 +2,6 @@ package mage.cards.k; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; @@ -44,7 +43,7 @@ public final class KayaGeistHunter extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KAYA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Creatures you control gain deathtouch until end of turn. Put a +1/+1 counter on up to one target creature token you control. Ability ability = new LoyaltyAbility(new GainAbilityControlledEffect( diff --git a/Mage.Sets/src/mage/cards/k/KayaGhostAssassin.java b/Mage.Sets/src/mage/cards/k/KayaGhostAssassin.java index 75183e44148..b30e9f50509 100644 --- a/Mage.Sets/src/mage/cards/k/KayaGhostAssassin.java +++ b/Mage.Sets/src/mage/cards/k/KayaGhostAssassin.java @@ -2,7 +2,6 @@ package mage.cards.k; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.delayed.AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -35,7 +34,7 @@ public final class KayaGhostAssassin extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KAYA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // 0: Exile Kaya, Ghost Assassin or up to one target creature. Return that card to the battlefield under its owner's control at the beginning of your next upkeep. // You lose 2 life. diff --git a/Mage.Sets/src/mage/cards/k/KayaOrzhovUsurper.java b/Mage.Sets/src/mage/cards/k/KayaOrzhovUsurper.java index 5b9dc2e3801..b2a67af4736 100644 --- a/Mage.Sets/src/mage/cards/k/KayaOrzhovUsurper.java +++ b/Mage.Sets/src/mage/cards/k/KayaOrzhovUsurper.java @@ -2,7 +2,6 @@ package mage.cards.k; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.*; @@ -37,7 +36,7 @@ public final class KayaOrzhovUsurper extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KAYA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Exile up to two target cards from a single graveyard. You gain 2 life if at least one creature card was exiled this way. Ability ability = new LoyaltyAbility(new KayaOrzhovUsurperExileEffect(), 1); diff --git a/Mage.Sets/src/mage/cards/k/KayaTheInexorable.java b/Mage.Sets/src/mage/cards/k/KayaTheInexorable.java index a5109c9bdd3..c919a5adfcc 100644 --- a/Mage.Sets/src/mage/cards/k/KayaTheInexorable.java +++ b/Mage.Sets/src/mage/cards/k/KayaTheInexorable.java @@ -5,7 +5,6 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.ExileTargetEffect; @@ -47,7 +46,7 @@ public final class KayaTheInexorable extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KAYA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Put a ghostform counter on up to one target nontoken creature. It gains "When this creature dies or is put into exile, return it to its owner's hand and create a 1/1 white Spirit creature token with flying." LoyaltyAbility ability = new LoyaltyAbility(new AddCountersTargetEffect(CounterType.GHOSTFORM.createInstance()), 1); diff --git a/Mage.Sets/src/mage/cards/k/KayasWrath.java b/Mage.Sets/src/mage/cards/k/KayasWrath.java index 72cbd5bf0d1..3e154b128a6 100644 --- a/Mage.Sets/src/mage/cards/k/KayasWrath.java +++ b/Mage.Sets/src/mage/cards/k/KayasWrath.java @@ -59,7 +59,7 @@ class KayasWrathEffect extends OneShotEffect { int counter = 0; for (Permanent permanent : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_PERMANENT_CREATURE, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game )) { if (permanent != null) { boolean isMine = permanent.isControlledBy(source.getControllerId()); diff --git a/Mage.Sets/src/mage/cards/k/KazaRoilChaser.java b/Mage.Sets/src/mage/cards/k/KazaRoilChaser.java index af14498a2c2..daba849d422 100644 --- a/Mage.Sets/src/mage/cards/k/KazaRoilChaser.java +++ b/Mage.Sets/src/mage/cards/k/KazaRoilChaser.java @@ -93,7 +93,7 @@ class KazaRoilChaserEffect extends CostModificationEffectImpl { if (watcher != null) { spellsCast = watcher.getCount(source.getControllerId()); } - wizardCount = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + wizardCount = game.getBattlefield().count(filter, source.getControllerId(), source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/k/KazanduBlademaster.java b/Mage.Sets/src/mage/cards/k/KazanduBlademaster.java index 3d835c30bd6..fb63020efc6 100644 --- a/Mage.Sets/src/mage/cards/k/KazanduBlademaster.java +++ b/Mage.Sets/src/mage/cards/k/KazanduBlademaster.java @@ -30,7 +30,7 @@ public final class KazanduBlademaster extends CardImpl { this.addAbility(FirstStrikeAbility.getInstance()); this.addAbility(VigilanceAbility.getInstance()); - this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true)); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true).setAbilityWord(null)); } private KazanduBlademaster(final KazanduBlademaster card) { diff --git a/Mage.Sets/src/mage/cards/k/KazanduStomper.java b/Mage.Sets/src/mage/cards/k/KazanduStomper.java index 2aebecaf339..2b7893ddb0e 100644 --- a/Mage.Sets/src/mage/cards/k/KazanduStomper.java +++ b/Mage.Sets/src/mage/cards/k/KazanduStomper.java @@ -73,7 +73,7 @@ class KazanduStomperEffect extends OneShotEffect { TargetPermanent target = new TargetPermanent( 0, 2, StaticFilters.FILTER_CONTROLLED_PERMANENT_LANDS, true ); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); return player.moveCards(new CardsImpl(target.getTargets()), Zone.HAND, source, game); } } diff --git a/Mage.Sets/src/mage/cards/k/KazuulTyrantOfTheCliffs.java b/Mage.Sets/src/mage/cards/k/KazuulTyrantOfTheCliffs.java index ec71b546df2..2fd169c6be9 100644 --- a/Mage.Sets/src/mage/cards/k/KazuulTyrantOfTheCliffs.java +++ b/Mage.Sets/src/mage/cards/k/KazuulTyrantOfTheCliffs.java @@ -78,7 +78,7 @@ class KazuulTyrantOfTheCliffsTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { return "Whenever a creature an opponent controls attacks, if you're the defending player, " + - "create a 3/3 red Ogre creature token unless that creature's controller pays {3}"; + "create a 3/3 red Ogre creature token unless that creature's controller pays {3}."; } } diff --git a/Mage.Sets/src/mage/cards/k/KazuulWarlord.java b/Mage.Sets/src/mage/cards/k/KazuulWarlord.java index b54d5cb093c..ba0084be938 100644 --- a/Mage.Sets/src/mage/cards/k/KazuulWarlord.java +++ b/Mage.Sets/src/mage/cards/k/KazuulWarlord.java @@ -19,7 +19,7 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class KazuulWarlord extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Ally creatures you control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Ally creature you control"); static { filter.add(SubType.ALLY.getPredicate()); @@ -35,7 +35,7 @@ public final class KazuulWarlord extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(3); - this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter), true)); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter), true).setAbilityWord(null)); } private KazuulWarlord(final KazuulWarlord card) { diff --git a/Mage.Sets/src/mage/cards/k/KederektLeviathan.java b/Mage.Sets/src/mage/cards/k/KederektLeviathan.java index a762841d9c6..e9912a5ebfe 100644 --- a/Mage.Sets/src/mage/cards/k/KederektLeviathan.java +++ b/Mage.Sets/src/mage/cards/k/KederektLeviathan.java @@ -20,7 +20,7 @@ import mage.filter.predicate.mageobject.AnotherPredicate; */ public final class KederektLeviathan extends CardImpl { - private static final FilterNonlandPermanent filter = new FilterNonlandPermanent("all other nonland permanents"); + private static final FilterNonlandPermanent filter = new FilterNonlandPermanent("other nonland permanents"); static{ filter.add(AnotherPredicate.instance); } diff --git a/Mage.Sets/src/mage/cards/k/KeepSafe.java b/Mage.Sets/src/mage/cards/k/KeepSafe.java index a7a676677e6..86857f6a1fe 100644 --- a/Mage.Sets/src/mage/cards/k/KeepSafe.java +++ b/Mage.Sets/src/mage/cards/k/KeepSafe.java @@ -31,7 +31,7 @@ public final class KeepSafe extends CardImpl { this.getSpellAbility().addTarget(new TargetSpell(filter)); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private KeepSafe(final KeepSafe card) { diff --git a/Mage.Sets/src/mage/cards/k/KeeperOfTheBeasts.java b/Mage.Sets/src/mage/cards/k/KeeperOfTheBeasts.java index 7451ab83548..75829c8c4e2 100644 --- a/Mage.Sets/src/mage/cards/k/KeeperOfTheBeasts.java +++ b/Mage.Sets/src/mage/cards/k/KeeperOfTheBeasts.java @@ -64,8 +64,8 @@ class KeeperOfTheBeastsTarget extends TargetPlayer { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set availablePossibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set availablePossibleTargets = super.possibleTargets(sourceControllerId, source, game); Set possibleTargets = new HashSet<>(); int creaturesController = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game); @@ -78,9 +78,9 @@ class KeeperOfTheBeastsTarget extends TargetPlayer { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { int count = 0; - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); Player controller = game.getPlayer(sourceControllerId); if (controller != null && targetSource != null) { for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { @@ -89,7 +89,7 @@ class KeeperOfTheBeastsTarget extends TargetPlayer { && game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, game) < game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game) && !player.hasLeft() - && filter.match(player, sourceId, sourceControllerId, game) + && filter.match(player, sourceControllerId, source, game) && player.canBeTargetedBy(targetSource, sourceControllerId, game)) { count++; if (count >= this.minNumberOfTargets) { diff --git a/Mage.Sets/src/mage/cards/k/KeeperOfTheDead.java b/Mage.Sets/src/mage/cards/k/KeeperOfTheDead.java index 5dc7fef6231..f7feb5dabfc 100644 --- a/Mage.Sets/src/mage/cards/k/KeeperOfTheDead.java +++ b/Mage.Sets/src/mage/cards/k/KeeperOfTheDead.java @@ -71,7 +71,7 @@ class KeeperOfDeadPredicate implements ObjectSourcePlayerPredicate { @Override public boolean apply(ObjectSourcePlayer input, Game game) { Player targetPlayer = input.getObject(); - Permanent sourceObject = game.getPermanent(input.getSourceId()); + Permanent sourceObject = input.getSource().getSourcePermanentIfItStillExists(game); Player controller = null; if (sourceObject != null) { controller = game.getPlayer(sourceObject.getControllerId()); @@ -114,16 +114,16 @@ class KeeperOfTheDeadCreatureTarget extends TargetPermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set availablePossibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set availablePossibleTargets = super.possibleTargets(sourceControllerId, source, game); Set possibleTargets = new HashSet<>(); - MageObject object = game.getObject(sourceId); + MageObject object = game.getObject(source); for (StackObject item : game.getState().getStack()) { - if (item.getId().equals(sourceId)) { + if (item.getId().equals(source.getSourceId())) { object = item; } - if (item.getSourceId().equals(sourceId)) { + if (item.getSourceId().equals(source.getSourceId())) { object = item; } } diff --git a/Mage.Sets/src/mage/cards/k/KeeperOfTheLens.java b/Mage.Sets/src/mage/cards/k/KeeperOfTheLens.java index 60812e38b54..c3938de579f 100644 --- a/Mage.Sets/src/mage/cards/k/KeeperOfTheLens.java +++ b/Mage.Sets/src/mage/cards/k/KeeperOfTheLens.java @@ -92,7 +92,7 @@ class KeeperOfTheLensLookFaceDownEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (controller == null || mageObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/k/KeeperOfTheLight.java b/Mage.Sets/src/mage/cards/k/KeeperOfTheLight.java index 498322f18d5..16797d55e8c 100644 --- a/Mage.Sets/src/mage/cards/k/KeeperOfTheLight.java +++ b/Mage.Sets/src/mage/cards/k/KeeperOfTheLight.java @@ -66,8 +66,8 @@ class KeeperOfTheLightTarget extends TargetPlayer { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set availablePossibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set availablePossibleTargets = super.possibleTargets(sourceControllerId, source, game); Set possibleTargets = new HashSet<>(); int lifeController = game.getPlayer(sourceControllerId).getLife(); @@ -84,9 +84,9 @@ class KeeperOfTheLightTarget extends TargetPlayer { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { int count = 0; - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); Player controller = game.getPlayer(sourceControllerId); if (controller != null && targetSource != null) { for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { @@ -94,7 +94,7 @@ class KeeperOfTheLightTarget extends TargetPlayer { if (player != null && controller.getLife() < player.getLife() && !player.hasLeft() - && filter.match(player, sourceId, sourceControllerId, game) + && filter.match(player, sourceControllerId, source, game) && player.canBeTargetedBy(targetSource, sourceControllerId, game)) { count++; if (count >= this.minNumberOfTargets) { diff --git a/Mage.Sets/src/mage/cards/k/KeldonBattlewagon.java b/Mage.Sets/src/mage/cards/k/KeldonBattlewagon.java index 862d3bebf5b..cfab13b1215 100644 --- a/Mage.Sets/src/mage/cards/k/KeldonBattlewagon.java +++ b/Mage.Sets/src/mage/cards/k/KeldonBattlewagon.java @@ -87,7 +87,7 @@ class KeldonBattlewagonCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - if (target.choose(Outcome.Tap, controllerId, source.getSourceId(), game)) { + if (target.choose(Outcome.Tap, controllerId, source.getSourceId(), source, game)) { for (UUID targetId : target.getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent == null) { @@ -104,7 +104,7 @@ class KeldonBattlewagonCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return target.canChoose(source.getSourceId(), controllerId, game); + return target.canChoose(controllerId, source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/k/KeldonFirebombers.java b/Mage.Sets/src/mage/cards/k/KeldonFirebombers.java index 7d8ba53e6d2..528e274c6c5 100644 --- a/Mage.Sets/src/mage/cards/k/KeldonFirebombers.java +++ b/Mage.Sets/src/mage/cards/k/KeldonFirebombers.java @@ -79,7 +79,7 @@ class KeldonFirebombersEffect extends OneShotEffect { FilterLandPermanent playerFilter = filter.copy(); playerFilter.add(new ControllerIdPredicate(playerId)); Target target = new TargetLandPermanent(amount, amount, playerFilter, true); - player.choose(outcome.Sacrifice, target, source.getSourceId(), game); + player.choose(outcome.Sacrifice, target, source, game); for (UUID landId : target.getTargets()) { Permanent land = game.getPermanent(landId); if (land != null) { diff --git a/Mage.Sets/src/mage/cards/k/KenBurningBrawler.java b/Mage.Sets/src/mage/cards/k/KenBurningBrawler.java new file mode 100644 index 00000000000..df26123ab9b --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KenBurningBrawler.java @@ -0,0 +1,90 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.ProwessAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KenBurningBrawler extends CardImpl { + + public KenBurningBrawler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Prowess + this.addAbility(new ProwessAbility()); + + // {R/W}: Ken gains first strike until end of turn. + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl<>("{R/W}"))); + + // Shoryuken—Whenever Ken deals combat damage, you may cast a sorcery spell from your hand with mana value less than or equal to that damage without paying its mana cost. + this.addAbility(new DealsCombatDamageTriggeredAbility( + new KenBurningBrawlerEffect(), false + ).withFlavorWord("Shoryuken")); + } + + private KenBurningBrawler(final KenBurningBrawler card) { + super(card); + } + + @Override + public KenBurningBrawler copy() { + return new KenBurningBrawler(this); + } +} + +class KenBurningBrawlerEffect extends OneShotEffect { + + KenBurningBrawlerEffect() { + super(Outcome.Benefit); + staticText = "you may cast a sorcery spell from your hand with mana value " + + "less than or equal to that damage without paying its mana cost"; + } + + private KenBurningBrawlerEffect(final KenBurningBrawlerEffect effect) { + super(effect); + } + + @Override + public KenBurningBrawlerEffect copy() { + return new KenBurningBrawlerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null || player.getHand().isEmpty()) { + return false; + } + FilterCard filter = new FilterCard(); + filter.add(CardType.SORCERY.getPredicate()); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 1 + (Integer) getValue("damage"))); + return CardUtil.castSpellWithAttributesForFree(player, source, game, new CardsImpl(player.getHand()), filter); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KeskitTheFleshSculptor.java b/Mage.Sets/src/mage/cards/k/KeskitTheFleshSculptor.java index f1a3716bd85..862b79d8209 100644 --- a/Mage.Sets/src/mage/cards/k/KeskitTheFleshSculptor.java +++ b/Mage.Sets/src/mage/cards/k/KeskitTheFleshSculptor.java @@ -5,16 +5,14 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.PartnerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AnotherPredicate; @@ -48,11 +46,11 @@ public final class KeskitTheFleshSculptor extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(3); - // {T}, Sacrifice three other artifacts and/or creatures: Look at the top three cards of your library. Put two of them into your hand and the other into your graveyard. - Ability ability = new SimpleActivatedAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(3), false, StaticValue.get(2), StaticFilters.FILTER_CARD, - Zone.GRAVEYARD, false, false - ), new TapSourceCost()); + // {T}, Sacrifice three other artifacts and/or creatures: Look at the top three cards of your library. + // Put two of them into your hand and the other into your graveyard. + Ability ability = new SimpleActivatedAbility( + new LookLibraryAndPickControllerEffect(3, 2, PutCards.HAND, PutCards.GRAVEYARD), + new TapSourceCost()); ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(3, filter))); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/k/KessigWolfrider.java b/Mage.Sets/src/mage/cards/k/KessigWolfrider.java index 8b68907f74c..cacc4724933 100644 --- a/Mage.Sets/src/mage/cards/k/KessigWolfrider.java +++ b/Mage.Sets/src/mage/cards/k/KessigWolfrider.java @@ -12,6 +12,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.StaticFilters; import mage.game.permanent.token.RedWolfToken; import mage.target.common.TargetCardInYourGraveyard; @@ -35,10 +36,10 @@ public final class KessigWolfrider extends CardImpl { // {2}{R}, {T}, Exile three cards from your graveyard: Create a 3/2 red Wolf creature token. Ability ability = new SimpleActivatedAbility( - new CreateTokenEffect(new RedWolfToken()), new ManaCostsImpl<>("2}{R}") + new CreateTokenEffect(new RedWolfToken()), new ManaCostsImpl<>("{2}{R}") ); ability.addCost(new TapSourceCost()); - ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(3, 3))); + ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(3, 3, StaticFilters.FILTER_CARDS_FROM_YOUR_GRAVEYARD))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KetriaTriome.java b/Mage.Sets/src/mage/cards/k/KetriaTriome.java index a85a5d44b5d..221c5e540fc 100644 --- a/Mage.Sets/src/mage/cards/k/KetriaTriome.java +++ b/Mage.Sets/src/mage/cards/k/KetriaTriome.java @@ -1,7 +1,7 @@ package mage.cards.k; import mage.abilities.common.EntersBattlefieldTappedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.keyword.CyclingAbility; import mage.abilities.mana.BlueManaAbility; import mage.abilities.mana.GreenManaAbility; @@ -34,7 +34,7 @@ public final class KetriaTriome extends CardImpl { this.addAbility(new EntersBattlefieldTappedAbility()); // Cycling {3} - this.addAbility(new CyclingAbility(new ManaCostsImpl("{3}"))); + this.addAbility(new CyclingAbility(new GenericManaCost(3))); } private KetriaTriome(final KetriaTriome card) { diff --git a/Mage.Sets/src/mage/cards/k/KeyToTheArchive.java b/Mage.Sets/src/mage/cards/k/KeyToTheArchive.java new file mode 100644 index 00000000000..8975adfef77 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KeyToTheArchive.java @@ -0,0 +1,69 @@ +package mage.cards.k; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.DraftFromSpellbookEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.abilities.effects.mana.AddManaInAnyCombinationEffect; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KeyToTheArchive extends CardImpl { + + private static final List spellbook = Collections.unmodifiableList(Arrays.asList( + "Approach of the Second Sun", + "Claim the Firstborn", + "Counterspell", + "Day of Judgment", + "Demonic Tutor", + "Despark", + "Doom Blade", + "Electrolyze", + "Growth Spiral", + "Krosan Grip", + "Lightning Bolt", + "Lightning Helix", + "Putrefy", + "Regrowth", + "Time Warp" + )); + + public KeyToTheArchive(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + + // Key to the Archive enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // When Key to the Archive enters the battlefield, draft a card from Key to the Archive's spellbook, then discard a card. + Ability ability = new EntersBattlefieldTriggeredAbility(new DraftFromSpellbookEffect(spellbook)); + ability.addEffect(new DiscardControllerEffect(1).concatBy(", then")); + this.addAbility(ability); + + // {T}: Add two mana in any combination of colors. + this.addAbility(new SimpleManaAbility( + Zone.BATTLEFIELD, new AddManaInAnyCombinationEffect(2), new TapSourceCost() + )); + } + + private KeyToTheArchive(final KeyToTheArchive card) { + super(card); + } + + @Override + public KeyToTheArchive copy() { + return new KeyToTheArchive(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KhalniGem.java b/Mage.Sets/src/mage/cards/k/KhalniGem.java index d6d6138991e..6e27ee769ca 100644 --- a/Mage.Sets/src/mage/cards/k/KhalniGem.java +++ b/Mage.Sets/src/mage/cards/k/KhalniGem.java @@ -64,7 +64,7 @@ class KhalniGemReturnToHandTargetEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); int landCount = game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, - source.getSourceId(), source.getControllerId(), game + source.getControllerId(), source, game ); if (player == null || landCount < 1) { return false; @@ -73,7 +73,7 @@ class KhalniGemReturnToHandTargetEffect extends OneShotEffect { Math.min(landCount, 2), StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND ); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); return player.moveCards(new CardsImpl(target.getTargets()), Zone.HAND, source, game); } diff --git a/Mage.Sets/src/mage/cards/k/KheruLichLord.java b/Mage.Sets/src/mage/cards/k/KheruLichLord.java index 8c037d34192..adbacf7cae3 100644 --- a/Mage.Sets/src/mage/cards/k/KheruLichLord.java +++ b/Mage.Sets/src/mage/cards/k/KheruLichLord.java @@ -84,7 +84,7 @@ class KheruLichLordEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - Cards cards = new CardsImpl(controller.getGraveyard().getCards(StaticFilters.FILTER_CARD_CREATURE, source.getSourceId(), source.getControllerId(), game)); + Cards cards = new CardsImpl(controller.getGraveyard().getCards(StaticFilters.FILTER_CARD_CREATURE, source.getControllerId(), source, game)); Card card = cards.getRandom(game); if (card != null) { controller.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/k/KheruMindEater.java b/Mage.Sets/src/mage/cards/k/KheruMindEater.java index 481e246db10..7a722dd5595 100644 --- a/Mage.Sets/src/mage/cards/k/KheruMindEater.java +++ b/Mage.Sets/src/mage/cards/k/KheruMindEater.java @@ -79,7 +79,7 @@ class KheruMindEaterExileEffect extends OneShotEffect { Target target = new TargetCardInHand(1, new FilterCard()); target.chooseTarget(Outcome.Exile, player.getId(), source, game); Card card = game.getCard(target.getFirstTarget()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (card != null && sourceObject != null) { if (player.moveCardsToExile(card, source, game, false, CardUtil.getCardExileZoneId(game, source), sourceObject.getIdName())) { card.setFaceDown(true, game); @@ -154,7 +154,7 @@ class KheruMindEaterLookAtCardEffect extends AsThoughEffectImpl { if (affectedControllerId.equals(source.getControllerId())) { Card card = game.getCard(objectId); if (card != null) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java b/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java index f2d1aa45cdd..af63724b798 100644 --- a/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java +++ b/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java @@ -32,7 +32,7 @@ public final class KheruSpellsnatcher extends CardImpl { this.toughness = new MageInt(3); // Morph {4}{U}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{4}{U}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl<>("{4}{U}{U}"))); // When Kheru Spellthief is turned face up, counter target spell. If that spell is countered this way, exile it instead of putting it into its owner's graveyard. You may cast that card without paying its mana cost as long as it remains exiled. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new KheruSpellsnatcherEffect()); diff --git a/Mage.Sets/src/mage/cards/k/KianneDeanOfSubstance.java b/Mage.Sets/src/mage/cards/k/KianneDeanOfSubstance.java index 2bf9fd8a883..a6364745843 100644 --- a/Mage.Sets/src/mage/cards/k/KianneDeanOfSubstance.java +++ b/Mage.Sets/src/mage/cards/k/KianneDeanOfSubstance.java @@ -212,7 +212,7 @@ class ImbrahamDeanOfTheoryEffect extends OneShotEffect { } TargetCard targetCard = new TargetCardInExile(0, 1, filter, null); targetCard.setNotTarget(true); - player.choose(outcome, targetCard, source.getSourceId(), game); + player.choose(outcome, targetCard, source, game); Card card = game.getCard(targetCard.getFirstTarget()); if (card != null) { player.moveCards(card, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/k/KillSwitch.java b/Mage.Sets/src/mage/cards/k/KillSwitch.java index 16ecc2596f9..2586798764d 100644 --- a/Mage.Sets/src/mage/cards/k/KillSwitch.java +++ b/Mage.Sets/src/mage/cards/k/KillSwitch.java @@ -1,57 +1,38 @@ - package mage.cards.k; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.condition.common.SourceTappedBeforeUntapStepCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.DontUntapInControllersUntapStepAllEffect; -import mage.abilities.effects.common.TapAllEffect; +import mage.abilities.costs.mana.GenericManaCost; +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.TargetController; -import mage.constants.Zone; -import mage.filter.common.FilterArtifactPermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTargets; + +import java.util.List; +import java.util.UUID; /** - * * @author spjspj */ public final class KillSwitch extends CardImpl { - - //static { - // filter.add(AnotherPredicate.instance); - // } - public KillSwitch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // {2}, {tap}: Tap all other artifacts. They don't untap during their controllers' untap steps for as long as Kill Switch remains tapped. - FilterArtifactPermanent filter = new FilterArtifactPermanent(); - filter.add(Predicates.not(new PermanentIdPredicate(getId()))); - - SourceTappedBeforeUntapStepCondition condition = new SourceTappedBeforeUntapStepCondition(); - condition.setPermanentId(this.getId()); - Effect effect = new ConditionalContinuousRuleModifyingEffect( - new DontUntapInControllersUntapStepAllEffect(Duration.WhileOnBattlefield, TargetController.ANY, filter), - condition); - effect.setText("Artifacts tapped this way don't untap during their controllers' untap steps for as long as {this} remains tapped"); - - Effect effect2 = new TapAllEffect(filter); - effect2.setText("Tap all other artifacts"); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect2, new ManaCostsImpl("{2}")); + Ability ability = new SimpleActivatedAbility(new KillSwitchEffect(), new GenericManaCost(2)); ability.addCost(new TapSourceCost()); - ability.addEffect(effect); - this.addAbility(ability); + this.addAbility(ability); } private KillSwitch(final KillSwitch card) { @@ -63,3 +44,80 @@ public final class KillSwitch extends CardImpl { return new KillSwitch(this); } } + +class KillSwitchEffect extends OneShotEffect { + + KillSwitchEffect() { + super(Outcome.Benefit); + staticText = "tap all other artifacts. They don't untap during their controllers' " + + "untap steps for as long as {this} remains tapped"; + } + + private KillSwitchEffect(final KillSwitchEffect effect) { + super(effect); + } + + @Override + public KillSwitchEffect copy() { + return new KillSwitchEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + List permanents = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_PERMANENT_ARTIFACT, + source.getControllerId(), source, game + ); + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + if (sourcePermanent != null) { + permanents.remove(sourcePermanent); + game.addEffect(new KillSwitchUntapEffect().setTargetPointer(new FixedTargets(permanents, game)), source); + } + for (Permanent permanent : permanents) { + permanent.tap(source, game); + } + return true; + } +} + +class KillSwitchUntapEffect extends ContinuousRuleModifyingEffectImpl { + + KillSwitchUntapEffect() { + super(Duration.Custom, Outcome.Detriment); + } + + private KillSwitchUntapEffect(final KillSwitchUntapEffect effect) { + super(effect); + } + + @Override + public KillSwitchUntapEffect copy() { + return new KillSwitchUntapEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.UNTAP; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (game.getTurn().getStepType() != PhaseStep.UNTAP) { + return false; + } + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + if (sourcePermanent == null || !sourcePermanent.isTapped()) { + discard(); + return false; + } + return getTargetPointer().getTargets(game, source).contains(event.getTargetId()) + && game.isActivePlayer(game.getControllerId(event.getTargetId())); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KillerService.java b/Mage.Sets/src/mage/cards/k/KillerService.java new file mode 100644 index 00000000000..c626a487de6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KillerService.java @@ -0,0 +1,61 @@ +package mage.cards.k; + +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.CompositeCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.common.OpponentsCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.FoodToken; +import mage.game.permanent.token.RhinoWarriorToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KillerService extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("a token"); + + static { + filter.add(TokenPredicate.TRUE); + } + + public KillerService(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); + + // When Killer Service enters the battlefield, create a number of Food tokens equal to the number of opponents you have. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect( + new FoodToken(), OpponentsCount.instance + ).setText("create a number of Food tokens equal to the number of opponents you have"))); + + // At the beginning of your end step, you may pay {2} and sacrifice a token. If you do, create a 4/4 green Rhino Warrior creature token. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new DoIfCostPaid( + new CreateTokenEffect(new RhinoWarriorToken()), + new CompositeCost( + new GenericManaCost(2), new SacrificeTargetCost(filter), + "pay {2} and sacrifice a token" + ) + ), TargetController.YOU, false + )); + } + + private KillerService(final KillerService card) { + super(card); + } + + @Override + public KillerService copy() { + return new KillerService(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KillerWhale.java b/Mage.Sets/src/mage/cards/k/KillerWhale.java index 5519b5a7400..0b6cffd00a4 100644 --- a/Mage.Sets/src/mage/cards/k/KillerWhale.java +++ b/Mage.Sets/src/mage/cards/k/KillerWhale.java @@ -30,7 +30,7 @@ public final class KillerWhale extends CardImpl { this.addAbility(new SimpleActivatedAbility( Zone.BATTLEFIELD, new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), - new ManaCostsImpl("U"))); + new ManaCostsImpl<>("{U}"))); } private KillerWhale(final KillerWhale card) { diff --git a/Mage.Sets/src/mage/cards/k/KinTreeInvocation.java b/Mage.Sets/src/mage/cards/k/KinTreeInvocation.java index c317ff54927..c629897cfaf 100644 --- a/Mage.Sets/src/mage/cards/k/KinTreeInvocation.java +++ b/Mage.Sets/src/mage/cards/k/KinTreeInvocation.java @@ -80,7 +80,7 @@ class SpiritWarriorToken extends TokenImpl { } public SpiritWarriorToken(int x) { - super("Spirit Warrior", "X/X black and green Spirit Warrior creature token, where X is the greatest toughness among creatures you control"); + super("Spirit Warrior Token", "X/X black and green Spirit Warrior creature token, where X is the greatest toughness among creatures you control"); this.cardType.add(CardType.CREATURE); this.subtype.add(SubType.SPIRIT); this.subtype.add(SubType.WARRIOR); diff --git a/Mage.Sets/src/mage/cards/k/KinTreeWarden.java b/Mage.Sets/src/mage/cards/k/KinTreeWarden.java index 0f4eea23baf..916e1d0ccbe 100644 --- a/Mage.Sets/src/mage/cards/k/KinTreeWarden.java +++ b/Mage.Sets/src/mage/cards/k/KinTreeWarden.java @@ -31,7 +31,7 @@ public final class KinTreeWarden extends CardImpl { // {2}: Regenerate Kin-Tree Warden this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new GenericManaCost(2))); // Morph {G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{G}"))); } private KinTreeWarden(final KinTreeWarden card) { diff --git a/Mage.Sets/src/mage/cards/k/Kindle.java b/Mage.Sets/src/mage/cards/k/Kindle.java index 9991f710a52..457244f8c50 100644 --- a/Mage.Sets/src/mage/cards/k/Kindle.java +++ b/Mage.Sets/src/mage/cards/k/Kindle.java @@ -67,7 +67,7 @@ class KindleCardsInAllGraveyardsCount implements DynamicValue { for (UUID playerUUID : playerList) { Player player = game.getPlayer(playerUUID); if (player != null) { - amount += player.getGraveyard().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + amount += player.getGraveyard().count(filter, sourceAbility.getControllerId(), sourceAbility, game); } } return amount + 2; diff --git a/Mage.Sets/src/mage/cards/k/KindledFury.java b/Mage.Sets/src/mage/cards/k/KindledFury.java index ab94e1f9fe8..1b851ea6488 100644 --- a/Mage.Sets/src/mage/cards/k/KindledFury.java +++ b/Mage.Sets/src/mage/cards/k/KindledFury.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.FirstStrikeAbility; @@ -11,17 +9,22 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class KindledFury extends CardImpl { public KindledFury(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); - this.getSpellAbility().addEffect(new BoostTargetEffect(1, 0, Duration.EndOfTurn)); - this.getSpellAbility().addEffect(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new BoostTargetEffect( + 1, 0, Duration.EndOfTurn + ).setText("target creature gets +1/+0")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains first strike until end of turn")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/k/KindredCharge.java b/Mage.Sets/src/mage/cards/k/KindredCharge.java index 82318a30d42..2a2d33f6a13 100644 --- a/Mage.Sets/src/mage/cards/k/KindredCharge.java +++ b/Mage.Sets/src/mage/cards/k/KindredCharge.java @@ -66,7 +66,7 @@ class KindredChargeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { SubType subType = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game); if (subType != null) { diff --git a/Mage.Sets/src/mage/cards/k/KindredDenial.java b/Mage.Sets/src/mage/cards/k/KindredDenial.java new file mode 100644 index 00000000000..d98ff7fde69 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KindredDenial.java @@ -0,0 +1,72 @@ +package mage.cards.k; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KindredDenial extends CardImpl { + + public KindredDenial(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}{U}"); + + // Counter target spell. Seek a card with the same mana value as that spell. + this.getSpellAbility().addEffect(new KindredDenialEffect()); + this.getSpellAbility().addTarget(new TargetSpell()); + } + + private KindredDenial(final KindredDenial card) { + super(card); + } + + @Override + public KindredDenial copy() { + return new KindredDenial(this); + } +} + +class KindredDenialEffect extends OneShotEffect { + + KindredDenialEffect() { + super(Outcome.Benefit); + staticText = "counter target spell. Seek a card with the same mana value as that spell"; + } + + private KindredDenialEffect(final KindredDenialEffect effect) { + super(effect); + } + + @Override + public KindredDenialEffect copy() { + return new KindredDenialEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Spell spell = game.getSpell(source.getFirstTarget()); + if (player == null || spell == null) { + return false; + } + int manaValue = spell.getManaValue(); + game.getStack().counter(spell.getId(), source, game);; + FilterCard filter = new FilterCard(); + filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, manaValue)); + player.seekCard(filter, source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KindredDominance.java b/Mage.Sets/src/mage/cards/k/KindredDominance.java index 80f1d7d2272..13725ba97e4 100644 --- a/Mage.Sets/src/mage/cards/k/KindredDominance.java +++ b/Mage.Sets/src/mage/cards/k/KindredDominance.java @@ -59,7 +59,7 @@ class KindredDominanceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Choice typeChoice = new ChoiceCreatureType(game.getObject(source.getSourceId())); + Choice typeChoice = new ChoiceCreatureType(game.getObject(source)); if (controller != null && controller.choose(outcome, typeChoice, game)) { game.informPlayers(controller.getLogName() + " has chosen " + typeChoice.getChoice()); FilterCreaturePermanent filter = new FilterCreaturePermanent("All creatures not of the chosen type"); diff --git a/Mage.Sets/src/mage/cards/k/KinnanBonderProdigy.java b/Mage.Sets/src/mage/cards/k/KinnanBonderProdigy.java index 857260f64d6..267302a2d7f 100644 --- a/Mage.Sets/src/mage/cards/k/KinnanBonderProdigy.java +++ b/Mage.Sets/src/mage/cards/k/KinnanBonderProdigy.java @@ -4,8 +4,8 @@ import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.TapForManaAllTriggeredManaAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.mana.AddManaOfAnyTypeProducedEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -47,14 +47,12 @@ public final class KinnanBonderProdigy extends CardImpl { effect, filter, SetTargetPointer.PERMANENT )); - // {5}{G}{U}: Look at the top five cards of your library. You may put a non-Human creature card from among them onto the battlefield. Put the rest on the bottom of your library in a random order. - this.addAbility(new SimpleActivatedAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), filter2, Zone.LIBRARY, false, - true, false, Zone.BATTLEFIELD, true, false, false - ).setBackInRandomOrder(true).setText("Look at the top five cards of your library. " + - "You may put a non-Human creature card from among them onto the battlefield. " + - "Put the rest on the bottom of your library in a random order." - ), new ManaCostsImpl("{5}{G}{U}"))); + // {5}{G}{U}: Look at the top five cards of your library. + // You may put a non-Human creature card from among them onto the battlefield. + // Put the rest on the bottom of your library in a random order. + this.addAbility(new SimpleActivatedAbility( + new LookLibraryAndPickControllerEffect(5, 1, filter2, PutCards.BATTLEFIELD, PutCards.BOTTOM_RANDOM), + new ManaCostsImpl("{5}{G}{U}"))); } private KinnanBonderProdigy(final KinnanBonderProdigy card) { diff --git a/Mage.Sets/src/mage/cards/k/KinsbaileBorderguard.java b/Mage.Sets/src/mage/cards/k/KinsbaileBorderguard.java index 9cedbc1ba6e..ac33842d1e7 100644 --- a/Mage.Sets/src/mage/cards/k/KinsbaileBorderguard.java +++ b/Mage.Sets/src/mage/cards/k/KinsbaileBorderguard.java @@ -79,7 +79,7 @@ class AllCountersCount implements DynamicValue { @Override public String getMessage() { - return "for each counter on it"; + return "counter on it"; } @Override diff --git a/Mage.Sets/src/mage/cards/k/KioraBehemothBeckoner.java b/Mage.Sets/src/mage/cards/k/KioraBehemothBeckoner.java index 4e2483500a2..1c741ab6b13 100644 --- a/Mage.Sets/src/mage/cards/k/KioraBehemothBeckoner.java +++ b/Mage.Sets/src/mage/cards/k/KioraBehemothBeckoner.java @@ -3,7 +3,6 @@ package mage.cards.k; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.UntapTargetEffect; import mage.cards.CardImpl; @@ -33,7 +32,7 @@ public final class KioraBehemothBeckoner extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KIORA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(7)); + this.setStartingLoyalty(7); // Whenever a creature with power 4 or greater enters the battlefield under your control, draw a card. this.addAbility(new EntersBattlefieldControlledTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/k/KioraMasterOfTheDepths.java b/Mage.Sets/src/mage/cards/k/KioraMasterOfTheDepths.java index dafd0b930d1..77d0ff745ec 100644 --- a/Mage.Sets/src/mage/cards/k/KioraMasterOfTheDepths.java +++ b/Mage.Sets/src/mage/cards/k/KioraMasterOfTheDepths.java @@ -3,7 +3,6 @@ package mage.cards.k; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -36,7 +35,7 @@ public final class KioraMasterOfTheDepths extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KIORA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Untap up to one target creature and up to one target land. LoyaltyAbility ability = new LoyaltyAbility(new KioraUntapEffect(), 1); @@ -119,7 +118,7 @@ class KioraRevealEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/k/KioraTheCrashingWave.java b/Mage.Sets/src/mage/cards/k/KioraTheCrashingWave.java index 8034982a791..9361f0c87b9 100644 --- a/Mage.Sets/src/mage/cards/k/KioraTheCrashingWave.java +++ b/Mage.Sets/src/mage/cards/k/KioraTheCrashingWave.java @@ -4,7 +4,6 @@ package mage.cards.k; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.PreventionEffectImpl; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -42,7 +41,7 @@ public final class KioraTheCrashingWave extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KIORA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(2)); + this.setStartingLoyalty(2); // +1: Until your next turn, prevent all damage that would be dealt to and dealt by target permanent an opponent controls. LoyaltyAbility ability = new LoyaltyAbility(new KioraPreventionEffect(), 1); diff --git a/Mage.Sets/src/mage/cards/k/KitchenImp.java b/Mage.Sets/src/mage/cards/k/KitchenImp.java index 922e70600ea..12b59351bf0 100644 --- a/Mage.Sets/src/mage/cards/k/KitchenImp.java +++ b/Mage.Sets/src/mage/cards/k/KitchenImp.java @@ -31,7 +31,7 @@ public final class KitchenImp extends CardImpl { this.addAbility(HasteAbility.getInstance()); // Madness {B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{B}"))); } private KitchenImp(final KitchenImp card) { diff --git a/Mage.Sets/src/mage/cards/k/KitesailApprentice.java b/Mage.Sets/src/mage/cards/k/KitesailApprentice.java index 39273c7faf3..8466c8089b7 100644 --- a/Mage.Sets/src/mage/cards/k/KitesailApprentice.java +++ b/Mage.Sets/src/mage/cards/k/KitesailApprentice.java @@ -1,8 +1,7 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.EquippedSourceCondition; import mage.abilities.decorator.ConditionalContinuousEffect; @@ -12,21 +11,18 @@ import mage.abilities.keyword.FlyingAbility; 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.constants.SubType; + +import java.util.UUID; /** - * * @author Loki */ public final class KitesailApprentice extends CardImpl { - private static final String rule1 = "As long as {this} is equipped, it gets +1/+1"; - private static final String rule2 = "As long as {this} is equipped, it has flying"; - public KitesailApprentice(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); this.subtype.add(SubType.KOR); this.subtype.add(SubType.SOLDIER); @@ -34,10 +30,14 @@ public final class KitesailApprentice extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - ConditionalContinuousEffect effect1 = new ConditionalContinuousEffect(new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), EquippedSourceCondition.instance, rule1); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect1)); - ConditionalContinuousEffect effect2 = new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()), EquippedSourceCondition.instance, rule2); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect2)); + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), + EquippedSourceCondition.instance, "as long as {this} is equipped, it gets +1/+1" + )); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect( + FlyingAbility.getInstance()), EquippedSourceCondition.instance, "and has flying" + )); + this.addAbility(ability); } private KitesailApprentice(final KitesailApprentice card) { diff --git a/Mage.Sets/src/mage/cards/k/KithkinGreatheart.java b/Mage.Sets/src/mage/cards/k/KithkinGreatheart.java index 40cb1872fe4..5d1f09a8074 100644 --- a/Mage.Sets/src/mage/cards/k/KithkinGreatheart.java +++ b/Mage.Sets/src/mage/cards/k/KithkinGreatheart.java @@ -1,10 +1,9 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; @@ -12,43 +11,41 @@ import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.common.FilterCreaturePermanent; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class KithkinGreatheart extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Giant"); - static { - filter.add(TargetController.YOU.getControllerPredicate()); - filter.add(SubType.GIANT.getPredicate()); - } - private static final String rule2 = "As long as you control a Giant, {this} has first strike"; + private static final FilterPermanent filter = new FilterPermanent(SubType.GIANT, "Giant"); + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); public KithkinGreatheart(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add(SubType.KITHKIN); this.subtype.add(SubType.SOLDIER); - this.color.setWhite(true); this.power = new MageInt(2); this.toughness = new MageInt(1); // As long as you control a Giant, Kithkin Greatheart gets +1/+1 and has first strike. - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( - new BoostSourceEffect(1,1, Duration.WhileOnBattlefield), - new PermanentsOnTheBattlefieldCondition(filter), - "As long as you control a Giant, Kithkin Greatheart gets +1/+1")); + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), + condition, "As long as you control a Giant, {this} gets +1/+1" + )); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(FirstStrikeAbility.getInstance()), + condition, "and has first strike" + )); this.addAbility(ability); - ConditionalContinuousEffect effect2 = new ConditionalContinuousEffect( - new GainAbilitySourceEffect(FirstStrikeAbility.getInstance()), - new PermanentsOnTheBattlefieldCondition(filter), - rule2); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect2)); - } private KithkinGreatheart(final KithkinGreatheart card) { diff --git a/Mage.Sets/src/mage/cards/k/KittKantoMayhemDiva.java b/Mage.Sets/src/mage/cards/k/KittKantoMayhemDiva.java new file mode 100644 index 00000000000..d0c936fa6c8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KittKantoMayhemDiva.java @@ -0,0 +1,79 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DoWhenCostPaid; +import mage.abilities.effects.common.combat.GoadTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.permanent.token.CitizenGreenWhiteToken; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KittKantoMayhemDiva extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature controlled by the active player"); + + static { + filter.add(TargetController.ACTIVE.getControllerPredicate()); + } + + public KittKantoMayhemDiva(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{G}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.BARD); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Kitt Kanto enters the battlefield, create a 1/1 green and white Citizen creature token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new CitizenGreenWhiteToken()))); + + // At the beginning of combat on each player's turn, you may tap two untapped creatures you control. When you do, target creature that player controls gets +2/+2 and gains trample until end of turn. Goad that creature. + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( + new BoostTargetEffect(2, 2) + .setText("target creature that player controls gets +2/+2"), + false + ); + ability.addEffect(new GainAbilityTargetEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + "and gains trample until end of turn" + )); + ability.addEffect(new GoadTargetEffect().setText("Goad that creature")); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(new BeginningOfCombatTriggeredAbility(new DoWhenCostPaid( + ability, + new TapTargetCost(new TargetControlledPermanent( + 2, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES + )), "Tap two untapped creatures you control?" + ), TargetController.EACH_PLAYER, false)); + } + + private KittKantoMayhemDiva(final KittKantoMayhemDiva card) { + super(card); + } + + @Override + public KittKantoMayhemDiva copy() { + return new KittKantoMayhemDiva(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KjeldoranFrostbeast.java b/Mage.Sets/src/mage/cards/k/KjeldoranFrostbeast.java index 184b9b72ebd..a84844592a8 100644 --- a/Mage.Sets/src/mage/cards/k/KjeldoranFrostbeast.java +++ b/Mage.Sets/src/mage/cards/k/KjeldoranFrostbeast.java @@ -1,26 +1,30 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EndOfCombatTriggeredAbility; import mage.abilities.effects.common.DestroyAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.BlockedByIdPredicate; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class KjeldoranFrostbeast extends CardImpl { + private static final FilterPermanent filter + = new FilterCreaturePermanent("creatures blocking or blocked by it"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.EITHER); + } + public KjeldoranFrostbeast(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{W}"); @@ -29,12 +33,8 @@ public final class KjeldoranFrostbeast extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(4); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures blocking or blocked by it"); - filter.add(Predicates.or(new BlockedByIdPredicate(this.getId()), - new BlockingAttackerIdPredicate(this.getId()))); // At end of combat, destroy all creatures blocking or blocked by Kjeldoran Frostbeast. - Ability ability = new EndOfCombatTriggeredAbility(new DestroyAllEffect(filter, false), false); - this.addAbility(ability); + this.addAbility(new EndOfCombatTriggeredAbility(new DestroyAllEffect(filter, false), false)); } private KjeldoranFrostbeast(final KjeldoranFrostbeast card) { diff --git a/Mage.Sets/src/mage/cards/k/KjeldoranRoyalGuard.java b/Mage.Sets/src/mage/cards/k/KjeldoranRoyalGuard.java index bf0db00f753..d1886525722 100644 --- a/Mage.Sets/src/mage/cards/k/KjeldoranRoyalGuard.java +++ b/Mage.Sets/src/mage/cards/k/KjeldoranRoyalGuard.java @@ -88,7 +88,7 @@ class KjeldoranRoyalGuardEffect extends ReplacementEffectImpl { && ((DamageEvent)event).isCombatDamage()) { Permanent p = game.getPermanent(source.getSourceId()); if (p != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (event.getSourceId().equals(permanent.getId())) { return true; } diff --git a/Mage.Sets/src/mage/cards/k/KlauthUnrivaledAncient.java b/Mage.Sets/src/mage/cards/k/KlauthUnrivaledAncient.java index 50e10e69888..3cf508338d0 100644 --- a/Mage.Sets/src/mage/cards/k/KlauthUnrivaledAncient.java +++ b/Mage.Sets/src/mage/cards/k/KlauthUnrivaledAncient.java @@ -87,7 +87,7 @@ class KlauthUnrivaledAncientEffect extends OneShotEffect { .getBattlefield() .getActivePermanents( StaticFilters.FILTER_ATTACKING_CREATURES, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game ).stream() .filter(Objects::nonNull) .map(MageObject::getPower) diff --git a/Mage.Sets/src/mage/cards/k/KnacksawClique.java b/Mage.Sets/src/mage/cards/k/KnacksawClique.java index 86bbe3e8fe6..dd2801061ba 100644 --- a/Mage.Sets/src/mage/cards/k/KnacksawClique.java +++ b/Mage.Sets/src/mage/cards/k/KnacksawClique.java @@ -80,7 +80,7 @@ class KnacksawCliqueEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player opponent = game.getPlayer(targetPointer.getFirst(game, source)); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && opponent != null) { if (opponent.getLibrary().hasCards()) { Library library = opponent.getLibrary(); diff --git a/Mage.Sets/src/mage/cards/k/KnightOfDusk.java b/Mage.Sets/src/mage/cards/k/KnightOfDusk.java index 4797519f740..7fa04e00e5c 100644 --- a/Mage.Sets/src/mage/cards/k/KnightOfDusk.java +++ b/Mage.Sets/src/mage/cards/k/KnightOfDusk.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -11,19 +9,26 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author dustinconrad */ public final class KnightOfDusk extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("creature blocking {this}"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.BLOCKING); + } + public KnightOfDusk(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.HUMAN); this.subtype.add(SubType.KNIGHT); @@ -31,10 +36,8 @@ public final class KnightOfDusk extends CardImpl { this.toughness = new MageInt(2); // {B}{B}: Destroy target creature blocking Knight of Dusk. - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking {this}"); - filter.add(new BlockingAttackerIdPredicate(this.getId())); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{B}{B}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{B}{B}")); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KnightOfValor.java b/Mage.Sets/src/mage/cards/k/KnightOfValor.java index 65d0c21d273..ba893fa3238 100644 --- a/Mage.Sets/src/mage/cards/k/KnightOfValor.java +++ b/Mage.Sets/src/mage/cards/k/KnightOfValor.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -10,22 +8,31 @@ import mage.abilities.keyword.FlankingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; + +import java.util.UUID; /** - * * @author LoneFox */ public final class KnightOfValor extends CardImpl { + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("each creature without flanking blocking {this}"); + + static { + filter.add(Predicates.not(new AbilityPredicate(FlankingAbility.class))); + filter.add(BlockingOrBlockedBySourcePredicate.BLOCKING); + } + public KnightOfValor(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.KNIGHT); this.power = new MageInt(2); @@ -34,10 +41,11 @@ public final class KnightOfValor extends CardImpl { // Flanking this.addAbility(new FlankingAbility()); // {1}{W}: Each creature without flanking blocking Knight of Valor gets -1/-1 until end of turn. Activate this ability only once each turn. - FilterCreaturePermanent filter = new FilterCreaturePermanent("each creature without flanking blocking {this}"); - filter.add(Predicates.not(new AbilityPredicate(FlankingAbility.class))); - filter.add(new BlockingAttackerIdPredicate(this.getId())); - this.addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new BoostAllEffect(-1, -1, Duration.EndOfTurn, filter, false), new ManaCostsImpl("{1}{W}"))); + this.addAbility(new LimitedTimesPerTurnActivatedAbility( + Zone.BATTLEFIELD, + new BoostAllEffect(-1, -1, Duration.EndOfTurn, filter, false), + new ManaCostsImpl<>("{1}{W}") + )); } private KnightOfValor(final KnightOfValor card) { diff --git a/Mage.Sets/src/mage/cards/k/KnockoutBlow.java b/Mage.Sets/src/mage/cards/k/KnockoutBlow.java new file mode 100644 index 00000000000..508f7efe084 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KnockoutBlow.java @@ -0,0 +1,57 @@ +package mage.cards.k; + +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceTargetsPermanentCondition; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.common.TargetAttackingOrBlockingCreature; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KnockoutBlow extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("a red creature"); + + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + } + + private static final Condition condition = new SourceTargetsPermanentCondition(filter); + + public KnockoutBlow(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); + + // This spell costs {2} less to cast if it target a red creature. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SpellCostReductionSourceEffect(2, condition).setCanWorksOnStackOnly(true) + ).setRuleAtTheTop(true)); + + // Knockout Blow deals 4 damage to target attacking or blocking creature and you gain 2 life. + this.getSpellAbility().addEffect(new DamageTargetEffect(4)); + this.getSpellAbility().addEffect(new GainLifeEffect(2).concatBy("and")); + this.getSpellAbility().addTarget(new TargetAttackingOrBlockingCreature()); + } + + private KnockoutBlow(final KnockoutBlow card) { + super(card); + } + + @Override + public KnockoutBlow copy() { + return new KnockoutBlow(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KnotvinePaladin.java b/Mage.Sets/src/mage/cards/k/KnotvinePaladin.java index 6cfbdc131b5..cbd33295f7a 100644 --- a/Mage.Sets/src/mage/cards/k/KnotvinePaladin.java +++ b/Mage.Sets/src/mage/cards/k/KnotvinePaladin.java @@ -1,42 +1,48 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; +import java.util.UUID; + /** - * * @author Loki */ public final class KnotvinePaladin extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("untapped creature you control"); static { filter.add(TappedPredicate.UNTAPPED); } + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + private static final Hint hint = new ValueHint("Untapped creatures you control", xValue); public KnotvinePaladin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.KNIGHT); - - - this.power = new MageInt(2); this.toughness = new MageInt(2); - this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(new PermanentsOnBattlefieldCount(filter), new PermanentsOnBattlefieldCount(filter), Duration.EndOfTurn), false)); + this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect( + xValue, xValue, Duration.EndOfTurn, true, "it" + ), false).addHint(hint)); } private KnotvinePaladin(final KnotvinePaladin card) { diff --git a/Mage.Sets/src/mage/cards/k/KnowledgePool.java b/Mage.Sets/src/mage/cards/k/KnowledgePool.java index c813eea3cb1..213ab9caccd 100644 --- a/Mage.Sets/src/mage/cards/k/KnowledgePool.java +++ b/Mage.Sets/src/mage/cards/k/KnowledgePool.java @@ -18,7 +18,6 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardIdPredicate; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.players.Player; @@ -38,10 +37,11 @@ public final class KnowledgePool extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}"); // Imprint - When Knowledge Pool enters the battlefield, each player exiles the top three cards of their library - this.addAbility(new EntersBattlefieldTriggeredAbility(new KnowledgePoolEffect1(), false).setAbilityWord(AbilityWord.IMPRINT)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new KnowledgePoolExileThreeCardsEffect(), false).setAbilityWord(AbilityWord.IMPRINT)); - // Whenever a player casts a spell from their hand, that player exiles it. If the player does, they may cast another nonland card exiled with Knowledge Pool without paying that card's mana cost. - this.addAbility(new KnowledgePoolAbility()); + // Whenever a player casts a spell from their hand, that player exiles it. + // If the player does, they may cast another nonland card exiled with Knowledge Pool without paying that card's mana cost. + this.addAbility(new KnowledgePoolWhenCastFromHandAbility()); } private KnowledgePool(final KnowledgePool card) { @@ -52,58 +52,62 @@ public final class KnowledgePool extends CardImpl { public KnowledgePool copy() { return new KnowledgePool(this); } - } -class KnowledgePoolEffect1 extends OneShotEffect { +class KnowledgePoolExileThreeCardsEffect extends OneShotEffect { - public KnowledgePoolEffect1() { + public KnowledgePoolExileThreeCardsEffect() { super(Outcome.Neutral); staticText = "each player exiles the top three cards of their library"; } - public KnowledgePoolEffect1(final KnowledgePoolEffect1 effect) { + public KnowledgePoolExileThreeCardsEffect(final KnowledgePoolExileThreeCardsEffect effect) { super(effect); } @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller == null || sourceObject == null) { - return false; - } + if (sourceObject == null) { return false; } + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); - if (player != null) { - player.moveCardsToExile(player.getLibrary().getTopCards(game, 3), source, game, true, - CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()), - sourceObject.getIdName() + " (" + sourceObject.getZoneChangeCounter(game) + ')'); - } + if (player == null) { continue; } + + player.moveCardsToExile( + player.getLibrary().getTopCards(game, 3), + source, + game, + true, + CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()), + sourceObject.getIdName() + " (" + sourceObject.getZoneChangeCounter(game) + ')' + ); } return true; } @Override - public KnowledgePoolEffect1 copy() { - return new KnowledgePoolEffect1(this); + public KnowledgePoolExileThreeCardsEffect copy() { + return new KnowledgePoolExileThreeCardsEffect(this); } - } -class KnowledgePoolAbility extends TriggeredAbilityImpl { +class KnowledgePoolWhenCastFromHandAbility extends TriggeredAbilityImpl { - public KnowledgePoolAbility() { - super(Zone.BATTLEFIELD, new KnowledgePoolEffect2(), false); + public KnowledgePoolWhenCastFromHandAbility() { + super(Zone.BATTLEFIELD, new KnowledgePoolExileAndPlayEffect(), false); } - public KnowledgePoolAbility(final KnowledgePoolAbility ability) { + private KnowledgePoolWhenCastFromHandAbility(final KnowledgePoolWhenCastFromHandAbility ability) { super(ability); } @Override - public KnowledgePoolAbility copy() { - return new KnowledgePoolAbility(this); + public KnowledgePoolWhenCastFromHandAbility copy() { + return new KnowledgePoolWhenCastFromHandAbility(this); } @Override @@ -113,65 +117,76 @@ class KnowledgePoolAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getZone() == Zone.HAND) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getTargetId())); - } - return true; - } - } - return false; - } + if (event.getZone() != Zone.HAND) { return false; } + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell == null) { return false; } + + for (Effect effect : this.getEffects()) { + effect.setTargetPointer(new FixedTarget(event.getTargetId())); + } + return true; + } } -class KnowledgePoolEffect2 extends OneShotEffect { +class KnowledgePoolExileAndPlayEffect extends OneShotEffect { - private static FilterNonlandCard filter = new FilterNonlandCard("nonland card exiled with Knowledge Pool"); - - public KnowledgePoolEffect2() { + public KnowledgePoolExileAndPlayEffect() { super(Outcome.Neutral); staticText = "Whenever a player casts a spell from their hand, that player exiles it. If the player does, they may cast another nonland card exiled with {this} without paying that card's mana cost"; } - public KnowledgePoolEffect2(final KnowledgePoolEffect2 effect) { + private KnowledgePoolExileAndPlayEffect(final KnowledgePoolExileAndPlayEffect effect) { super(effect); } @Override public boolean apply(Game game, Ability source) { Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); + if (spell == null) { return false; } + Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null && spell != null && sourceObject != null) { - UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), sourceObject.getZoneChangeCounter(game)); - if (controller.moveCardsToExile(spell, source, game, true, exileZoneId, sourceObject.getIdName())) { - Player player = game.getPlayer(spell.getControllerId()); - if (player != null && player.chooseUse(Outcome.PlayForFree, "Cast another nonland card exiled with " + sourceObject.getLogName() + " without paying that card's mana cost?", source, game)) { - FilterNonlandCard realFilter = filter.copy(); - realFilter.add(Predicates.not(new CardIdPredicate(spell.getSourceId()))); - TargetCardInExile target = new TargetCardInExile(0, 1, realFilter, source.getSourceId()); - target.setNotTarget(true); - if (player.choose(Outcome.PlayForFree, game.getExile().getExileZone(exileZoneId), target, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null && !card.getId().equals(spell.getSourceId())) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - player.cast(player.chooseAbilityForCast(card, game, true), game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - } - } - } - return true; - } + if (sourceObject == null ) { return false; } + + Player spellController = game.getPlayer(spell.getControllerId()); + if (spellController == null) { return false; } + + UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), sourceObject.getZoneChangeCounter(game)); + + if (!spellController.moveCardsToExile(spell, source, game, true, exileZoneId, sourceObject.getIdName())) { + // The card didn't make it to exile, none of Knowledge Pool's effect applied + return false; } - return false; + + // From here on down the function returns true since at least part of the effect went off + + if (!spellController.chooseUse(Outcome.PlayForFree, "Cast another nonland card exiled with " + sourceObject.getLogName() + " without paying that card's mana cost?", source, game)) { + // Pleyer didn't want to cast another spell BUT their original spell was exiled with Knowledge Pool, so return true. + return true; + } + FilterNonlandCard filter = new FilterNonlandCard("nonland card exiled with Knowledge Pool"); + filter.add(Predicates.not(new CardIdPredicate(spell.getSourceId()))); + + TargetCardInExile target = new TargetCardInExile(0, 1, filter, source.getSourceId()); + target.setNotTarget(true); + + if (!spellController.choose(Outcome.PlayForFree, game.getExile().getExileZone(exileZoneId), target, game)) { + // Player chose to not cast any ofthe spells + return true; + } + + Card card = game.getCard(target.getFirstTarget()); + if (card == null || card.getId().equals(spell.getSourceId())) { return true; } + + game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); + spellController.cast(spellController.chooseAbilityForCast(card, game, true), game, true, new ApprovingObject(source, game)); + game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); + + return true; } @Override - public KnowledgePoolEffect2 copy() { - return new KnowledgePoolEffect2(this); + public KnowledgePoolExileAndPlayEffect copy() { + return new KnowledgePoolExileAndPlayEffect(this); } - } diff --git a/Mage.Sets/src/mage/cards/k/KnuckleboneWitch.java b/Mage.Sets/src/mage/cards/k/KnuckleboneWitch.java index c86cc70798c..885060a7617 100644 --- a/Mage.Sets/src/mage/cards/k/KnuckleboneWitch.java +++ b/Mage.Sets/src/mage/cards/k/KnuckleboneWitch.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; @@ -9,32 +7,30 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.TargetController; import mage.counters.CounterType; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; + +import java.util.UUID; /** - * * @author markedagain */ public final class KnuckleboneWitch extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Goblin you control"); - static { - filter.add(TargetController.YOU.getControllerPredicate()); - filter.add(SubType.GOBLIN.getPredicate()); - } - + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.GOBLIN); + public KnuckleboneWitch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.SHAMAN); this.power = new MageInt(1); this.toughness = new MageInt(1); // Whenever a Goblin you control dies, you may put a +1/+1 counter on Knucklebone Witch. - this.addAbility(new DiesCreatureTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true, filter )); + this.addAbility(new DiesCreatureTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true, filter + ).setTriggerPhrase("Whenever a Goblin you control is put into a graveyard from the battlefield, ")); } private KnuckleboneWitch(final KnuckleboneWitch card) { diff --git a/Mage.Sets/src/mage/cards/k/KodamaOfTheEastTree.java b/Mage.Sets/src/mage/cards/k/KodamaOfTheEastTree.java index e85cd70256d..4001ab4c0af 100644 --- a/Mage.Sets/src/mage/cards/k/KodamaOfTheEastTree.java +++ b/Mage.Sets/src/mage/cards/k/KodamaOfTheEastTree.java @@ -124,11 +124,11 @@ class KodamaOfTheEastTreeEffect extends OneShotEffect { ComparisonType.FEWER_THAN, permanent.getManaValue() + 1 )); TargetCardInHand target = new TargetCardInHand(filter); - if (!target.canChoose(source.getSourceId(), source.getControllerId(), game) + if (!target.canChoose(source.getControllerId(), source, game) || !player.chooseUse(outcome, "Put a permanent card onto the battlefield?", source, game)) { return false; } - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card == null) { return false; diff --git a/Mage.Sets/src/mage/cards/k/KodamasReach.java b/Mage.Sets/src/mage/cards/k/KodamasReach.java index 9ace6ccedc8..78b073b8f9b 100644 --- a/Mage.Sets/src/mage/cards/k/KodamasReach.java +++ b/Mage.Sets/src/mage/cards/k/KodamasReach.java @@ -63,7 +63,7 @@ class KodamasReachEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/k/KolaghanForerunners.java b/Mage.Sets/src/mage/cards/k/KolaghanForerunners.java index 91ee35e5728..010c61480fd 100644 --- a/Mage.Sets/src/mage/cards/k/KolaghanForerunners.java +++ b/Mage.Sets/src/mage/cards/k/KolaghanForerunners.java @@ -38,7 +38,7 @@ public final class KolaghanForerunners extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.ALL, effect).addHint(CreaturesYouControlHint.instance)); // Dash {2}{R} - this.addAbility(new DashAbility(this, "{2}{R}")); + this.addAbility(new DashAbility("{2}{R}")); } private KolaghanForerunners(final KolaghanForerunners card) { diff --git a/Mage.Sets/src/mage/cards/k/KolaghanSkirmisher.java b/Mage.Sets/src/mage/cards/k/KolaghanSkirmisher.java index d7c63560204..55080fbe8d4 100644 --- a/Mage.Sets/src/mage/cards/k/KolaghanSkirmisher.java +++ b/Mage.Sets/src/mage/cards/k/KolaghanSkirmisher.java @@ -23,7 +23,7 @@ public final class KolaghanSkirmisher extends CardImpl { this.toughness = new MageInt(2); // Dash {2}{B} - this.addAbility(new DashAbility(this, "{2}{B}")); + this.addAbility(new DashAbility("{2}{B}")); } private KolaghanSkirmisher(final KolaghanSkirmisher card) { diff --git a/Mage.Sets/src/mage/cards/k/KolaghanStormsinger.java b/Mage.Sets/src/mage/cards/k/KolaghanStormsinger.java index e5d948f7651..d30ffdd6c56 100644 --- a/Mage.Sets/src/mage/cards/k/KolaghanStormsinger.java +++ b/Mage.Sets/src/mage/cards/k/KolaghanStormsinger.java @@ -32,7 +32,7 @@ public final class KolaghanStormsinger extends CardImpl { // Haste this.addAbility(HasteAbility.getInstance()); // Megamorph {R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{R}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{R}"), true)); // When Kolaghan Stormsinger is turned face up, target creature gains haste until end of turn. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn), false); diff --git a/Mage.Sets/src/mage/cards/k/KolaghanTheStormsFury.java b/Mage.Sets/src/mage/cards/k/KolaghanTheStormsFury.java index 9d000e820da..9cf7be7dceb 100644 --- a/Mage.Sets/src/mage/cards/k/KolaghanTheStormsFury.java +++ b/Mage.Sets/src/mage/cards/k/KolaghanTheStormsFury.java @@ -42,7 +42,7 @@ public final class KolaghanTheStormsFury extends CardImpl { false, filter, SetTargetPointer.NONE, false)); // Dash {3}{B}{R} - this.addAbility(new DashAbility(this, "{3}{B}{R}")); + this.addAbility(new DashAbility("{3}{B}{R}")); } private KolaghanTheStormsFury(final KolaghanTheStormsFury card) { diff --git a/Mage.Sets/src/mage/cards/k/KolaghansCommand.java b/Mage.Sets/src/mage/cards/k/KolaghansCommand.java index 2ab9ab5a6f9..b242b9db486 100644 --- a/Mage.Sets/src/mage/cards/k/KolaghansCommand.java +++ b/Mage.Sets/src/mage/cards/k/KolaghansCommand.java @@ -41,20 +41,17 @@ public final class KolaghansCommand extends CardImpl { this.getSpellAbility().getTargets().add(new TargetCardInYourGraveyard(1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); // or Target player discards a card; - Mode mode = new Mode(); - mode.addEffect(new DiscardTargetEffect(1)); + Mode mode = new Mode(new DiscardTargetEffect(1)); mode.addTarget(new TargetPlayer()); this.getSpellAbility().getModes().addMode(mode); // or Destroy target artifact; - mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetPermanent(filter)); this.getSpellAbility().getModes().addMode(mode); // or Kolaghan's Command deals 2 damage to any target. - mode = new Mode(); - mode.addEffect(new DamageTargetEffect(2)); + mode = new Mode(new DamageTargetEffect(2)); mode.addTarget(new TargetAnyTarget()); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/k/KolvoriGodOfKinship.java b/Mage.Sets/src/mage/cards/k/KolvoriGodOfKinship.java index 44ecc57252e..bf25793fed7 100644 --- a/Mage.Sets/src/mage/cards/k/KolvoriGodOfKinship.java +++ b/Mage.Sets/src/mage/cards/k/KolvoriGodOfKinship.java @@ -14,9 +14,9 @@ import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.VigilanceAbility; @@ -73,11 +73,9 @@ public final class KolvoriGodOfKinship extends ModalDoubleFacesCard { // {1}{G}, {T}: Look at the top six cards of your library. // You may reveal a legendary creature card from among them and put it into your hand. // Put the rest on the bottom of your library in a random order. - ability = new SimpleActivatedAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(6), false, StaticValue.get(1), filter2, - Zone.LIBRARY, false, true, false, Zone.HAND, - true, false, false).setBackInRandomOrder(true), new ManaCostsImpl("{1}{G}") - ); + ability = new SimpleActivatedAbility( + new LookLibraryAndPickControllerEffect(6, 1, filter2, PutCards.HAND, PutCards.BOTTOM_RANDOM), + new ManaCostsImpl("{1}{G}")); ability.addCost(new TapSourceCost()); this.getLeftHalfCard().addAbility(ability); @@ -148,7 +146,7 @@ class TheRinghartCrestManaCondition extends CreatureCastManaCondition { @Override public boolean apply(Game game, Ability source) { if (super.apply(game, source)) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object != null) { if (object.isLegendary()) { return true; diff --git a/Mage.Sets/src/mage/cards/k/KomainuBattleArmor.java b/Mage.Sets/src/mage/cards/k/KomainuBattleArmor.java new file mode 100644 index 00000000000..d64439ad352 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KomainuBattleArmor.java @@ -0,0 +1,137 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.combat.GoadTargetEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.abilities.keyword.ReconfigureAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.DamagedEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KomainuBattleArmor extends CardImpl { + + public KomainuBattleArmor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.EQUIPMENT); + this.subtype.add(SubType.DOG); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Menace + this.addAbility(new MenaceAbility(false)); + + // Equipped creature gets +2/+2 and has menace. + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 2)); + ability.addEffect(new GainAbilityAttachedEffect( + new MenaceAbility(false), AttachmentType.EQUIPMENT + ).setText("and has menace")); + this.addAbility(ability); + + // Whenever Komainu Battle Armor or equipped creature deals combat damage to a player, goad each creature that player controls. + this.addAbility(new KomainuBattleArmorTriggeredAbility()); + + // Reconfigure {4} + this.addAbility(new ReconfigureAbility("{4}")); + } + + private KomainuBattleArmor(final KomainuBattleArmor card) { + super(card); + } + + @Override + public KomainuBattleArmor copy() { + return new KomainuBattleArmor(this); + } +} + +class KomainuBattleArmorTriggeredAbility extends TriggeredAbilityImpl { + + KomainuBattleArmorTriggeredAbility() { + super(Zone.BATTLEFIELD, new KomainuBattleArmorEffect()); + } + + private KomainuBattleArmorTriggeredAbility(final KomainuBattleArmorTriggeredAbility ability) { + super(ability); + } + + @Override + public KomainuBattleArmorTriggeredAbility copy() { + return new KomainuBattleArmorTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!((DamagedEvent) event).isCombatDamage()) { + return false; + } + if (getSourceId().equals(event.getSourceId())) { + getEffects().setTargetPointer(new FixedTarget(event.getTargetId())); + return true; + } + Permanent permanent = getSourcePermanentOrLKI(game); + if (permanent != null && event.getSourceId().equals(permanent.getAttachedTo())) { + getEffects().setTargetPointer(new FixedTarget(event.getTargetId())); + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever {this} or equipped creature deals combat damage to a player, goad each creature that player controls."; + } +} + +class KomainuBattleArmorEffect extends OneShotEffect { + + KomainuBattleArmorEffect() { + super(Outcome.Benefit); + } + + private KomainuBattleArmorEffect(final KomainuBattleArmorEffect effect) { + super(effect); + } + + @Override + public KomainuBattleArmorEffect copy() { + return new KomainuBattleArmorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + UUID playerId = getTargetPointer().getFirst(game, source); + if (playerId == null) { + return false; + } + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, + playerId, source, game + )) { + game.addEffect(new GoadTargetEffect().setTargetPointer(new FixedTarget(permanent, game)), source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KondasBanner.java b/Mage.Sets/src/mage/cards/k/KondasBanner.java index 7d9cfcad479..5ce41c639b7 100644 --- a/Mage.Sets/src/mage/cards/k/KondasBanner.java +++ b/Mage.Sets/src/mage/cards/k/KondasBanner.java @@ -108,7 +108,7 @@ class KondasBannerTypeBoostEffect extends BoostAllEffect { if (equipment != null && equipment.getAttachedTo() != null) { Permanent equipedCreature = game.getPermanent(equipment.getAttachedTo()); if (equipedCreature != null) { - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (perm.shareCreatureTypes(game, equipedCreature)) { perm.addPower(power.calculate(game, source, this)); perm.addToughness(toughness.calculate(game, source, this)); @@ -148,7 +148,7 @@ class KondasBannerColorBoostEffect extends BoostAllEffect { if (equipment != null && equipment.getAttachedTo() != null) { Permanent equipedCreature = game.getPermanent(equipment.getAttachedTo()); if (equipedCreature != null) { - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (equipedCreature.getColor(game).shares(perm.getColor(game))) { perm.addPower(power.calculate(game, source, this)); perm.addToughness(toughness.calculate(game, source, this)); diff --git a/Mage.Sets/src/mage/cards/k/KorChant.java b/Mage.Sets/src/mage/cards/k/KorChant.java index 7b14735d97e..94729ddb3b4 100644 --- a/Mage.Sets/src/mage/cards/k/KorChant.java +++ b/Mage.Sets/src/mage/cards/k/KorChant.java @@ -71,7 +71,7 @@ class KorChantEffect extends RedirectionEffect { @Override public void init(Ability source, Game game) { super.init(source, game); - this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/k/KorDirge.java b/Mage.Sets/src/mage/cards/k/KorDirge.java index 2d66c71f3cd..acacebbe74d 100644 --- a/Mage.Sets/src/mage/cards/k/KorDirge.java +++ b/Mage.Sets/src/mage/cards/k/KorDirge.java @@ -71,7 +71,7 @@ class KorDirgeEffect extends RedirectionEffect { @Override public void init(Ability source, Game game) { super.init(source, game); - this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/k/KorHookmaster.java b/Mage.Sets/src/mage/cards/k/KorHookmaster.java index 91b330cfa5d..64e80a529d4 100644 --- a/Mage.Sets/src/mage/cards/k/KorHookmaster.java +++ b/Mage.Sets/src/mage/cards/k/KorHookmaster.java @@ -30,7 +30,7 @@ public final class KorHookmaster extends CardImpl { // When Kor Hookmaster enters the battlefield, tap target creature an opponent controls. // That creature doesn't untap during its controller's next untap step. EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); - ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect()); + ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("that creature")); ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KorozdaGuildmage.java b/Mage.Sets/src/mage/cards/k/KorozdaGuildmage.java index 64bcc640084..b52a1d5fddc 100644 --- a/Mage.Sets/src/mage/cards/k/KorozdaGuildmage.java +++ b/Mage.Sets/src/mage/cards/k/KorozdaGuildmage.java @@ -1,4 +1,3 @@ - package mage.cards.k; import java.util.UUID; @@ -8,6 +7,7 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.SacrificeCostCreaturesToughness; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; @@ -17,7 +17,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.permanent.token.SaprolingToken; @@ -46,13 +45,17 @@ public final class KorozdaGuildmage extends CardImpl { this.toughness = new MageInt(2); // {1}{B}{G}: Target creature gets +1/+1 and gains intimidate until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(1,1, Duration.EndOfTurn),new ManaCostsImpl("{1}{B}{G}")); - ability.addEffect(new GainAbilityTargetEffect(IntimidateAbility.getInstance(), Duration.EndOfTurn)); + Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); + effect.setText("target creature gets +1/+1"); + Ability ability = new SimpleActivatedAbility(effect, new ManaCostsImpl("{1}{B}{G}")); + effect = new GainAbilityTargetEffect(IntimidateAbility.getInstance(), Duration.EndOfTurn); + effect.setText("and gains intimidate until end of turn. (It can't be blocked except by artifact creatures and/or creatures that share a color with it.)"); + ability.addEffect(effect); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); // {2}{B}{G}, Sacrifice a nontoken creature: create X 1/1 green Saproling creature tokens, where X is the sacrificed creature's toughness. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new SaprolingToken(),SacrificeCostCreaturesToughness.instance),new ManaCostsImpl("{2}{B}{G}")); + ability = new SimpleActivatedAbility(new CreateTokenEffect(new SaprolingToken(),SacrificeCostCreaturesToughness.instance),new ManaCostsImpl("{2}{B}{G}")); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(1,1,filter, true))); this.addAbility(ability); @@ -66,4 +69,4 @@ public final class KorozdaGuildmage extends CardImpl { public KorozdaGuildmage copy() { return new KorozdaGuildmage(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/k/KoseiPenitentWarlord.java b/Mage.Sets/src/mage/cards/k/KoseiPenitentWarlord.java new file mode 100644 index 00000000000..4e113e3d678 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KoseiPenitentWarlord.java @@ -0,0 +1,122 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToOpponentTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.Counter; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KoseiPenitentWarlord extends CardImpl { + + public KoseiPenitentWarlord(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.SAMURAI); + this.power = new MageInt(0); + this.toughness = new MageInt(5); + + // As long as Kosei, Penitent Warlord is enchanted, equipped, and has a counter on it, Kosei has "Whenever Kosei, Penitent Warlord deals combat damage to an opponent, you draw that many cards and Kosei deals that much damage to each other opponent." + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(new DealsDamageToOpponentTriggeredAbility( + new KoseiPenitentWarlordEffect(), false, true, true + )), KoseiPenitentWarlordCondition.instance, "as long as {this} is enchanted, equipped, " + + "and has a counter on it, {this} has \"Whenever {this} deals combat damage to an opponent, " + + "you draw that many cards and {this} deals that much damage to each other opponent.\"" + ))); + } + + private KoseiPenitentWarlord(final KoseiPenitentWarlord card) { + super(card); + } + + @Override + public KoseiPenitentWarlord copy() { + return new KoseiPenitentWarlord(this); + } +} + +enum KoseiPenitentWarlordCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + return sourcePermanent != null + && sourcePermanent.getCounters(game) + .values() + .stream() + .mapToInt(Counter::getCount) + .anyMatch(x -> x > 0) + && sourcePermanent + .getAttachments() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .anyMatch(permanent -> permanent.hasSubtype(SubType.EQUIPMENT, game)) + && sourcePermanent + .getAttachments() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .anyMatch(permanent -> permanent.hasSubtype(SubType.AURA, game)); + } +} + +class KoseiPenitentWarlordEffect extends OneShotEffect { + + KoseiPenitentWarlordEffect() { + super(Outcome.Benefit); + staticText = "you draw that many cards and {this} deals that much damage to each other opponent"; + } + + private KoseiPenitentWarlordEffect(final KoseiPenitentWarlordEffect effect) { + super(effect); + } + + @Override + public KoseiPenitentWarlordEffect copy() { + return new KoseiPenitentWarlordEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + int damage = (Integer) getValue("damage"); + if (controller == null || damage < 1) { + return false; + } + controller.drawCards(damage, source, game); + UUID damagedOpponentId = getTargetPointer().getFirst(game, source); + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + if (opponentId.equals(damagedOpponentId)) { + continue; + } + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + opponent.damage(damage, source, game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KothOfTheHammer.java b/Mage.Sets/src/mage/cards/k/KothOfTheHammer.java index 6f0b674845a..864a76c9f8e 100644 --- a/Mage.Sets/src/mage/cards/k/KothOfTheHammer.java +++ b/Mage.Sets/src/mage/cards/k/KothOfTheHammer.java @@ -6,7 +6,6 @@ import mage.MageInt; import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.mana.DynamicManaEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -43,7 +42,7 @@ public final class KothOfTheHammer extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.KOTH); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Untap target Mountain. It becomes a 4/4 red Elemental creature until end of turn. It's still a land. Ability ability = new LoyaltyAbility(new UntapTargetEffect(), 1); diff --git a/Mage.Sets/src/mage/cards/k/KothophedSoulHoarder.java b/Mage.Sets/src/mage/cards/k/KothophedSoulHoarder.java index 39549524d24..fca295312f4 100644 --- a/Mage.Sets/src/mage/cards/k/KothophedSoulHoarder.java +++ b/Mage.Sets/src/mage/cards/k/KothophedSoulHoarder.java @@ -52,7 +52,7 @@ public final class KothophedSoulHoarder extends CardImpl { Ability ability = new ZoneChangeAllTriggeredAbility(Zone.BATTLEFIELD, Zone.BATTLEFIELD, Zone.GRAVEYARD, effect, filter, "Whenever a permanent owned by another player is put into a graveyard from the battlefield, ", false); effect = new LoseLifeSourceControllerEffect(1); - effect.setText("and lose 1 life"); + effect.setText("and you lose 1 life"); ability.addEffect(effect); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KotoseTheSilentSpider.java b/Mage.Sets/src/mage/cards/k/KotoseTheSilentSpider.java new file mode 100644 index 00000000000..5f89cc4ac04 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KotoseTheSilentSpider.java @@ -0,0 +1,208 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCardInOpponentsGraveyard; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class KotoseTheSilentSpider extends CardImpl { + + private static final FilterCard filter + = new FilterCard("card other than a basic land card in an opponent's graveyard"); + + static { + filter.add(Predicates.not(Predicates.and( + CardType.LAND.getPredicate(), + SuperType.BASIC.getPredicate() + ))); + } + + public KotoseTheSilentSpider(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{B}"); + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NINJA); + + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // When Kotose, Silent Spider enters the battlefield, exile target card in an opponent's graveyard other than a basic land card. Search that player's graveyard, hand, and library for any number of cards with the same name as that card and exile them. For as long as you control Kotose, you may play one of the exiled cards, and you may spend mana as though it were mana of any color to cast it. + Ability ability = new EntersBattlefieldTriggeredAbility(new KotoseTheSilentSpiderEffect()); + ability.addTarget(new TargetCardInOpponentsGraveyard(filter)); + this.addAbility(ability, new KotoseTheSilentSpiderWatcher()); + } + + private KotoseTheSilentSpider(final KotoseTheSilentSpider card) { + super(card); + } + + @Override + public KotoseTheSilentSpider copy() { + return new KotoseTheSilentSpider(this); + } +} + +class KotoseTheSilentSpiderEffect extends OneShotEffect { + + public KotoseTheSilentSpiderEffect() { + super(Outcome.Exile); + this.staticText = "exile target card other than a basic land card from an opponent's graveyard. " + + "Search that player's graveyard, hand, and library for any number of cards with the same name " + + "as that card and exile them. Then that player shuffles. For as long as you control {this}, you may " + + "play one of the exiled cards, and you may spend mana as though it were mana of any color to cast it"; + } + + public KotoseTheSilentSpiderEffect(final KotoseTheSilentSpiderEffect effect) { + super(effect); + } + + @Override + public KotoseTheSilentSpiderEffect copy() { + return new KotoseTheSilentSpiderEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + if (controller == null || card == null) { + return false; + } + Player opponent = game.getPlayer(card.getOwnerId()); + if (opponent == null) { + return false; + } + UUID exileId = CardUtil.getExileZoneId(game, source); + String exileName = CardUtil.getSourceName(game, source); + controller.moveCardsToExile(card, source, game, true, exileId, exileName); + Cards cards = new CardsImpl(); + FilterCard filter = new FilterCard("cards named " + card.getName() + " from " + opponent.getName() + "'s graveyard"); + filter.add(new NamePredicate(card.getName())); + + TargetCardInGraveyard targetCardInGraveyard = new TargetCardInGraveyard(0, Integer.MAX_VALUE, filter); + controller.choose(outcome, opponent.getGraveyard(), targetCardInGraveyard, game); + cards.addAll(targetCardInGraveyard.getTargets()); + + filter.setMessage("cards named " + card.getName() + " from " + opponent.getName() + "'s hand"); + TargetCardInHand targetCardInHand = new TargetCardInHand(0, Integer.MAX_VALUE, filter); + controller.choose(outcome, opponent.getHand(), targetCardInHand, game); + cards.addAll(targetCardInHand.getTargets()); + + filter.setMessage("cards named " + card.getName() + " from " + opponent.getName() + "'s library"); + TargetCardInLibrary target = new TargetCardInLibrary(0, Integer.MAX_VALUE, filter); + controller.searchLibrary(target, source, game, opponent.getId()); + target.getTargets() + .stream() + .map(cardId -> opponent.getLibrary().getCard(cardId, game)) + .forEach(cards::add); + + Set cardSet = cards.getCards(game); + controller.moveCardsToExile(cardSet, source, game, true, exileId, exileName); + opponent.shuffleLibrary(source, game); + cardSet.add(card); + if (cardSet.isEmpty() || source.getSourcePermanentIfItStillExists(game) == null) { + return true; + } + KotoseTheSilentSpiderWatcher.addCards(source, cardSet, game); + for (Card exiledCard : cardSet) { + CardUtil.makeCardPlayable( + game, source, exiledCard, Duration.WhileControlled, true, + null, new KotoseTheSilentSpiderCondition(exiledCard, game) + ); + } + return true; + } +} + +class KotoseTheSilentSpiderCondition implements Condition { + + private final MageObjectReference mor; + + KotoseTheSilentSpiderCondition(Card card, Game game) { + this.mor = new MageObjectReference(card, game); + } + + @Override + public boolean apply(Game game, Ability source) { + return KotoseTheSilentSpiderWatcher.checkCard(game, source, mor); + } +} + +class KotoseTheSilentSpiderWatcher extends Watcher { + + private final Map>> morMap = new HashMap<>(); + + public KotoseTheSilentSpiderWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.CLEANUP_STEP_POST) { + morMap.entrySet().removeIf(e -> !e.getKey().zoneCounterIsCurrent(game)); + morMap.values() + .stream() + .flatMap(Collection::stream) + .map(set -> set.removeIf(mor -> !mor.zoneCounterIsCurrent(game))); + morMap.values().removeIf(Set::isEmpty); + return; + } + if (event.getType() != GameEvent.EventType.SPELL_CAST || event.getAdditionalReference() == null) { + return; + } + Spell spell = game.getSpell(event.getTargetId()); + if (spell == null) { + return; + } + morMap.getOrDefault( + event.getAdditionalReference().getApprovingMageObjectReference(), Collections.emptySet() + ).removeIf(set -> set + .stream() + .anyMatch(mor -> mor.getSourceId().equals(spell.getMainCard().getId()) + && mor.getZoneChangeCounter() + 1 == spell.getZoneChangeCounter(game))); + } + + static void addCards(Ability source, Set cards, Game game) { + game.getState() + .getWatcher(KotoseTheSilentSpiderWatcher.class) + .morMap + .computeIfAbsent(new MageObjectReference(source), x -> new HashSet<>()) + .add(cards + .stream() + .map(card -> new MageObjectReference(card, game)) + .collect(Collectors.toSet())); + } + + static boolean checkCard(Game game, Ability source, MageObjectReference mor) { + return game.getState() + .getWatcher(KotoseTheSilentSpiderWatcher.class) + .morMap + .getOrDefault(new MageObjectReference(source), Collections.emptySet()) + .stream() + .flatMap(Collection::stream) + .anyMatch(mor::equals); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KozilekTheGreatDistortion.java b/Mage.Sets/src/mage/cards/k/KozilekTheGreatDistortion.java index 23050d59ae0..9f5ff59456b 100644 --- a/Mage.Sets/src/mage/cards/k/KozilekTheGreatDistortion.java +++ b/Mage.Sets/src/mage/cards/k/KozilekTheGreatDistortion.java @@ -123,7 +123,7 @@ class KozilekDiscardCost extends CostImpl { TargetCardInHand target = new TargetCardInHand(filter); this.getTargets().clear(); this.getTargets().add(target); - if (targets.choose(Outcome.Discard, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.Discard, controllerId, source.getSourceId(), source, game)) { for (UUID targetId : targets.get(0).getTargets()) { Card card = player.getHand().get(targetId, game); if (card == null) { diff --git a/Mage.Sets/src/mage/cards/k/KraulHarpooner.java b/Mage.Sets/src/mage/cards/k/KraulHarpooner.java index c2f85a100b8..80594ab4cc6 100644 --- a/Mage.Sets/src/mage/cards/k/KraulHarpooner.java +++ b/Mage.Sets/src/mage/cards/k/KraulHarpooner.java @@ -7,14 +7,10 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.FlyingAbility; -import mage.constants.SubType; +import mage.constants.*; import mage.abilities.keyword.ReachAbility; 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.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; @@ -53,7 +49,7 @@ public final class KraulHarpooner extends CardImpl { new KraulHarpoonerEffect(), false ); ability.addTarget(new TargetPermanent(0, 1, filter, false)); - ability.withFlavorWord("Undergrowth"); + ability.setAbilityWord(AbilityWord.UNDERGROWTH); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KraumLudevicsOpus.java b/Mage.Sets/src/mage/cards/k/KraumLudevicsOpus.java index 5341966c66c..955727ba834 100644 --- a/Mage.Sets/src/mage/cards/k/KraumLudevicsOpus.java +++ b/Mage.Sets/src/mage/cards/k/KraumLudevicsOpus.java @@ -1,9 +1,7 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.CastSecondSpellTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; @@ -13,14 +11,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.watchers.common.CastSpellLastTurnWatcher; +import mage.constants.TargetController; + +import java.util.UUID; /** - * * @author Styxo */ public final class KraumLudevicsOpus extends CardImpl { @@ -40,11 +35,12 @@ public final class KraumLudevicsOpus extends CardImpl { this.addAbility(HasteAbility.getInstance()); // Whenever an opponent casts their second spell each turn, draw a card. - this.addAbility(new KraumLudevicsOpusTriggeredAbility(), new CastSpellLastTurnWatcher()); + this.addAbility(new CastSecondSpellTriggeredAbility( + new DrawCardSourceControllerEffect(1), TargetController.OPPONENT + )); // Partner this.addAbility(PartnerAbility.getInstance()); - } private KraumLudevicsOpus(final KraumLudevicsOpus card) { @@ -56,40 +52,3 @@ public final class KraumLudevicsOpus extends CardImpl { return new KraumLudevicsOpus(this); } } - -class KraumLudevicsOpusTriggeredAbility extends TriggeredAbilityImpl { - - public KraumLudevicsOpusTriggeredAbility() { - super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1)); - } - - public KraumLudevicsOpusTriggeredAbility(final KraumLudevicsOpusTriggeredAbility ability) { - super(ability); - } - - @Override - public KraumLudevicsOpusTriggeredAbility copy() { - return new KraumLudevicsOpusTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SPELL_CAST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (game.getOpponents(controllerId).contains(event.getPlayerId())) { - CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); - if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) == 2) { - return true; - } - } - return false; - } - - @Override - public String getRule() { - return "Whenever an opponent casts their second spell each turn, draw a card."; - } -} diff --git a/Mage.Sets/src/mage/cards/k/KrosanCloudscraper.java b/Mage.Sets/src/mage/cards/k/KrosanCloudscraper.java index 46d57b5246c..c04ba14adf7 100644 --- a/Mage.Sets/src/mage/cards/k/KrosanCloudscraper.java +++ b/Mage.Sets/src/mage/cards/k/KrosanCloudscraper.java @@ -31,7 +31,7 @@ public final class KrosanCloudscraper extends CardImpl { this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl("{G}{G}")), TargetController.YOU, false)); // Morph {7}{G}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{7}{G}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{7}{G}{G}"))); } private KrosanCloudscraper(final KrosanCloudscraper card) { diff --git a/Mage.Sets/src/mage/cards/k/KrosanColossus.java b/Mage.Sets/src/mage/cards/k/KrosanColossus.java index 1cfea736acc..c1e74d77477 100644 --- a/Mage.Sets/src/mage/cards/k/KrosanColossus.java +++ b/Mage.Sets/src/mage/cards/k/KrosanColossus.java @@ -23,7 +23,7 @@ public final class KrosanColossus extends CardImpl { this.toughness = new MageInt(9); // Morph {6}{G}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{6}{G}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{6}{G}{G}"))); } private KrosanColossus(final KrosanColossus card) { diff --git a/Mage.Sets/src/mage/cards/k/KrovikanWhispers.java b/Mage.Sets/src/mage/cards/k/KrovikanWhispers.java index 9f9575ce691..fd85574f988 100644 --- a/Mage.Sets/src/mage/cards/k/KrovikanWhispers.java +++ b/Mage.Sets/src/mage/cards/k/KrovikanWhispers.java @@ -42,7 +42,7 @@ public final class KrovikanWhispers extends CardImpl { this.addAbility(ability); // Cumulative upkeep-Pay {U} or {B}. - this.addAbility(new CumulativeUpkeepAbility(new OrCost(new ManaCostsImpl("{U}"), new ManaCostsImpl("{B}"), "{U} or {B}"))); + this.addAbility(new CumulativeUpkeepAbility(new OrCost("{U} or {B}", new ManaCostsImpl("{U}"), new ManaCostsImpl("{B}")))); // You control enchanted creature. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ControlEnchantedEffect())); diff --git a/Mage.Sets/src/mage/cards/k/KrumarBondKin.java b/Mage.Sets/src/mage/cards/k/KrumarBondKin.java index 23548f0556a..82c71024240 100644 --- a/Mage.Sets/src/mage/cards/k/KrumarBondKin.java +++ b/Mage.Sets/src/mage/cards/k/KrumarBondKin.java @@ -25,7 +25,7 @@ public final class KrumarBondKin extends CardImpl { this.toughness = new MageInt(3); // Morph {4}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{B}"))); } private KrumarBondKin(final KrumarBondKin card) { diff --git a/Mage.Sets/src/mage/cards/k/KruphixsInsight.java b/Mage.Sets/src/mage/cards/k/KruphixsInsight.java index 435a61613df..7d9103fa6fa 100644 --- a/Mage.Sets/src/mage/cards/k/KruphixsInsight.java +++ b/Mage.Sets/src/mage/cards/k/KruphixsInsight.java @@ -1,13 +1,12 @@ - package mage.cards.k; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.effects.common.RevealLibraryPickControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.FilterCard; /** @@ -16,7 +15,7 @@ import mage.filter.FilterCard; */ public final class KruphixsInsight extends CardImpl { - private static final FilterCard filter = new FilterCard("up to three enchantment cards"); + private static final FilterCard filter = new FilterCard("enchantment cards"); static { filter.add(CardType.ENCHANTMENT.getPredicate()); @@ -25,9 +24,13 @@ public final class KruphixsInsight extends CardImpl { public KruphixsInsight(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{G}"); - - // Reveal the top six cards of your library. Put up to three enchantment cards from among them into your hand and the rest of the revealed cards into your graveyard. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(6), false, StaticValue.get(3), filter, Zone.GRAVEYARD, false, true, true,Zone.HAND, false)); + // Reveal the top six cards of your library. Put up to three enchantment cards from among them into your hand + // and the rest of the revealed cards into your graveyard. + Effect effect = new RevealLibraryPickControllerEffect(6, 3, filter, PutCards.HAND, PutCards.GRAVEYARD, false); + effect.setText("reveal the top six cards of your library. " + + "Put up to three enchantment cards from among them into your hand " + + "and the rest of the revealed cards into your graveyard"); + this.getSpellAbility().addEffect(effect); } private KruphixsInsight(final KruphixsInsight card) { diff --git a/Mage.Sets/src/mage/cards/k/Kudzu.java b/Mage.Sets/src/mage/cards/k/Kudzu.java index ddbfa6d95c9..9c3745caf22 100644 --- a/Mage.Sets/src/mage/cards/k/Kudzu.java +++ b/Mage.Sets/src/mage/cards/k/Kudzu.java @@ -86,7 +86,7 @@ class KudzuEffect extends OneShotEffect { target.setNotTarget(true); //not a target, it is chosen Card kudzuCard = game.getCard(source.getSourceId()); if (kudzuCard != null && landsController != null) { - if (landsController.choose(Outcome.Detriment, target, source.getId(), game)) { + if (landsController.choose(Outcome.Detriment, target, source, game)) { if (target.getFirstTarget() != null) { Permanent landChosen = game.getPermanent(target.getFirstTarget()); if (landChosen != null) { diff --git a/Mage.Sets/src/mage/cards/k/KulrathKnight.java b/Mage.Sets/src/mage/cards/k/KulrathKnight.java index b1d359845c7..c26ddddf7f2 100644 --- a/Mage.Sets/src/mage/cards/k/KulrathKnight.java +++ b/Mage.Sets/src/mage/cards/k/KulrathKnight.java @@ -84,6 +84,6 @@ class KulrathKnightRestrictionEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filter.match(permanent, source.getControllerId(), source, game); } } diff --git a/Mage.Sets/src/mage/cards/k/KumanoFacesKakkazan.java b/Mage.Sets/src/mage/cards/k/KumanoFacesKakkazan.java new file mode 100644 index 00000000000..80ea9b04903 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KumanoFacesKakkazan.java @@ -0,0 +1,176 @@ +package mage.cards.k; + +import java.util.Set; +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; +import mage.abilities.keyword.TransformAbility; +import mage.constants.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.Player; + +/** + * + * @author weirddan455 + */ +public final class KumanoFacesKakkazan extends CardImpl { + + public KumanoFacesKakkazan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}"); + + this.subtype.add(SubType.SAGA); + this.secondSideCardClazz = mage.cards.e.EtchingOfKumano.class; + + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I — Kumano Faces Kakkazan deals 1 damage to each opponent and each planeswalker they control. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new KumanoFacesKakkazanDamageEffect()); + + // II — When you cast your next creature spell this turn, that creature enters the battlefield with an additional +1/+1 counter on it. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new CreateDelayedTriggeredAbilityEffect(new KumanoFacesKakkazanTriggeredAbility())); + + // III — Exile this Saga, then return it to the battlefield transformed under your control. + this.addAbility(new TransformAbility()); + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + + this.addAbility(sagaAbility); + } + + private KumanoFacesKakkazan(final KumanoFacesKakkazan card) { + super(card); + } + + @Override + public KumanoFacesKakkazan copy() { + return new KumanoFacesKakkazan(this); + } +} + +class KumanoFacesKakkazanDamageEffect extends OneShotEffect { + + public KumanoFacesKakkazanDamageEffect() { + super(Outcome.Damage); + this.staticText = "{this} deals 1 damage to each opponent and each planeswalker they control"; + } + + private KumanoFacesKakkazanDamageEffect(final KumanoFacesKakkazanDamageEffect effect) { + super(effect); + } + + @Override + public KumanoFacesKakkazanDamageEffect copy() { + return new KumanoFacesKakkazanDamageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Set opponents = game.getOpponents(source.getControllerId()); + if (opponents.isEmpty()) { + return false; + } + for (UUID opponentId : opponents) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + opponent.damage(1, source, game); + } + } + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(CardType.PLANESWALKER, game)) { + if (opponents.contains(permanent.getControllerId())) { + permanent.damage(1, source, game); + } + } + return true; + } +} + +class KumanoFacesKakkazanTriggeredAbility extends DelayedTriggeredAbility { + + public KumanoFacesKakkazanTriggeredAbility() { + super(null, Duration.EndOfTurn); + } + + private KumanoFacesKakkazanTriggeredAbility(final KumanoFacesKakkazanTriggeredAbility ability) { + super(ability); + } + + @Override + public KumanoFacesKakkazanTriggeredAbility copy() { + return new KumanoFacesKakkazanTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (this.isControlledBy(event.getPlayerId())) { + Spell spell = game.getSpell(event.getTargetId()); + if (spell != null && spell.isCreature(game)) { + this.getEffects().clear(); + this.getEffects().add(new KumanoFacesKakkazanCounterEffect(spell.getSourceId())); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "When you cast your next creature spell this turn, that creature enters the battlefield with an additional +1/+1 counter on it."; + } +} + +class KumanoFacesKakkazanCounterEffect extends ReplacementEffectImpl { + + private final UUID spellCastId; + + public KumanoFacesKakkazanCounterEffect(UUID spellCastId) { + super(Duration.EndOfTurn, Outcome.BoostCreature); + this.spellCastId = spellCastId; + } + + private KumanoFacesKakkazanCounterEffect(final KumanoFacesKakkazanCounterEffect effect) { + super(effect); + this.spellCastId = effect.spellCastId; + } + + @Override + public KumanoFacesKakkazanCounterEffect copy() { + return new KumanoFacesKakkazanCounterEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return spellCastId.equals(event.getTargetId()); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + if (creature != null) { + creature.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game, event.getAppliedEffects()); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KuraTheBoundlessSky.java b/Mage.Sets/src/mage/cards/k/KuraTheBoundlessSky.java index 45a0f219b2a..801a4ddbfa5 100644 --- a/Mage.Sets/src/mage/cards/k/KuraTheBoundlessSky.java +++ b/Mage.Sets/src/mage/cards/k/KuraTheBoundlessSky.java @@ -46,7 +46,7 @@ public final class KuraTheBoundlessSky extends CardImpl { // When Kura, the Boundless Sky dies, choose one — // • Search your library for up to three land cards, reveal them, put them into your hand, then shuffle. Ability ability = new DiesSourceTriggeredAbility(new SearchLibraryPutInHandEffect( - new TargetCardInLibrary(0, 3, StaticFilters.FILTER_CARD_LANDS) + new TargetCardInLibrary(0, 3, StaticFilters.FILTER_CARD_LANDS), true )); // • Create an X/X green Spirit creature token, where X is the number of lands you control. diff --git a/Mage.Sets/src/mage/cards/k/KynaiosAndTiroOfMeletis.java b/Mage.Sets/src/mage/cards/k/KynaiosAndTiroOfMeletis.java index ad848a5cba2..de2b58d8727 100644 --- a/Mage.Sets/src/mage/cards/k/KynaiosAndTiroOfMeletis.java +++ b/Mage.Sets/src/mage/cards/k/KynaiosAndTiroOfMeletis.java @@ -88,7 +88,7 @@ class KynaiosAndTirosEffect extends OneShotEffect { } target.clearChosen(); boolean playedLand = false; - if (target.canChoose(source.getSourceId(), currentPlayer.getId(), game) && currentPlayer.chooseUse(outcome, "Put a land card from your hand onto the battlefield?", source, game)) { + if (target.canChoose(currentPlayer.getId(), source, game) && currentPlayer.chooseUse(outcome, "Put a land card from your hand onto the battlefield?", source, game)) { if (target.chooseTarget(outcome, currentPlayer.getId(), source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/l/LabyrinthMinotaur.java b/Mage.Sets/src/mage/cards/l/LabyrinthMinotaur.java index d05bfc44de7..1f042dae7a0 100644 --- a/Mage.Sets/src/mage/cards/l/LabyrinthMinotaur.java +++ b/Mage.Sets/src/mage/cards/l/LabyrinthMinotaur.java @@ -1,9 +1,8 @@ - package mage.cards.l; import java.util.UUID; import mage.MageInt; -import mage.abilities.common.BlocksSourceTriggeredAbility; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; import mage.constants.SubType; import mage.cards.CardImpl; @@ -24,7 +23,9 @@ public final class LabyrinthMinotaur extends CardImpl { this.toughness = new MageInt(4); // Whenever Labyrinth Minotaur blocks a creature, that creature doesn't untap during its controller's next untap step. - this.addAbility(new BlocksSourceTriggeredAbility(new DontUntapInControllersNextUntapStepTargetEffect("that creature"), false, true)); + this.addAbility(new BlocksCreatureTriggeredAbility( + new DontUntapInControllersNextUntapStepTargetEffect("that creature") + )); } private LabyrinthMinotaur(final LabyrinthMinotaur card) { diff --git a/Mage.Sets/src/mage/cards/l/LaceWithMoonglove.java b/Mage.Sets/src/mage/cards/l/LaceWithMoonglove.java index 518a6355837..a8656cd7fd7 100644 --- a/Mage.Sets/src/mage/cards/l/LaceWithMoonglove.java +++ b/Mage.Sets/src/mage/cards/l/LaceWithMoonglove.java @@ -22,7 +22,7 @@ public final class LaceWithMoonglove extends CardImpl { this.getSpellAbility().addEffect(new GainAbilityTargetEffect(DeathtouchAbility.getInstance(), Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private LaceWithMoonglove(final LaceWithMoonglove card) { diff --git a/Mage.Sets/src/mage/cards/l/LagrellaTheMagpie.java b/Mage.Sets/src/mage/cards/l/LagrellaTheMagpie.java new file mode 100644 index 00000000000..20de8227915 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LagrellaTheMagpie.java @@ -0,0 +1,193 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.OnLeaveReturnExiledToBattlefieldAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LagrellaTheMagpie extends CardImpl { + + public LagrellaTheMagpie(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // When Lagrella, the Magpie enters the battlefield, exile any number of other target creatures controlled by different players until Lagrella leaves the battlefield. When an exiled card enters the battlefield under your control this way, put two +1/+1 counters on it. + Ability ability = new EntersBattlefieldTriggeredAbility(new LagrellaTheMagpieEffect(), false); + ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility())); + ability.addTarget(new LagrellaTheMagpieTarget()); + this.addAbility(ability); + } + + private LagrellaTheMagpie(final LagrellaTheMagpie card) { + super(card); + } + + @Override + public LagrellaTheMagpie copy() { + return new LagrellaTheMagpie(this); + } +} + +class LagrellaTheMagpieEffect extends OneShotEffect { + + LagrellaTheMagpieEffect() { + super(Outcome.Benefit); + staticText = "exile any number of other target creatures controlled by different players " + + "until {this} leaves the battlefield. When an exiled card enters the battlefield " + + "under your control this way, put two +1/+1 counters on it"; + } + + private LagrellaTheMagpieEffect(final LagrellaTheMagpieEffect effect) { + super(effect); + } + + @Override + public LagrellaTheMagpieEffect copy() { + return new LagrellaTheMagpieEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(); + this.getTargetPointer() + .getTargets(game, source) + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .forEach(cards::add); + if (cards.isEmpty()) { + return false; + } + player.moveCardsToExile( + cards.getCards(game), source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + game.addDelayedTriggeredAbility(new LagrellaTheMagpieTriggeredAbility(cards, game), source); + return true; + } +} + +class LagrellaTheMagpieTarget extends TargetPermanent { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("other creatures controlled by different players"); + + static { + filter.add(AnotherPredicate.instance); + } + + LagrellaTheMagpieTarget() { + super(0, Integer.MAX_VALUE, filter, false); + } + + private LagrellaTheMagpieTarget(final LagrellaTheMagpieTarget target) { + super(target); + } + + @Override + public LagrellaTheMagpieTarget copy() { + return new LagrellaTheMagpieTarget(this); + } + + @Override + public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { + if (!super.canTarget(controllerId, id, source, game)) { + return false; + } + Permanent creature = game.getPermanent(id); + if (creature == null) { + return false; + } + return this.getTargets() + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .noneMatch(permanent -> !creature.getId().equals(permanent.getId()) + && creature.isControlledBy(permanent.getControllerId()) + ); + } +} + +class LagrellaTheMagpieTriggeredAbility extends DelayedTriggeredAbility { + + private final Set morSet = new HashSet<>(); + + LagrellaTheMagpieTriggeredAbility(Cards cards, Game game) { + super(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)), Duration.Custom, false, false); + cards.getCards(game) + .stream() + .map(card -> new MageObjectReference(card, game, 1)) + .forEach(morSet::add); + } + + private LagrellaTheMagpieTriggeredAbility(final LagrellaTheMagpieTriggeredAbility ability) { + super(ability); + this.morSet.addAll(ability.morSet); + } + + @Override + public LagrellaTheMagpieTriggeredAbility copy() { + return new LagrellaTheMagpieTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + if (permanent.isControlledBy(this.getControllerId()) + && morSet.stream().anyMatch(mor -> mor.refersTo(permanent, game))) { + this.getEffects().setTargetPointer(new FixedTarget(permanent, game)); + return true; + } + return false; + } + + @Override + public String getRule() { + return "When an exiled card enters the battlefield under your control this way, put two +1/+1 counters on it."; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LamplighterOfSelhoff.java b/Mage.Sets/src/mage/cards/l/LamplighterOfSelhoff.java index a354078460a..b19c75453f7 100644 --- a/Mage.Sets/src/mage/cards/l/LamplighterOfSelhoff.java +++ b/Mage.Sets/src/mage/cards/l/LamplighterOfSelhoff.java @@ -41,7 +41,7 @@ public final class LamplighterOfSelhoff extends CardImpl { this.addAbility(new ConditionalInterveningIfTriggeredAbility( triggeredAbility, new PermanentsOnTheBattlefieldCondition(filter), - "When {this} enters the battlefield, if you control another Zombie, you may a draw card. If you do, discard a card.")); + "When {this} enters the battlefield, if you control another Zombie, you may draw a card. If you do, discard a card.")); } private LamplighterOfSelhoff(final LamplighterOfSelhoff card) { diff --git a/Mage.Sets/src/mage/cards/l/LancerSliver.java b/Mage.Sets/src/mage/cards/l/LancerSliver.java index c1eccc28917..b3e4f497227 100644 --- a/Mage.Sets/src/mage/cards/l/LancerSliver.java +++ b/Mage.Sets/src/mage/cards/l/LancerSliver.java @@ -28,7 +28,7 @@ public final class LancerSliver extends CardImpl { // Sliver creatures you control have first strike. this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield, - StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS + StaticFilters.FILTER_PERMANENT_SLIVERS ))); } diff --git a/Mage.Sets/src/mage/cards/l/LandscaperColos.java b/Mage.Sets/src/mage/cards/l/LandscaperColos.java index 7cbaf9a0d39..b0e69ca1221 100644 --- a/Mage.Sets/src/mage/cards/l/LandscaperColos.java +++ b/Mage.Sets/src/mage/cards/l/LandscaperColos.java @@ -40,6 +40,7 @@ public final class LandscaperColos extends CardImpl { false, "put target card from an opponent's graveyard on the bottom of their library" )); ability.addTarget(new TargetCardInGraveyard()); + this.addAbility(ability); // Basic landcycling {1}{W} this.addAbility(new BasicLandcyclingAbility(new ManaCostsImpl<>("{1}{W}"))); diff --git a/Mage.Sets/src/mage/cards/l/Landslide.java b/Mage.Sets/src/mage/cards/l/Landslide.java index a396fb20a9f..6bff3cab0c7 100644 --- a/Mage.Sets/src/mage/cards/l/Landslide.java +++ b/Mage.Sets/src/mage/cards/l/Landslide.java @@ -64,7 +64,7 @@ class LandslideEffect extends OneShotEffect { Player you = game.getPlayer(source.getControllerId()); if (you != null) { Target target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); - if (!target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (!target.canChoose(source.getControllerId(), source, game)) { return false; } you.chooseTarget(Outcome.Detriment, target, source, game); diff --git a/Mage.Sets/src/mage/cards/l/LanternScout.java b/Mage.Sets/src/mage/cards/l/LanternScout.java index 042d19bd2a5..44304962ae5 100644 --- a/Mage.Sets/src/mage/cards/l/LanternScout.java +++ b/Mage.Sets/src/mage/cards/l/LanternScout.java @@ -1,48 +1,37 @@ - package mage.cards.l; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.AllyEntersBattlefieldTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.keyword.LifelinkAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author fireshoes */ public final class LanternScout extends CardImpl { public LanternScout(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.SCOUT); this.subtype.add(SubType.ALLY); this.power = new MageInt(3); this.toughness = new MageInt(2); - FilterPermanent filter = new FilterPermanent("{this} or another Ally"); - filter.add(Predicates.or( - new CardIdPredicate(this.getId()), - SubType.ALLY.getPredicate())); - // Rally — Whenever Lantern Scout or another Ally enters the battlefield under your control, creatures you control gain lifelink until end of turn. - Effect effect = new GainAbilityAllEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn, new FilterControlledCreaturePermanent()); - effect.setText("creatures you control gain lifelink until end of turn"); - Ability ability = new AllyEntersBattlefieldTriggeredAbility( - effect, false); - this.addAbility(ability); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new GainAbilityAllEffect( + LifelinkAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURES + ), false).setAbilityWord(AbilityWord.RALLY)); } private LanternScout(final LanternScout card) { diff --git a/Mage.Sets/src/mage/cards/l/LastKiss.java b/Mage.Sets/src/mage/cards/l/LastKiss.java index d6a5cac4f01..061cf0288ba 100644 --- a/Mage.Sets/src/mage/cards/l/LastKiss.java +++ b/Mage.Sets/src/mage/cards/l/LastKiss.java @@ -20,7 +20,7 @@ public final class LastKiss extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{B}"); this.getSpellAbility().addEffect(new DamageTargetEffect(2)); - this.getSpellAbility().addEffect(new GainLifeEffect(2)); + this.getSpellAbility().addEffect(new GainLifeEffect(2).concatBy("and")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/l/LastLaugh.java b/Mage.Sets/src/mage/cards/l/LastLaugh.java index 498a0813852..08300cb451e 100644 --- a/Mage.Sets/src/mage/cards/l/LastLaugh.java +++ b/Mage.Sets/src/mage/cards/l/LastLaugh.java @@ -65,7 +65,7 @@ class LastLaughStateTriggeredAbility extends StateTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - return game.getBattlefield().count(new FilterCreaturePermanent(), this.getSourceId(), this.getControllerId(), game) == 0; + return game.getBattlefield().count(new FilterCreaturePermanent(), this.getControllerId(), this, game) == 0; } @Override diff --git a/Mage.Sets/src/mage/cards/l/LastStand.java b/Mage.Sets/src/mage/cards/l/LastStand.java index 98c74e67ef0..d0a50accba1 100644 --- a/Mage.Sets/src/mage/cards/l/LastStand.java +++ b/Mage.Sets/src/mage/cards/l/LastStand.java @@ -79,27 +79,27 @@ class LastStandEffect extends OneShotEffect { // Target opponent loses 2 life for each Swamp you control Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); if (opponent != null) { - int swamps = game.getBattlefield().count(filterSwamp, source.getSourceId(), source.getControllerId(), game); + int swamps = game.getBattlefield().count(filterSwamp, source.getControllerId(), source, game); opponent.loseLife(swamps * 2, game, source, false); } // Last Stand deals damage equal to the number of Mountains you control to target creature. Permanent creature = game.getPermanent(source.getTargets().get(1).getFirstTarget()); if (creature != null) { - int mountains = game.getBattlefield().count(filterMountain, source.getSourceId(), source.getControllerId(), game); + int mountains = game.getBattlefield().count(filterMountain, source.getControllerId(), source, game); if (mountains > 0) { creature.damage(mountains, source.getSourceId(), source, game, false, true); } } // Create a 1/1 green Saproling creature token for each Forest you control. - int forests = game.getBattlefield().count(filterForest, source.getSourceId(), source.getControllerId(), game); + int forests = game.getBattlefield().count(filterForest, source.getControllerId(), source, game); if (forests > 0) { new CreateTokenEffect(new SaprolingToken(), forests).apply(game, source); } // You gain 2 life for each Plains you control. - int plains = game.getBattlefield().count(filterPlains, source.getSourceId(), source.getControllerId(), game); + int plains = game.getBattlefield().count(filterPlains, source.getControllerId(), source, game); controller.gainLife(plains * 2, game, source); // Draw a card for each Island you control, then discard that many cards - int islands = game.getBattlefield().count(filterIsland, source.getSourceId(), source.getControllerId(), game); + int islands = game.getBattlefield().count(filterIsland, source.getControllerId(), source, game); if (islands > 0) { controller.drawCards(islands, source, game); controller.discard(islands, false, false, source, game); diff --git a/Mage.Sets/src/mage/cards/l/LathrilBladeOfTheElves.java b/Mage.Sets/src/mage/cards/l/LathrilBladeOfTheElves.java index c51eca941a8..2872d2bdbf9 100644 --- a/Mage.Sets/src/mage/cards/l/LathrilBladeOfTheElves.java +++ b/Mage.Sets/src/mage/cards/l/LathrilBladeOfTheElves.java @@ -48,9 +48,8 @@ public final class LathrilBladeOfTheElves extends CardImpl { this.addAbility(new MenaceAbility(false)); // Whenever Lathril, Blade of the Elves deals combat damage to a player, create that many 1/1 green Elf Warrior creature tokens. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new CreateTokenEffect( - new ElfWarriorToken(), SavedDamageValue.instance - ).setText("create that many 1/1 green Elf Warrior creature tokens"), false, true)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new CreateTokenEffect(new ElfWarriorToken(), SavedDamageValue.MANY), false, true)); // {T}, Tap ten untapped Elves you control: Each opponent loses 10 life and you gain 10 life. Ability ability = new SimpleActivatedAbility(new LoseLifeOpponentsEffect(10), new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/l/LavabellySliver.java b/Mage.Sets/src/mage/cards/l/LavabellySliver.java index 86d764c8918..303049facca 100644 --- a/Mage.Sets/src/mage/cards/l/LavabellySliver.java +++ b/Mage.Sets/src/mage/cards/l/LavabellySliver.java @@ -30,13 +30,15 @@ public final class LavabellySliver extends CardImpl { this.toughness = new MageInt(2); // Sliver creatures you control have "When this creature enters the battlefield, it deals 1 damage to target player or planeswalker and you gain 1 life." - Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(1, "When this creature enters the battlefield, it"),false,true); + Ability ability = new EntersBattlefieldTriggeredAbility( + new DamageTargetEffect(1, "it"), + false, true + ).setTriggerPhrase("When this creature enters the battlefield, "); ability.addEffect(new GainLifeEffect(1).concatBy("and")); ability.addTarget(new TargetPlayerOrPlaneswalker()); this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - ability, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS) - .withForceQuotes() - )); + ability, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_SLIVERS + ).withForceQuotes())); } private LavabellySliver(final LavabellySliver card) { diff --git a/Mage.Sets/src/mage/cards/l/Lavalanche.java b/Mage.Sets/src/mage/cards/l/Lavalanche.java index b9432f0e639..93212fd37f4 100644 --- a/Mage.Sets/src/mage/cards/l/Lavalanche.java +++ b/Mage.Sets/src/mage/cards/l/Lavalanche.java @@ -72,7 +72,7 @@ class LavalancheEffect extends OneShotEffect { FilterPermanent filter = new FilterPermanent("and each creature that player or that planeswalker's controller controls"); filter.add(CardType.CREATURE.getPredicate()); filter.add(new ControllerIdPredicate(targetPlayer.getId())); - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); for (Permanent permanent : permanents) { permanent.damage(amount.calculate(game, source, this), source.getSourceId(), source, game, false, true); } diff --git a/Mage.Sets/src/mage/cards/l/LaviniaAzoriusRenegade.java b/Mage.Sets/src/mage/cards/l/LaviniaAzoriusRenegade.java index 9419111fda6..1da6683b3d8 100644 --- a/Mage.Sets/src/mage/cards/l/LaviniaAzoriusRenegade.java +++ b/Mage.Sets/src/mage/cards/l/LaviniaAzoriusRenegade.java @@ -71,7 +71,7 @@ class LaviniaAzoriusRenegadeReplacementEffect extends ContinuousRuleModifyingEff @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast noncreature spells with mana value greater than " + getLandCount(source, event, game) + " (" + mageObject.getIdName() + ")."; } @@ -100,7 +100,7 @@ class LaviniaAzoriusRenegadeReplacementEffect extends ContinuousRuleModifyingEff int landCount = 0; UUID playerId = event.getPlayerId(); if(playerId != null) { - List permanents = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LAND, playerId, source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LAND, playerId, source, game); for (Permanent permanent : permanents) { if (permanent.isControlledBy(playerId)) { landCount++; diff --git a/Mage.Sets/src/mage/cards/l/LeadTheStampede.java b/Mage.Sets/src/mage/cards/l/LeadTheStampede.java index 7b5a8bd81a4..23840ef293e 100644 --- a/Mage.Sets/src/mage/cards/l/LeadTheStampede.java +++ b/Mage.Sets/src/mage/cards/l/LeadTheStampede.java @@ -1,10 +1,12 @@ package mage.cards.l; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterCard; +import mage.filter.StaticFilters; import java.util.UUID; @@ -13,22 +15,16 @@ import java.util.UUID; */ public final class LeadTheStampede extends CardImpl { - private static final FilterCard filter = new FilterCard("any number of creature cards"); - - static { - filter.add(CardType.CREATURE.getPredicate()); - } - public LeadTheStampede(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); // Look at the top five cards of your library. You may reveal any number of creature cards from among them and put the revealed cards into your hand. Put the rest on the bottom of your library in any order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - 5, 5, filter, true - ).setText("Look at the top five cards of your library. " + - "You may reveal any number of creature cards from among them " + - "and put the revealed cards into your hand. " + - "Put the rest on the bottom of your library in any order.")); + Effect effect = new LookLibraryAndPickControllerEffect( + 5, Integer.MAX_VALUE, StaticFilters.FILTER_CARD_CREATURES, PutCards.HAND, PutCards.BOTTOM_ANY); + effect.setText("look at the top five cards of your library. " + + "You may reveal any number of creature cards from among them and put the revealed cards into your hand. " + + "Put the rest on the bottom of your library in any order"); + this.getSpellAbility().addEffect(effect); } private LeadTheStampede(final LeadTheStampede card) { diff --git a/Mage.Sets/src/mage/cards/l/LeapOfFlame.java b/Mage.Sets/src/mage/cards/l/LeapOfFlame.java index 5561998ddcd..aa48c41638b 100644 --- a/Mage.Sets/src/mage/cards/l/LeapOfFlame.java +++ b/Mage.Sets/src/mage/cards/l/LeapOfFlame.java @@ -25,7 +25,7 @@ public final class LeapOfFlame extends CardImpl { // Replicate {U}{R} - this.addAbility(new ReplicateAbility(this, "{U}{R}")); + this.addAbility(new ReplicateAbility("{U}{R}")); // Target creature gets +1/+0 and gains flying and first strike until end of turn. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); Effect effect = new BoostTargetEffect(1,0,Duration.EndOfTurn); diff --git a/Mage.Sets/src/mage/cards/l/LeaveInTheDust.java b/Mage.Sets/src/mage/cards/l/LeaveInTheDust.java index 8647ad4a527..fdaf2059c2a 100644 --- a/Mage.Sets/src/mage/cards/l/LeaveInTheDust.java +++ b/Mage.Sets/src/mage/cards/l/LeaveInTheDust.java @@ -23,7 +23,7 @@ public final class LeaveInTheDust extends CardImpl { this.getSpellAbility().addTarget(new TargetNonlandPermanent()); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } diff --git a/Mage.Sets/src/mage/cards/l/LeaveNoTrace.java b/Mage.Sets/src/mage/cards/l/LeaveNoTrace.java index 4e53026639e..d2e46889b32 100644 --- a/Mage.Sets/src/mage/cards/l/LeaveNoTrace.java +++ b/Mage.Sets/src/mage/cards/l/LeaveNoTrace.java @@ -1,12 +1,11 @@ - package mage.cards.l; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Outcome; import mage.filter.FilterPermanent; @@ -14,6 +13,8 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetEnchantmentPermanent; +import java.util.UUID; + /** * @author Loki */ @@ -25,12 +26,12 @@ public final class LeaveNoTrace extends CardImpl { } public LeaveNoTrace(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); // Radiance - Destroy target enchantment and each other enchantment that shares a color with it. this.getSpellAbility().addEffect(new LeaveNoTraceEffect()); this.getSpellAbility().addTarget(new TargetEnchantmentPermanent()); + this.getSpellAbility().setAbilityWord(AbilityWord.RADIANCE); } private LeaveNoTrace(final LeaveNoTrace card) { @@ -52,7 +53,7 @@ class LeaveNoTraceEffect extends OneShotEffect { LeaveNoTraceEffect() { super(Outcome.DestroyPermanent); - staticText = "Radiance - Destroy target enchantment and each other enchantment that shares a color with it"; + staticText = "Destroy target enchantment and each other enchantment that shares a color with it"; } LeaveNoTraceEffect(final LeaveNoTraceEffect effect) { diff --git a/Mage.Sets/src/mage/cards/l/LedevChampion.java b/Mage.Sets/src/mage/cards/l/LedevChampion.java index 4f90d1b3557..0a733a52153 100644 --- a/Mage.Sets/src/mage/cards/l/LedevChampion.java +++ b/Mage.Sets/src/mage/cards/l/LedevChampion.java @@ -79,8 +79,8 @@ class LedevChampionEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { int tappedAmount = 0; TargetCreaturePermanent target = new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) - && target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), game)) { + if (target.canChoose(source.getControllerId(), source, game) + && target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), source, game)) { for (UUID creatureId : target.getTargets()) { Permanent creature = game.getPermanent(creatureId); if (creature != null) { diff --git a/Mage.Sets/src/mage/cards/l/LedgerShredder.java b/Mage.Sets/src/mage/cards/l/LedgerShredder.java new file mode 100644 index 00000000000..5a33300933b --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LedgerShredder.java @@ -0,0 +1,43 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.common.CastSecondSpellTriggeredAbility; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LedgerShredder extends CardImpl { + + public LedgerShredder(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever a player casts their second spell each turn, Ledger Shredder connives. + this.addAbility(new CastSecondSpellTriggeredAbility(new ConniveSourceEffect("{this}"), TargetController.ANY)); + } + + private LedgerShredder(final LedgerShredder card) { + super(card); + } + + @Override + public LedgerShredder copy() { + return new LedgerShredder(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LeechBonder.java b/Mage.Sets/src/mage/cards/l/LeechBonder.java index c6a617def39..9959fd28819 100644 --- a/Mage.Sets/src/mage/cards/l/LeechBonder.java +++ b/Mage.Sets/src/mage/cards/l/LeechBonder.java @@ -43,7 +43,7 @@ public final class LeechBonder extends CardImpl { this.toughness = new MageInt(3); // Leech Bonder enters the battlefield with two -1/-1 counters on it. - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance(2)))); + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance(2)), "with two -1/-1 counters on it")); // {U}, {untap}: Move a counter from target creature onto another target creature. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LeechBonderEffect(), new ManaCostsImpl("{U}")); diff --git a/Mage.Sets/src/mage/cards/l/LegionLoyalist.java b/Mage.Sets/src/mage/cards/l/LegionLoyalist.java index 290ed7147b2..41bea8a3819 100644 --- a/Mage.Sets/src/mage/cards/l/LegionLoyalist.java +++ b/Mage.Sets/src/mage/cards/l/LegionLoyalist.java @@ -68,7 +68,7 @@ class CantBeBlockedByTokenEffect extends RestrictionEffect { @Override public void init(Ability source, Game game) { affectedObjectsSet = true; - for (Permanent perm : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), source.getControllerId(), source, game)) { affectedObjectList.add(new MageObjectReference(perm, game)); } } diff --git a/Mage.Sets/src/mage/cards/l/LegionsInitiative.java b/Mage.Sets/src/mage/cards/l/LegionsInitiative.java index 59f63017d12..e3ffe081f0a 100644 --- a/Mage.Sets/src/mage/cards/l/LegionsInitiative.java +++ b/Mage.Sets/src/mage/cards/l/LegionsInitiative.java @@ -64,7 +64,7 @@ public final class LegionsInitiative extends CardImpl { ))); // {R}{W}, Exile Legion's Initiative: Exile all creatures you control. At the beginning of the next combat, return those cards to the battlefield under their owner's control and those creatures gain haste until end of turn. - Ability ability = new SimpleActivatedAbility(new LegionsInitiativeExileEffect(), new ManaCostsImpl("{R}{W}")); + Ability ability = new SimpleActivatedAbility(new LegionsInitiativeExileEffect(), new ManaCostsImpl<>("{R}{W}")); ability.addEffect(new CreateDelayedTriggeredAbilityEffect( new AtTheBeginOfCombatDelayedTriggeredAbility(new LegionsInitiativeReturnFromExileEffect()) )); @@ -102,7 +102,7 @@ class LegionsInitiativeExileEffect extends OneShotEffect { Cards cards = new CardsImpl(); game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game ).stream().filter(Objects::nonNull).forEach(cards::add); return player.moveCardsToExile( cards.getCards(game), source, game, true, @@ -136,7 +136,7 @@ class LegionsInitiativeReturnFromExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source, -1)); if (player == null || exile == null || exile.isEmpty()) { return false; } diff --git a/Mage.Sets/src/mage/cards/l/LensOfClarity.java b/Mage.Sets/src/mage/cards/l/LensOfClarity.java index 12f9baa9952..d96e4a21579 100644 --- a/Mage.Sets/src/mage/cards/l/LensOfClarity.java +++ b/Mage.Sets/src/mage/cards/l/LensOfClarity.java @@ -85,7 +85,7 @@ class LensOfClarityLookLibraryEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (controller == null || mageObject == null) { return false; } @@ -148,7 +148,7 @@ class LensOfClarityLookFaceDownEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller= game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (controller == null || mageObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/l/LeoninBola.java b/Mage.Sets/src/mage/cards/l/LeoninBola.java index 9f5596be2ee..21128f60a8a 100644 --- a/Mage.Sets/src/mage/cards/l/LeoninBola.java +++ b/Mage.Sets/src/mage/cards/l/LeoninBola.java @@ -27,7 +27,7 @@ public final class LeoninBola extends CardImpl { // Equipped creature has "{tap}, Unattach Leonin Bola: Tap target creature." this.addAbility(new SimpleStaticAbility(new GainAbilityWithAttachmentEffect( - "equipped creature has \"{tap}, Unattach {this}: Tap target creature.\"", + "equipped creature has \"{T}, Unattach {this}: Tap target creature.\"", new TapTargetEffect(), new TargetCreaturePermanent(), new UnattachCost(), new TapSourceCost() ))); diff --git a/Mage.Sets/src/mage/cards/l/LesserWerewolf.java b/Mage.Sets/src/mage/cards/l/LesserWerewolf.java index 6af8537ff7a..9e9f46690fe 100644 --- a/Mage.Sets/src/mage/cards/l/LesserWerewolf.java +++ b/Mage.Sets/src/mage/cards/l/LesserWerewolf.java @@ -12,14 +12,13 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.counters.BoostCounter; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.BlockedByIdPredicate; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import java.util.UUID; @@ -28,6 +27,13 @@ import java.util.UUID; */ public final class LesserWerewolf extends CardImpl { + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature blocking or blocked by {this}"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.EITHER); + } + public LesserWerewolf(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.WEREWOLF); @@ -35,13 +41,12 @@ public final class LesserWerewolf extends CardImpl { this.toughness = new MageInt(4); // {B}: If Lesser Werewolf’s power is 1 or more, it gets -1/-0 until end of turn and put a -0/-1 counter on target creature blocking or blocked by Lesser Werewolf. Activate this ability only during the declare blockers step. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new LesserWerewolfEffect(), new ManaCostsImpl("{B}"), new IsStepCondition(PhaseStep.DECLARE_BLOCKERS, false)); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking or blocked by Lesser Werewolf"); - filter.add(Predicates.or(new BlockedByIdPredicate(this.getId()), - new BlockingAttackerIdPredicate(this.getId()))); - ability.addTarget(new TargetCreaturePermanent(filter)); + Ability ability = new ConditionalActivatedAbility( + Zone.BATTLEFIELD, new LesserWerewolfEffect(), new ManaCostsImpl<>("{B}"), + new IsStepCondition(PhaseStep.DECLARE_BLOCKERS, false) + ); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); - } private LesserWerewolf(final LesserWerewolf card) { @@ -75,13 +80,13 @@ class LesserWerewolfEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Permanent targetPermanent = game.getPermanent(targetPointer.getFirst(game, source)); // must be valid target - if (controller != null && sourcePermanent != null && targetPermanent != null) { - if (sourcePermanent.getPower().getValue() >= 1) { - game.addEffect(new BoostSourceEffect(-1, 0, Duration.EndOfTurn), source); - new AddCountersTargetEffect(new BoostCounter(0, -1), outcome).apply(game, source); - } - return true; + if (controller == null || sourcePermanent == null || targetPermanent == null) { + return false; } - return false; + if (sourcePermanent.getPower().getValue() >= 1) { + game.addEffect(new BoostSourceEffect(-1, 0, Duration.EndOfTurn), source); + new AddCountersTargetEffect(new BoostCounter(0, -1), outcome).apply(game, source); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/l/LethalExploit.java b/Mage.Sets/src/mage/cards/l/LethalExploit.java new file mode 100644 index 00000000000..634113aa0e4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LethalExploit.java @@ -0,0 +1,81 @@ +package mage.cards.l; + +import java.util.UUID; + +import mage.MageObject; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; +import mage.watchers.common.ControlledModifiedCreatureAsSpellCastWatcher; + +/** + * + * @author weirddan455 + */ +public final class LethalExploit extends CardImpl { + + public LethalExploit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); + + // Target creature gets -2/-2 until end of turn. It gets an additional -1/-1 until end of turn for each modified creature you controlled as you cast this spell. + this.getSpellAbility().addEffect(new LethalExploitEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addWatcher(new ControlledModifiedCreatureAsSpellCastWatcher()); + } + + private LethalExploit(final LethalExploit card) { + super(card); + } + + @Override + public LethalExploit copy() { + return new LethalExploit(this); + } +} + +class LethalExploitEffect extends ContinuousEffectImpl { + + private int boostValue = -2; + + public LethalExploitEffect() { + super(Duration.EndOfTurn, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.UnboostCreature); + this.staticText = "Target creature gets -2/-2 until end of turn. It gets an additional -1/-1 until end of turn for each modified creature you controlled as you cast this spell"; + } + + private LethalExploitEffect(final LethalExploitEffect effect) { + super(effect); + this.boostValue = effect.boostValue; + } + + @Override + public LethalExploitEffect copy() { + return new LethalExploitEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + ControlledModifiedCreatureAsSpellCastWatcher watcher = game.getState().getWatcher(ControlledModifiedCreatureAsSpellCastWatcher.class); + MageObject sourceObject = source.getSourceObject(game); + if (watcher != null && sourceObject != null) { + boostValue -= watcher.getModifiedCreatureCount(new MageObjectReference(sourceObject, game)); + } + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent target = game.getPermanent(source.getFirstTarget()); + if (target == null) { + return false; + } + target.addPower(boostValue); + target.addToughness(boostValue); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LeylineOfSingularity.java b/Mage.Sets/src/mage/cards/l/LeylineOfSingularity.java index ab4cd05904c..9b23e8d8652 100644 --- a/Mage.Sets/src/mage/cards/l/LeylineOfSingularity.java +++ b/Mage.Sets/src/mage/cards/l/LeylineOfSingularity.java @@ -59,7 +59,7 @@ class SetSupertypeAllEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanent.addSuperType(SuperType.LEGENDARY); } return true; diff --git a/Mage.Sets/src/mage/cards/l/Lhurgoyf.java b/Mage.Sets/src/mage/cards/l/Lhurgoyf.java index 7632bab57c4..846738bfb2f 100644 --- a/Mage.Sets/src/mage/cards/l/Lhurgoyf.java +++ b/Mage.Sets/src/mage/cards/l/Lhurgoyf.java @@ -66,7 +66,7 @@ class LhurgoyfEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { int number = 0; for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { diff --git a/Mage.Sets/src/mage/cards/l/LiberatingCombustion.java b/Mage.Sets/src/mage/cards/l/LiberatingCombustion.java index 939aabfa81b..56d2c4efe96 100644 --- a/Mage.Sets/src/mage/cards/l/LiberatingCombustion.java +++ b/Mage.Sets/src/mage/cards/l/LiberatingCombustion.java @@ -1,7 +1,5 @@ - package mage.cards.l; -import java.util.UUID; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.search.SearchLibraryGraveyardPutInHandEffect; import mage.cards.CardImpl; @@ -11,8 +9,9 @@ import mage.filter.FilterCard; import mage.filter.predicate.mageobject.NamePredicate; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class LiberatingCombustion extends CardImpl { @@ -29,9 +28,9 @@ public final class LiberatingCombustion extends CardImpl { // Liberating Combustion deals 6 damage to target creature. this.getSpellAbility().addEffect(new DamageTargetEffect(6)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - + // You may search your library and/or graveyard for a card named Chandra, Pyrogenius, reveal it, and put it into your hand. If you search your library this way, shuffle it. - this.getSpellAbility().addEffect(new SearchLibraryGraveyardPutInHandEffect(filter)); + this.getSpellAbility().addEffect(new SearchLibraryGraveyardPutInHandEffect(filter, false, true)); } private LiberatingCombustion(final LiberatingCombustion card) { diff --git a/Mage.Sets/src/mage/cards/l/LibraryOfLatNam.java b/Mage.Sets/src/mage/cards/l/LibraryOfLatNam.java index 45a8450f7e1..7fa69b2d3df 100644 --- a/Mage.Sets/src/mage/cards/l/LibraryOfLatNam.java +++ b/Mage.Sets/src/mage/cards/l/LibraryOfLatNam.java @@ -1,10 +1,7 @@ - package mage.cards.l; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; @@ -14,25 +11,24 @@ import mage.constants.CardType; import mage.constants.TargetController; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author Quercitron */ public final class LibraryOfLatNam extends CardImpl { public LibraryOfLatNam(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{U}"); // An opponent chooses one this.getSpellAbility().getModes().setModeChooser(TargetController.OPPONENT); + // You draw three cards at the beginning of the next turn's upkeep; - this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(3)), false)); + this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(3).setText("you draw three cards")), false)); + // or you search your library for a card, put that card into your hand, then shuffle your library. - Mode mode = new Mode(); - Effect effect = new SearchLibraryPutInHandEffect(new TargetCardInLibrary(), false, true); - //effect.setText("you search your library for a card, put that card into your hand, then shuffle your library"); - mode.addEffect(effect); - this.getSpellAbility().addMode(mode); + this.getSpellAbility().addMode(new Mode(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(), false, true).setText("you search your library for a card, put that card into your hand, then shuffle"))); } private LibraryOfLatNam(final LibraryOfLatNam card) { diff --git a/Mage.Sets/src/mage/cards/l/Lich.java b/Mage.Sets/src/mage/cards/l/Lich.java index e507b5eefed..c37a5006608 100644 --- a/Mage.Sets/src/mage/cards/l/Lich.java +++ b/Mage.Sets/src/mage/cards/l/Lich.java @@ -168,8 +168,8 @@ class LichDamageEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Target target = new TargetControlledPermanent(amount, amount, filter, true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - if (controller.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) { + if (target.canChoose(controller.getId(), source, game)) { + if (controller.choose(Outcome.Sacrifice, target, source, game)) { for (UUID targetId : target.getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/l/LichLordOfUnx.java b/Mage.Sets/src/mage/cards/l/LichLordOfUnx.java index 3fe38ce728a..36ee8ba72a0 100644 --- a/Mage.Sets/src/mage/cards/l/LichLordOfUnx.java +++ b/Mage.Sets/src/mage/cards/l/LichLordOfUnx.java @@ -1,36 +1,36 @@ - package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.game.permanent.token.ZombieWizardToken; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author Loki */ public final class LichLordOfUnx extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Zombies you control"); - - static { - filter.add(SubType.ZOMBIE.getPredicate()); - } + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.ZOMBIE); + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + private static final Hint hint = new ValueHint("Zombies you control", xValue); public LichLordOfUnx(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}"); @@ -40,13 +40,21 @@ public final class LichLordOfUnx extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new ZombieWizardToken()), new ManaCostsImpl("{U}{B}")); + Ability ability = new SimpleActivatedAbility( + new CreateTokenEffect(new ZombieWizardToken()), new ManaCostsImpl<>("{U}{B}") + ); ability.addCost(new TapSourceCost()); this.addAbility(ability); - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseLifeTargetEffect(new PermanentsOnBattlefieldCount(filter)), new ManaCostsImpl("{U}{U}{B}{B}")); - ability.addEffect(new PutLibraryIntoGraveTargetEffect(new PermanentsOnBattlefieldCount(filter, 1))); + + ability = new SimpleActivatedAbility( + new LoseLifeTargetEffect(xValue) + .setText("target player loses X life"), + new ManaCostsImpl<>("{U}{U}{B}{B}") + ); + ability.addEffect(new PutLibraryIntoGraveTargetEffect(xValue) + .setText("and mills X cards, where X is the number of Zombies you control")); ability.addTarget(new TargetPlayer()); - this.addAbility(ability); + this.addAbility(ability.addHint(hint)); } private LichLordOfUnx(final LichLordOfUnx card) { @@ -57,5 +65,4 @@ public final class LichLordOfUnx extends CardImpl { public LichLordOfUnx copy() { return new LichLordOfUnx(this); } - } diff --git a/Mage.Sets/src/mage/cards/l/LichsMastery.java b/Mage.Sets/src/mage/cards/l/LichsMastery.java index 74ebde08dc4..e95944317a3 100644 --- a/Mage.Sets/src/mage/cards/l/LichsMastery.java +++ b/Mage.Sets/src/mage/cards/l/LichsMastery.java @@ -197,20 +197,20 @@ class LichsMasteryLoseLifeEffect extends OneShotEffect { int permCount = game.getBattlefield().getActivePermanents(filter, controller.getId(), game).size(); if (graveCount + handCount == 0 || (permCount > 0 && controller.chooseUse(Outcome.Exile, "Exile permanent you control? (No = from hand or graveyard)", source, game))) { Target target = new TargetControlledPermanent(1, 1, new FilterControlledPermanent(), true); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); Effect effect = new ExileTargetEffect(); effect.setTargetPointer(new FixedTarget(target.getFirstTarget(), game)); effect.apply(game, source); } else if (graveCount == 0 || (handCount > 0 && controller.chooseUse(Outcome.Exile, "Exile a card from your hand? (No = from graveyard)", source, game))) { Target target = new TargetCardInHand(1, 1, new FilterCard()); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); Card card = controller.getHand().get(target.getFirstTarget(), game); if (card != null) { controller.moveCards(card, Zone.EXILED, source, game); } } else if (graveCount > 0) { Target target = new TargetCardInYourGraveyard(1, 1, new FilterCard(), true); - target.choose(Outcome.Exile, source.getControllerId(), source.getSourceId(), game); + target.choose(Outcome.Exile, source.getControllerId(), source.getSourceId(), source, game); Card card = controller.getGraveyard().get(target.getFirstTarget(), game); if (card != null) { controller.moveCards(card, Zone.EXILED, source, game); diff --git a/Mage.Sets/src/mage/cards/l/LichsMirror.java b/Mage.Sets/src/mage/cards/l/LichsMirror.java index 84c5c7858ac..56f69d6ab81 100644 --- a/Mage.Sets/src/mage/cards/l/LichsMirror.java +++ b/Mage.Sets/src/mage/cards/l/LichsMirror.java @@ -70,7 +70,7 @@ class LichsMirrorEffect extends ReplacementEffectImpl { filter.add(new OwnerIdPredicate(player.getId())); toLib.addAll(player.getHand()); toLib.addAll(player.getGraveyard()); - for(Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)){ + for(Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)){ toLib.add(permanent); } player.shuffleCardsToLibrary(toLib, game, source); diff --git a/Mage.Sets/src/mage/cards/l/LiegeOfTheAxe.java b/Mage.Sets/src/mage/cards/l/LiegeOfTheAxe.java index 3ba86d786f8..4043a22eb3d 100644 --- a/Mage.Sets/src/mage/cards/l/LiegeOfTheAxe.java +++ b/Mage.Sets/src/mage/cards/l/LiegeOfTheAxe.java @@ -29,7 +29,7 @@ public final class LiegeOfTheAxe extends CardImpl { // Vigilance this.addAbility(VigilanceAbility.getInstance()); // Morph {1}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{W}"))); // When Liege of the Axe is turned face up, untap it. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new UntapSourceEffect())); } diff --git a/Mage.Sets/src/mage/cards/l/LiegeOfThePit.java b/Mage.Sets/src/mage/cards/l/LiegeOfThePit.java index c38c7f76f89..2e33b43f41f 100644 --- a/Mage.Sets/src/mage/cards/l/LiegeOfThePit.java +++ b/Mage.Sets/src/mage/cards/l/LiegeOfThePit.java @@ -39,7 +39,7 @@ public final class LiegeOfThePit extends CardImpl { // At the beginning of your upkeep, sacrifice a creature other than Liege of the Pit. If you can't, Liege of the Pit deals 7 damage to you. this.addAbility(new BeginningOfUpkeepTriggeredAbility(new LiegeOfThePitEffect(), TargetController.YOU, false)); // Morph {B}{B}{B}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{B}{B}{B}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{B}{B}{B}{B}"))); } private LiegeOfThePit(final LiegeOfThePit card) { @@ -57,7 +57,7 @@ class LiegeOfThePitEffect extends OneShotEffect { public LiegeOfThePitEffect() { super(Outcome.Damage); - this.staticText = "Sacrifice a creature other than {this}. If you can't {this} deals 7 damage to you."; + this.staticText = "sacrifice a creature other than {this}. If you can't, {this} deals 7 damage to you."; } public LiegeOfThePitEffect(final LiegeOfThePitEffect effect) { @@ -84,8 +84,8 @@ class LiegeOfThePitEffect extends OneShotEffect { filter.add(AnotherPredicate.instance); Target target = new TargetControlledCreaturePermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + if (target.canChoose(player.getId(), source, game)) { + player.choose(Outcome.Sacrifice, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.sacrifice(source, game); diff --git a/Mage.Sets/src/mage/cards/l/LieutenantsOfTheGuard.java b/Mage.Sets/src/mage/cards/l/LieutenantsOfTheGuard.java index d9cdd4137ba..f1e67d220de 100644 --- a/Mage.Sets/src/mage/cards/l/LieutenantsOfTheGuard.java +++ b/Mage.Sets/src/mage/cards/l/LieutenantsOfTheGuard.java @@ -7,6 +7,7 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.choices.TwoChoiceVote; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; @@ -35,7 +36,7 @@ public final class LieutenantsOfTheGuard extends CardImpl { // strength vote and put a 1/1 white Soldier creature token onto the battlefield for each numbers vote. this.addAbility(new EntersBattlefieldTriggeredAbility( new LieutenantsOfTheGuardEffect(), false) - .withFlavorWord("Council's dilemma") + .setAbilityWord(AbilityWord.COUNCILS_DILEMMA) ); } diff --git a/Mage.Sets/src/mage/cards/l/LifeAndLimb.java b/Mage.Sets/src/mage/cards/l/LifeAndLimb.java index c7ac0295611..27fa809f16a 100644 --- a/Mage.Sets/src/mage/cards/l/LifeAndLimb.java +++ b/Mage.Sets/src/mage/cards/l/LifeAndLimb.java @@ -67,7 +67,7 @@ class LifeAndLimbEffect extends ContinuousEffectImpl { public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - for (Permanent permanent : game.getState().getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getState().getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { switch (layer) { case TypeChangingEffects_4: permanent.addCardType(game, CardType.CREATURE); diff --git a/Mage.Sets/src/mage/cards/l/LifeInsurance.java b/Mage.Sets/src/mage/cards/l/LifeInsurance.java new file mode 100644 index 00000000000..aded7dcfd2b --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LifeInsurance.java @@ -0,0 +1,51 @@ +package mage.cards.l; + +import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.keyword.ExtortAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LifeInsurance extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("a nontoken creature"); + + static { + filter.add(TokenPredicate.FALSE); + } + + public LifeInsurance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}{B}"); + + // Extort + this.addAbility(new ExtortAbility()); + + // Whenever a nontoken creature dies, you lose 1 life and create a Treasure token. + Ability ability = new DiesCreatureTriggeredAbility( + new LoseLifeSourceControllerEffect(1), false, filter + ); + ability.addEffect(new CreateTokenEffect(new TreasureToken()).concatBy("and")); + this.addAbility(ability); + } + + private LifeInsurance(final LifeInsurance card) { + super(card); + } + + @Override + public LifeInsurance copy() { + return new LifeInsurance(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LifeOfTheParty.java b/Mage.Sets/src/mage/cards/l/LifeOfTheParty.java new file mode 100644 index 00000000000..059b4abcb22 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LifeOfTheParty.java @@ -0,0 +1,120 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.combat.GoadTargetEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; +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.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentToken; +import mage.target.targetpointer.FixedTargets; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LifeOfTheParty extends CardImpl { + + public LifeOfTheParty(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(0); + this.toughness = new MageInt(1); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Whenever Life of the Party attacks, it gets +X/+0 until end of turn, where X is the number of creatures you control. + this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect( + CreaturesYouControlCount.instance, StaticValue.get(0), + Duration.EndOfTurn, true, "it" + ))); + + // When Life of the Party enters the battlefield, if it's not a token, each opponent creates a token that's a copy of it. The tokens are goaded for the rest of the game. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new LifeOfThePartyEffect()), LifeOfTheParty::checkSource, + "When {this} enters the battlefield, if it's not a token, each opponent creates a " + + "token that's a copy of it. The tokens are goaded for the rest of the game." + )); + } + + private LifeOfTheParty(final LifeOfTheParty card) { + super(card); + } + + @Override + public LifeOfTheParty copy() { + return new LifeOfTheParty(this); + } + + static boolean checkSource(Game game, Ability source) { + return !(source.getSourcePermanentOrLKI(game) instanceof PermanentToken); + } +} + +class LifeOfThePartyEffect extends OneShotEffect { + + LifeOfThePartyEffect() { + super(Outcome.Benefit); + } + + private LifeOfThePartyEffect(final LifeOfThePartyEffect effect) { + super(effect); + } + + @Override + public LifeOfThePartyEffect copy() { + return new LifeOfThePartyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = (Permanent) getValue("permanentEnteredBattlefield"); + if (permanent == null) { + return false; + } + List permanents = new ArrayList<>(); + for (UUID playerId : game.getOpponents(source.getControllerId())) { + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(playerId); + effect.setSavedPermanent(permanent); + effect.apply(game, source); + permanents.addAll(effect.getAddedPermanents()); + } + if (permanents.isEmpty()) { + return false; + } + game.addEffect( + new GoadTargetEffect() + .setDuration(Duration.EndOfGame) + .setTargetPointer(new FixedTargets(permanents, game)), + source + ); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LifecraftAwakening.java b/Mage.Sets/src/mage/cards/l/LifecraftAwakening.java index 9c08e51a19b..8a539a44f70 100644 --- a/Mage.Sets/src/mage/cards/l/LifecraftAwakening.java +++ b/Mage.Sets/src/mage/cards/l/LifecraftAwakening.java @@ -37,8 +37,9 @@ public final class LifecraftAwakening extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{G}"); // Put X +1/+1 counters on target artifact you control. If it isn't a creature or Vehicle, it becomes a 0/0 Construct artifact creature. - ManacostVariableValue manaX = ManacostVariableValue.REGULAR; - getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(), manaX)); + getSpellAbility().addEffect(new AddCountersTargetEffect( + CounterType.P1P1.createInstance(), ManacostVariableValue.REGULAR + ).setText("put X +1/+1 counters on target artifact you control")); getSpellAbility().addTarget(new TargetArtifactPermanent(filter)); getSpellAbility().addEffect(new LifecraftAwakeningEffect()); } diff --git a/Mage.Sets/src/mage/cards/l/Lifeline.java b/Mage.Sets/src/mage/cards/l/Lifeline.java index a605b975ceb..f5003f3fd69 100644 --- a/Mage.Sets/src/mage/cards/l/Lifeline.java +++ b/Mage.Sets/src/mage/cards/l/Lifeline.java @@ -69,7 +69,7 @@ class LifelineEffect extends OneShotEffect { Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false); effect.setTargetPointer(new FixedTarget(card, game)); effect.setText("return that card to the battlefield under it's owner's control at the beginning of the next end step"); - game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone.BATTLEFIELD, effect, TargetController.ANY), source); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect, TargetController.ANY), source); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/l/LightEmUp.java b/Mage.Sets/src/mage/cards/l/LightEmUp.java new file mode 100644 index 00000000000..3c3d0946999 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LightEmUp.java @@ -0,0 +1,36 @@ +package mage.cards.l; + +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.CasualtyAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LightEmUp extends CardImpl { + + public LightEmUp(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); + + // Casualty 2 + this.addAbility(new CasualtyAbility(this, 2)); + + // Light 'Em Up deals 2 damage to target creature or planeswalker. + this.getSpellAbility().addEffect(new DamageTargetEffect(2)); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + } + + private LightEmUp(final LightEmUp card) { + super(card); + } + + @Override + public LightEmUp copy() { + return new LightEmUp(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LightPawsEmperorsVoice.java b/Mage.Sets/src/mage/cards/l/LightPawsEmperorsVoice.java new file mode 100644 index 00000000000..3619abaa48b --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LightPawsEmperorsVoice.java @@ -0,0 +1,135 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.card.AuraCardCanAttachToPermanentId; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; + +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LightPawsEmperorsVoice extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.AURA, "an Aura"); + + static { + filter.add(LightPawsEmperorsVoicePredicate.instance); + } + + public LightPawsEmperorsVoice(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.FOX); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever an Aura enters the battlefield under your control, if you cast it, you may search your library for an Aura card with mana value less than or equal to that Aura and with a different name than each Aura you control, put that card onto the battlefield attached to Light-Paws, Emperor's Voice, then shuffle. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new LightPawsEmperorsVoiceEffect(), filter)); + } + + private LightPawsEmperorsVoice(final LightPawsEmperorsVoice card) { + super(card); + } + + @Override + public LightPawsEmperorsVoice copy() { + return new LightPawsEmperorsVoice(this); + } +} + +enum LightPawsEmperorsVoicePredicate implements Predicate { + instance; + + @Override + public boolean apply(Permanent input, Game game) { + int zcc = input.getZoneChangeCounter(game); + Spell spell = game.getStack().getSpell(input.getId()); + return (spell != null && spell.getZoneChangeCounter(game) == zcc - 1) + || game.getLastKnownInformation(input.getId(), Zone.STACK, zcc - 1) != null; + } +} + +class LightPawsEmperorsVoiceEffect extends OneShotEffect { + + private static enum LightPawsEmperorsVoiceEffectPredicate implements ObjectSourcePlayerPredicate { + instance; + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.AURA); + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return game.getBattlefield() + .getActivePermanents( + filter, input.getPlayerId(), + input.getSource(), game + ).stream() + .filter(Objects::nonNull) + .noneMatch(permanent -> CardUtil.haveSameNames(permanent, input.getObject())); + } + } + + LightPawsEmperorsVoiceEffect() { + super(Outcome.Benefit); + staticText = "if you cast it, you may search your library for an Aura card with mana value " + + "less than or equal to that Aura and with a different name than each Aura you control, " + + "put that card onto the battlefield attached to {this}, then shuffle"; + } + + private LightPawsEmperorsVoiceEffect(final LightPawsEmperorsVoiceEffect effect) { + super(effect); + } + + @Override + public LightPawsEmperorsVoiceEffect copy() { + return new LightPawsEmperorsVoiceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent aura = (Permanent) getValue("permanentEnteringBattlefield"); + if (player == null || aura == null || !player.chooseUse( + outcome, "Search for an Aura?", source, game + )) { + return false; + } + FilterCard filter = new FilterCard("Aura card with mana value less than or equal to " + aura.getManaValue()); + filter.add(SubType.AURA.getPredicate()); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, aura.getManaValue() + 1)); + filter.add(LightPawsEmperorsVoiceEffectPredicate.instance); + TargetCardInLibrary target = new TargetCardInLibrary(filter); + player.searchLibrary(target, source, game); + Card card = player.getLibrary().getCard(target.getFirstTarget(), game); + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (card != null && permanent != null + && new AuraCardCanAttachToPermanentId(permanent.getId()).apply(card, game)) { + game.getState().setValue("attachTo:" + card.getId(), permanent); + player.moveCards(card, Zone.BATTLEFIELD, source, game); + permanent.addAttachment(card.getId(), source, game); + } + player.shuffleLibrary(source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LightningAxe.java b/Mage.Sets/src/mage/cards/l/LightningAxe.java index 4a9b7404d8a..8b917033489 100644 --- a/Mage.Sets/src/mage/cards/l/LightningAxe.java +++ b/Mage.Sets/src/mage/cards/l/LightningAxe.java @@ -22,7 +22,7 @@ public final class LightningAxe extends CardImpl { // As an additional cost to cast Lightning Axe, discard a card or pay {5}. - this.getSpellAbility().addCost(new OrCost(new DiscardCardCost(), new GenericManaCost(5),"discard a card or pay {5}")); + this.getSpellAbility().addCost(new OrCost("discard a card or pay {5}", new DiscardCardCost(), new GenericManaCost(5))); // Lightning Axe deals 5 damage to target creature. this.getSpellAbility().addEffect(new DamageTargetEffect(5)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/l/LightningBerserker.java b/Mage.Sets/src/mage/cards/l/LightningBerserker.java index 6eb687a740a..03da0b0da42 100644 --- a/Mage.Sets/src/mage/cards/l/LightningBerserker.java +++ b/Mage.Sets/src/mage/cards/l/LightningBerserker.java @@ -33,7 +33,7 @@ public final class LightningBerserker extends CardImpl { new ManaCostsImpl("{R}"))); // Dash {R} - this.addAbility(new DashAbility(this, "{R}")); + this.addAbility(new DashAbility("{R}")); } private LightningBerserker(final LightningBerserker card) { diff --git a/Mage.Sets/src/mage/cards/l/LightningCrafter.java b/Mage.Sets/src/mage/cards/l/LightningCrafter.java index a3e22d3711b..a83e8999256 100644 --- a/Mage.Sets/src/mage/cards/l/LightningCrafter.java +++ b/Mage.Sets/src/mage/cards/l/LightningCrafter.java @@ -1,8 +1,5 @@ - package mage.cards.l; -import java.util.EnumSet; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -16,22 +13,23 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class LightningCrafter extends CardImpl { public LightningCrafter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.SHAMAN); this.power = new MageInt(3); this.toughness = new MageInt(3); // Champion a Goblin or Shaman - this.addAbility(new ChampionAbility(this, EnumSet.of(SubType.GOBLIN, SubType.SHAMAN), false)); - + this.addAbility(new ChampionAbility(this, SubType.GOBLIN, SubType.SHAMAN)); + // {T}: Lightning Crafter deals 3 damage to any target. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(3), new TapSourceCost()); ability.addTarget(new TargetAnyTarget()); diff --git a/Mage.Sets/src/mage/cards/l/LightningReaver.java b/Mage.Sets/src/mage/cards/l/LightningReaver.java index b6e96e71be3..1cf6efbb224 100644 --- a/Mage.Sets/src/mage/cards/l/LightningReaver.java +++ b/Mage.Sets/src/mage/cards/l/LightningReaver.java @@ -1,12 +1,11 @@ package mage.cards.l; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CountersSourceCount; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FearAbility; import mage.abilities.keyword.HasteAbility; @@ -17,8 +16,6 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.TargetController; import mage.counters.CounterType; -import mage.game.Game; -import mage.players.Player; import java.util.UUID; @@ -27,12 +24,12 @@ import java.util.UUID; */ public final class LightningReaver extends CardImpl { + private static final DynamicValue xValue = new CountersSourceCount(CounterType.CHARGE); + public LightningReaver(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{R}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.BEAST); - - this.power = new MageInt(3); this.toughness = new MageInt(3); @@ -41,10 +38,12 @@ public final class LightningReaver extends CardImpl { this.addAbility(FearAbility.getInstance()); // Whenever Lightning Reaver deals combat damage to a player, put a charge counter on it. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), false)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new AddCountersSourceEffect(CounterType.CHARGE.createInstance()).setText("put a charge counter on it"), false)); // At the beginning of your end step, Lightning Reaver deals damage equal to the number of charge counters on it to each opponent. - this.addAbility(new BeginningOfEndStepTriggeredAbility(new DamageOpponentsEffect(), TargetController.YOU, false)); + this.addAbility(new BeginningOfEndStepTriggeredAbility(new DamagePlayersEffect( + Outcome.Damage, xValue, TargetController.OPPONENT + ).setText("{this} deals damage equal to the number of charge counters on it to each opponent"), TargetController.YOU, false)); } private LightningReaver(final LightningReaver card) { @@ -56,32 +55,3 @@ public final class LightningReaver extends CardImpl { return new LightningReaver(this); } } - -class DamageOpponentsEffect extends OneShotEffect { - - public DamageOpponentsEffect() { - super(Outcome.Damage); - staticText = "Lightning Reaver deals damage equal to the number of charge counters on it to each opponent"; - } - - public DamageOpponentsEffect(final DamageOpponentsEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - DynamicValue amount = new CountersSourceCount(CounterType.CHARGE); - for (UUID playerId : game.getOpponents(source.getControllerId())) { - Player player = game.getPlayer(playerId); - if (player != null) { - player.damage(amount.calculate(game, source, this), source.getSourceId(), source, game); - } - } - return true; - } - - @Override - public DamageOpponentsEffect copy() { - return new DamageOpponentsEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/l/LightningRunner.java b/Mage.Sets/src/mage/cards/l/LightningRunner.java index c22a3a5e397..2a1aa9ee4b0 100644 --- a/Mage.Sets/src/mage/cards/l/LightningRunner.java +++ b/Mage.Sets/src/mage/cards/l/LightningRunner.java @@ -62,8 +62,8 @@ class LightningRunnerEffect extends OneShotEffect { LightningRunnerEffect() { super(Outcome.Benefit); - staticText = "you get {E}{E}, then you may pay {E}{E}{E}{E}{E}{E}{E}{E}. If you do, " - + "untap all creatures you control and after this phase, there is an additional combat phase"; + staticText = "you get {E}{E}, then you may pay {E}{E}{E}{E}{E}{E}{E}{E}. If you pay, " + + "untap all creatures you control, and after this phase, there is an additional combat phase"; } LightningRunnerEffect(final LightningRunnerEffect effect) { diff --git a/Mage.Sets/src/mage/cards/l/LilianaDeathMage.java b/Mage.Sets/src/mage/cards/l/LilianaDeathMage.java index 4c7d3bb390e..3942a1ec3dd 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaDeathMage.java +++ b/Mage.Sets/src/mage/cards/l/LilianaDeathMage.java @@ -2,7 +2,6 @@ package mage.cards.l; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.LoseLifeTargetControllerEffect; @@ -34,7 +33,7 @@ public final class LilianaDeathMage extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.LILIANA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Return up to one target creature card from your graveyard to your hand. Ability plusAbility = new LoyaltyAbility(new LilianaDeathMagePlusEffect(), 1); diff --git a/Mage.Sets/src/mage/cards/l/LilianaDeathWielder.java b/Mage.Sets/src/mage/cards/l/LilianaDeathWielder.java index 45625088b15..9744b354e4c 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaDeathWielder.java +++ b/Mage.Sets/src/mage/cards/l/LilianaDeathWielder.java @@ -4,7 +4,6 @@ package mage.cards.l; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; @@ -39,7 +38,7 @@ public final class LilianaDeathWielder extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.LILIANA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +2: Put a -1/-1 counter on up to one target creature. LoyaltyAbility ability = new LoyaltyAbility(new AddCountersTargetEffect(CounterType.M1M1.createInstance(1)), 2); diff --git a/Mage.Sets/src/mage/cards/l/LilianaDeathsMajesty.java b/Mage.Sets/src/mage/cards/l/LilianaDeathsMajesty.java index e7433ed24d7..3c759a02eca 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaDeathsMajesty.java +++ b/Mage.Sets/src/mage/cards/l/LilianaDeathsMajesty.java @@ -3,7 +3,6 @@ package mage.cards.l; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyAllEffect; import mage.abilities.effects.common.MillCardsControllerEffect; @@ -38,7 +37,7 @@ public final class LilianaDeathsMajesty extends CardImpl { this.subtype.add(SubType.LILIANA); //Starting Loyalty: 5 - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Create a 2/2 black Zombie creature token. Put the top two cards of your library into your graveyard. LoyaltyAbility ability = new LoyaltyAbility(new CreateTokenEffect(new ZombieToken()), 1); diff --git a/Mage.Sets/src/mage/cards/l/LilianaDefiantNecromancer.java b/Mage.Sets/src/mage/cards/l/LilianaDefiantNecromancer.java index 53587507f17..90f93f7558f 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaDefiantNecromancer.java +++ b/Mage.Sets/src/mage/cards/l/LilianaDefiantNecromancer.java @@ -2,7 +2,6 @@ package mage.cards.l; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.common.PayVariableLoyaltyCost; import mage.abilities.effects.common.GetEmblemEffect; @@ -44,7 +43,7 @@ public final class LilianaDefiantNecromancer extends CardImpl { this.nightCard = true; - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +2: Each player discards a card. this.addAbility(new LoyaltyAbility(new DiscardEachPlayerEffect(1, false), 2)); diff --git a/Mage.Sets/src/mage/cards/l/LilianaDreadhordeGeneral.java b/Mage.Sets/src/mage/cards/l/LilianaDreadhordeGeneral.java index a3aae6bee5a..9ff716577a5 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaDreadhordeGeneral.java +++ b/Mage.Sets/src/mage/cards/l/LilianaDreadhordeGeneral.java @@ -3,7 +3,6 @@ package mage.cards.l; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.DiesCreatureTriggeredAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -31,14 +30,14 @@ import java.util.UUID; */ public final class LilianaDreadhordeGeneral extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent(" creatures"); + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("creatures"); public LilianaDreadhordeGeneral(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{B}{B}"); this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.LILIANA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(6)); + this.setStartingLoyalty(6); // Whenever a creature you control dies, draw a card. this.addAbility(new DiesCreatureTriggeredAbility( @@ -102,13 +101,13 @@ class LilianaDreadhordeGeneralEffect extends OneShotEffect { filter.add(cardType.getPredicate()); Target target = new TargetControlledPermanent(filter); target.setNotTarget(true); - if (opponent.choose(outcome, target, source.getSourceId(), game)) { + if (opponent.choose(outcome, target, source, game)) { keepFilter.add(Predicates.not(new CardIdPredicate(target.getFirstTarget()))); } } } for (Permanent permanent : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { - if (keepFilter.match(permanent, source.getSourceId(), source.getControllerId(), game)) { + if (keepFilter.match(permanent, source.getControllerId(), source, game)) { permanent.sacrifice(source, game); } } diff --git a/Mage.Sets/src/mage/cards/l/LilianaOfTheDarkRealms.java b/Mage.Sets/src/mage/cards/l/LilianaOfTheDarkRealms.java index 59add5556bc..48f603ce55d 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaOfTheDarkRealms.java +++ b/Mage.Sets/src/mage/cards/l/LilianaOfTheDarkRealms.java @@ -2,7 +2,6 @@ package mage.cards.l; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -37,7 +36,7 @@ public final class LilianaOfTheDarkRealms extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.LILIANA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Search your library for a Swamp card, reveal it, and put it into your hand. Then shuffle your library. this.addAbility(new LoyaltyAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true), 1)); @@ -86,7 +85,7 @@ class LilianaOfTheDarkRealmsEffect extends OneShotEffect { if (player == null) { return false; } - int swamps = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int swamps = game.getBattlefield().count(filter, source.getControllerId(), source, game); if (swamps < 1) { return false; } diff --git a/Mage.Sets/src/mage/cards/l/LilianaOfTheVeil.java b/Mage.Sets/src/mage/cards/l/LilianaOfTheVeil.java index 0206587777a..88f3359b5ca 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaOfTheVeil.java +++ b/Mage.Sets/src/mage/cards/l/LilianaOfTheVeil.java @@ -1,4 +1,3 @@ - package mage.cards.l; import java.util.ArrayList; @@ -6,7 +5,6 @@ import java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeEffect; import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; @@ -18,6 +16,7 @@ import mage.constants.Outcome; import mage.constants.SuperType; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; +import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -29,13 +28,13 @@ import mage.target.TargetPlayer; * @author North */ public final class LilianaOfTheVeil extends CardImpl { - + public LilianaOfTheVeil(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{B}{B}"); this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.LILIANA); - - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + + this.setStartingLoyalty(3); // +1: Each player discards a card. this.addAbility(new LoyaltyAbility(new DiscardEachPlayerEffect(), 1)); @@ -50,11 +49,11 @@ public final class LilianaOfTheVeil extends CardImpl { ability.addTarget(new TargetPlayer()); this.addAbility(ability); } - + private LilianaOfTheVeil(final LilianaOfTheVeil card) { super(card); } - + @Override public LilianaOfTheVeil copy() { return new LilianaOfTheVeil(this); @@ -62,31 +61,33 @@ public final class LilianaOfTheVeil extends CardImpl { } class LilianaOfTheVeilEffect extends OneShotEffect { - + public LilianaOfTheVeilEffect() { super(Outcome.Sacrifice); this.staticText = "Separate all permanents target player controls into two piles. That player sacrifices all permanents in the pile of their choice"; } - + public LilianaOfTheVeilEffect(final LilianaOfTheVeilEffect effect) { super(effect); } - + @Override public LilianaOfTheVeilEffect copy() { return new LilianaOfTheVeilEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); Player targetPlayer = game.getPlayer(source.getFirstTarget()); if (player != null && targetPlayer != null) { int count = game.getBattlefield().countAll(new FilterPermanent(), targetPlayer.getId(), game); - TargetPermanent target = new TargetPermanent(0, count, new FilterPermanent("permanents to put in the first pile"), true); + FilterPermanent filter = new FilterPermanent("permanents to put in the first pile"); + filter.add(new ControllerIdPredicate(targetPlayer.getId())); + TargetPermanent target = new TargetPermanent(0, count, filter, true); List pile1 = new ArrayList<>(); target.setRequired(false); - if (player.choose(Outcome.Neutral, target, source.getSourceId(), game)) { + if (player.choose(Outcome.Neutral, target, source, game)) { List targets = target.getTargets(); for (UUID targetId : targets) { Permanent p = game.getPermanent(targetId); @@ -101,20 +102,20 @@ class LilianaOfTheVeilEffect extends OneShotEffect { pile2.add(p); } } - + boolean choice = targetPlayer.choosePile(Outcome.DestroyPermanent, "Choose a pile to sacrifice.", pile1, pile2, game); - + if (choice) { sacrificePermanents(pile1, game, source); } else { sacrificePermanents(pile2, game, source); } - + return true; } return false; } - + private void sacrificePermanents(List pile, Game game, Ability source) { for (Permanent permanent : pile) { if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/l/LilianaTheLastHope.java b/Mage.Sets/src/mage/cards/l/LilianaTheLastHope.java index 9d2d78f3b7b..d216a1dfc9d 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaTheLastHope.java +++ b/Mage.Sets/src/mage/cards/l/LilianaTheLastHope.java @@ -4,7 +4,6 @@ package mage.cards.l; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -37,7 +36,7 @@ public final class LilianaTheLastHope extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.LILIANA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Up to one target creature gets -2/-1 until your next turn. Effect effect = new BoostTargetEffect(-2, -1, Duration.UntilYourNextTurn); @@ -90,9 +89,9 @@ class LilianaTheLastHopeEffect extends OneShotEffect { } TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + if (target.canChoose(source.getControllerId(), source, game) && controller.chooseUse(outcome, "Return a creature card from your graveyard to hand?", source, game) - && controller.choose(Outcome.ReturnToHand, target, source.getSourceId(), game)) { + && controller.choose(Outcome.ReturnToHand, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { controller.moveCards(card, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/l/LilianaTheNecromancer.java b/Mage.Sets/src/mage/cards/l/LilianaTheNecromancer.java index 32fbb00af88..646ff5fad78 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaTheNecromancer.java +++ b/Mage.Sets/src/mage/cards/l/LilianaTheNecromancer.java @@ -1,23 +1,13 @@ package mage.cards.l; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; -import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.cards.Card; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.cards.*; +import mage.constants.*; import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; import mage.game.Game; @@ -28,8 +18,9 @@ import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class LilianaTheNecromancer extends CardImpl { @@ -39,7 +30,7 @@ public final class LilianaTheNecromancer extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.LILIANA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Target player loses 2 life. Ability ability = new LoyaltyAbility(new LoseLifeTargetEffect(2), 1); @@ -47,13 +38,13 @@ public final class LilianaTheNecromancer extends CardImpl { this.addAbility(ability); // −1: Return target creature card from your graveyard to your hand. - ability = new LoyaltyAbility(new ReturnToHandTargetEffect(), -1); + ability = new LoyaltyAbility(new ReturnFromGraveyardToHandTargetEffect(), -1); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); // −7: Destroy up to two target creatures. Put up to two creature cards from graveyards onto the battlefield under your control. ability = new LoyaltyAbility(new DestroyTargetEffect(), -7); - ability.addTarget(new TargetCreaturePermanent(0, 2)); + ability.addTarget(new TargetCreaturePermanent(0, 2, StaticFilters.FILTER_PERMANENT_CREATURES, false)); ability.addEffect(new LilianaTheNecromancerEffect()); this.addAbility(ability); } @@ -94,7 +85,7 @@ class LilianaTheNecromancerEffect extends OneShotEffect { } Target target = new TargetCardInGraveyard(0, 2, filter); target.setNotTarget(true); - if (!player.choose(outcome, target, source.getSourceId(), game)) { + if (!player.choose(outcome, target, source, game)) { return false; } Cards cardsToMove = new CardsImpl(); diff --git a/Mage.Sets/src/mage/cards/l/LilianaUntouchedByDeath.java b/Mage.Sets/src/mage/cards/l/LilianaUntouchedByDeath.java index f15486a6883..d7915caf2f1 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaUntouchedByDeath.java +++ b/Mage.Sets/src/mage/cards/l/LilianaUntouchedByDeath.java @@ -2,7 +2,6 @@ package mage.cards.l; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.AsThoughEffectImpl; @@ -33,7 +32,7 @@ public final class LilianaUntouchedByDeath extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.LILIANA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Put the top three cards of your library into your graveyard. If at least one of them is a Zombie card, each opponent loses 2 life and you gain 2 life. this.addAbility(new LoyaltyAbility(new LilianaUntouchedByDeathEffect(), 1)); diff --git a/Mage.Sets/src/mage/cards/l/LilianaVess.java b/Mage.Sets/src/mage/cards/l/LilianaVess.java index f5cc13bdc67..d378c51db85 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaVess.java +++ b/Mage.Sets/src/mage/cards/l/LilianaVess.java @@ -5,7 +5,6 @@ import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; @@ -34,7 +33,7 @@ public final class LilianaVess extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.LILIANA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Target player discards a card. LoyaltyAbility ability1 = new LoyaltyAbility(new DiscardTargetEffect(1), 1); ability1.addTarget(new TargetPlayer()); diff --git a/Mage.Sets/src/mage/cards/l/LilianaWakerOfTheDead.java b/Mage.Sets/src/mage/cards/l/LilianaWakerOfTheDead.java index 81087aab8eb..4d59e896f13 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaWakerOfTheDead.java +++ b/Mage.Sets/src/mage/cards/l/LilianaWakerOfTheDead.java @@ -2,7 +2,6 @@ package mage.cards.l; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.OneShotEffect; @@ -40,7 +39,7 @@ public final class LilianaWakerOfTheDead extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.LILIANA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Each player discards a card. Each opponent who can't loses 3 life. this.addAbility(new LoyaltyAbility(new LilianaWakerOfTheDeadDiscardEffect(), 1)); diff --git a/Mage.Sets/src/mage/cards/l/LilianasScrounger.java b/Mage.Sets/src/mage/cards/l/LilianasScrounger.java index bea115fe3ad..8058e8b2694 100644 --- a/Mage.Sets/src/mage/cards/l/LilianasScrounger.java +++ b/Mage.Sets/src/mage/cards/l/LilianasScrounger.java @@ -76,14 +76,14 @@ class LilianasScroungerEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player == null || game.getBattlefield().count( - filter, source.getSourceId(), source.getControllerId(), game + filter, source.getControllerId(), source, game ) < 1 || !player.chooseUse( outcome, "Put a loyalty counter on a Liliana planeswalker you control?", source, game )) { return false; } TargetPermanent target = new TargetPermanent(0, 1, filter, true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); return permanent != null && permanent.addCounters(CounterType.LOYALTY.createInstance(), source.getControllerId(), source, game); } diff --git a/Mage.Sets/src/mage/cards/l/LilianasSpoils.java b/Mage.Sets/src/mage/cards/l/LilianasSpoils.java index 10ba3bbeef0..53ce1878388 100644 --- a/Mage.Sets/src/mage/cards/l/LilianasSpoils.java +++ b/Mage.Sets/src/mage/cards/l/LilianasSpoils.java @@ -2,13 +2,12 @@ package mage.cards.l; import java.util.UUID; import mage.ObjectColor; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetOpponent; @@ -34,12 +33,7 @@ public final class LilianasSpoils extends CardImpl { // Look at the top five cards of your library. You may reveal a black card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), filter, - Zone.LIBRARY, false, true, false, Zone.HAND, true, false, false - ).setBackInRandomOrder(true).setText("Look at the top five cards of your library. " - + "You may reveal a black card from among them and put it into your hand. " - + "Put the rest on the bottom of your library in a random order.") - ); + 5, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM).concatBy("
")); } private LilianasSpoils(final LilianasSpoils card) { diff --git a/Mage.Sets/src/mage/cards/l/LimDulsHex.java b/Mage.Sets/src/mage/cards/l/LimDulsHex.java index 5af0a76c39a..9dd7081f6a3 100644 --- a/Mage.Sets/src/mage/cards/l/LimDulsHex.java +++ b/Mage.Sets/src/mage/cards/l/LimDulsHex.java @@ -61,7 +61,7 @@ class LimDulsHexEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - OrCost costToPay = new OrCost(new ManaCostsImpl("{B}"), new ManaCostsImpl("{3}"), "{B} or {3}"); + OrCost costToPay = new OrCost("{B} or {3}", new ManaCostsImpl("{B}"), new ManaCostsImpl("{3}")); costToPay.clearPaid(); if (!(player.chooseUse(Outcome.Benefit, "Pay {B} or {3}?", source, game) && costToPay.pay(source, game, source, player.getId(), false, null))) { game.informPlayers(player.getLogName() + " chooses not to pay " + costToPay.getText() + " to prevent 1 damage from " + sourcePermanent.getLogName()); diff --git a/Mage.Sets/src/mage/cards/l/LinessaZephyrMage.java b/Mage.Sets/src/mage/cards/l/LinessaZephyrMage.java index 2156ede808c..bdc7d33c8a8 100644 --- a/Mage.Sets/src/mage/cards/l/LinessaZephyrMage.java +++ b/Mage.Sets/src/mage/cards/l/LinessaZephyrMage.java @@ -97,7 +97,7 @@ class LinessaZephyrMageEffect extends OneShotEffect { // Target player returns a creature they control to its owner's hand, Target target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (target.choose(Outcome.ReturnToHand, targetPlayer.getId(), source.getSourceId(), game)) { + if (target.choose(Outcome.ReturnToHand, targetPlayer.getId(), source.getSourceId(), source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { targetPlayer.moveCards(permanent, Zone.HAND, source, game); @@ -109,7 +109,7 @@ class LinessaZephyrMageEffect extends OneShotEffect { filter.add(CardType.ARTIFACT.getPredicate()); target = new TargetControlledPermanent(filter); target.setNotTarget(true); - if (target.choose(Outcome.ReturnToHand, targetPlayer.getId(), source.getSourceId(), game)) { + if (target.choose(Outcome.ReturnToHand, targetPlayer.getId(), source.getSourceId(), source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { targetPlayer.moveCards(permanent, Zone.HAND, source, game); @@ -121,7 +121,7 @@ class LinessaZephyrMageEffect extends OneShotEffect { filter.add(CardType.ENCHANTMENT.getPredicate()); target = new TargetControlledPermanent(filter); target.setNotTarget(true); - if (target.choose(Outcome.ReturnToHand, targetPlayer.getId(), source.getSourceId(), game)) { + if (target.choose(Outcome.ReturnToHand, targetPlayer.getId(), source.getSourceId(), source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { targetPlayer.moveCards(permanent, Zone.HAND, source, game); @@ -133,7 +133,7 @@ class LinessaZephyrMageEffect extends OneShotEffect { filter.add(CardType.LAND.getPredicate()); target = new TargetControlledPermanent(filter); target.setNotTarget(true); - if (target.choose(Outcome.ReturnToHand, targetPlayer.getId(), source.getSourceId(), game)) { + if (target.choose(Outcome.ReturnToHand, targetPlayer.getId(), source.getSourceId(), source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { targetPlayer.moveCards(permanent, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/l/LivingBreakthrough.java b/Mage.Sets/src/mage/cards/l/LivingBreakthrough.java index ada98c582e5..31cc5e63f97 100644 --- a/Mage.Sets/src/mage/cards/l/LivingBreakthrough.java +++ b/Mage.Sets/src/mage/cards/l/LivingBreakthrough.java @@ -78,7 +78,7 @@ class LivingBreakthroughEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast spells with mana value " + manaValue + " this turn (" + mageObject.getIdName() + ")."; diff --git a/Mage.Sets/src/mage/cards/l/LivingDestiny.java b/Mage.Sets/src/mage/cards/l/LivingDestiny.java index 09879698dba..c07c1ed96e1 100644 --- a/Mage.Sets/src/mage/cards/l/LivingDestiny.java +++ b/Mage.Sets/src/mage/cards/l/LivingDestiny.java @@ -1,7 +1,5 @@ - package mage.cards.l; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.common.RevealTargetFromHandCost; import mage.abilities.effects.OneShotEffect; @@ -9,25 +7,28 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInHand; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class LivingDestiny extends CardImpl { - public LivingDestiny(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{G}"); + private static final FilterCard filter = new FilterCreatureCard("a creature card from your hand"); + public LivingDestiny(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{G}"); // As an additional cost to cast Living Destiny, reveal a creature card from your hand. - TargetCardInHand targetCard = new TargetCardInHand(new FilterCreatureCard("a creature card")); + TargetCardInHand targetCard = new TargetCardInHand(filter); this.getSpellAbility().addCost(new RevealTargetFromHandCost(targetCard)); - + // You gain life equal to the revealed card's converted mana cost. this.getSpellAbility().addEffect(new LivingDestinyEffect()); } @@ -46,7 +47,7 @@ class LivingDestinyEffect extends OneShotEffect { public LivingDestinyEffect() { super(Outcome.GainLife); - staticText = "You gain life equal to its mana value"; + staticText = "You gain life equal to the revealed card's mana value"; } public LivingDestinyEffect(LivingDestinyEffect effect) { @@ -70,5 +71,4 @@ class LivingDestinyEffect extends OneShotEffect { public LivingDestinyEffect copy() { return new LivingDestinyEffect(this); } - } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/l/LivingHive.java b/Mage.Sets/src/mage/cards/l/LivingHive.java index bcc6c973dc7..77df233c3b1 100644 --- a/Mage.Sets/src/mage/cards/l/LivingHive.java +++ b/Mage.Sets/src/mage/cards/l/LivingHive.java @@ -1,21 +1,16 @@ - package mage.cards.l; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Outcome; -import mage.game.Game; import mage.game.permanent.token.InsectToken; -import mage.players.Player; /** * @@ -33,7 +28,8 @@ public final class LivingHive extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); // Whenever Living Hive deals combat damage to a player, create that many 1/1 green Insect creature tokens. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new LivingHiveEffect(), false, true)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new CreateTokenEffect(new InsectToken(), SavedDamageValue.MANY), false, true)); } private LivingHive(final LivingHive card) { @@ -45,33 +41,3 @@ public final class LivingHive extends CardImpl { return new LivingHive(this); } } - -class LivingHiveEffect extends OneShotEffect { - - public LivingHiveEffect() { - super(Outcome.PutCreatureInPlay); - this.staticText = "create that many 1/1 green Insect creature tokens"; - } - - public LivingHiveEffect(final LivingHiveEffect effect) { - super(effect); - } - - @Override - public LivingHiveEffect copy() { - return new LivingHiveEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(targetPointer.getFirst(game, source)); - if (player != null) { - int amount = (Integer)getValue("damage"); - if (amount > 0) { - return new CreateTokenEffect(new InsectToken(), amount).apply(game, source); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/l/LivingLore.java b/Mage.Sets/src/mage/cards/l/LivingLore.java index b45827d5ea7..9b75b7c7bcf 100644 --- a/Mage.Sets/src/mage/cards/l/LivingLore.java +++ b/Mage.Sets/src/mage/cards/l/LivingLore.java @@ -1,30 +1,33 @@ package mage.cards.l; -import java.util.UUID; -import mage.ApprovingObject; import mage.MageInt; import mage.MageObject; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.DealsCombatDamageTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.*; -import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.StaticFilters; import mage.game.ExileZone; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.TargetCard; import mage.target.common.TargetCardInYourGraveyard; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class LivingLore extends CardImpl { @@ -36,15 +39,21 @@ public final class LivingLore extends CardImpl { this.toughness = new MageInt(0); // As Living Lore enters the battlefield, exile an instant or sorcery card from your graveyard. - this.addAbility(new AsEntersBattlefieldAbility(new LivingLoreExileEffect(), - "exile an instant or sorcery card from your graveyard")); + this.addAbility(new AsEntersBattlefieldAbility( + new LivingLoreExileEffect(), "exile an instant or sorcery card from your graveyard" + )); // Living Lore's power and toughness are each equal to the exiled card's converted mana cost. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new LivingLoreSetPowerToughnessSourceEffect())); + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SetPowerToughnessSourceEffect(LivingLoreValue.instance, Duration.EndOfGame) + .setText("{this}'s power and toughness are each equal to the exiled card's mana value") + )); // Whenever Living Lore deals combat damage, you may sacrifice it. If you do, // you may cast the exiled card without paying its mana cost. - this.addAbility(new DealsCombatDamageTriggeredAbility(new LivingLoreSacrificeEffect(), true)); + this.addAbility(new DealsCombatDamageTriggeredAbility(new DoIfCostPaid( + new LivingLoreCastEffect(), new SacrificeSourceCost().setText("sacrifice it") + ), false)); } private LivingLore(final LivingLore card) { @@ -76,125 +85,82 @@ class LivingLoreExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId()); - if (sourcePermanent != null && controller != null) { - TargetCardInYourGraveyard target = new TargetCardInYourGraveyard( - new FilterInstantOrSorceryCard("instant or sorcery card from your graveyard")); - if (controller.chooseTarget(outcome, target, source, game)) { - UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), - game.getState().getZoneChangeCounter(source.getSourceId()) + 1); - Card card = controller.getGraveyard().get(target.getFirstTarget(), game); - if (card != null) { - controller.moveCardsToExile(card, source, game, true, exileId, - sourcePermanent.getIdName()); - } - } - return true; + if (controller == null) { + return false; } - return false; - } - -} - -class LivingLoreSetPowerToughnessSourceEffect extends ContinuousEffectImpl { - - public LivingLoreSetPowerToughnessSourceEffect() { - super(Duration.Custom, Layer.PTChangingEffects_7, SubLayer.SetPT_7b, Outcome.BoostCreature); - staticText = "{this}'s power and toughness are each equal to the exiled card's mana value"; - } - - public LivingLoreSetPowerToughnessSourceEffect(final LivingLoreSetPowerToughnessSourceEffect effect) { - super(effect); - } - - @Override - public LivingLoreSetPowerToughnessSourceEffect copy() { - return new LivingLoreSetPowerToughnessSourceEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); - int zcc = game.getState().getZoneChangeCounter(source.getSourceId()); - if (permanent == null) { - permanent = game.getPermanentEntering(source.getSourceId()); - zcc++; - } - if (permanent == null) { - return true; - } - UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), zcc); - if (exileId != null) { - ExileZone exileZone = game.getExile().getExileZone(exileId); - if (exileZone == null) { - return false; - } - Card exiledCard = null; - for (Card card : exileZone.getCards(game)) { - exiledCard = card; - break; - } - if (exiledCard != null) { - int value = exiledCard.getManaValue(); - permanent.getPower().setValue(value); - permanent.getToughness().setValue(value); - } + TargetCard target = new TargetCardInYourGraveyard( + StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD + ); + target.setNotTarget(true); + controller.chooseTarget(outcome, target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return false; } + controller.moveCardsToExile( + card, source, game, true, + CardUtil.getExileZoneId(game, source, 1), + CardUtil.getSourceName(game, source) + ); return true; } } -class LivingLoreSacrificeEffect extends OneShotEffect { +enum LivingLoreValue implements DynamicValue { + instance; - public LivingLoreSacrificeEffect() { - super(Outcome.PlayForFree); - this.staticText = "you may sacrifice it. If you do, you may cast " - + "the exiled card without paying its mana cost"; + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + int offset = game.getPermanent(sourceAbility.getSourceId()) != null ? 1 : 0; + ExileZone exileZone = game + .getExile() + .getExileZone(CardUtil.getExileZoneId(game, sourceAbility, offset)); + if (exileZone == null) { + return 0; + } + return exileZone + .getCards(game) + .stream() + .mapToInt(MageObject::getManaValue) + .sum(); } - public LivingLoreSacrificeEffect(final LivingLoreSacrificeEffect effect) { + @Override + public LivingLoreValue copy() { + return this; + } + + @Override + public String getMessage() { + return ""; + } +} + +class LivingLoreCastEffect extends OneShotEffect { + + LivingLoreCastEffect() { + super(Outcome.PlayForFree); + this.staticText = "you may cast the exiled card without paying its mana cost"; + } + + public LivingLoreCastEffect(final LivingLoreCastEffect effect) { super(effect); } @Override - public LivingLoreSacrificeEffect copy() { - return new LivingLoreSacrificeEffect(this); + public LivingLoreCastEffect copy() { + return new LivingLoreCastEffect(this); } @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - MageObject mageObject = source.getSourceObject(game); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null - && mageObject != null - && new MageObjectReference(permanent, game).refersTo(mageObject, game)) { - if (permanent.sacrifice(source, game)) { - UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), - source.getSourceObjectZoneChangeCounter()); - if (exileId != null) { - ExileZone exileZone = game.getExile().getExileZone(exileId); - Card exiledCard = null; - if (exileZone != null) { - for (Card card : exileZone.getCards(game)) { - exiledCard = card; - break; - } - } - if (exiledCard != null) { - if (exiledCard.getSpellAbility().canChooseTarget(game, controller.getId())) { - game.getState().setValue("PlayFromNotOwnHandZone" + exiledCard.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(exiledCard, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + exiledCard.getId(), null); - } - } - } - } - } - return true; - } - return false; + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source, -2)); + return controller != null + && exileZone != null + && !exileZone.isEmpty() + && CardUtil.castSpellWithAttributesForFree( + controller, source, game, new CardsImpl(exileZone), StaticFilters.FILTER_CARD + ); } } diff --git a/Mage.Sets/src/mage/cards/l/LivingWish.java b/Mage.Sets/src/mage/cards/l/LivingWish.java index 908e848bd46..c57235bde5f 100644 --- a/Mage.Sets/src/mage/cards/l/LivingWish.java +++ b/Mage.Sets/src/mage/cards/l/LivingWish.java @@ -8,8 +8,7 @@ import mage.abilities.hint.common.OpenSideboardHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; /** * @@ -17,19 +16,11 @@ import mage.filter.predicate.Predicates; */ public final class LivingWish extends CardImpl { - private static final FilterCard filter = new FilterCard("creature or land card"); - - static { - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.LAND.getPredicate())); - } - public LivingWish(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); // You may reveal a creature or land card you own from outside the game and put it into your hand. - this.getSpellAbility().addEffect(new WishEffect(filter)); + this.getSpellAbility().addEffect(new WishEffect(StaticFilters.FILTER_CARD_CREATURE_OR_LAND)); this.getSpellAbility().addHint(OpenSideboardHint.instance); // Exile Living Wish. diff --git a/Mage.Sets/src/mage/cards/l/LlanowarDruid.java b/Mage.Sets/src/mage/cards/l/LlanowarDruid.java index 1ed02835f1c..d30a37f1664 100644 --- a/Mage.Sets/src/mage/cards/l/LlanowarDruid.java +++ b/Mage.Sets/src/mage/cards/l/LlanowarDruid.java @@ -72,7 +72,7 @@ class LlanowarDruidEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanent.untap(game); } return true; diff --git a/Mage.Sets/src/mage/cards/l/LlanowarEmpath.java b/Mage.Sets/src/mage/cards/l/LlanowarEmpath.java index 6e205ca21cb..4d56a816d68 100644 --- a/Mage.Sets/src/mage/cards/l/LlanowarEmpath.java +++ b/Mage.Sets/src/mage/cards/l/LlanowarEmpath.java @@ -35,7 +35,7 @@ public final class LlanowarEmpath extends CardImpl { this.toughness = new MageInt(2); // When Llanowar Empath enters the battlefield, scry 2, then reveal the top card of your library. If it's a creature card, put it into your hand. - Ability ability = new EntersBattlefieldTriggeredAbility(new ScryEffect(2)); + Ability ability = new EntersBattlefieldTriggeredAbility(new ScryEffect(2, false)); ability.addEffect(new LlanowarEmpathEffect()); this.addAbility(ability); } @@ -68,7 +68,7 @@ class LlanowarEmpathEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Player controller = game.getPlayer(source.getControllerId()); if (controller == null || sourceObject == null) { return false; diff --git a/Mage.Sets/src/mage/cards/l/LlawanCephalidEmpress.java b/Mage.Sets/src/mage/cards/l/LlawanCephalidEmpress.java index e8820ad3939..d5f90562e65 100644 --- a/Mage.Sets/src/mage/cards/l/LlawanCephalidEmpress.java +++ b/Mage.Sets/src/mage/cards/l/LlawanCephalidEmpress.java @@ -91,7 +91,7 @@ class LlawanCephalidRuleModifyingEffect extends ContinuousRuleModifyingEffectImp @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast blue creature spells (" + mageObject.getLogName() + " in play)."; } diff --git a/Mage.Sets/src/mage/cards/l/Lobotomy.java b/Mage.Sets/src/mage/cards/l/Lobotomy.java index ecc9d919444..cf2aa8a9315 100644 --- a/Mage.Sets/src/mage/cards/l/Lobotomy.java +++ b/Mage.Sets/src/mage/cards/l/Lobotomy.java @@ -64,7 +64,7 @@ class LobotomyEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player targetPlayer = game.getPlayer(source.getFirstTarget()); Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (targetPlayer != null && sourceObject != null && controller != null) { // reveal hand of target player diff --git a/Mage.Sets/src/mage/cards/l/LolthSpiderQueen.java b/Mage.Sets/src/mage/cards/l/LolthSpiderQueen.java index 986ee74bd55..ed17d8a2a27 100644 --- a/Mage.Sets/src/mage/cards/l/LolthSpiderQueen.java +++ b/Mage.Sets/src/mage/cards/l/LolthSpiderQueen.java @@ -3,7 +3,6 @@ package mage.cards.l; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.DiesCreatureTriggeredAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -31,7 +30,7 @@ public final class LolthSpiderQueen extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.LOLTH); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // Whenever a creature you control dies, put a loyalty counter on Lolth, Spider Queen. this.addAbility(new DiesCreatureTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/l/LoneRevenant.java b/Mage.Sets/src/mage/cards/l/LoneRevenant.java index 3da6350b8e5..0e5bf3f7e80 100644 --- a/Mage.Sets/src/mage/cards/l/LoneRevenant.java +++ b/Mage.Sets/src/mage/cards/l/LoneRevenant.java @@ -1,31 +1,30 @@ - package mage.cards.l; import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.HexproofAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; +import mage.filter.StaticFilters; /** * - * @author jeffwadsworth + * @author awjackson */ public final class LoneRevenant extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, ComparisonType.EQUAL_TO, 0); + public LoneRevenant(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}"); this.subtype.add(SubType.SPIRIT); @@ -35,8 +34,17 @@ public final class LoneRevenant extends CardImpl { this.addAbility(HexproofAbility.getInstance()); - // Whenever Lone Revenant deals combat damage to a player, if you control no other creatures, look at the top four cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order. - this.addAbility(new LoneRevenantTriggeredAbility()); + // Whenever Lone Revenant deals combat damage to a player, + // if you control no other creatures, look at the top four cards of your library. + // Put one of them into your hand and the rest on the bottom of your library in any order. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new DealsCombatDamageToAPlayerTriggeredAbility( + new LookLibraryAndPickControllerEffect(4, 1, PutCards.HAND, PutCards.BOTTOM_ANY), + false + ), condition, "Whenever {this} deals combat damage to a player, " + + "if you control no other creatures, look at the top four cards of your library. " + + "Put one of them into your hand and the rest on the bottom of your library in any order." + )); } private LoneRevenant(final LoneRevenant card) { @@ -48,46 +56,3 @@ public final class LoneRevenant extends CardImpl { return new LoneRevenant(this); } } - -class LoneRevenantTriggeredAbility extends TriggeredAbilityImpl { - - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - - public LoneRevenantTriggeredAbility() { - super(Zone.BATTLEFIELD, new LookLibraryAndPickControllerEffect(StaticValue.get(4), false, StaticValue.get(1), new FilterCard(), Zone.LIBRARY, false, false)); - } - - public LoneRevenantTriggeredAbility(final LoneRevenantTriggeredAbility ability) { - super(ability); - } - - @Override - public LoneRevenantTriggeredAbility copy() { - return new LoneRevenantTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getSourceId().equals(this.sourceId) && ((DamagedPlayerEvent) event).isCombatDamage()) { - Permanent permanent = game.getPermanent(event.getSourceId()); - int number = game.getBattlefield().countAll(filter, controllerId, game); - - if (permanent != null && number != 1) { - return false; - } - return permanent != null || number == 0; - } - return false; - } - - @Override - public String getTriggerPhrase() { - return "Whenever {this} deals combat damage to a player, if you control no other creatures, " ; - } - -} diff --git a/Mage.Sets/src/mage/cards/l/LongRest.java b/Mage.Sets/src/mage/cards/l/LongRest.java index 6c33c98d469..0e06d2c73d2 100644 --- a/Mage.Sets/src/mage/cards/l/LongRest.java +++ b/Mage.Sets/src/mage/cards/l/LongRest.java @@ -64,7 +64,7 @@ class LongRestTarget extends TargetCardInYourGraveyard { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); Set manaValues = new HashSet<>(); for (UUID targetId : this.getTargets()) { @@ -73,7 +73,7 @@ class LongRestTarget extends TargetCardInYourGraveyard { manaValues.add(card.getManaValue()); } } - for (UUID possibleTargetId : super.possibleTargets(sourceId, sourceControllerId, game)) { + for (UUID possibleTargetId : super.possibleTargets(sourceControllerId, source, game)) { Card card = game.getCard(possibleTargetId); if (card != null && !manaValues.contains(card.getManaValue())) { possibleTargets.add(possibleTargetId); diff --git a/Mage.Sets/src/mage/cards/l/LongTermPlans.java b/Mage.Sets/src/mage/cards/l/LongTermPlans.java index 3b799b4e2a2..a5b82b22f8b 100644 --- a/Mage.Sets/src/mage/cards/l/LongTermPlans.java +++ b/Mage.Sets/src/mage/cards/l/LongTermPlans.java @@ -1,7 +1,5 @@ - package mage.cards.l; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -13,8 +11,9 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author emerald000 */ public final class LongTermPlans extends CardImpl { @@ -55,18 +54,16 @@ class LongTermPlansEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - TargetCardInLibrary target = new TargetCardInLibrary(); - if (player.searchLibrary(target, source, game)) { - Card card = player.getLibrary().remove(target.getFirstTarget(), game); - if (card != null) { - player.shuffleLibrary(source, game); - // must hides the card name from other players - player.putCardOnTopXOfLibrary(card, game, source, 3, false); - } - } - return true; + if (player == null) { + return false; } - return false; + TargetCardInLibrary target = new TargetCardInLibrary(); + player.searchLibrary(target, source, game); + Card card = player.getLibrary().getCard(target.getFirstTarget(), game); + player.shuffleLibrary(source, game); + if (card != null) { + player.putCardOnTopXOfLibrary(card, game, source, 3, false); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/l/LordOfShatterskullPass.java b/Mage.Sets/src/mage/cards/l/LordOfShatterskullPass.java index fce2b0ad845..090eec0977e 100644 --- a/Mage.Sets/src/mage/cards/l/LordOfShatterskullPass.java +++ b/Mage.Sets/src/mage/cards/l/LordOfShatterskullPass.java @@ -86,7 +86,7 @@ class LordOfShatterskullPassEffect extends OneShotEffect { if (defenderId != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent(); filter.add(new ControllerIdPredicate(defenderId)); - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); for (Permanent permanent : permanents) { permanent.damage(6, source.getSourceId(), source, game, false, true); } diff --git a/Mage.Sets/src/mage/cards/l/LordOfThePit.java b/Mage.Sets/src/mage/cards/l/LordOfThePit.java index bf22afa10eb..d0bb22f878d 100644 --- a/Mage.Sets/src/mage/cards/l/LordOfThePit.java +++ b/Mage.Sets/src/mage/cards/l/LordOfThePit.java @@ -80,8 +80,8 @@ class LordOfThePitEffect extends OneShotEffect { filter.add(AnotherPredicate.instance); Target target = new TargetControlledCreaturePermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + if (target.canChoose(player.getId(), source, game)) { + player.choose(Outcome.Sacrifice, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.sacrifice(source, game); diff --git a/Mage.Sets/src/mage/cards/l/LordOfTheUndead.java b/Mage.Sets/src/mage/cards/l/LordOfTheUndead.java index 1db05716b12..32f4233d3d5 100644 --- a/Mage.Sets/src/mage/cards/l/LordOfTheUndead.java +++ b/Mage.Sets/src/mage/cards/l/LordOfTheUndead.java @@ -1,27 +1,25 @@ - package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; 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.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreaturePermanent; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Loki */ public final class LordOfTheUndead extends CardImpl { @@ -34,16 +32,19 @@ public final class LordOfTheUndead extends CardImpl { } public LordOfTheUndead(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.ZOMBIE); this.power = new MageInt(2); this.toughness = new MageInt(2); // Other Zombie creatures get +1/+1. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, true))); + this.addAbility(new SimpleStaticAbility(new BoostAllEffect( + 1, 1, Duration.WhileOnBattlefield, filter, true + ))); + // {1}{B}, {tap}: Return target Zombie card from your graveyard to your hand. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{1}{B}")); + Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl<>("{1}{B}")); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCardInYourGraveyard(filterCard)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/l/LordWindgrace.java b/Mage.Sets/src/mage/cards/l/LordWindgrace.java index e57753a4106..b2308200308 100644 --- a/Mage.Sets/src/mage/cards/l/LordWindgrace.java +++ b/Mage.Sets/src/mage/cards/l/LordWindgrace.java @@ -4,7 +4,6 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyTargetEffect; @@ -42,7 +41,7 @@ public final class LordWindgrace extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.WINDGRACE); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +2: Discard a card, then draw a card. If a land card is discarded this way, draw an additional card. this.addAbility(new LoyaltyAbility(new LordWindgraceEffect(), 2)); diff --git a/Mage.Sets/src/mage/cards/l/LordXanderTheCollector.java b/Mage.Sets/src/mage/cards/l/LordXanderTheCollector.java new file mode 100644 index 00000000000..f9e4101f387 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LordXanderTheCollector.java @@ -0,0 +1,149 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LordXanderTheCollector extends CardImpl { + + public LordXanderTheCollector(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{B}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.DEMON); + this.subtype.add(SubType.NOBLE); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // When Lord Xander, the Collector enters the battlefield, target opponent discards half the cards in their hand, rounded down. + Ability ability = new EntersBattlefieldTriggeredAbility(LordXanderTheCollectorEffectType.DISCARD.makeEffect()); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + + // Whenever Lord Xander attacks, defending player mills half their library, rounded down. + this.addAbility(new AttacksTriggeredAbility( + LordXanderTheCollectorEffectType.MILL.makeEffect(), + false, null, SetTargetPointer.PLAYER + )); + + // When Lord Xander dies, target opponent sacrifices half the nonland permanents they control, rounded down. + ability = new DiesSourceTriggeredAbility(LordXanderTheCollectorEffectType.SACRIFICE.makeEffect()); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + private LordXanderTheCollector(final LordXanderTheCollector card) { + super(card); + } + + @Override + public LordXanderTheCollector copy() { + return new LordXanderTheCollector(this); + } +} + +enum LordXanderTheCollectorEffectType { + DISCARD, MILL, SACRIFICE; + + LordXanderTheCollectorEffect makeEffect() { + return new LordXanderTheCollectorEffect(this); + } +} + +class LordXanderTheCollectorEffect extends OneShotEffect { + private final LordXanderTheCollectorEffectType effectType; + + LordXanderTheCollectorEffect(LordXanderTheCollectorEffectType LordXanderTheCollectorEffectType) { + super(Outcome.Benefit); + this.effectType = LordXanderTheCollectorEffectType; + } + + private LordXanderTheCollectorEffect(final LordXanderTheCollectorEffect effect) { + super(effect); + this.effectType = effect.effectType; + } + + @Override + public LordXanderTheCollectorEffect copy() { + return new LordXanderTheCollectorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (player == null) { + return false; + } + int count; + switch (effectType) { + case DISCARD: + count = player.getHand().size(); + if (count < 2) { + return false; + } + player.discard(count / 2, false, false, source, game); + return true; + case MILL: + count = player.getLibrary().size(); + if (count < 2) { + return false; + } + player.millCards(count / 2, source, game); + return true; + case SACRIFICE: + count = game.getBattlefield().count( + StaticFilters.FILTER_CONTROLLED_PERMANENT_NON_LAND, player.getId(), source, game + ); + if (count < 2) { + return false; + } + TargetPermanent target = new TargetControlledPermanent( + count / 2, StaticFilters.FILTER_CONTROLLED_PERMANENT_NON_LAND + ); + target.setNotTarget(true); + target.withChooseHint("sacrifice"); + player.choose(outcome, target, source, game); + for (UUID permanentId : target.getTargets()) { + Permanent permanent = game.getPermanent(permanentId); + if (permanent != null) { + permanent.sacrifice(source, game); + } + } + return true; + } + return false; + } + + @Override + public String getText(Mode mode) { + switch (effectType) { + case DISCARD: + return "target opponent discards half the cards in their hand, rounded down"; + case MILL: + return "defending player mills half their library, rounded down"; + case SACRIFICE: + return "target opponent sacrifices half the nonland permanents they control, rounded down"; + } + return ""; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LoseFocus.java b/Mage.Sets/src/mage/cards/l/LoseFocus.java index 0c53eca9b6d..a517cb9a5ad 100644 --- a/Mage.Sets/src/mage/cards/l/LoseFocus.java +++ b/Mage.Sets/src/mage/cards/l/LoseFocus.java @@ -19,7 +19,7 @@ public final class LoseFocus extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Replicate {U} - this.addAbility(new ReplicateAbility(this, "{U}")); + this.addAbility(new ReplicateAbility("{U}")); // Counter target spell unless its controller pays {2}. this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(new GenericManaCost(2))); diff --git a/Mage.Sets/src/mage/cards/l/LostAuramancers.java b/Mage.Sets/src/mage/cards/l/LostAuramancers.java index c4d91966e90..68b695b7a64 100644 --- a/Mage.Sets/src/mage/cards/l/LostAuramancers.java +++ b/Mage.Sets/src/mage/cards/l/LostAuramancers.java @@ -86,6 +86,6 @@ class LostAuramancersAbility extends PutIntoGraveFromBattlefieldSourceTriggeredA @Override public String getRule() { - return "When {this} dies, if it had no time counters on it, you may search your library for an enchantment card and put it onto the battlefield. If you do, shuffle."; + return "When {this} dies, if it had no time counters on it, you may search your library for an enchantment card, put it onto the battlefield, then shuffle."; } } diff --git a/Mage.Sets/src/mage/cards/l/LostInTheWoods.java b/Mage.Sets/src/mage/cards/l/LostInTheWoods.java index 9f6d2e115e7..bbc4d0d2ca2 100644 --- a/Mage.Sets/src/mage/cards/l/LostInTheWoods.java +++ b/Mage.Sets/src/mage/cards/l/LostInTheWoods.java @@ -51,7 +51,7 @@ class LostInTheWoodsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject == null || controller == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/l/LostOrderOfJarkeld.java b/Mage.Sets/src/mage/cards/l/LostOrderOfJarkeld.java index b393e26c171..237a5619406 100644 --- a/Mage.Sets/src/mage/cards/l/LostOrderOfJarkeld.java +++ b/Mage.Sets/src/mage/cards/l/LostOrderOfJarkeld.java @@ -1,30 +1,29 @@ package mage.cards.l; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.AdditiveDynamicValue; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.ChooseOpponentEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.dynamicvalue.AdditiveDynamicValue; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.Effect; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** * @author TheElk801 */ public final class LostOrderOfJarkeld extends CardImpl { - protected FilterCreaturePermanent filter = new FilterCreaturePermanent(); - public LostOrderOfJarkeld(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); @@ -39,8 +38,9 @@ public final class LostOrderOfJarkeld extends CardImpl { // Lost Order of Jarkeld's power and toughness are each equal to 1 plus the number of creatures the chosen player controls. this.addAbility(new SimpleStaticAbility( Zone.ALL, - new SetPowerToughnessSourceEffect( - new AdditiveDynamicValue(new CreaturesControlledByChosenPlayer(), StaticValue.get(1)), Duration.EndOfGame) + new SetPowerToughnessSourceEffect(new AdditiveDynamicValue( + CreaturesControlledByChosenPlayer.instance, StaticValue.get(1) + ), Duration.EndOfGame) )); } @@ -54,7 +54,8 @@ public final class LostOrderOfJarkeld extends CardImpl { } } -class CreaturesControlledByChosenPlayer implements DynamicValue { +enum CreaturesControlledByChosenPlayer implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -70,7 +71,7 @@ class CreaturesControlledByChosenPlayer implements DynamicValue { @Override public CreaturesControlledByChosenPlayer copy() { - return new CreaturesControlledByChosenPlayer(); + return this; } @Override diff --git a/Mage.Sets/src/mage/cards/l/LotlethGiant.java b/Mage.Sets/src/mage/cards/l/LotlethGiant.java index 6bed0be0a87..aba511b5ca6 100644 --- a/Mage.Sets/src/mage/cards/l/LotlethGiant.java +++ b/Mage.Sets/src/mage/cards/l/LotlethGiant.java @@ -6,6 +6,7 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.common.DamageTargetEffect; +import mage.constants.AbilityWord; import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -33,7 +34,7 @@ public final class LotlethGiant extends CardImpl { StaticFilters.FILTER_CARD_CREATURE ), "it"), false); ability.addTarget(new TargetOpponent()); - ability.withFlavorWord("Undergrowth"); + ability.setAbilityWord(AbilityWord.UNDERGROWTH); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/LowlandOaf.java b/Mage.Sets/src/mage/cards/l/LowlandOaf.java index 83b598a6930..4a2b491377c 100644 --- a/Mage.Sets/src/mage/cards/l/LowlandOaf.java +++ b/Mage.Sets/src/mage/cards/l/LowlandOaf.java @@ -49,7 +49,7 @@ public final class LowlandOaf extends CardImpl { effect.setText("Target Goblin creature you control gets +1/+0"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost()); effect = new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn); - effect.setText("and gains flying until end of turn. "); + effect.setText("and gains flying until end of turn."); ability.addEffect(effect); ability.addEffect(new LowlandOafEffect()); ability.addTarget(new TargetCreaturePermanent(filter)); diff --git a/Mage.Sets/src/mage/cards/l/LoxodonPeacekeeper.java b/Mage.Sets/src/mage/cards/l/LoxodonPeacekeeper.java index d3d9f59c715..2ab58b39f5a 100644 --- a/Mage.Sets/src/mage/cards/l/LoxodonPeacekeeper.java +++ b/Mage.Sets/src/mage/cards/l/LoxodonPeacekeeper.java @@ -105,8 +105,8 @@ class LoxodonPeacekeeperEffect extends OneShotEffect { } } TargetPlayer target = new TargetPlayer(1, 1, true, filter); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - while (!target.isChosen() && target.canChoose(source.getSourceId(), controller.getId(), game) && controller.canRespond()) { + if (target.canChoose(controller.getId(), source, game)) { + while (!target.isChosen() && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target, source, game); } } else { diff --git a/Mage.Sets/src/mage/cards/l/LoyalSentry.java b/Mage.Sets/src/mage/cards/l/LoyalSentry.java index e5d2e0a825a..dc6fb19ff2e 100644 --- a/Mage.Sets/src/mage/cards/l/LoyalSentry.java +++ b/Mage.Sets/src/mage/cards/l/LoyalSentry.java @@ -1,10 +1,9 @@ - package mage.cards.l; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.common.BlocksSourceTriggeredAbility; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.effects.common.DestroySourceEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; @@ -27,8 +26,9 @@ public final class LoyalSentry extends CardImpl { this.toughness = new MageInt(1); // When Loyal Sentry blocks a creature, destroy that creature and Loyal Sentry. - Ability ability = new BlocksSourceTriggeredAbility(new DestroyTargetEffect().setText("destroy that creature"), false, true, true); + TriggeredAbility ability = new BlocksCreatureTriggeredAbility(new DestroyTargetEffect().setText("destroy that creature")); ability.addEffect(new DestroySourceEffect().setText("and {this}")); + ability.setTriggerPhrase("When {this} blocks a creature, "); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/l/Lucille.java b/Mage.Sets/src/mage/cards/l/Lucille.java index 2a8babc4bd5..a1018db8978 100644 --- a/Mage.Sets/src/mage/cards/l/Lucille.java +++ b/Mage.Sets/src/mage/cards/l/Lucille.java @@ -83,10 +83,10 @@ class LucilleEffect extends OneShotEffect { } TargetPermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), player.getId(), game)) { + if (!target.canChoose(player.getId(), source, game)) { return false; } - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); return permanent.sacrifice(source, game) && new WalkerToken().putOntoBattlefield(1, game, source, source.getControllerId() diff --git a/Mage.Sets/src/mage/cards/l/LukeSkywalkerTheLastJedi.java b/Mage.Sets/src/mage/cards/l/LukeSkywalkerTheLastJedi.java index 108eaadae30..610f5c67943 100644 --- a/Mage.Sets/src/mage/cards/l/LukeSkywalkerTheLastJedi.java +++ b/Mage.Sets/src/mage/cards/l/LukeSkywalkerTheLastJedi.java @@ -4,7 +4,6 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.ExileSourceEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.PutOnLibraryTargetEffect; @@ -38,7 +37,7 @@ public final class LukeSkywalkerTheLastJedi extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.LUKE); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Put two +1/+1 counters on up to one target creature. Ability ability1 = new LoyaltyAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)), 2); diff --git a/Mage.Sets/src/mage/cards/l/LukkaCoppercoatOutcast.java b/Mage.Sets/src/mage/cards/l/LukkaCoppercoatOutcast.java index 0cfdb483c9b..b38b7b3e108 100644 --- a/Mage.Sets/src/mage/cards/l/LukkaCoppercoatOutcast.java +++ b/Mage.Sets/src/mage/cards/l/LukkaCoppercoatOutcast.java @@ -2,7 +2,6 @@ package mage.cards.l; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; @@ -33,7 +32,7 @@ public final class LukkaCoppercoatOutcast extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.LUKKA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Exile the top three cards of your library. Creature cards exiled this way gain "You may cast this card from exile as long as you control a Lukka planeswalker." this.addAbility(new LoyaltyAbility(new LukkaCoppercoatOutcastExileEffect(), 1)); diff --git a/Mage.Sets/src/mage/cards/l/LumberingBattlement.java b/Mage.Sets/src/mage/cards/l/LumberingBattlement.java index 76767b99897..43a0161993f 100644 --- a/Mage.Sets/src/mage/cards/l/LumberingBattlement.java +++ b/Mage.Sets/src/mage/cards/l/LumberingBattlement.java @@ -106,7 +106,7 @@ class LumberingBattlementEffect extends OneShotEffect { return false; } Target target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); - if (!player.choose(Outcome.Neutral, target, source.getSourceId(), game)) { + if (!player.choose(Outcome.Neutral, target, source, game)) { return false; } Set cards = new HashSet<>(); diff --git a/Mage.Sets/src/mage/cards/l/LumengridDrake.java b/Mage.Sets/src/mage/cards/l/LumengridDrake.java index c97c60d14ee..d1e5d6e8178 100644 --- a/Mage.Sets/src/mage/cards/l/LumengridDrake.java +++ b/Mage.Sets/src/mage/cards/l/LumengridDrake.java @@ -22,7 +22,7 @@ import java.util.UUID; */ public final class LumengridDrake extends CardImpl { - private static final String ruleText = "Metalcraft — When {this} enters the battlefield, if you control three or more artifacts, return target creature to its owner's hand."; + private static final String ruleText = "When {this} enters the battlefield, if you control three or more artifacts, return target creature to its owner's hand."; public LumengridDrake(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); diff --git a/Mage.Sets/src/mage/cards/l/LuminatePrimordial.java b/Mage.Sets/src/mage/cards/l/LuminatePrimordial.java index c46a57342e7..f0e2304b9cc 100644 --- a/Mage.Sets/src/mage/cards/l/LuminatePrimordial.java +++ b/Mage.Sets/src/mage/cards/l/LuminatePrimordial.java @@ -13,6 +13,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Controllable; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -98,19 +99,23 @@ class LuminatePrimordialEffect extends OneShotEffect { Set permanents = source .getTargets() .stream() - .map(Target::getFirstTarget) + .map(Target::getTargets) + .flatMap(Collection::stream) .map(game::getPermanent) .filter(Objects::nonNull) .collect(Collectors.toSet()); - Map map = new HashMap<>(); - permanents.stream().map(p -> map.put(p.getControllerId(), p.getPower().getValue())); + Map map = permanents + .stream() + .collect(Collectors.toMap( + Controllable::getControllerId, + permanent -> permanent.getPower().getValue() + )); controller.moveCards(permanents, Zone.EXILED, source, game); for (Map.Entry entry : map.entrySet()) { Player player = game.getPlayer(entry.getKey()); - if (player == null || entry.getValue() < 1) { - continue; + if (player != null && entry.getValue() > 0) { + player.gainLife(entry.getValue(), game, source); } - player.gainLife(entry.getValue(), game, source); } return true; } diff --git a/Mage.Sets/src/mage/cards/l/LuminescentRain.java b/Mage.Sets/src/mage/cards/l/LuminescentRain.java index ea5c1580f91..8f656a804b1 100644 --- a/Mage.Sets/src/mage/cards/l/LuminescentRain.java +++ b/Mage.Sets/src/mage/cards/l/LuminescentRain.java @@ -59,7 +59,7 @@ class LuminescentRainEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Choice typeChoice = new ChoiceCreatureType(game.getObject(source.getSourceId())); + Choice typeChoice = new ChoiceCreatureType(game.getObject(source)); if (player != null && player.choose(Outcome.BoostCreature, typeChoice, game)) { FilterControlledPermanent filter = new FilterControlledPermanent(); filter.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); diff --git a/Mage.Sets/src/mage/cards/l/LumithreadField.java b/Mage.Sets/src/mage/cards/l/LumithreadField.java index 401ac81f3ad..9534763ff0b 100644 --- a/Mage.Sets/src/mage/cards/l/LumithreadField.java +++ b/Mage.Sets/src/mage/cards/l/LumithreadField.java @@ -25,7 +25,7 @@ public final class LumithreadField extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(0, 1, Duration.WhileOnBattlefield))); // Morph {1}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{W}"))); } private LumithreadField(final LumithreadField card) { diff --git a/Mage.Sets/src/mage/cards/l/LurkingPredators.java b/Mage.Sets/src/mage/cards/l/LurkingPredators.java index e9adf690e58..95777916ff9 100644 --- a/Mage.Sets/src/mage/cards/l/LurkingPredators.java +++ b/Mage.Sets/src/mage/cards/l/LurkingPredators.java @@ -59,7 +59,7 @@ class LurkingPredatorsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/l/LuxiorGiadasGift.java b/Mage.Sets/src/mage/cards/l/LuxiorGiadasGift.java new file mode 100644 index 00000000000..e26cbd048f3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LuxiorGiadasGift.java @@ -0,0 +1,125 @@ +package mage.cards.l; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.Counter; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.*; +import java.util.stream.IntStream; + +/** + * @author TheElk801 + */ +public final class LuxiorGiadasGift extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPlaneswalkerPermanent("planeswalker"); + + public LuxiorGiadasGift(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature gets +1/+1 for each counter on it. + this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect( + LuxiorGiadasGiftValue.instance, LuxiorGiadasGiftValue.instance + ))); + + // Equipped permanent isn't a planeswalker and is a creature in addition to its other types. + this.addAbility(new SimpleStaticAbility(new LuxiorGiadasGiftEffect())); + + // Equip planeswalker {1} + this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(1), new TargetPermanent(filter))); + + // Equip {3} + this.addAbility(new EquipAbility(3)); + } + + private LuxiorGiadasGift(final LuxiorGiadasGift card) { + super(card); + } + + @Override + public LuxiorGiadasGift copy() { + return new LuxiorGiadasGift(this); + } +} + +enum LuxiorGiadasGiftValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return Optional.of(sourceAbility.getSourcePermanentIfItStillExists(game)) + .filter(Objects::nonNull) + .map(Permanent::getAttachedTo) + .map(game::getPermanent) + .filter(Objects::nonNull) + .map(permanent -> permanent.getCounters(game)) + .map(HashMap::values) + .map(Collection::stream) + .map(x -> x.mapToInt(Counter::getCount)) + .map(IntStream::sum) + .orElse(0); + } + + @Override + public LuxiorGiadasGiftValue copy() { + return this; + } + + @Override + public String getMessage() { + return "counter on it"; + } + + @Override + public String toString() { + return "1"; + } +} + +class LuxiorGiadasGiftEffect extends ContinuousEffectImpl { + + LuxiorGiadasGiftEffect() { + super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); + staticText = "equipped permanent isn't a planeswalker and is a creature in addition to its other types"; + } + + private LuxiorGiadasGiftEffect(final LuxiorGiadasGiftEffect effect) { + super(effect); + } + + @Override + public LuxiorGiadasGiftEffect copy() { + return new LuxiorGiadasGiftEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Optional.of(source.getSourcePermanentIfItStillExists(game)) + .filter(Objects::nonNull) + .map(Permanent::getAttachedTo) + .map(game::getPermanent) + .ifPresent(permanent -> { + permanent.removeCardType(game, CardType.PLANESWALKER); + permanent.removeAllSubTypes(game, SubTypeSet.PlaneswalkerType); + permanent.addCardType(game, CardType.CREATURE); + }); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LuxuriousLibation.java b/Mage.Sets/src/mage/cards/l/LuxuriousLibation.java new file mode 100644 index 00000000000..8d1a47af15b --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LuxuriousLibation.java @@ -0,0 +1,39 @@ +package mage.cards.l; + +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.game.permanent.token.CitizenGreenWhiteToken; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LuxuriousLibation extends CardImpl { + + public LuxuriousLibation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{G}"); + + // Target creature gets +X/+X until end of turn. Create a 1/1 green and white Citizen creature token. + this.getSpellAbility().addEffect(new BoostTargetEffect( + ManacostVariableValue.REGULAR, ManacostVariableValue.REGULAR, Duration.EndOfTurn + )); + this.getSpellAbility().addEffect(new CreateTokenEffect(new CitizenGreenWhiteToken())); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private LuxuriousLibation(final LuxuriousLibation card) { + super(card); + } + + @Override + public LuxuriousLibation copy() { + return new LuxuriousLibation(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LyevDecree.java b/Mage.Sets/src/mage/cards/l/LyevDecree.java index 1032a08f8cd..e51bf2f9045 100644 --- a/Mage.Sets/src/mage/cards/l/LyevDecree.java +++ b/Mage.Sets/src/mage/cards/l/LyevDecree.java @@ -1,5 +1,3 @@ - - package mage.cards.l; import java.util.UUID; @@ -7,32 +5,21 @@ import mage.abilities.effects.common.DetainTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; -import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; /** * * @author LevelX2 */ - public final class LyevDecree extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponents control"); - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public LyevDecree(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{W}"); - // Detain up to two target creatures your opponents control. this.getSpellAbility().addEffect(new DetainTargetEffect()); - Target target = new TargetCreaturePermanent(0,2,filter,false); - this.getSpellAbility().addTarget(target); + this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent(0, 2)); } private LyevDecree(final LyevDecree card) { @@ -43,5 +30,4 @@ public final class LyevDecree extends CardImpl { public LyevDecree copy() { return new LyevDecree(this); } - } diff --git a/Mage.Sets/src/mage/cards/m/Machinate.java b/Mage.Sets/src/mage/cards/m/Machinate.java index 7d1914214a5..d5523806106 100644 --- a/Mage.Sets/src/mage/cards/m/Machinate.java +++ b/Mage.Sets/src/mage/cards/m/Machinate.java @@ -1,36 +1,31 @@ - package mage.cards.m; import java.util.UUID; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; -import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.common.FilterControlledPermanent; +import mage.filter.StaticFilters; /** * * @author Alexsandr0x */ public final class Machinate extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("artifacts you control"); - static { - filter.add(CardType.ARTIFACT.getPredicate()); - } + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACTS, null); public Machinate(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{U}"); // Look at the top X cards of your library, where X is the number of artifacts you control. Put one of those cards into your hand and the rest on the bottom of your library in any order. - DynamicValue artifactsOnControl = new PermanentsOnBattlefieldCount(filter); - LookLibraryAndPickControllerEffect effect = new LookLibraryAndPickControllerEffect(artifactsOnControl, false, StaticValue.get(1), new FilterCard(), Zone.LIBRARY, false, false); - effect.setText("Look at the top X cards of your library, where X is the number of artifacts you control. Put one of those cards into your hand and the rest on the bottom of your library in any order."); + Effect effect = new LookLibraryAndPickControllerEffect(xValue, 1, PutCards.HAND, PutCards.BOTTOM_ANY); + effect.setText("look at the top X cards of your library, where X is the number of artifacts you control. " + + "Put one of those cards into your hand and the rest on the bottom of your library in any order"); this.getSpellAbility().addEffect(effect); } diff --git a/Mage.Sets/src/mage/cards/m/MaddeningImp.java b/Mage.Sets/src/mage/cards/m/MaddeningImp.java index 59d88458f8e..2fe231c94ee 100644 --- a/Mage.Sets/src/mage/cards/m/MaddeningImp.java +++ b/Mage.Sets/src/mage/cards/m/MaddeningImp.java @@ -118,7 +118,7 @@ class MaddeningImpCreateDelayedTriggeredAbilityEffect extends OneShotEffect { } } AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility - = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone.ALL, new MaddeningImpDelayedDestroyEffect(activeCreatures), TargetController.ANY, new InvertCondition(TargetAttackedThisTurnCondition.instance)); + = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new MaddeningImpDelayedDestroyEffect(activeCreatures), TargetController.ANY, new InvertCondition(TargetAttackedThisTurnCondition.instance)); delayedAbility.getDuration(); game.addDelayedTriggeredAbility(delayedAbility, source); return true; diff --git a/Mage.Sets/src/mage/cards/m/MadrushCyclops.java b/Mage.Sets/src/mage/cards/m/MadrushCyclops.java index 321c7c410c8..d5dc0370df1 100644 --- a/Mage.Sets/src/mage/cards/m/MadrushCyclops.java +++ b/Mage.Sets/src/mage/cards/m/MadrushCyclops.java @@ -1,8 +1,5 @@ - - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -10,32 +7,32 @@ import mage.abilities.keyword.HasteAbility; 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.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author Loki */ public final class MadrushCyclops extends CardImpl { - public MadrushCyclops (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{R}{G}"); + public MadrushCyclops(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{R}{G}"); this.subtype.add(SubType.CYCLOPS); this.subtype.add(SubType.WARRIOR); - - - this.power = new MageInt(3); this.toughness = new MageInt(4); - + // Creatures you control have haste. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield, new FilterCreaturePermanent()))); + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + HasteAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_CREATURES + ))); } - public MadrushCyclops (final MadrushCyclops card) { + public MadrushCyclops(final MadrushCyclops card) { super(card); } @@ -43,5 +40,4 @@ public final class MadrushCyclops extends CardImpl { public MadrushCyclops copy() { return new MadrushCyclops(this); } - } diff --git a/Mage.Sets/src/mage/cards/m/MaelstromArchangel.java b/Mage.Sets/src/mage/cards/m/MaelstromArchangel.java index 2385d6d5961..e0cecd87b5e 100644 --- a/Mage.Sets/src/mage/cards/m/MaelstromArchangel.java +++ b/Mage.Sets/src/mage/cards/m/MaelstromArchangel.java @@ -1,31 +1,24 @@ package mage.cards.m; -import java.util.UUID; -import mage.ApprovingObject; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.cost.CastFromHandForFreeEffect; import mage.abilities.keyword.FlyingAbility; -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.filter.FilterCard; -import mage.filter.common.FilterNonlandCard; -import mage.game.Game; -import mage.players.Player; -import mage.target.Target; -import mage.target.common.TargetCardInHand; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class MaelstromArchangel extends CardImpl { + private static final FilterCard filter = new FilterCard("a spell"); + public MaelstromArchangel(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}{B}{R}{G}"); this.subtype.add(SubType.ANGEL); @@ -37,8 +30,7 @@ public final class MaelstromArchangel extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever Maelstrom Archangel deals combat damage to a player, you may cast a nonland card from your hand without paying its mana cost. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new MaelstromArchangelCastEffect(), false)); - + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new CastFromHandForFreeEffect(filter), false)); } private MaelstromArchangel(final MaelstromArchangel card) { @@ -50,53 +42,3 @@ public final class MaelstromArchangel extends CardImpl { return new MaelstromArchangel(this); } } - -class MaelstromArchangelCastEffect extends OneShotEffect { - - private static final FilterCard filter = new FilterNonlandCard("spell from your hand"); - - public MaelstromArchangelCastEffect() { - super(Outcome.PlayForFree); - this.staticText = "you may cast a spell from your hand without paying its mana cost"; - } - - public MaelstromArchangelCastEffect(final MaelstromArchangelCastEffect effect) { - super(effect); - } - - @Override - public MaelstromArchangelCastEffect copy() { - return new MaelstromArchangelCastEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Target target = new TargetCardInHand(filter); - if (target.canChoose(source.getSourceId(), controller.getId(), game) - && controller.chooseUse(outcome, "Cast a spell from your hand without paying its mana cost?", source, game)) { - Card cardToCast = null; - boolean cancel = false; - while (controller.canRespond() && !cancel) { - if (controller.chooseTarget(outcome, target, source, game)) { - cardToCast = game.getCard(target.getFirstTarget()); - if (cardToCast != null && cardToCast.getSpellAbility().canChooseTarget(game, controller.getId())) { - cancel = true; - } - } else { - cancel = true; - } - } - if (cardToCast != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(cardToCast, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), null); - } - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/m/MaelstromDjinn.java b/Mage.Sets/src/mage/cards/m/MaelstromDjinn.java index 96c5ec2a88d..a0998a4d4bb 100644 --- a/Mage.Sets/src/mage/cards/m/MaelstromDjinn.java +++ b/Mage.Sets/src/mage/cards/m/MaelstromDjinn.java @@ -35,7 +35,7 @@ public final class MaelstromDjinn extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Morph {2}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{U}"))); // When Maelstrom Djinn is turned face up, put two time counters on it and it gains vanishing. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new AddCountersSourceEffect(CounterType.TIME.createInstance(2))); Effect effect = new GainAbilitySourceEffect(new VanishingUpkeepAbility(0), Duration.WhileOnBattlefield); diff --git a/Mage.Sets/src/mage/cards/m/MaestrosAscendancy.java b/Mage.Sets/src/mage/cards/m/MaestrosAscendancy.java new file mode 100644 index 00000000000..80d9f158113 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaestrosAscendancy.java @@ -0,0 +1,182 @@ +package mage.cards.m; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.Costs; +import mage.abilities.costs.CostsImpl; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.players.Player; +import mage.watchers.Watcher; + +import java.util.*; + +/** + * @author TheElk801 + */ +public final class MaestrosAscendancy extends CardImpl { + + public MaestrosAscendancy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}{B}{R}"); + + // Once during each of your turns, you may cast an instant or sorcery spell from your graveyard by sacrificing a creature in addition to paying its other costs. If a spell cast this way would be put into your graveyard, exile it instead. + Ability ability = new SimpleStaticAbility(new MaestrosAscendancyCastEffect()); + ability.addEffect(new MaestrosAscendancyExileEffect()); + this.addAbility(ability, new MaestrosAscendancyWatcher()); + } + + private MaestrosAscendancy(final MaestrosAscendancy card) { + super(card); + } + + @Override + public MaestrosAscendancy copy() { + return new MaestrosAscendancy(this); + } +} + +class MaestrosAscendancyCastEffect extends AsThoughEffectImpl { + + MaestrosAscendancyCastEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.AIDontUseIt); + staticText = "once during each of your turns, you may cast an instant or sorcery spell " + + "from your graveyard by sacrificing a creature in addition to paying its other costs."; + } + + private MaestrosAscendancyCastEffect(final MaestrosAscendancyCastEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public MaestrosAscendancyCastEffect copy() { + return new MaestrosAscendancyCastEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + if (!source.isControlledBy(affectedControllerId) + || !game.isActivePlayer(affectedControllerId)) { + return false; + } + Card card = game.getCard(objectId); + Player player = game.getPlayer(affectedControllerId); + if (card == null + || player == null + || !card.isOwnedBy(affectedControllerId) + || !card.isInstantOrSorcery(game) + || !game.getState().getZone(objectId).match(Zone.GRAVEYARD) + || !MaestrosAscendancyWatcher.checkPlayer(source, game)) { + return false; + } + Costs newCosts = new CostsImpl<>(); + newCosts.addAll(card.getSpellAbility().getCosts()); + newCosts.add(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT)); + player.setCastSourceIdWithAlternateMana(card.getId(), card.getManaCost(), newCosts); + return true; + } +} + +class MaestrosAscendancyExileEffect extends ReplacementEffectImpl { + + MaestrosAscendancyExileEffect() { + super(Duration.WhileOnBattlefield, Outcome.Exile); + staticText = "If a spell cast this way would be put into your graveyard, exile it instead"; + } + + private MaestrosAscendancyExileEffect(final MaestrosAscendancyExileEffect effect) { + super(effect); + } + + @Override + public MaestrosAscendancyExileEffect copy() { + return new MaestrosAscendancyExileEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + Card card = game.getCard(event.getTargetId()); + return controller != null && card != null + && controller.moveCards(card, Zone.EXILED, source, game); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + return zEvent.getToZone() == Zone.GRAVEYARD + && MaestrosAscendancyWatcher.checkSpell(zEvent.getTargetId(), source, game); + } +} + +class MaestrosAscendancyWatcher extends Watcher { + + private final Map> playerMap = new HashMap<>(); + private final Map> spellMap = new HashMap<>(); + + MaestrosAscendancyWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.SPELL_CAST + && event.getAdditionalReference() != null) { + playerMap.computeIfAbsent( + event.getAdditionalReference() + .getApprovingMageObjectReference(), + x -> new HashSet<>() + ).add(event.getPlayerId()); + spellMap.computeIfAbsent( + event.getAdditionalReference() + .getApprovingMageObjectReference(), + x -> new HashSet<>() + ).add(new MageObjectReference(event.getTargetId(), game)); + } + } + + @Override + public void reset() { + super.reset(); + playerMap.clear(); + spellMap.clear(); + } + + static boolean checkPlayer(Ability source, Game game) { + return game + .getState() + .getWatcher(MaestrosAscendancyWatcher.class) + .playerMap + .getOrDefault(new MageObjectReference(source), Collections.emptySet()) + .contains(source.getControllerId()); + } + + static boolean checkSpell(UUID id, Ability source, Game game) { + return game + .getState() + .getWatcher(MaestrosAscendancyWatcher.class) + .spellMap + .getOrDefault(new MageObjectReference(source), Collections.emptySet()) + .contains(new MageObjectReference(id, game)); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MaestrosCharm.java b/Mage.Sets/src/mage/cards/m/MaestrosCharm.java new file mode 100644 index 00000000000..4539577dd4f --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaestrosCharm.java @@ -0,0 +1,49 @@ +package mage.cards.m; + +import mage.abilities.Mode; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MaestrosCharm extends CardImpl { + + public MaestrosCharm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}{B}{R}"); + + // Choose one — + // • Look at the top five cards of your library. Put one of those cards into your hand and the rest into your graveyard. + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(5, 1, PutCards.HAND, PutCards.GRAVEYARD) + .setText("look at the top five cards of your library. " + + "Put one of those cards into your hand and the rest into your graveyard")); + + // • Each opponent loses 3 life and you gain 3 life. + Mode mode = new Mode(new LoseLifeOpponentsEffect(3)); + mode.addEffect(new GainLifeEffect(3).concatBy("and")); + this.getSpellAbility().addMode(mode); + + // • Maestros Charm deals 5 damage to target creature or planeswalker. + mode = new Mode(new DamageTargetEffect(5)); + mode.addTarget(new TargetCreatureOrPlaneswalker()); + this.getSpellAbility().addMode(mode); + } + + private MaestrosCharm(final MaestrosCharm card) { + super(card); + } + + @Override + public MaestrosCharm copy() { + return new MaestrosCharm(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MaestrosConfluence.java b/Mage.Sets/src/mage/cards/m/MaestrosConfluence.java new file mode 100644 index 00000000000..cd3ab2d3321 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaestrosConfluence.java @@ -0,0 +1,94 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.effects.common.combat.GoadTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.predicate.mageobject.MonocoloredPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MaestrosConfluence extends CardImpl { + + private static final FilterCard filter + = new FilterInstantOrSorceryCard("monocolored instant or sorcery card from your graveyard"); + + static { + filter.add(MonocoloredPredicate.instance); + } + + public MaestrosConfluence(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}{B}{R}"); + + // 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); + + // • Return target monocolored instant or sorcery card from your graveyard to your hand. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); + + // • Target creature gets -3/-3 until end of turn. + this.getSpellAbility().addMode(new Mode( + new BoostTargetEffect(-3, -3) + ).addTarget(new TargetCreaturePermanent())); + + // • Goad each creature target player controls. + this.getSpellAbility().addMode(new Mode(new MaestrosConfluenceEffect()).addTarget(new TargetPlayer())); + } + + private MaestrosConfluence(final MaestrosConfluence card) { + super(card); + } + + @Override + public MaestrosConfluence copy() { + return new MaestrosConfluence(this); + } +} + +class MaestrosConfluenceEffect extends OneShotEffect { + + MaestrosConfluenceEffect() { + super(Outcome.Benefit); + staticText = "goad each creature target player controls"; + } + + private MaestrosConfluenceEffect(final MaestrosConfluenceEffect effect) { + super(effect); + } + + @Override + public MaestrosConfluenceEffect copy() { + return new MaestrosConfluenceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, source.getFirstTarget(), source, game + )) { + game.addEffect(new GoadTargetEffect().setTargetPointer(new FixedTarget(permanent, game)), source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MaestrosDiabolist.java b/Mage.Sets/src/mage/cards/m/MaestrosDiabolist.java new file mode 100644 index 00000000000..85596a1765f --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaestrosDiabolist.java @@ -0,0 +1,69 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.DevilToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MaestrosDiabolist extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.DEVIL); + + static { + filter.add(TokenPredicate.TRUE); + } + + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0); + + public MaestrosDiabolist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{B}{R}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Whenever Maestros Diabolist attacks, if you don't control a Devil token, create a tapped and attacking 1/1 red Devil creature token with "When this creature dies, it deals 1 damage to any target." + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new AttacksTriggeredAbility( + new CreateTokenEffect(new DevilToken(), 1, true, true) + ), condition, "Whenever {this} attacks, if you don't control a Devil token, " + + "create a tapped and attacking 1/1 red Devil creature token with " + + "\"When this creature dies, it deals 1 damage to any target.\"" + )); + } + + private MaestrosDiabolist(final MaestrosDiabolist card) { + super(card); + } + + @Override + public MaestrosDiabolist copy() { + return new MaestrosDiabolist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MaestrosInitiate.java b/Mage.Sets/src/mage/cards/m/MaestrosInitiate.java new file mode 100644 index 00000000000..da18eef2ddc --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaestrosInitiate.java @@ -0,0 +1,48 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.ExileSourceFromGraveCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MaestrosInitiate extends CardImpl { + + public MaestrosInitiate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // {4}{U/R}, Exile Maestros Initiate from your graveyard: Draw two cards, then discard a card. + Ability ability = new SimpleActivatedAbility( + Zone.GRAVEYARD, + new DrawDiscardControllerEffect(2, 1), + new ManaCostsImpl<>("{4}{U/R}") + ); + ability.addCost(new ExileSourceFromGraveCost()); + this.addAbility(ability); + } + + private MaestrosInitiate(final MaestrosInitiate card) { + super(card); + } + + @Override + public MaestrosInitiate copy() { + return new MaestrosInitiate(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MaestrosTheater.java b/Mage.Sets/src/mage/cards/m/MaestrosTheater.java new file mode 100644 index 00000000000..9fe34869dac --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaestrosTheater.java @@ -0,0 +1,57 @@ +package mage.cards.m; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.effects.common.DoWhenCostPaid; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MaestrosTheater extends CardImpl { + + private static final FilterCard filter = new FilterCard("a basic Island, Swamp, or Mountain card"); + + static { + filter.add(SuperType.BASIC.getPredicate()); + filter.add(Predicates.or( + SubType.ISLAND.getPredicate(), + SubType.SWAMP.getPredicate(), + SubType.MOUNTAIN.getPredicate() + )); + } + + public MaestrosTheater(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // When Maestros Theater enters the battlefield, sacrifice it. When you do, search your library for a basic Island, Swamp, or Mountain card, put it onto the battlefield tapped, then shuffle and you gain 1 life. + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new SearchLibraryPutInPlayEffect( + new TargetCardInLibrary(filter), true, true + ), false); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DoWhenCostPaid( + ability, new SacrificeSourceCost().setText("sacrifice it"), null, false + ))); + } + + private MaestrosTheater(final MaestrosTheater card) { + super(card); + } + + @Override + public MaestrosTheater copy() { + return new MaestrosTheater(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MageSlayer.java b/Mage.Sets/src/mage/cards/m/MageSlayer.java index 7aad17b500c..a19286ecf4d 100644 --- a/Mage.Sets/src/mage/cards/m/MageSlayer.java +++ b/Mage.Sets/src/mage/cards/m/MageSlayer.java @@ -47,7 +47,7 @@ class MageSlayerEffect extends OneShotEffect { public MageSlayerEffect() { super(Outcome.Damage); - staticText = "it deals damage equal to the player or planeswalker it's attacking"; + staticText = "it deals damage equal to its power to the player or planeswalker it's attacking"; } public MageSlayerEffect(final MageSlayerEffect effect) { diff --git a/Mage.Sets/src/mage/cards/m/MagefireWings.java b/Mage.Sets/src/mage/cards/m/MagefireWings.java index 0362b9fd073..6f56ccc17bc 100644 --- a/Mage.Sets/src/mage/cards/m/MagefireWings.java +++ b/Mage.Sets/src/mage/cards/m/MagefireWings.java @@ -1,8 +1,5 @@ - - package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; @@ -12,38 +9,36 @@ import mage.abilities.keyword.EnchantAbility; 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.constants.*; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class MagefireWings extends CardImpl { - public MagefireWings (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{U}{R}"); + public MagefireWings(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}{R}"); this.subtype.add(SubType.AURA); - - TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, 0, Duration.WhileOnBattlefield))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA))); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect( + 2, 0, Duration.WhileOnBattlefield + )); + ability.addEffect(new GainAbilityAttachedEffect( + FlyingAbility.getInstance(), AttachmentType.AURA + ).setText("and has flying")); + this.addAbility(ability); } - public MagefireWings (final MagefireWings card) { + public MagefireWings(final MagefireWings card) { super(card); } @@ -51,5 +46,4 @@ public final class MagefireWings extends CardImpl { public MagefireWings copy() { return new MagefireWings(this); } - } diff --git a/Mage.Sets/src/mage/cards/m/MagesAttendant.java b/Mage.Sets/src/mage/cards/m/MagesAttendant.java new file mode 100644 index 00000000000..d2a65389b58 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MagesAttendant.java @@ -0,0 +1,39 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.MagesAttendantToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MagesAttendant extends CardImpl { + + public MagesAttendant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // When Mage's Attendant enters the battlefield, create a 1/1 blue Wizard creature token with "{1}, Sacrifice this creature: Counter target noncreature spell unless its controller pays {1}." + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new MagesAttendantToken()))); + } + + private MagesAttendant(final MagesAttendant card) { + super(card); + } + + @Override + public MagesAttendant copy() { + return new MagesAttendant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MagisterOfWorth.java b/Mage.Sets/src/mage/cards/m/MagisterOfWorth.java index e17c33b70c9..19504f0e93d 100644 --- a/Mage.Sets/src/mage/cards/m/MagisterOfWorth.java +++ b/Mage.Sets/src/mage/cards/m/MagisterOfWorth.java @@ -11,10 +11,7 @@ import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.choices.TwoChoiceVote; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; @@ -42,7 +39,7 @@ public final class MagisterOfWorth extends CardImpl { // Will of the council - When Magister of Worth enters the battlefield, starting with you, each player votes for grace or condemnation. If grace gets more votes, each player returns each creature card from their graveyard to the battlefield. If condemnation gets more votes or the vote is tied, destroy all creatures other than Magister of Worth. this.addAbility(new EntersBattlefieldTriggeredAbility( new MagisterOfWorthEffect(), false) - .withFlavorWord("Will of the council") + .setAbilityWord(AbilityWord.WILL_OF_THE_COUNCIL) ); } diff --git a/Mage.Sets/src/mage/cards/m/MagmaPhoenix.java b/Mage.Sets/src/mage/cards/m/MagmaPhoenix.java index d970d3aaec7..3543d76cf85 100644 --- a/Mage.Sets/src/mage/cards/m/MagmaPhoenix.java +++ b/Mage.Sets/src/mage/cards/m/MagmaPhoenix.java @@ -30,7 +30,7 @@ public final class MagmaPhoenix extends CardImpl { this.toughness = new MageInt(3); this.addAbility(FlyingAbility.getInstance()); - this.addAbility(new DiesSourceTriggeredAbility(new DamageEverythingEffect(3), false)); + this.addAbility(new DiesSourceTriggeredAbility(new DamageEverythingEffect(3, "it"), false)); this.addAbility(new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), new ManaCostsImpl("{3}{R}{R}"))); } diff --git a/Mage.Sets/src/mage/cards/m/MagmaSliver.java b/Mage.Sets/src/mage/cards/m/MagmaSliver.java index 682c3140cdc..a281441a773 100644 --- a/Mage.Sets/src/mage/cards/m/MagmaSliver.java +++ b/Mage.Sets/src/mage/cards/m/MagmaSliver.java @@ -39,15 +39,15 @@ public final class MagmaSliver extends CardImpl { // where X is the number of Slivers on the battlefield." Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(new PermanentsOnBattlefieldCount( - StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS), + StaticFilters.FILTER_PERMANENT_ALL_SLIVERS), StaticValue.get(0), Duration.EndOfTurn, true), new TapSourceCost()); Target target = new TargetCreaturePermanent( new FilterCreaturePermanent(SubType.SLIVER, "Sliver creature")); ability.addTarget(target); Effect effect = new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, - StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS); - effect.setText("All Slivers have \"{T}: Target Sliver creature gets +X/+0 until end of turn," + StaticFilters.FILTER_PERMANENT_ALL_SLIVERS); + effect.setText("All Slivers have \"{T}: Target Sliver creature gets +X/+0 until end of turn, " + "where X is the number of Slivers on the battlefield.\""); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); diff --git a/Mage.Sets/src/mage/cards/m/MagneticMountain.java b/Mage.Sets/src/mage/cards/m/MagneticMountain.java index 0287a7b0b63..e95f10e8223 100644 --- a/Mage.Sets/src/mage/cards/m/MagneticMountain.java +++ b/Mage.Sets/src/mage/cards/m/MagneticMountain.java @@ -87,7 +87,7 @@ class MagneticMountainEffect extends OneShotEffect { int countBattlefield = game.getBattlefield().getAllActivePermanents(filter2, game.getActivePlayerId(), game).size(); while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.Benefit, "Pay {4} and untap a tapped blue creature under your control?", source, game)) { Target tappedCreatureTarget = new TargetControlledCreaturePermanent(1, 1, filter2, true); - if (player.choose(Outcome.Untap, tappedCreatureTarget, source.getSourceId(), game)) { + if (player.choose(Outcome.Untap, tappedCreatureTarget, source, game)) { Cost cost = ManaUtil.createManaCost(4, false); Permanent tappedCreature = game.getPermanent(tappedCreatureTarget.getFirstTarget()); if (tappedCreature != null && cost.pay(source, game, source, player.getId(), false)) { diff --git a/Mage.Sets/src/mage/cards/m/MagnigothTreefolk.java b/Mage.Sets/src/mage/cards/m/MagnigothTreefolk.java index 422bad620d0..a3cb6e0f08b 100644 --- a/Mage.Sets/src/mage/cards/m/MagnigothTreefolk.java +++ b/Mage.Sets/src/mage/cards/m/MagnigothTreefolk.java @@ -1,64 +1,36 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; -import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; -import mage.abilities.keyword.ForestwalkAbility; -import mage.abilities.keyword.IslandwalkAbility; -import mage.abilities.keyword.MountainwalkAbility; -import mage.abilities.keyword.PlainswalkAbility; -import mage.abilities.keyword.SwampwalkAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.hint.common.DomainHint; +import mage.abilities.keyword.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterLandPermanent; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; /** - * * @author emerald000 */ public final class MagnigothTreefolk extends CardImpl { - - private static final FilterLandPermanent filterPlains = new FilterLandPermanent(SubType.PLAINS, "Plains"); - private static final FilterLandPermanent filterIsland = new FilterLandPermanent(SubType.ISLAND, "Island"); - private static final FilterLandPermanent filterSwamp = new FilterLandPermanent(SubType.SWAMP, "Swamp"); - private static final FilterLandPermanent filterMountain = new FilterLandPermanent(SubType.MOUNTAIN, "Mountain"); - private static final FilterLandPermanent filterForest = new FilterLandPermanent(SubType.FOREST, "Forest"); public MagnigothTreefolk(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.TREEFOLK); this.power = new MageInt(2); this.toughness = new MageInt(6); // Domain - For each basic land type among lands you control, Magnigoth Treefolk has landwalk of that type. - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, - new ConditionalContinuousEffect( - new GainAbilitySourceEffect(new PlainswalkAbility()), - new PermanentsOnTheBattlefieldCondition(filterPlains), - "Domain — For each basic land type among lands you control, {this} has landwalk of that type.")); - ability.addEffect(new ConditionalContinuousEffect( - new GainAbilitySourceEffect(new IslandwalkAbility(), Duration.WhileOnBattlefield, false, true), - new PermanentsOnTheBattlefieldCondition(filterIsland), - "")); - ability.addEffect(new ConditionalContinuousEffect( - new GainAbilitySourceEffect(new SwampwalkAbility(), Duration.WhileOnBattlefield, false, true), - new PermanentsOnTheBattlefieldCondition(filterSwamp), - "")); - ability.addEffect(new ConditionalContinuousEffect( - new GainAbilitySourceEffect(new MountainwalkAbility(), Duration.WhileOnBattlefield, false, true), - new PermanentsOnTheBattlefieldCondition(filterMountain), - "")); - ability.addEffect(new ConditionalContinuousEffect( - new GainAbilitySourceEffect(new ForestwalkAbility(), Duration.WhileOnBattlefield, false, true), - new PermanentsOnTheBattlefieldCondition(filterForest), - "")); - this.addAbility(ability); + this.addAbility(new SimpleStaticAbility(new MagnigothTreefolkEffect()).setAbilityWord(AbilityWord.DOMAIN).addHint(DomainHint.instance)); } private MagnigothTreefolk(final MagnigothTreefolk card) { @@ -71,3 +43,64 @@ public final class MagnigothTreefolk extends CardImpl { } } +class MagnigothTreefolkEffect extends ContinuousEffectImpl { + + MagnigothTreefolkEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "for each basic land type among lands you control, {this} has landwalk of that type"; + } + + private MagnigothTreefolkEffect(final MagnigothTreefolkEffect effect) { + super(effect); + } + + @Override + public MagnigothTreefolkEffect copy() { + return new MagnigothTreefolkEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + return false; + } + List landTypes = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_PERMANENT_LANDS, + source.getControllerId(), source, game + ).stream() + .map(p -> SubType + .getBasicLands() + .stream() + .filter(subType -> p.hasSubtype(subType, game)) + .collect(Collectors.toSet())) + .flatMap(Collection::stream) + .distinct() + .collect(Collectors.toList()); + if (landTypes.isEmpty()) { + return false; + } + for (SubType subType : landTypes) { + switch (subType) { + case PLAINS: + permanent.addAbility(new PlainswalkAbility(), source.getSourceId(), game); + break; + case ISLAND: + permanent.addAbility(new IslandwalkAbility(), source.getSourceId(), game); + break; + case SWAMP: + permanent.addAbility(new SwampwalkAbility(), source.getSourceId(), game); + break; + case MOUNTAIN: + permanent.addAbility(new MountainwalkAbility(), source.getSourceId(), game); + break; + case FOREST: + permanent.addAbility(new ForestwalkAbility(), source.getSourceId(), game); + break; + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MagosiTheWaterveil.java b/Mage.Sets/src/mage/cards/m/MagosiTheWaterveil.java index f987cad643a..6f121fc9236 100644 --- a/Mage.Sets/src/mage/cards/m/MagosiTheWaterveil.java +++ b/Mage.Sets/src/mage/cards/m/MagosiTheWaterveil.java @@ -1,10 +1,9 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.CompositeCost; import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.costs.common.ReturnToHandFromBattlefieldSourceCost; import mage.abilities.costs.common.TapSourceCost; @@ -16,17 +15,17 @@ import mage.abilities.mana.BlueManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.counters.CounterType; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class MagosiTheWaterveil extends CardImpl { public MagosiTheWaterveil(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // Magosi, the Waterveil enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); @@ -35,17 +34,21 @@ public final class MagosiTheWaterveil extends CardImpl { this.addAbility(new BlueManaAbility()); // {U}, {T}: Put an eon counter on Magosi, the Waterveil. Skip your next turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.EON.createInstance()), new ManaCostsImpl("{U}")); - ability.addEffect(new SkipNextTurnSourceEffect()); + Ability ability = new SimpleActivatedAbility( + new AddCountersSourceEffect(CounterType.EON.createInstance()), new ManaCostsImpl<>("{U}") + ); + ability.addEffect(new SkipNextTurnSourceEffect().setText("skip your next turn")); ability.addCost(new TapSourceCost()); this.addAbility(ability); // {T}, Remove an eon counter from Magosi, the Waterveil and return it to its owner's hand: Take an extra turn after this one. - Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddExtraTurnControllerEffect(), new TapSourceCost()); - ability2.addCost(new RemoveCountersSourceCost(CounterType.EON.createInstance())); - ability2.addCost(new ReturnToHandFromBattlefieldSourceCost()); + Ability ability2 = new SimpleActivatedAbility(new AddExtraTurnControllerEffect(), new TapSourceCost()); + ability2.addCost(new CompositeCost( + new RemoveCountersSourceCost(CounterType.EON.createInstance()), + new ReturnToHandFromBattlefieldSourceCost(), + "remove an eon counter from {this} and return it to its owner's hand" + )); this.addAbility(ability2); - } private MagosiTheWaterveil(final MagosiTheWaterveil card) { diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheJar.java b/Mage.Sets/src/mage/cards/m/MagusOfTheJar.java index 5e1d5d9046b..907df1ad160 100644 --- a/Mage.Sets/src/mage/cards/m/MagusOfTheJar.java +++ b/Mage.Sets/src/mage/cards/m/MagusOfTheJar.java @@ -132,7 +132,7 @@ class MagusoftheJarDelayedEffect extends OneShotEffect { continue; } player.discard(player.getHand(), false, source, game); - player.moveCards(cards.getCards(filter, source.getSourceId(), playerId, game), Zone.HAND, source, game); + player.moveCards(cards.getCards(filter, playerId, source, game), Zone.HAND, source, game); } return true; } diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheScroll.java b/Mage.Sets/src/mage/cards/m/MagusOfTheScroll.java index 59ebe48a53e..1900ddc9618 100644 --- a/Mage.Sets/src/mage/cards/m/MagusOfTheScroll.java +++ b/Mage.Sets/src/mage/cards/m/MagusOfTheScroll.java @@ -65,7 +65,7 @@ class MagusOfTheScrollEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player you = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); if (sourceObject != null && you != null && cardName != null && !cardName.isEmpty()) { if (!you.getHand().isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/m/MairsilThePretender.java b/Mage.Sets/src/mage/cards/m/MairsilThePretender.java index 7329c29521e..ae8a638df3a 100644 --- a/Mage.Sets/src/mage/cards/m/MairsilThePretender.java +++ b/Mage.Sets/src/mage/cards/m/MairsilThePretender.java @@ -93,18 +93,22 @@ class MairsilThePretenderExileEffect extends OneShotEffect { if (controller.chooseUse(Outcome.Detriment, "Exile a card from your hand? (No = from graveyard)", source, game)) { // from hand target = new TargetCardInHand(0, 1, filter); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); } else { // from graveyard target = new TargetCardInYourGraveyard(0, 1, filter); - target.choose(outcome, source.getControllerId(), source.getSourceId(), game); + target.choose(outcome, source.getControllerId(), source.getSourceId(), source, game); } Card card = controller.getHand().get(target.getFirstTarget(), game); if (card != null) { - CardUtil.moveCardWithCounter(game, source, controller, card, Zone.EXILED, CounterType.CAGE.createInstance()); + return CardUtil.moveCardWithCounter(game, source, controller, card, Zone.EXILED, CounterType.CAGE.createInstance()); } - return true; + card = controller.getGraveyard().get(target.getFirstTarget(), game); + if (card != null) { + return CardUtil.moveCardWithCounter(game, source, controller, card, Zone.EXILED, CounterType.CAGE.createInstance()); + } + return false; } } diff --git a/Mage.Sets/src/mage/cards/m/MajesticMetamorphosis.java b/Mage.Sets/src/mage/cards/m/MajesticMetamorphosis.java new file mode 100644 index 00000000000..f55ea7479e7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MajesticMetamorphosis.java @@ -0,0 +1,102 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MajesticMetamorphosis extends CardImpl { + + public MajesticMetamorphosis(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}"); + + // Until end of turn, target artifact or creature becomes a 4/4 Angel artifact creature and gains flying. + this.getSpellAbility().addEffect(new MajesticMetamorphosisEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE)); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); + } + + private MajesticMetamorphosis(final MajesticMetamorphosis card) { + super(card); + } + + @Override + public MajesticMetamorphosis copy() { + return new MajesticMetamorphosis(this); + } +} + +class MajesticMetamorphosisEffect extends ContinuousEffectImpl { + + MajesticMetamorphosisEffect() { + super(Duration.EndOfTurn, Outcome.Benefit); + staticText = "until end of turn, target artifact or creature becomes " + + "a 4/4 Angel artifact creature and gains flying"; + } + + private MajesticMetamorphosisEffect(final MajesticMetamorphosisEffect effect) { + super(effect); + } + + @Override + public MajesticMetamorphosisEffect copy() { + return new MajesticMetamorphosisEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + discard(); + return false; + } + switch (layer) { + case TypeChangingEffects_4: + permanent.removeAllCardTypes(game); + permanent.addCardType(game, CardType.ARTIFACT, CardType.CREATURE); + permanent.removeAllSubTypes(game); + permanent.addSubType(game, SubType.ANGEL); + return true; + case AbilityAddingRemovingEffects_6: + permanent.addAbility(FlyingAbility.getInstance(), source.getSourceId(), game); + return true; + case PTChangingEffects_7: + if (sublayer == SubLayer.SetPT_7b) { + permanent.getPower().setValue(4); + permanent.getToughness().setValue(4); + return true; + } + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + switch (layer) { + case TypeChangingEffects_4: + case AbilityAddingRemovingEffects_6: + case PTChangingEffects_7: + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MakeDisappear.java b/Mage.Sets/src/mage/cards/m/MakeDisappear.java new file mode 100644 index 00000000000..b49f889815f --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MakeDisappear.java @@ -0,0 +1,37 @@ +package mage.cards.m; + +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CounterUnlessPaysEffect; +import mage.abilities.keyword.CasualtyAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MakeDisappear extends CardImpl { + + public MakeDisappear(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); + + // Casualty 1 + this.addAbility(new CasualtyAbility(this, 1)); + + // Counter target spell unless its controller pays {2}. + this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(new GenericManaCost(2))); + this.getSpellAbility().addTarget(new TargetSpell()); + } + + private MakeDisappear(final MakeDisappear card) { + super(card); + } + + @Override + public MakeDisappear copy() { + return new MakeDisappear(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MakindiShieldmate.java b/Mage.Sets/src/mage/cards/m/MakindiShieldmate.java index c2014f5be7c..6ab3df8597b 100644 --- a/Mage.Sets/src/mage/cards/m/MakindiShieldmate.java +++ b/Mage.Sets/src/mage/cards/m/MakindiShieldmate.java @@ -29,7 +29,7 @@ public final class MakindiShieldmate extends CardImpl { this.addAbility(DefenderAbility.getInstance()); - this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true)); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true).setAbilityWord(null)); } private MakindiShieldmate(final MakindiShieldmate card) { diff --git a/Mage.Sets/src/mage/cards/m/MalevolentWhispers.java b/Mage.Sets/src/mage/cards/m/MalevolentWhispers.java index c90b9876a88..2a1eae5a819 100644 --- a/Mage.Sets/src/mage/cards/m/MalevolentWhispers.java +++ b/Mage.Sets/src/mage/cards/m/MalevolentWhispers.java @@ -40,7 +40,7 @@ public final class MalevolentWhispers extends CardImpl { this.getSpellAbility().addEffect(effect); // Madness {3}{R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{3}{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{3}{R}"))); } private MalevolentWhispers(final MalevolentWhispers card) { diff --git a/Mage.Sets/src/mage/cards/m/Malfunction.java b/Mage.Sets/src/mage/cards/m/Malfunction.java index 76e452d221c..0c124b02ede 100644 --- a/Mage.Sets/src/mage/cards/m/Malfunction.java +++ b/Mage.Sets/src/mage/cards/m/Malfunction.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -12,15 +10,16 @@ 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.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Malfunction extends CardImpl { @@ -34,7 +33,7 @@ public final class Malfunction extends CardImpl { } public Malfunction(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}"); this.subtype.add(SubType.AURA); // Enchant artifact or creature. @@ -45,7 +44,7 @@ public final class Malfunction extends CardImpl { this.addAbility(ability); // When Malfunction enters the battlefield, tap enchanted permanent. - this.addAbility(new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect())); + this.addAbility(new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect().setText("tap enchanted permanent"))); // Enchanted permanent doesn't untap during its controller's untap step. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DontUntapInControllersUntapStepEnchantedEffect("permanent"))); diff --git a/Mage.Sets/src/mage/cards/m/MammothUmbra.java b/Mage.Sets/src/mage/cards/m/MammothUmbra.java index 48733925860..ed7a4331739 100644 --- a/Mage.Sets/src/mage/cards/m/MammothUmbra.java +++ b/Mage.Sets/src/mage/cards/m/MammothUmbra.java @@ -1,8 +1,5 @@ - package mage.cards.m; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; @@ -17,6 +14,8 @@ import mage.constants.*; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * @author Loki */ @@ -26,17 +25,20 @@ public final class MammothUmbra extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{W}"); this.subtype.add(SubType.AURA); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Enchanted creature gets +3/+3 and has vigilance. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(3, 3, Duration.WhileOnBattlefield))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(VigilanceAbility.getInstance(), AttachmentType.AURA))); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect( + 3, 3, Duration.WhileOnBattlefield + )); + ability.addEffect(new GainAbilityAttachedEffect( + VigilanceAbility.getInstance(), AttachmentType.AURA + ).setText("and has vigilance")); + this.addAbility(ability); // Totem armor this.addAbility(new TotemArmorAbility()); diff --git a/Mage.Sets/src/mage/cards/m/ManaBreach.java b/Mage.Sets/src/mage/cards/m/ManaBreach.java index 9134774fdfe..c9eea4fabdb 100644 --- a/Mage.Sets/src/mage/cards/m/ManaBreach.java +++ b/Mage.Sets/src/mage/cards/m/ManaBreach.java @@ -61,13 +61,13 @@ class ManaBreachEffect extends OneShotEffect { Player player = game.getPlayer(targetPointer.getFirst(game, source)); if (player == null || game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, - source.getSourceId(), player.getId(), game + player.getId(), source, game ) < 1) { return false; } TargetPermanent target = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); return player.moveCards(game.getPermanent(target.getFirstTarget()), Zone.HAND, source, game); } } diff --git a/Mage.Sets/src/mage/cards/m/ManaChargedDragon.java b/Mage.Sets/src/mage/cards/m/ManaChargedDragon.java index c354adfdeeb..bcebf236c20 100644 --- a/Mage.Sets/src/mage/cards/m/ManaChargedDragon.java +++ b/Mage.Sets/src/mage/cards/m/ManaChargedDragon.java @@ -10,10 +10,7 @@ import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TrampleAbility; 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.*; import mage.game.Game; import mage.players.Player; import mage.util.ManaUtil; @@ -39,7 +36,7 @@ public final class ManaChargedDragon extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Join forces - Whenever Mana-Charged Dragon attacks or blocks, each player starting with you may pay any amount of mana. Mana-Charged Dragon gets +X/+0 until end of turn, where X is the total amount of mana paid this way. - this.addAbility(new ManaChargedDragonTriggeredAbility()); + this.addAbility(new AttacksOrBlocksTriggeredAbility(new ManaChargedDragonEffect(), false).setAbilityWord(AbilityWord.JOIN_FORCES)); } private ManaChargedDragon(final ManaChargedDragon card) { @@ -52,18 +49,6 @@ public final class ManaChargedDragon extends CardImpl { } } -class ManaChargedDragonTriggeredAbility extends AttacksOrBlocksTriggeredAbility { - - ManaChargedDragonTriggeredAbility() { - super(new ManaChargedDragonEffect(), false); - } - - @Override - public String getRule() { - return "Join forces — Whenever {this} attacks or blocks, each player starting with you may pay any amount of mana. {this} gets +X/+0 until end of turn, where X is the total amount of mana paid this way"; - } -} - class ManaChargedDragonEffect extends OneShotEffect { ManaChargedDragonEffect() { diff --git a/Mage.Sets/src/mage/cards/m/ManaSeverance.java b/Mage.Sets/src/mage/cards/m/ManaSeverance.java index 52200030945..0699e19cfd5 100644 --- a/Mage.Sets/src/mage/cards/m/ManaSeverance.java +++ b/Mage.Sets/src/mage/cards/m/ManaSeverance.java @@ -1,78 +1,75 @@ package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.effects.SearchEffect; -import mage.cards.Card; +import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.common.FilterLandCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author nick.myers */ public final class ManaSeverance extends CardImpl { - + public ManaSeverance(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}"); + // Search your library for any number of land cards and remove them from the game. // Shuffle your library afterwards. this.getSpellAbility().addEffect(new ManaSeveranceEffect()); } - + private ManaSeverance(final ManaSeverance card) { super(card); } - + @Override public ManaSeverance copy() { return new ManaSeverance(this); } - + } -class ManaSeveranceEffect extends SearchEffect { - +class ManaSeveranceEffect extends OneShotEffect { + public ManaSeveranceEffect() { - super(new TargetCardInLibrary(0, Integer.MAX_VALUE, new FilterLandCard()), Outcome.Exile); + super(Outcome.Benefit); this.staticText = "search your library for any number of land cards, exile them, then shuffle"; } - + public ManaSeveranceEffect(final ManaSeveranceEffect effect) { super(effect); } - + @Override public ManaSeveranceEffect copy() { return new ManaSeveranceEffect(this); } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - if (controller.searchLibrary(target, source, game)) { - if (!target.getTargets().isEmpty()) { - for (UUID cardId : target.getTargets()) { - Card card = controller.getLibrary().getCard(cardId, game); - if (card != null) { - controller.moveCardToExileWithInfo(card, null, "", source, game, Zone.LIBRARY, true); - } - } - } - } - controller.shuffleLibrary(source, game); - return true; + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; } - return false; + TargetCardInLibrary target = new TargetCardInLibrary( + 0, Integer.MAX_VALUE, StaticFilters.FILTER_CARD_LANDS + ); + player.searchLibrary(target, source, game); + Cards cards = new CardsImpl(target.getTargets()); + cards.retainZone(Zone.LIBRARY, game); + player.moveCards(cards, Zone.EXILED, source, game); + player.shuffleLibrary(source, game); + return true; } } diff --git a/Mage.Sets/src/mage/cards/m/ManaVortex.java b/Mage.Sets/src/mage/cards/m/ManaVortex.java index 24b0dbd401b..01efb4e7a89 100644 --- a/Mage.Sets/src/mage/cards/m/ManaVortex.java +++ b/Mage.Sets/src/mage/cards/m/ManaVortex.java @@ -123,7 +123,7 @@ class ManaVortexStateTriggeredAbility extends StateTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - return game.getBattlefield().count(StaticFilters.FILTER_LANDS, this.getSourceId(), this.getControllerId(), game) == 0; + return game.getBattlefield().count(StaticFilters.FILTER_LANDS, this.getControllerId(), this, game) == 0; } @Override diff --git a/Mage.Sets/src/mage/cards/m/ManaWeb.java b/Mage.Sets/src/mage/cards/m/ManaWeb.java index 4e1709a9cc9..73567bf953b 100644 --- a/Mage.Sets/src/mage/cards/m/ManaWeb.java +++ b/Mage.Sets/src/mage/cards/m/ManaWeb.java @@ -112,7 +112,7 @@ class ManaWebeffect extends OneShotEffect { boolean tappedLands = false; for (Permanent opponentPermanent : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, - permanent.getControllerId(), source.getSourceId(), game + permanent.getControllerId(), source, game )) { Set manaTypes = AnyColorLandsProduceManaAbility.getManaTypesFromPermanent(opponentPermanent, game); if (!Collections.disjoint(manaTypes, manaTypesSource)) { diff --git a/Mage.Sets/src/mage/cards/m/ManaforceMace.java b/Mage.Sets/src/mage/cards/m/ManaforceMace.java index a1583955e9c..8b2b457dc6f 100644 --- a/Mage.Sets/src/mage/cards/m/ManaforceMace.java +++ b/Mage.Sets/src/mage/cards/m/ManaforceMace.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.dynamicvalue.common.DomainValue; @@ -10,24 +8,27 @@ import mage.abilities.hint.common.DomainHint; import mage.abilities.keyword.EquipAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author North */ public final class ManaforceMace extends CardImpl { public ManaforceMace(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); this.subtype.add(SubType.EQUIPMENT); // Domain - Equipped creature gets +1/+1 for each basic land type among lands you control. - DomainValue value = new DomainValue(); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(value, value)).addHint(DomainHint.instance)); + this.addAbility(new SimpleStaticAbility( + new BoostEquippedEffect(DomainValue.REGULAR, DomainValue.REGULAR) + ).addHint(DomainHint.instance).setAbilityWord(AbilityWord.DOMAIN)); + // Equip {3} this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(3), false)); } diff --git a/Mage.Sets/src/mage/cards/m/Manamorphose.java b/Mage.Sets/src/mage/cards/m/Manamorphose.java index ea68f248123..02eea023827 100644 --- a/Mage.Sets/src/mage/cards/m/Manamorphose.java +++ b/Mage.Sets/src/mage/cards/m/Manamorphose.java @@ -22,7 +22,7 @@ public final class Manamorphose extends CardImpl { this.getSpellAbility().addEffect(new AddManaInAnyCombinationEffect(2)); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private Manamorphose(final Manamorphose card) { diff --git a/Mage.Sets/src/mage/cards/m/Manaplasm.java b/Mage.Sets/src/mage/cards/m/Manaplasm.java index f83ef347dbd..18f35efb833 100644 --- a/Mage.Sets/src/mage/cards/m/Manaplasm.java +++ b/Mage.Sets/src/mage/cards/m/Manaplasm.java @@ -1,38 +1,39 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.common.InfoEffect; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostSourceEffect; 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.constants.SubType; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.stack.Spell; -import mage.target.targetpointer.FixedTarget; + +import java.util.Optional; +import java.util.UUID; /** - * * @author Plopman */ public final class Manaplasm extends CardImpl { public Manaplasm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.OOZE); this.power = new MageInt(1); this.toughness = new MageInt(1); // Whenever you cast a spell, Manaplasm gets +X/+X until end of turn, where X is that spell's converted mana cost. - this.addAbility(new ManaplasmAbility()); - + this.addAbility(new SpellCastControllerTriggeredAbility(new BoostSourceEffect( + ManaplasmValue.instance, ManaplasmValue.instance, + Duration.EndOfTurn, true + ), false)); } private Manaplasm(final Manaplasm card) { @@ -45,44 +46,26 @@ public final class Manaplasm extends CardImpl { } } +enum ManaplasmValue implements DynamicValue { + instance; -class ManaplasmAbility extends TriggeredAbilityImpl { - - public ManaplasmAbility() { - super(Zone.BATTLEFIELD, new InfoEffect("{this} gets +X/+X until end of turn, where X is that spell's mana value"), false); - } - - - - public ManaplasmAbility(final ManaplasmAbility ability) { - super(ability); + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return Optional.of((Spell) effect.getValue("spellCast")).map(Spell::getManaValue).orElse(0); } @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SPELL_CAST; + public ManaplasmValue copy() { + return this; } @Override - public boolean checkTrigger(GameEvent event, Game game) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null && spell.isControlledBy(controllerId)) { - this.getEffects().remove(0); - int x = spell.getManaValue(); - this.addEffect(new BoostSourceEffect(x,x, Duration.EndOfTurn)); - this.getEffects().get(0).setTargetPointer(new FixedTarget(event.getPlayerId())); - return true; - } - return false; + public String getMessage() { + return "that spell's mana value"; } @Override - public String getRule() { - return "Whenever you cast a spell, {this} gets +X/+X until end of turn, where X is that spell's mana value"; - } - - @Override - public ManaplasmAbility copy() { - return new ManaplasmAbility(this); + public String toString() { + return "X"; } } diff --git a/Mage.Sets/src/mage/cards/m/ManascapeRefractor.java b/Mage.Sets/src/mage/cards/m/ManascapeRefractor.java index 1dd80ca1346..076f44dda0a 100644 --- a/Mage.Sets/src/mage/cards/m/ManascapeRefractor.java +++ b/Mage.Sets/src/mage/cards/m/ManascapeRefractor.java @@ -77,7 +77,7 @@ class ManascapeRefractorGainAbilitiesEffect extends ContinuousEffectImpl { } for (Ability ability : game.getState() .getBattlefield() - .getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game) + .getActivePermanents(filter, source.getControllerId(), source, game) .stream() .map(permanent -> permanent.getAbilities(game)) .flatMap(Collection::stream) diff --git a/Mage.Sets/src/mage/cards/m/MandateOfPeace.java b/Mage.Sets/src/mage/cards/m/MandateOfPeace.java index c763b0c8f9e..8b99ab9412e 100644 --- a/Mage.Sets/src/mage/cards/m/MandateOfPeace.java +++ b/Mage.Sets/src/mage/cards/m/MandateOfPeace.java @@ -73,7 +73,7 @@ class MandateOfPeaceOpponentsCantCastSpellsEffect extends ContinuousRuleModifyin @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast spells this turn (" + mageObject.getIdName() + ")."; } @@ -117,11 +117,11 @@ class MandateOfPeaceEndCombatEffect extends OneShotEffect { combat.endCombat(game); if (!game.getStack().isEmpty()) { game.getStack().stream() - .filter(stackObject -> stackObject instanceof Spell) + .filter(Spell.class::isInstance) .forEach(stackObject -> ((Spell) stackObject).moveToExile(null, "", null, game)); game.getStack().stream() - .filter(stackObject -> stackObject instanceof Ability) + .filter(Ability.class::isInstance) .forEach(stackObject -> game.getStack().remove(stackObject, game)); } return true; diff --git a/Mage.Sets/src/mage/cards/m/MangaraTheDiplomat.java b/Mage.Sets/src/mage/cards/m/MangaraTheDiplomat.java index 7b1d5b3135c..2906626a04e 100644 --- a/Mage.Sets/src/mage/cards/m/MangaraTheDiplomat.java +++ b/Mage.Sets/src/mage/cards/m/MangaraTheDiplomat.java @@ -2,18 +2,15 @@ package mage.cards.m; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.CastSecondSpellTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; 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.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; -import mage.watchers.common.CastSpellLastTurnWatcher; import java.util.UUID; @@ -35,10 +32,12 @@ public final class MangaraTheDiplomat extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // Whenever an opponent attacks with creatures, if two or more of those creatures are attacking you and/or a planeswalker you control, draw a card. - this.addAbility(new MangaraTheDiplomatAttackTriggeredAbility()); + this.addAbility(new MangaraTheDiplomatTriggeredAbility()); // Whenever an opponent casts their second spell each turn, draw a card. - this.addAbility(new MangaraTheDiplomatCastTriggeredAbility()); + this.addAbility(new CastSecondSpellTriggeredAbility( + new DrawCardSourceControllerEffect(1), TargetController.OPPONENT + )); } private MangaraTheDiplomat(final MangaraTheDiplomat card) { @@ -51,13 +50,13 @@ public final class MangaraTheDiplomat extends CardImpl { } } -class MangaraTheDiplomatAttackTriggeredAbility extends TriggeredAbilityImpl { +class MangaraTheDiplomatTriggeredAbility extends TriggeredAbilityImpl { - MangaraTheDiplomatAttackTriggeredAbility() { + MangaraTheDiplomatTriggeredAbility() { super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1)); } - private MangaraTheDiplomatAttackTriggeredAbility(final MangaraTheDiplomatAttackTriggeredAbility ability) { + private MangaraTheDiplomatTriggeredAbility(final MangaraTheDiplomatTriggeredAbility ability) { super(ability); } @@ -81,8 +80,8 @@ class MangaraTheDiplomatAttackTriggeredAbility extends TriggeredAbilityImpl { } @Override - public MangaraTheDiplomatAttackTriggeredAbility copy() { - return new MangaraTheDiplomatAttackTriggeredAbility(this); + public MangaraTheDiplomatTriggeredAbility copy() { + return new MangaraTheDiplomatTriggeredAbility(this); } @Override @@ -92,40 +91,3 @@ class MangaraTheDiplomatAttackTriggeredAbility extends TriggeredAbilityImpl { "and/or planeswalkers you control, draw a card."; } } - - -class MangaraTheDiplomatCastTriggeredAbility extends TriggeredAbilityImpl { - - MangaraTheDiplomatCastTriggeredAbility() { - super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1)); - } - - private MangaraTheDiplomatCastTriggeredAbility(final MangaraTheDiplomatCastTriggeredAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SPELL_CAST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Player player = game.getPlayer(getControllerId()); - CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); - return player != null - && watcher != null - && player.hasOpponent(event.getPlayerId(), game) - && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) == 2; - } - - @Override - public MangaraTheDiplomatCastTriggeredAbility copy() { - return new MangaraTheDiplomatCastTriggeredAbility(this); - } - - @Override - public String getRule() { - return "Whenever an opponent casts their second spell each turn, draw a card."; - } -} diff --git a/Mage.Sets/src/mage/cards/m/MantleOfTheAncients.java b/Mage.Sets/src/mage/cards/m/MantleOfTheAncients.java index f37062f168a..6c8cc3da6d6 100644 --- a/Mage.Sets/src/mage/cards/m/MantleOfTheAncients.java +++ b/Mage.Sets/src/mage/cards/m/MantleOfTheAncients.java @@ -95,7 +95,7 @@ class MantleOfTheAncientsEffect extends OneShotEffect { FilterCard filter = new FilterCard("Aura or Equipment card that can be attached to " + permanent.getName()); filter.add(new MantleOfTheAncientsPredicate(permanent)); TargetCard target = new TargetCardInYourGraveyard(0, Integer.MAX_VALUE, filter, true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Cards cards = new CardsImpl(target.getTargets()); if (cards.isEmpty()) { return false; diff --git a/Mage.Sets/src/mage/cards/m/MarangRiverProwler.java b/Mage.Sets/src/mage/cards/m/MarangRiverProwler.java index 93319975761..a410726cdc9 100644 --- a/Mage.Sets/src/mage/cards/m/MarangRiverProwler.java +++ b/Mage.Sets/src/mage/cards/m/MarangRiverProwler.java @@ -91,7 +91,7 @@ class MarangRiverProwlerCastEffect extends AsThoughEffectImpl { if (card != null && card.isOwnedBy(affectedControllerId) && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD - && game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0) { + && game.getBattlefield().count(filter, source.getControllerId(), source, game) > 0) { return true; } } diff --git a/Mage.Sets/src/mage/cards/m/MarangRiverSkeleton.java b/Mage.Sets/src/mage/cards/m/MarangRiverSkeleton.java index 57215f6aa9e..9adbddd484d 100644 --- a/Mage.Sets/src/mage/cards/m/MarangRiverSkeleton.java +++ b/Mage.Sets/src/mage/cards/m/MarangRiverSkeleton.java @@ -29,7 +29,7 @@ public final class MarangRiverSkeleton extends CardImpl { this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{B}"))); // Megamorph {3}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{B}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{B}"), true)); } private MarangRiverSkeleton(final MarangRiverSkeleton card) { diff --git a/Mage.Sets/src/mage/cards/m/MarathWillOfTheWild.java b/Mage.Sets/src/mage/cards/m/MarathWillOfTheWild.java index 0761fc9cdf3..ecee5ad42fb 100644 --- a/Mage.Sets/src/mage/cards/m/MarathWillOfTheWild.java +++ b/Mage.Sets/src/mage/cards/m/MarathWillOfTheWild.java @@ -62,14 +62,12 @@ public final class MarathWillOfTheWild extends CardImpl { ability.addTarget(new TargetCreaturePermanent()); // or Marath deals X damage to any target; - Mode mode = new Mode(); - mode.addEffect(new DamageTargetEffect(ManacostVariableValue.REGULAR)); + Mode mode = new Mode(new DamageTargetEffect(ManacostVariableValue.REGULAR)); mode.addTarget(new TargetAnyTarget()); ability.addMode(mode); // or create an X/X green Elemental creature token. - mode = new Mode(); - mode.addEffect(new MarathWillOfTheWildCreateTokenEffect()); + mode = new Mode(new MarathWillOfTheWildCreateTokenEffect()); ability.addMode(mode); // X can't be 0. diff --git a/Mage.Sets/src/mage/cards/m/MaraudingLooter.java b/Mage.Sets/src/mage/cards/m/MaraudingLooter.java index 945b6d21e5c..18878bafd25 100644 --- a/Mage.Sets/src/mage/cards/m/MaraudingLooter.java +++ b/Mage.Sets/src/mage/cards/m/MaraudingLooter.java @@ -34,7 +34,7 @@ public final class MaraudingLooter extends CardImpl { Ability ability = new ConditionalInterveningIfTriggeredAbility( new BeginningOfEndStepTriggeredAbility(new DrawDiscardControllerEffect(1, 1, true), TargetController.YOU, false), RaidCondition.instance, - "Raid — At the beginning of your end step, " + "At the beginning of your end step, " + "if you attacked this turn, " + "you may draw a card. If you do, discard a card."); ability.setAbilityWord(AbilityWord.RAID); diff --git a/Mage.Sets/src/mage/cards/m/MarchFromTheTomb.java b/Mage.Sets/src/mage/cards/m/MarchFromTheTomb.java index 9288987ed6b..9e017de387c 100644 --- a/Mage.Sets/src/mage/cards/m/MarchFromTheTomb.java +++ b/Mage.Sets/src/mage/cards/m/MarchFromTheTomb.java @@ -56,7 +56,7 @@ class MarchFromTheTombTarget extends TargetCardInYourGraveyard { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { int cmcLeft = 8; for (UUID targetId : this.getTargets()) { Card card = game.getCard(targetId); @@ -64,7 +64,7 @@ class MarchFromTheTombTarget extends TargetCardInYourGraveyard { cmcLeft -= card.getManaValue(); } } - Set possibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); Set leftPossibleTargets = new HashSet<>(); for (UUID targetId : possibleTargets) { Card card = game.getCard(targetId); diff --git a/Mage.Sets/src/mage/cards/m/MarchOfBurgeoningLife.java b/Mage.Sets/src/mage/cards/m/MarchOfBurgeoningLife.java new file mode 100644 index 00000000000..784a9948af4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MarchOfBurgeoningLife.java @@ -0,0 +1,127 @@ +package mage.cards.m; + +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.costs.costadjusters.ExileCardsFromHandAdjuster; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreatureCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInLibrary; +import mage.target.targetadjustment.TargetAdjuster; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MarchOfBurgeoningLife extends CardImpl { + + private static final FilterCard filter = new FilterCard("green cards from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.GREEN)); + } + + public MarchOfBurgeoningLife(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{G}"); + + // As an additional cost to cast this spell, you may exile any number of green cards from your hand. This spell costs {2} less to cast for each card exiled this way. + ExileCardsFromHandAdjuster.addAdjusterAndMessage(this, filter); + + // Choose target creature with mana value less than X. Search your library for a creature card with the same name as that creature, put it onto the battlefield tapped, then shuffle. + this.getSpellAbility().addEffect(new MarchOfBurgeoningLifeEffect()); + this.getSpellAbility().setTargetAdjuster(MarchOfBurgeoningLifeAdjuster.instance); + } + + private MarchOfBurgeoningLife(final MarchOfBurgeoningLife card) { + super(card); + } + + @Override + public MarchOfBurgeoningLife copy() { + return new MarchOfBurgeoningLife(this); + } +} + +enum MarchOfBurgeoningLifeAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int xValue = ability.getManaCostsToPay().getX(); + FilterPermanent filter = new FilterCreaturePermanent("creature with mana value less than " + xValue); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, xValue)); + ability.getTargets().clear(); + ability.addTarget(new TargetPermanent(filter)); + } +} + +class MarchOfBurgeoningLifeEffect extends OneShotEffect { + + private static class MarchOfBurgeoningLifePredicate implements Predicate { + private final Permanent permanent; + + private MarchOfBurgeoningLifePredicate(Permanent permanent) { + this.permanent = permanent; + } + + @Override + public boolean apply(Card input, Game game) { + return CardUtil.haveSameNames(permanent, input); + } + } + + MarchOfBurgeoningLifeEffect() { + super(Outcome.Benefit); + staticText = "choose target creature with mana value less than X. Search your library for a creature card " + + "with the same name as that creature, put it onto the battlefield tapped, then shuffle"; + } + + private MarchOfBurgeoningLifeEffect(final MarchOfBurgeoningLifeEffect effect) { + super(effect); + } + + @Override + public MarchOfBurgeoningLifeEffect copy() { + return new MarchOfBurgeoningLifeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (player == null || permanent == null) { + return false; + } + FilterCard filter = new FilterCreatureCard("creature card with the same name as " + permanent.getName()); + filter.add(new MarchOfBurgeoningLifePredicate(permanent)); + TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); + player.searchLibrary(target, source, game); + Card card = player.getLibrary().getCard(target.getFirstTarget(), game); + if (card != null) { + player.moveCards( + card, Zone.BATTLEFIELD, source, game, true, + false, false, null + ); + } + player.shuffleLibrary(source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MarchOfOtherworldlyLight.java b/Mage.Sets/src/mage/cards/m/MarchOfOtherworldlyLight.java new file mode 100644 index 00000000000..5d4738b0380 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MarchOfOtherworldlyLight.java @@ -0,0 +1,74 @@ +package mage.cards.m; + +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.costs.costadjusters.ExileCardsFromHandAdjuster; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MarchOfOtherworldlyLight extends CardImpl { + + private static final FilterCard filter = new FilterCard("white cards from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + } + + public MarchOfOtherworldlyLight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{W}"); + + // As an additional cost to cast this spell, you may exile any number of white cards from your hand. This spell costs {2} less to cast for each card exiled this way. + ExileCardsFromHandAdjuster.addAdjusterAndMessage(this, filter); + + // Exile target artifact, creature, or enchantment with mana value X or less. + this.getSpellAbility().addEffect(new ExileTargetEffect( + "exile target artifact, creature, or enchantment with mana value X or less" + )); + this.getSpellAbility().setTargetAdjuster(MarchOfOtherworldlyLightAdjuster.instance); + } + + private MarchOfOtherworldlyLight(final MarchOfOtherworldlyLight card) { + super(card); + } + + @Override + public MarchOfOtherworldlyLight copy() { + return new MarchOfOtherworldlyLight(this); + } +} + +enum MarchOfOtherworldlyLightAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int xValue = ability.getManaCostsToPay().getX(); + FilterPermanent filter = new FilterPermanent( + "artifact, creature, or enchantment with mana value " + xValue + " or less" + ); + filter.add(Predicates.or( + CardType.ARTIFACT.getPredicate(), + CardType.CREATURE.getPredicate(), + CardType.ENCHANTMENT.getPredicate() + )); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, xValue + 1)); + ability.getTargets().clear(); + ability.addTarget(new TargetPermanent(filter)); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MarchOfRecklessJoy.java b/Mage.Sets/src/mage/cards/m/MarchOfRecklessJoy.java new file mode 100644 index 00000000000..b3d06c514ef --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MarchOfRecklessJoy.java @@ -0,0 +1,137 @@ +package mage.cards.m; + +import mage.MageObjectReference; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.costs.costadjusters.ExileCardsFromHandAdjuster; +import mage.abilities.effects.OneShotEffect; +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.WatcherScope; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MarchOfRecklessJoy extends CardImpl { + + private static final FilterCard filter = new FilterCard("red cards from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + } + + public MarchOfRecklessJoy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{R}"); + + // As an additional cost to cast this spell, you may exile any number of red cards from your hand. This spell costs {2} less to cast for each card exiled this way. + ExileCardsFromHandAdjuster.addAdjusterAndMessage(this, filter); + + // Exile the top X cards of your library. You may play up to two of those cards until the end of your next turn. + this.getSpellAbility().addEffect(new MarchOfRecklessJoyEffect()); + this.getSpellAbility().addWatcher(new MarchOfRecklessJoyWatcher()); + } + + private MarchOfRecklessJoy(final MarchOfRecklessJoy card) { + super(card); + } + + @Override + public MarchOfRecklessJoy copy() { + return new MarchOfRecklessJoy(this); + } +} + +class MarchOfRecklessJoyEffect extends OneShotEffect { + + public MarchOfRecklessJoyEffect() { + super(Outcome.Benefit); + this.staticText = "exile the top X cards of your library. " + + "You may play up to two of those cards until the end of your next turn."; + } + + public MarchOfRecklessJoyEffect(final MarchOfRecklessJoyEffect effect) { + super(effect); + } + + @Override + public MarchOfRecklessJoyEffect copy() { + return new MarchOfRecklessJoyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + int xValue = source.getManaCostsToPay().getX(); + if (player == null || xValue < 1 || player.getLibrary().size() < 1) { + return false; + } + Set cards = player.getLibrary().getTopCards(game, xValue); + player.moveCardsToExile( + cards, source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + for (Card card : cards) { + CardUtil.makeCardPlayable( + game, source, card, Duration.UntilEndOfYourNextTurn, + false, null, MarchOfRecklessJoyCondition.instance + ); + } + return true; + } +} + +enum MarchOfRecklessJoyCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return MarchOfRecklessJoyWatcher.check(source, game); + } +} + +class MarchOfRecklessJoyWatcher extends Watcher { + + private final Map morMap = new HashMap<>(); + + public MarchOfRecklessJoyWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.SPELL_CAST || event.getAdditionalReference() == null) { + return; + } + morMap.compute(event + .getAdditionalReference() + .getApprovingMageObjectReference(), + CardUtil::setOrIncrementValue + ); + } + + static boolean check(Ability source, Game game) { + return game + .getState() + .getWatcher(MarchOfRecklessJoyWatcher.class) + .morMap + .getOrDefault(new MageObjectReference(source, 1), 0) < 2; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MarchOfSouls.java b/Mage.Sets/src/mage/cards/m/MarchOfSouls.java index b0337f4bff4..183ed39b85b 100644 --- a/Mage.Sets/src/mage/cards/m/MarchOfSouls.java +++ b/Mage.Sets/src/mage/cards/m/MarchOfSouls.java @@ -59,7 +59,7 @@ class MarchOfSoulsEffect extends OneShotEffect { Map playersWithCreatures = new HashMap<>(); for (Permanent p : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_PERMANENT_CREATURES, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game )) { UUID controllerId = p.getControllerId(); if (p.destroy(source, game, true)) { diff --git a/Mage.Sets/src/mage/cards/m/MarchOfSwirlingMist.java b/Mage.Sets/src/mage/cards/m/MarchOfSwirlingMist.java new file mode 100644 index 00000000000..0e96217d801 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MarchOfSwirlingMist.java @@ -0,0 +1,58 @@ +package mage.cards.m; + +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.costs.costadjusters.ExileCardsFromHandAdjuster; +import mage.abilities.effects.common.PhaseOutTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MarchOfSwirlingMist extends CardImpl { + + private static final FilterCard filter = new FilterCard("blue cards from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLUE)); + } + + public MarchOfSwirlingMist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{U}"); + + // As an additional cost to cast this spell, you may exile any number of blue cards from your hand. This spell costs {2} less to cast for each card exiled this way. + ExileCardsFromHandAdjuster.addAdjusterAndMessage(this, filter); + + // Up to X target creatures phase out. + this.getSpellAbility().addEffect(new PhaseOutTargetEffect().setText("up to X target creatures phase out")); + this.getSpellAbility().setTargetAdjuster(MarchOfSwirlingMistAdjuster.instance); + } + + private MarchOfSwirlingMist(final MarchOfSwirlingMist card) { + super(card); + } + + @Override + public MarchOfSwirlingMist copy() { + return new MarchOfSwirlingMist(this); + } +} + +enum MarchOfSwirlingMistAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(0, ability.getManaCostsToPay().getX())); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MarchOfTheDrowned.java b/Mage.Sets/src/mage/cards/m/MarchOfTheDrowned.java index e9627395db0..28696df48c1 100644 --- a/Mage.Sets/src/mage/cards/m/MarchOfTheDrowned.java +++ b/Mage.Sets/src/mage/cards/m/MarchOfTheDrowned.java @@ -32,8 +32,7 @@ public final class MarchOfTheDrowned extends CardImpl { this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); 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.addEffect(new ReturnFromGraveyardToHandTargetEffect()); + Mode mode = new Mode(new ReturnFromGraveyardToHandTargetEffect()); mode.addTarget(new TargetCardInYourGraveyard(2, filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/m/MarchOfWretchedSorrow.java b/Mage.Sets/src/mage/cards/m/MarchOfWretchedSorrow.java new file mode 100644 index 00000000000..3c61d72da59 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MarchOfWretchedSorrow.java @@ -0,0 +1,48 @@ +package mage.cards.m; + +import mage.ObjectColor; +import mage.abilities.costs.costadjusters.ExileCardsFromHandAdjuster; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MarchOfWretchedSorrow extends CardImpl { + + private static final FilterCard filter = new FilterCard("black cards from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + } + + public MarchOfWretchedSorrow(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{B}"); + + // As an additional cost to cast this spell, you may exile any number of black cards from your hand. This spell costs {2} less to cast for each card exiled this way. + ExileCardsFromHandAdjuster.addAdjusterAndMessage(this, filter); + + // March of Wretched Sorrow deals X damage to target creature or planeswalker and you gain X life. + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.REGULAR)); + this.getSpellAbility().addEffect(new GainLifeEffect(ManacostVariableValue.REGULAR).concatBy("and")); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + } + + private MarchOfWretchedSorrow(final MarchOfWretchedSorrow card) { + super(card); + } + + @Override + public MarchOfWretchedSorrow copy() { + return new MarchOfWretchedSorrow(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MarduCharm.java b/Mage.Sets/src/mage/cards/m/MarduCharm.java index 759c4753685..0c34d72d7bd 100644 --- a/Mage.Sets/src/mage/cards/m/MarduCharm.java +++ b/Mage.Sets/src/mage/cards/m/MarduCharm.java @@ -49,13 +49,11 @@ public final class MarduCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // * Create two 1/1 white Warrior creature tokens. They gain first strike until end of turn. - Mode mode = new Mode(); - mode.addEffect(new MarduCharmCreateTokenEffect()); + Mode mode = new Mode(new MarduCharmCreateTokenEffect()); this.getSpellAbility().addMode(mode); // * Target opponent reveals their hand. You choose a noncreature, nonland card from it. That player discards that card. - mode = new Mode(); - mode.addEffect(new DiscardCardYouChooseTargetEffect(filter)); + mode = new Mode(new DiscardCardYouChooseTargetEffect(filter)); mode.addTarget(new TargetOpponent()); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/m/MarduHeartPiercer.java b/Mage.Sets/src/mage/cards/m/MarduHeartPiercer.java index 8ec386ad3c0..d9cc5a9acaa 100644 --- a/Mage.Sets/src/mage/cards/m/MarduHeartPiercer.java +++ b/Mage.Sets/src/mage/cards/m/MarduHeartPiercer.java @@ -32,7 +32,7 @@ public final class MarduHeartPiercer extends CardImpl { // Raid - When Mardu Heart-Piercer enters the battlefield, if you attacked this turn, Mardu Heart-Piercer deals 2 damage to any target. Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2)), RaidCondition.instance, - "Raid — When {this} enters the battlefield, if you attacked this turn, {this} deals 2 damage to any target."); + "When {this} enters the battlefield, if you attacked this turn, {this} deals 2 damage to any target."); ability.addTarget(new TargetAnyTarget()); ability.setAbilityWord(AbilityWord.RAID); ability.addHint(RaidHint.instance); diff --git a/Mage.Sets/src/mage/cards/m/MarduHordechief.java b/Mage.Sets/src/mage/cards/m/MarduHordechief.java index 18bbbff9304..57c6e81d8de 100644 --- a/Mage.Sets/src/mage/cards/m/MarduHordechief.java +++ b/Mage.Sets/src/mage/cards/m/MarduHordechief.java @@ -33,7 +33,7 @@ public final class MarduHordechief extends CardImpl { this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( new CreateTokenEffect(new WarriorToken())), RaidCondition.instance, - "Raid — When {this} enters the battlefield, if you attacked this turn, create a 1/1 white Warrior creature token.") + "When {this} enters the battlefield, if you attacked this turn, create a 1/1 white Warrior creature token.") .setAbilityWord(AbilityWord.RAID) .addHint(RaidHint.instance), new PlayerAttackedWatcher()); diff --git a/Mage.Sets/src/mage/cards/m/MarduScout.java b/Mage.Sets/src/mage/cards/m/MarduScout.java index 376d6a595f5..e633ecf067b 100644 --- a/Mage.Sets/src/mage/cards/m/MarduScout.java +++ b/Mage.Sets/src/mage/cards/m/MarduScout.java @@ -23,7 +23,7 @@ public final class MarduScout extends CardImpl { this.toughness = new MageInt(1); // Dash {1}{R} - this.addAbility(new DashAbility(this, "{1}{R}")); + this.addAbility(new DashAbility("{1}{R}")); } private MarduScout(final MarduScout card) { diff --git a/Mage.Sets/src/mage/cards/m/MarduShadowspear.java b/Mage.Sets/src/mage/cards/m/MarduShadowspear.java index 3b000f46bcc..30621d3a92b 100644 --- a/Mage.Sets/src/mage/cards/m/MarduShadowspear.java +++ b/Mage.Sets/src/mage/cards/m/MarduShadowspear.java @@ -26,7 +26,7 @@ public final class MarduShadowspear extends CardImpl { // Whenever Mardu Shadowspear attacks, each opponent loses 1 life. this.addAbility(new AttacksTriggeredAbility(new LoseLifeOpponentsEffect(1),false)); // Dash {1}{B} - this.addAbility(new DashAbility(this, "{1}{B}")); + this.addAbility(new DashAbility("{1}{B}")); } private MarduShadowspear(final MarduShadowspear card) { diff --git a/Mage.Sets/src/mage/cards/m/MarduSkullhunter.java b/Mage.Sets/src/mage/cards/m/MarduSkullhunter.java index cc16958f4d7..da5ed40170f 100644 --- a/Mage.Sets/src/mage/cards/m/MarduSkullhunter.java +++ b/Mage.Sets/src/mage/cards/m/MarduSkullhunter.java @@ -36,7 +36,7 @@ public final class MarduSkullhunter extends CardImpl { // Raid - When Mardu Skullhunter enters the battlefield, if you attacked this turn, target opponent discards a card. Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(1)), RaidCondition.instance, - "Raid — When {this} enters the battlefield, if you attacked this turn, target opponent discards a card."); + "When {this} enters the battlefield, if you attacked this turn, target opponent discards a card."); ability.addTarget(new TargetOpponent()); ability.setAbilityWord(AbilityWord.RAID); ability.addHint(RaidHint.instance); diff --git a/Mage.Sets/src/mage/cards/m/MarduStrikeLeader.java b/Mage.Sets/src/mage/cards/m/MarduStrikeLeader.java index 91c9d2540c3..10e2bf1afee 100644 --- a/Mage.Sets/src/mage/cards/m/MarduStrikeLeader.java +++ b/Mage.Sets/src/mage/cards/m/MarduStrikeLeader.java @@ -29,7 +29,7 @@ public final class MarduStrikeLeader extends CardImpl { this.addAbility(new AttacksTriggeredAbility(new CreateTokenEffect(new MarduStrikeLeaderWarriorToken()), false)); // Dash {3}{B} - this.addAbility(new DashAbility(this, "{3}{B}")); + this.addAbility(new DashAbility("{3}{B}")); } private MarduStrikeLeader(final MarduStrikeLeader card) { diff --git a/Mage.Sets/src/mage/cards/m/MarduWarshrieker.java b/Mage.Sets/src/mage/cards/m/MarduWarshrieker.java index 98e1f9b3dab..3c0ebbd6c8c 100644 --- a/Mage.Sets/src/mage/cards/m/MarduWarshrieker.java +++ b/Mage.Sets/src/mage/cards/m/MarduWarshrieker.java @@ -33,7 +33,7 @@ public final class MarduWarshrieker extends CardImpl { this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( new AddManaToManaPoolSourceControllerEffect(new Mana(1, 0, 1, 1, 0, 0, 0, 0))), RaidCondition.instance, - "Raid — When {this} enters the battlefield, if you attacked this turn, add {R}{W}{B}.") + "When {this} enters the battlefield, if you attacked this turn, add {R}{W}{B}.") .setAbilityWord(AbilityWord.RAID) .addHint(RaidHint.instance), new PlayerAttackedWatcher()); diff --git a/Mage.Sets/src/mage/cards/m/MarisiBreakerOfTheCoil.java b/Mage.Sets/src/mage/cards/m/MarisiBreakerOfTheCoil.java index 4c0d98ee1eb..f11c5eda0b5 100644 --- a/Mage.Sets/src/mage/cards/m/MarisiBreakerOfTheCoil.java +++ b/Mage.Sets/src/mage/cards/m/MarisiBreakerOfTheCoil.java @@ -1,12 +1,10 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.combat.GoadTargetEffect; import mage.cards.CardImpl; @@ -15,8 +13,11 @@ import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** * @author TheElk801 */ @@ -86,8 +87,6 @@ class MarisiBreakerOfTheCoilSpellEffect extends ContinuousRuleModifyingEffectImp class MarisiBreakerOfTheCoilEffect extends OneShotEffect { - private static final Effect effect = new GoadTargetEffect(); - MarisiBreakerOfTheCoilEffect() { super(Outcome.Benefit); staticText = "goad each creature that player controls " @@ -105,13 +104,12 @@ class MarisiBreakerOfTheCoilEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - game.getBattlefield().getAllActivePermanents( + for (Permanent permanent : game.getBattlefield().getAllActivePermanents( StaticFilters.FILTER_PERMANENT_CREATURE, targetPointer.getFirst(game, source), game - ).stream().forEach(permanent -> { - effect.setTargetPointer(new FixedTarget(permanent, game)); - effect.apply(game, source); - }); + )) { + game.addEffect(new GoadTargetEffect().setTargetPointer(new FixedTarget(permanent, game)), source); + } return true; } } diff --git a/Mage.Sets/src/mage/cards/m/MarshHulk.java b/Mage.Sets/src/mage/cards/m/MarshHulk.java index 4866a37b2b9..61d8410a643 100644 --- a/Mage.Sets/src/mage/cards/m/MarshHulk.java +++ b/Mage.Sets/src/mage/cards/m/MarshHulk.java @@ -24,7 +24,7 @@ public final class MarshHulk extends CardImpl { this.toughness = new MageInt(6); // Megamorph {6}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{6}{B}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{6}{B}"), true)); } private MarshHulk(final MarshHulk card) { diff --git a/Mage.Sets/src/mage/cards/m/MarshalingCry.java b/Mage.Sets/src/mage/cards/m/MarshalingCry.java index 7a2535de656..09d9d3de591 100644 --- a/Mage.Sets/src/mage/cards/m/MarshalingCry.java +++ b/Mage.Sets/src/mage/cards/m/MarshalingCry.java @@ -29,7 +29,7 @@ public final class MarshalingCry extends CardImpl { effect.setText("Creatures you control get +1/+1"); this.getSpellAbility().addEffect(effect); effect = new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn); - effect.setText("and vigilance until end of turn"); + effect.setText("and gain vigilance until end of turn"); this.getSpellAbility().addEffect(effect); // Cycling {2} diff --git a/Mage.Sets/src/mage/cards/m/MarshalingTheTroops.java b/Mage.Sets/src/mage/cards/m/MarshalingTheTroops.java index a3d30b01d4c..8fc7f6aa9f4 100644 --- a/Mage.Sets/src/mage/cards/m/MarshalingTheTroops.java +++ b/Mage.Sets/src/mage/cards/m/MarshalingTheTroops.java @@ -66,7 +66,7 @@ class MarshalingTheTroopsEffect extends OneShotEffect { } TargetPermanent target = new TargetControlledPermanent(0, Integer.MAX_VALUE, MarshalingTheTroops.filter, true); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); if (target.getTargets().isEmpty()) { return false; } diff --git a/Mage.Sets/src/mage/cards/m/MartialImpetus.java b/Mage.Sets/src/mage/cards/m/MartialImpetus.java index a57193f549a..0516b0fae56 100644 --- a/Mage.Sets/src/mage/cards/m/MartialImpetus.java +++ b/Mage.Sets/src/mage/cards/m/MartialImpetus.java @@ -2,8 +2,9 @@ package mage.cards.m; import mage.abilities.Ability; import mage.abilities.common.AttacksAttachedTriggeredAbility; -import mage.abilities.common.GoadAttachedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.combat.GoadAttachedEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.keyword.EnchantAbility; @@ -44,7 +45,9 @@ public final class MartialImpetus extends CardImpl { this.addAbility(ability); // Enchanted creature gets +1/+1 and is goaded. - this.addAbility(new GoadAttachedAbility(new BoostEnchantedEffect(1, 1))); + ability = new SimpleStaticAbility(new BoostEnchantedEffect(1, 1)); + ability.addEffect(new GoadAttachedEffect()); + this.addAbility(ability); // Whenever enchanted creature attacks, each other creature that's attacking one of your opponents gets +1/+1 until end of turn. this.addAbility(new AttacksAttachedTriggeredAbility( @@ -69,7 +72,7 @@ enum MartialImpetusPredicate implements ObjectSourcePlayerPredicate { @Override public boolean apply(ObjectSourcePlayer input, Game game) { - Permanent martialImpetus = game.getPermanentOrLKIBattlefield(input.getSourceId()); + Permanent martialImpetus = input.getSource().getSourcePermanentOrLKI(game); if (martialImpetus != null) { Permanent attachedTo = game.getPermanentOrLKIBattlefield(martialImpetus.getAttachedTo()); UUID auraControllerId = martialImpetus.getControllerId(); @@ -78,7 +81,7 @@ enum MartialImpetusPredicate implements ObjectSourcePlayerPredicate { && input.getObject() != attachedTo // must be other creature && input.getObject().isAttacking() // attacking && game.getOpponents(auraControllerId) // check for opponents of aura's controller - .contains(game.getCombat().getDefendingPlayerId(input.getObject().getId(), game))) { + .contains(game.getCombat().getDefendingPlayerId(input.getObject().getId(), game))) { return true; } } diff --git a/Mage.Sets/src/mage/cards/m/Martyrdom.java b/Mage.Sets/src/mage/cards/m/Martyrdom.java index 760afe28229..789fe2ff0a8 100644 --- a/Mage.Sets/src/mage/cards/m/Martyrdom.java +++ b/Mage.Sets/src/mage/cards/m/Martyrdom.java @@ -1,7 +1,6 @@ package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.ActivatedAbilityImpl; import mage.abilities.costs.mana.GenericManaCost; @@ -9,13 +8,7 @@ import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.RedirectionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.events.GameEvent; @@ -23,8 +16,9 @@ import mage.game.permanent.Permanent; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author L_J */ public final class Martyrdom extends CardImpl { @@ -78,7 +72,6 @@ class MartyrdomGainAbilityTargetEffect extends ContinuousEffectImpl { class MartyrdomActivatedAbility extends ActivatedAbilityImpl { - private static FilterCreaturePermanent filter = new FilterCreaturePermanent(); private UUID caster; public MartyrdomActivatedAbility(UUID caster) { @@ -94,15 +87,14 @@ class MartyrdomActivatedAbility extends ActivatedAbilityImpl { @Override public ActivationStatus canActivate(UUID playerId, Game game) { - if (playerId.equals(caster)) { - Permanent permanent = game.getBattlefield().getPermanent(this.getSourceId()); - if (permanent != null) { - if (filter.match(permanent, permanent.getId(), permanent.getControllerId(), game)) { - return super.canActivate(playerId, game); - } - } + if (!playerId.equals(caster)) { + return ActivationStatus.getFalse(); } - return ActivationStatus.getFalse(); + Permanent permanent = game.getBattlefield().getPermanent(this.getSourceId()); + if (permanent == null || !permanent.isCreature(game)) { + return ActivationStatus.getFalse(); + } + return super.canActivate(playerId, game); } @Override @@ -138,7 +130,7 @@ class MartyrdomRedirectDamageTargetEffect extends RedirectionEffect { 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 (filter.match(permanent, permanent.getControllerId(), source, game)) { if (event.getTargetId().equals(getTargetPointer().getFirst(game, source))) { if (event.getTargetId() != null) { TargetAnyTarget target = new TargetAnyTarget(); diff --git a/Mage.Sets/src/mage/cards/m/MartyrsBond.java b/Mage.Sets/src/mage/cards/m/MartyrsBond.java index 2b9d47bb5ce..a152e19f225 100644 --- a/Mage.Sets/src/mage/cards/m/MartyrsBond.java +++ b/Mage.Sets/src/mage/cards/m/MartyrsBond.java @@ -135,7 +135,7 @@ class MartyrsBondEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null && !playerId.equals(controller.getId())) { TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), playerId, game)) { + if (target.canChoose(playerId, source, game)) { player.chooseTarget(Outcome.Sacrifice, target, source, game); perms.add(target.getFirstTarget()); } diff --git a/Mage.Sets/src/mage/cards/m/MartyrsCry.java b/Mage.Sets/src/mage/cards/m/MartyrsCry.java index 2d7e1adeed5..b5928415c93 100644 --- a/Mage.Sets/src/mage/cards/m/MartyrsCry.java +++ b/Mage.Sets/src/mage/cards/m/MartyrsCry.java @@ -75,7 +75,7 @@ class MartyrsCryEffect extends OneShotEffect { return false; } List permanents = game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game ); Map playerMap = permanents .stream() diff --git a/Mage.Sets/src/mage/cards/m/MaskOfIntolerance.java b/Mage.Sets/src/mage/cards/m/MaskOfIntolerance.java index d685e2e230f..d8ad1f425e5 100644 --- a/Mage.Sets/src/mage/cards/m/MaskOfIntolerance.java +++ b/Mage.Sets/src/mage/cards/m/MaskOfIntolerance.java @@ -1,10 +1,8 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.IntCompareCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.DomainValue; @@ -15,22 +13,25 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.TargetController; -import mage.constants.Zone; import mage.game.Game; +import java.util.UUID; + /** - * * @author LoneFox */ public final class MaskOfIntolerance extends CardImpl { + private static final Condition condition = new MaskOfIntoleranceCondition(); + public MaskOfIntolerance(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // At the beginning of each player's upkeep, if there are four or more basic land types among lands that player controls, Mask of Intolerance deals 3 damage to that player. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new DamageTargetEffect(3), TargetController.ANY, false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new MaskOfIntoleranceCondition(), - "At the beginning of each player's upkeep, if there are four or more basic land types among lands that player controls, {this} deals 3 damage to that player.").addHint(DomainHint.instance)); + this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfUpkeepTriggeredAbility( + new DamageTargetEffect(3), TargetController.ANY, false + ), condition, "At the beginning of each player's upkeep, if there are four or more basic land types " + + "among lands that player controls, {this} deals 3 damage to that player.").addHint(DomainHint.instance)); } private MaskOfIntolerance(final MaskOfIntolerance card) { @@ -51,6 +52,6 @@ class MaskOfIntoleranceCondition extends IntCompareCondition { @Override protected int getInputValue(Game game, Ability source) { - return new DomainValue(1, game.getActivePlayerId()).calculate(game, source, null); + return DomainValue.ACTIVE.calculate(game, source, null); } } diff --git a/Mage.Sets/src/mage/cards/m/MaskOfTheSchemer.java b/Mage.Sets/src/mage/cards/m/MaskOfTheSchemer.java new file mode 100644 index 00000000000..d254d7d0f23 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaskOfTheSchemer.java @@ -0,0 +1,78 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MaskOfTheSchemer extends CardImpl { + + public MaskOfTheSchemer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{U}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Whenever equipped creature deals combat damage to a player, it connives X, where X is the amount of damage it dealt to that player. + this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility( + new MaskOfTheSchemerEffect(), "equipped", false + )); + + // Equip {2} + this.addAbility(new EquipAbility(2)); + } + + private MaskOfTheSchemer(final MaskOfTheSchemer card) { + super(card); + } + + @Override + public MaskOfTheSchemer copy() { + return new MaskOfTheSchemer(this); + } +} + +class MaskOfTheSchemerEffect extends OneShotEffect { + + MaskOfTheSchemerEffect() { + super(Outcome.Benefit); + staticText = "it connives X, where X is the amount of damage it dealt to that player. " + + "(Draw X card, then discard X cards. Put a +1/+1 counter " + + "on that creature for each nonland card discarded this way.)"; + } + + private MaskOfTheSchemerEffect(final MaskOfTheSchemerEffect effect) { + super(effect); + } + + @Override + public MaskOfTheSchemerEffect copy() { + return new MaskOfTheSchemerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent equipment = source.getSourcePermanentOrLKI(game); + int damage = (Integer) getValue("damage"); + if (equipment == null || damage < 1) { + return false; + } + Permanent permanent = game.getPermanent(equipment.getAttachedTo()); + if (permanent == null) { + return false; + } + return permanent != null && ConniveSourceEffect.connive(permanent, damage, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MaskedBandits.java b/Mage.Sets/src/mage/cards/m/MaskedBandits.java new file mode 100644 index 00000000000..dcf87bfd653 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MaskedBandits.java @@ -0,0 +1,45 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.GiveManaAbilityAndCastSourceAbility; +import mage.abilities.keyword.MenaceAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MaskedBandits extends CardImpl { + + public MaskedBandits(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{R}{G}"); + + this.subtype.add(SubType.RACCOON); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Menace + this.addAbility(new MenaceAbility()); + + // {2}, Exile Masked Bandits from your hand: Target land gains "{T}: Add {B}, {R}, or {G}" until Masked Bandits is cast from exile. You may cast Masked Bandits for as long as it remains exiled. + this.addAbility(new GiveManaAbilityAndCastSourceAbility("BRG")); + } + + private MaskedBandits(final MaskedBandits card) { + super(card); + } + + @Override + public MaskedBandits copy() { + return new MaskedBandits(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MasterOfArms.java b/Mage.Sets/src/mage/cards/m/MasterOfArms.java index 650ba2fa18b..1fbef160b7a 100644 --- a/Mage.Sets/src/mage/cards/m/MasterOfArms.java +++ b/Mage.Sets/src/mage/cards/m/MasterOfArms.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -12,19 +10,26 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LoneFox */ public final class MasterOfArms extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("creature blocking {this}"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.BLOCKING); + } + public MasterOfArms(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.SOLDIER); this.power = new MageInt(2); @@ -32,11 +37,10 @@ public final class MasterOfArms extends CardImpl { // First strike this.addAbility(FirstStrikeAbility.getInstance()); + // {1}{W}: Tap target creature blocking Master of Arms. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new ManaCostsImpl("{1}{W}")); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking {this}"); - filter.add(new BlockingAttackerIdPredicate(this.getId())); - ability.addTarget(new TargetCreaturePermanent(filter)); + Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new ManaCostsImpl<>("{1}{W}")); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MasterOfPearls.java b/Mage.Sets/src/mage/cards/m/MasterOfPearls.java index e3238f5cd45..e0733f71467 100644 --- a/Mage.Sets/src/mage/cards/m/MasterOfPearls.java +++ b/Mage.Sets/src/mage/cards/m/MasterOfPearls.java @@ -29,7 +29,7 @@ public final class MasterOfPearls extends CardImpl { this.toughness = new MageInt(2); // Morph {3}{W}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{W}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{W}{W}"))); // When Master of Pearls is turned face up, creatures you control get +2/+2 until end of turn. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new BoostControlledEffect(2, 2, Duration.EndOfTurn, FILTER_PERMANENT_CREATURES))); } diff --git a/Mage.Sets/src/mage/cards/m/MasterOfTheVeil.java b/Mage.Sets/src/mage/cards/m/MasterOfTheVeil.java index 339cc3dd012..8bae3f75117 100644 --- a/Mage.Sets/src/mage/cards/m/MasterOfTheVeil.java +++ b/Mage.Sets/src/mage/cards/m/MasterOfTheVeil.java @@ -44,7 +44,7 @@ public final class MasterOfTheVeil extends CardImpl { this.toughness = new MageInt(3); // Morph {2}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{U}"))); // When Master of the Veil is turned face up, you may turn target creature with a morph ability face down. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new MasterOfTheVeilEffect(), false, true); diff --git a/Mage.Sets/src/mage/cards/m/MasterTrinketeer.java b/Mage.Sets/src/mage/cards/m/MasterTrinketeer.java index 62dbdf42c70..ca21dfa78ab 100644 --- a/Mage.Sets/src/mage/cards/m/MasterTrinketeer.java +++ b/Mage.Sets/src/mage/cards/m/MasterTrinketeer.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -13,36 +11,42 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.game.permanent.token.ServoToken; +import java.util.UUID; + /** - * * @author fireshoes */ public final class MasterTrinketeer extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Servo and Thopter creatures"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Servos and Thopters"); static { - filter.add(Predicates.or(SubType.SERVO.getPredicate(), - SubType.THOPTER.getPredicate())); + filter.add(Predicates.or( + SubType.SERVO.getPredicate(), + SubType.THOPTER.getPredicate() + )); } public MasterTrinketeer(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.DWARF); this.subtype.add(SubType.ARTIFICER); this.power = new MageInt(3); this.toughness = new MageInt(2); // Servo and Thopter creatures you control get +1/+1. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filter, false))); + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 1, Duration.WhileOnBattlefield, filter, false + ))); // {3}{W}: Create a 1/1 colorless Servo artifact creature token. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new ServoToken(), 1), new ManaCostsImpl("{3}{W}"))); + this.addAbility(new SimpleActivatedAbility( + new CreateTokenEffect(new ServoToken(), 1), new ManaCostsImpl<>("{3}{W}") + )); } private MasterTrinketeer(final MasterTrinketeer card) { diff --git a/Mage.Sets/src/mage/cards/m/MasterWarcraft.java b/Mage.Sets/src/mage/cards/m/MasterWarcraft.java index f8451295410..8e1af2b218f 100644 --- a/Mage.Sets/src/mage/cards/m/MasterWarcraft.java +++ b/Mage.Sets/src/mage/cards/m/MasterWarcraft.java @@ -116,7 +116,7 @@ class MasterWarcraftChooseAttackersEffect extends ContinuousRuleModifyingEffectI if (!controller.chooseTarget(Outcome.Benefit, target, source, game)) { return false; // the attack declaration resumes for the active player as normal } - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(), source.getControllerId(), source, game)) { // Choose creatures that will be attacking this combat if (target.getTargets().contains(permanent.getId())) { diff --git a/Mage.Sets/src/mage/cards/m/MatcaRioters.java b/Mage.Sets/src/mage/cards/m/MatcaRioters.java index ded107e59ec..7476b3398d3 100644 --- a/Mage.Sets/src/mage/cards/m/MatcaRioters.java +++ b/Mage.Sets/src/mage/cards/m/MatcaRioters.java @@ -30,7 +30,7 @@ public final class MatcaRioters extends CardImpl { this.toughness = new MageInt(0); // Domain - Matca Rioters's power and toughness are each equal to the number of basic land types among lands you control. - Effect effect = new SetPowerToughnessSourceEffect(new DomainValue(), Duration.EndOfGame); + Effect effect = new SetPowerToughnessSourceEffect(DomainValue.REGULAR, Duration.EndOfGame); effect.setText("Domain — {this}'s power and toughness are each equal to the number of basic land types among lands you control."); this.addAbility(new SimpleStaticAbility(Zone.ALL, effect).addHint(DomainHint.instance)); } diff --git a/Mage.Sets/src/mage/cards/m/MayaelTheAnima.java b/Mage.Sets/src/mage/cards/m/MayaelTheAnima.java index 4ce1b241f7c..65806b51bb1 100644 --- a/Mage.Sets/src/mage/cards/m/MayaelTheAnima.java +++ b/Mage.Sets/src/mage/cards/m/MayaelTheAnima.java @@ -7,13 +7,13 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; +import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.PowerPredicate; @@ -41,8 +41,8 @@ public final class MayaelTheAnima extends CardImpl { // {3}{R}{G}{W}, {tap}: Look at the top five cards of your library. // You may put a creature card with power 5 or greater from among them onto the battlefield. // Put the rest on the bottom of your library in any order. - SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new LookLibraryAndPickControllerEffect(5,1, filter,false, false, Zone.BATTLEFIELD, true), + SimpleActivatedAbility ability = new SimpleActivatedAbility( + new LookLibraryAndPickControllerEffect(5, 1, filter, PutCards.BATTLEFIELD, PutCards.BOTTOM_ANY), new ManaCostsImpl("{3}{R}{G}{W}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/m/MayhemPatrol.java b/Mage.Sets/src/mage/cards/m/MayhemPatrol.java new file mode 100644 index 00000000000..567491701d4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MayhemPatrol.java @@ -0,0 +1,50 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.BlitzAbility; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MayhemPatrol extends CardImpl { + + public MayhemPatrol(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.DEVIL); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Menace + this.addAbility(new MenaceAbility()); + + // Whenever Mayhem Patrol attacks, target creature gets +1/+0 until end of turn. + Ability ability = new AttacksTriggeredAbility(new BoostTargetEffect(1, 0)); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + // Blitz {1}{R} + this.addAbility(new BlitzAbility(this, "{1}{R}")); + } + + private MayhemPatrol(final MayhemPatrol card) { + super(card); + } + + @Override + public MayhemPatrol copy() { + return new MayhemPatrol(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MeanderingTowershell.java b/Mage.Sets/src/mage/cards/m/MeanderingTowershell.java index a70162003ab..1baeccec205 100644 --- a/Mage.Sets/src/mage/cards/m/MeanderingTowershell.java +++ b/Mage.Sets/src/mage/cards/m/MeanderingTowershell.java @@ -72,7 +72,7 @@ class MeanderingTowershellEffect extends OneShotEffect { public MeanderingTowershellEffect() { super(Outcome.Detriment); - this.staticText = "exile it. Return it to the battlefield under your control tapped and attacking at the beginning of the next declare attackers step on your next turn"; + this.staticText = "exile it. Return it to the battlefield under your control tapped and attacking at the beginning of the declare attackers step on your next turn"; } public MeanderingTowershellEffect(final MeanderingTowershellEffect effect) { diff --git a/Mage.Sets/src/mage/cards/m/MeasureOfWickedness.java b/Mage.Sets/src/mage/cards/m/MeasureOfWickedness.java index 499dcd2bc31..0bcfd0d637c 100644 --- a/Mage.Sets/src/mage/cards/m/MeasureOfWickedness.java +++ b/Mage.Sets/src/mage/cards/m/MeasureOfWickedness.java @@ -19,7 +19,7 @@ import mage.constants.SubLayer; import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -34,7 +34,7 @@ public final class MeasureOfWickedness extends CardImpl { private static final FilterCard filter = new FilterCard("another card"); static { - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); } public MeasureOfWickedness(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MechtitanCore.java b/Mage.Sets/src/mage/cards/m/MechtitanCore.java new file mode 100644 index 00000000000..f3d1d3bac9b --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MechtitanCore.java @@ -0,0 +1,183 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.CompositeCost; +import mage.abilities.costs.common.ExileSourceCost; +import mage.abilities.costs.common.ExileTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.CrewAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.*; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.token.MechtitanToken; +import mage.game.permanent.token.Token; +import mage.players.Player; +import mage.target.common.TargetControlledPermanent; +import mage.target.targetpointer.FixedTargets; +import mage.util.CardUtil; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MechtitanCore extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledArtifactPermanent("other artifact creatures and/or Vehicles you control"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(Predicates.or( + CardType.CREATURE.getPredicate(), + SubType.VEHICLE.getPredicate() + )); + } + + public MechtitanCore(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // {5}, Exile Mechtitan Core and four other artifact creatures and/or Vehicles you control: Create Mechtitan, a legendary 10/10 Construct artifact creature token with flying, vigilance, trample, lifelink, and haste that's all colors. When that token leaves the battlefield, return all cards exiled with Mechtitan Core except Mechtitan Core to the battlefield tapped under their owners' control. + Ability ability = new SimpleActivatedAbility(new MechtitanCoreTokenEffect(), new GenericManaCost(5)); + ability.addCost(new CompositeCost( + new ExileSourceCost(), new ExileTargetCost(new TargetControlledPermanent(4, filter)), + "exile {this} and four other artifact creatures and/or Vehicles you control")); + this.addAbility(ability); + + // Crew 2 + this.addAbility(new CrewAbility(2)); + } + + private MechtitanCore(final MechtitanCore card) { + super(card); + } + + @Override + public MechtitanCore copy() { + return new MechtitanCore(this); + } +} + +class MechtitanCoreTokenEffect extends OneShotEffect { + + MechtitanCoreTokenEffect() { + super(Outcome.Benefit); + staticText = "create Mechtitan, a legendary 10/10 Construct artifact creature token with flying, " + + "vigilance, trample, lifelink, and haste that's all colors. " + + "When that token leaves the battlefield, return all cards exiled with {this} except " + + "{this} to the battlefield tapped under their owners' control"; + } + + private MechtitanCoreTokenEffect(final MechtitanCoreTokenEffect effect) { + super(effect); + } + + @Override + public MechtitanCoreTokenEffect copy() { + return new MechtitanCoreTokenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Token token = new MechtitanToken(); + token.putOntoBattlefield(1, game, source); + game.addDelayedTriggeredAbility(new MechtitanCoreTriggeredAbility(token, source, game), source); + return true; + } +} + +class MechtitanCoreTriggeredAbility extends DelayedTriggeredAbility { + + private final Set tokenIds = new HashSet<>(); + + MechtitanCoreTriggeredAbility(Token token, Ability source, Game game) { + super(new MechtitanCoreReturnEffect(), Duration.Custom, false, false); + this.getEffects().setTargetPointer(new FixedTargets(game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)), game)); + tokenIds.addAll(token.getLastAddedTokenIds()); + } + + private MechtitanCoreTriggeredAbility(final MechtitanCoreTriggeredAbility ability) { + super(ability); + this.tokenIds.addAll(ability.tokenIds); + } + + @Override + public MechtitanCoreTriggeredAbility copy() { + return new MechtitanCoreTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return tokenIds.contains(event.getTargetId()) + && ((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD; + } + + @Override + public boolean isInactive(Game game) { + return tokenIds + .stream() + .map(game::getPermanent) + .noneMatch(Objects::nonNull); + } + + @Override + public String getRule() { + return "When that token leaves the battlefield, return all cards exiled with {this} except " + + "{this} to the battlefield tapped under their owners' control"; + } +} + +class MechtitanCoreReturnEffect extends OneShotEffect { + + MechtitanCoreReturnEffect() { + super(Outcome.Benefit); + } + + private MechtitanCoreReturnEffect(final MechtitanCoreReturnEffect effect) { + super(effect); + } + + @Override + public MechtitanCoreReturnEffect copy() { + return new MechtitanCoreReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(getTargetPointer().getTargets(game, source)); + return player.moveCards( + cards.getCards(game), Zone.BATTLEFIELD, source, game, + true, false, true, null + ); + } +} +// and I'll form the head! diff --git a/Mage.Sets/src/mage/cards/m/MeddlingMage.java b/Mage.Sets/src/mage/cards/m/MeddlingMage.java index fbe56650a40..ddd4654e737 100644 --- a/Mage.Sets/src/mage/cards/m/MeddlingMage.java +++ b/Mage.Sets/src/mage/cards/m/MeddlingMage.java @@ -70,7 +70,7 @@ class MeddlingMageReplacementEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast a spell with that name (" + mageObject.getName() + " in play)."; } diff --git a/Mage.Sets/src/mage/cards/m/MedomaisProphecy.java b/Mage.Sets/src/mage/cards/m/MedomaisProphecy.java index 85079d76fc0..4424a709475 100644 --- a/Mage.Sets/src/mage/cards/m/MedomaisProphecy.java +++ b/Mage.Sets/src/mage/cards/m/MedomaisProphecy.java @@ -61,7 +61,7 @@ class MedomaisProphecyTriggerEffect extends OneShotEffect { MedomaisProphecyTriggerEffect() { super(Outcome.Benefit); - staticText = "When you cast a spell with the chosen card name for the first time this turn, draw two cards."; + staticText = "When you cast a spell with the chosen name for the first time this turn, draw two cards."; } private MedomaisProphecyTriggerEffect(final MedomaisProphecyTriggerEffect effect) { diff --git a/Mage.Sets/src/mage/cards/m/MeetingOfTheFive.java b/Mage.Sets/src/mage/cards/m/MeetingOfTheFive.java new file mode 100644 index 00000000000..6d6b605215c --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MeetingOfTheFive.java @@ -0,0 +1,144 @@ +package mage.cards.m; + +import mage.ConditionalMana; +import mage.MageObject; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.Cost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.asthought.CanPlayCardControllerEffect; +import mage.abilities.effects.mana.AddConditionalManaEffect; +import mage.abilities.mana.builder.ConditionalManaBuilder; +import mage.abilities.mana.conditional.ManaCondition; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MeetingOfTheFive extends CardImpl { + + public MeetingOfTheFive(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{W}{U}{B}{R}{G}"); + + // Exile the top ten cards of your library. You may cast spells with exactly three colors from among them this turn. Add {W}{W}{U}{U}{B}{B}{R}{R}{G}{G}. Spend this mana only to cast spells with exactly three colors. + this.getSpellAbility().addEffect(new MeetingOfTheFiveExileEffect()); + this.getSpellAbility().addEffect(new AddConditionalManaEffect(new Mana( + 2, 2, 2, 2, 2, 0, 0, 0 + ), new MeetingOfTheFiveManaBuilder())); + } + + private MeetingOfTheFive(final MeetingOfTheFive card) { + super(card); + } + + @Override + public MeetingOfTheFive copy() { + return new MeetingOfTheFive(this); + } +} + +class MeetingOfTheFiveExileEffect extends OneShotEffect { + + MeetingOfTheFiveExileEffect() { + super(Outcome.Benefit); + staticText = "exile the top ten cards of your library. You may cast " + + "spells with exactly three colors from among them this turn"; + } + + private MeetingOfTheFiveExileEffect(final MeetingOfTheFiveExileEffect effect) { + super(effect); + } + + @Override + public MeetingOfTheFiveExileEffect copy() { + return new MeetingOfTheFiveExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 10)); + if (cards.isEmpty()) { + return false; + } + player.moveCards(cards, Zone.EXILED, source, game); + for (Card card : cards.getCards(game)) { + game.addEffect(new MeetingOfTheFiveCastEffect(game, card), source); + } + return true; + } +} + +class MeetingOfTheFiveCastEffect extends CanPlayCardControllerEffect { + + MeetingOfTheFiveCastEffect(Game game, Card card) { + super(game, card.getId(), card.getZoneChangeCounter(game), Duration.EndOfTurn); + } + + private MeetingOfTheFiveCastEffect(final MeetingOfTheFiveCastEffect effect) { + super(effect); + } + + @Override + public MeetingOfTheFiveCastEffect copy() { + return new MeetingOfTheFiveCastEffect(this); + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + return super.applies(sourceId, source, affectedControllerId, game) + && game.getCard(sourceId).getColor(game).getColorCount() == 3; + } +} + +class MeetingOfTheFiveManaBuilder extends ConditionalManaBuilder { + + @Override + public ConditionalMana build(Object... options) { + return new MeetingOfTheFiveConditionalMana(this.mana); + } + + @Override + public String getRule() { + return "Spend this mana only to cast spells with exactly three colors"; + } +} + +class MeetingOfTheFiveConditionalMana extends ConditionalMana { + + public MeetingOfTheFiveConditionalMana(Mana mana) { + super(mana); + staticText = "Spend this mana only to cast spells with exactly three colors"; + addCondition(new MeetingOfTheFiveManaCondition()); + } +} + +class MeetingOfTheFiveManaCondition extends ManaCondition implements Condition { + + @Override + public boolean apply(Game game, Ability source) { + if (!(source instanceof SpellAbility)) { + return false; + } + MageObject object = game.getObject(source); + return object != null && object.getColor(game).getColorCount() == 3; + } + + @Override + public boolean apply(Game game, Ability source, UUID originalId, Cost costsToPay) { + return apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MeganticSliver.java b/Mage.Sets/src/mage/cards/m/MeganticSliver.java index 2e0ae9898fa..069a4e564ea 100644 --- a/Mage.Sets/src/mage/cards/m/MeganticSliver.java +++ b/Mage.Sets/src/mage/cards/m/MeganticSliver.java @@ -1,20 +1,18 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.BoostControlledEffect; 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.constants.SubType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class MeganticSliver extends CardImpl { @@ -27,7 +25,10 @@ public final class MeganticSliver extends CardImpl { this.toughness = new MageInt(3); // Sliver creatures you control get +3/+3. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(3, 3, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS))); + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 3, 3, Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_SLIVERS + ))); } private MeganticSliver(final MeganticSliver card) { diff --git a/Mage.Sets/src/mage/cards/m/Meglonoth.java b/Mage.Sets/src/mage/cards/m/Meglonoth.java index 7769165fffe..870b0f67276 100644 --- a/Mage.Sets/src/mage/cards/m/Meglonoth.java +++ b/Mage.Sets/src/mage/cards/m/Meglonoth.java @@ -2,7 +2,7 @@ package mage.cards.m; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.BlocksSourceTriggeredAbility; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.VigilanceAbility; @@ -35,7 +35,7 @@ public final class Meglonoth extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Whenever Meglonoth blocks a creature, Meglonoth deals damage to that creature's controller equal to Meglonoth's power. - this.addAbility(new BlocksSourceTriggeredAbility(new MeglonothEffect(), false, true)); + this.addAbility(new BlocksCreatureTriggeredAbility(new MeglonothEffect())); } diff --git a/Mage.Sets/src/mage/cards/m/MeletisAstronomer.java b/Mage.Sets/src/mage/cards/m/MeletisAstronomer.java index 1ed62998eef..74c2d17d17b 100644 --- a/Mage.Sets/src/mage/cards/m/MeletisAstronomer.java +++ b/Mage.Sets/src/mage/cards/m/MeletisAstronomer.java @@ -1,16 +1,16 @@ - package mage.cards.m; import java.util.UUID; import mage.MageInt; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.HeroicAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; +import mage.filter.common.FilterEnchantmentCard; /** * @@ -18,11 +18,8 @@ import mage.filter.FilterCard; */ public final class MeletisAstronomer extends CardImpl { - private static final FilterCard filter = new FilterCard("an enchantment card"); - static { - filter.add(CardType.ENCHANTMENT.getPredicate()); - } - + private static final FilterCard filter = new FilterEnchantmentCard("an enchantment card"); + public MeletisAstronomer(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); this.subtype.add(SubType.HUMAN); @@ -32,7 +29,7 @@ public final class MeletisAstronomer extends CardImpl { this.toughness = new MageInt(3); // Heroic — Whenever you cast a spell that targets Meletis Astronomer, look at the top three cards of your library. You may reveal an enchantment card from among them and put it into your hand. Put the rest on the bottom of your library in any order. - this.addAbility(new HeroicAbility(new LookLibraryAndPickControllerEffect(3, 1, filter, true, false, Zone.HAND, true), false)); + this.addAbility(new HeroicAbility(new LookLibraryAndPickControllerEffect(3, 1, filter, PutCards.HAND, PutCards.BOTTOM_ANY))); } private MeletisAstronomer(final MeletisAstronomer card) { diff --git a/Mage.Sets/src/mage/cards/m/Melting.java b/Mage.Sets/src/mage/cards/m/Melting.java index c1827df03cd..ff759cdf784 100644 --- a/Mage.Sets/src/mage/cards/m/Melting.java +++ b/Mage.Sets/src/mage/cards/m/Melting.java @@ -61,7 +61,7 @@ class MeltingEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanent.getSuperType().remove(SuperType.SNOW); } return true; diff --git a/Mage.Sets/src/mage/cards/m/MemorialToUnity.java b/Mage.Sets/src/mage/cards/m/MemorialToUnity.java index 20218b09d23..40ee1b646e0 100644 --- a/Mage.Sets/src/mage/cards/m/MemorialToUnity.java +++ b/Mage.Sets/src/mage/cards/m/MemorialToUnity.java @@ -1,4 +1,3 @@ - package mage.cards.m; import mage.abilities.Ability; @@ -7,15 +6,13 @@ 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.dynamicvalue.common.StaticValue; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.mana.GreenManaAbility; 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 java.util.UUID; @@ -27,21 +24,20 @@ public final class MemorialToUnity extends CardImpl { public MemorialToUnity(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - // Memorial to Uniity enters the battlefield tapped. + // Memorial to Unity enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); this.addAbility(new GreenManaAbility()); - // {2}{G}, {T}, Sacrifice Memorial to Unity: Look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. Then put the rest on the bottom of your library in a random order. - Effect effect = new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), new FilterCreatureCard("a creature card"), false, true - ).setBackInRandomOrder(true); - - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{2}{G}")); + // {2}{G}, {T}, Sacrifice Memorial to Unity: Look at the top five cards of your library. + // You may reveal a creature card from among them and put it into your hand. + // Then put the rest on the bottom of your library in a random order. + Ability ability = new SimpleActivatedAbility( + new LookLibraryAndPickControllerEffect(5, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_RANDOM), + new ManaCostsImpl("{2}{G}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); - } private MemorialToUnity(final MemorialToUnity card) { @@ -52,5 +48,4 @@ public final class MemorialToUnity extends CardImpl { public MemorialToUnity copy() { return new MemorialToUnity(this); } - } diff --git a/Mage.Sets/src/mage/cards/m/MemoryDeluge.java b/Mage.Sets/src/mage/cards/m/MemoryDeluge.java index 76bd75248d6..c713c1bb139 100644 --- a/Mage.Sets/src/mage/cards/m/MemoryDeluge.java +++ b/Mage.Sets/src/mage/cards/m/MemoryDeluge.java @@ -2,14 +2,12 @@ package mage.cards.m; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.ManaSpentToCastCount; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.FlashbackAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import java.util.UUID; @@ -23,9 +21,8 @@ public final class MemoryDeluge extends CardImpl { // Look at the top X cards of your library, where X is the amount of mana spent to cast this spell. Put two of them into your hand and the rest on the bottom of your library in a random order. this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - ManaSpentToCastCount.instance, false, StaticValue.get(2), - StaticFilters.FILTER_CARD, Zone.LIBRARY, false, false - ).setBackInRandomOrder(true).setText("look at the top X cards of your library, where X " + + ManaSpentToCastCount.instance, 2, PutCards.HAND, PutCards.BOTTOM_RANDOM + ).setText("look at the top X cards of your library, where X " + "is the amount of mana spent to cast this spell. Put two of them into your " + "hand and the rest on the bottom of your library in a random order")); diff --git a/Mage.Sets/src/mage/cards/m/MemoryErosion.java b/Mage.Sets/src/mage/cards/m/MemoryErosion.java index 1d4967685e3..5250cac0f0d 100644 --- a/Mage.Sets/src/mage/cards/m/MemoryErosion.java +++ b/Mage.Sets/src/mage/cards/m/MemoryErosion.java @@ -1,31 +1,23 @@ - package mage.cards.m; -import java.util.UUID; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect; +import mage.abilities.common.SpellCastOpponentTriggeredAbility; +import mage.abilities.effects.common.MillCardsTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.stack.Spell; -import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; /** - * * @author Plopman */ public final class MemoryErosion extends CardImpl { public MemoryErosion(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{U}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}{U}"); // Whenever an opponent casts a spell, that player puts the top two cards of their library into their graveyard. - this.addAbility(new SpellCastTriggeredAbility()); + this.addAbility(new SpellCastOpponentTriggeredAbility(new MillCardsTargetEffect(2), false)); } private MemoryErosion(final MemoryErosion card) { @@ -37,42 +29,3 @@ public final class MemoryErosion extends CardImpl { return new MemoryErosion(this); } } - - -class SpellCastTriggeredAbility extends TriggeredAbilityImpl { - - public SpellCastTriggeredAbility() { - super(Zone.BATTLEFIELD, new PutLibraryIntoGraveTargetEffect(2), false); - } - - - - public SpellCastTriggeredAbility(final SpellCastTriggeredAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SPELL_CAST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null && game.getOpponents(this.getControllerId()).contains(spell.getControllerId())) { - this.getEffects().get(0).setTargetPointer(new FixedTarget(event.getPlayerId())); - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever an opponent casts a spell, that player mills two cards"; - } - - @Override - public SpellCastTriggeredAbility copy() { - return new SpellCastTriggeredAbility(this); - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/MemoryJar.java b/Mage.Sets/src/mage/cards/m/MemoryJar.java index 66876a13891..d5aa4537057 100644 --- a/Mage.Sets/src/mage/cards/m/MemoryJar.java +++ b/Mage.Sets/src/mage/cards/m/MemoryJar.java @@ -131,7 +131,7 @@ class MemoryJarDelayedEffect extends OneShotEffect { continue; } player.discard(player.getHand(), false, source, game); - player.moveCards(cards.getCards(filter, source.getSourceId(), playerId, game), Zone.HAND, source, game); + player.moveCards(cards.getCards(filter, playerId, source, game), Zone.HAND, source, game); } return true; } diff --git a/Mage.Sets/src/mage/cards/m/MemorySluice.java b/Mage.Sets/src/mage/cards/m/MemorySluice.java index a911e031f89..13ee4e0952f 100644 --- a/Mage.Sets/src/mage/cards/m/MemorySluice.java +++ b/Mage.Sets/src/mage/cards/m/MemorySluice.java @@ -23,7 +23,7 @@ public final class MemorySluice extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayer()); // Conspire - this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE)); + this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.ONE)); } diff --git a/Mage.Sets/src/mage/cards/m/MemoryTheft.java b/Mage.Sets/src/mage/cards/m/MemoryTheft.java index ae3d3ec6007..ea88bfaf0c4 100644 --- a/Mage.Sets/src/mage/cards/m/MemoryTheft.java +++ b/Mage.Sets/src/mage/cards/m/MemoryTheft.java @@ -77,8 +77,8 @@ class MemoryTheftEffect extends OneShotEffect { filter.add(AdventurePredicate.instance); filter.add(new OwnerIdPredicate(player.getId())); TargetCard target = new TargetCardInExile(0, 1, filter, null, true); - if (!target.canChoose(source.getSourceId(), source.getControllerId(), game) - || !controller.choose(outcome, target, source.getSourceId(), game)) { + if (!target.canChoose(source.getControllerId(), source, game) + || !controller.choose(outcome, target, source, game)) { return false; } Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/m/MentorsGuidance.java b/Mage.Sets/src/mage/cards/m/MentorsGuidance.java index 47def4b42a5..e53de32e14a 100644 --- a/Mage.Sets/src/mage/cards/m/MentorsGuidance.java +++ b/Mage.Sets/src/mage/cards/m/MentorsGuidance.java @@ -41,10 +41,9 @@ public final class MentorsGuidance extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}"); // When you cast this spell, copy it if you control a planeswalker, Cleric, Druid, Shaman, Warlock, or Wizard. - new CastSourceTriggeredAbility(new ConditionalOneShotEffect( + this.addAbility(new CastSourceTriggeredAbility(new ConditionalOneShotEffect( new CopySourceSpellEffect(), condition, "copy it if you control " + - "a planeswalker, Cleric, Druid, Shaman, Warlock, or Wizard" - )); + "a planeswalker, Cleric, Druid, Shaman, Warlock, or Wizard"))); // Scry 1, then draw a card. this.getSpellAbility().addEffect(new ScryEffect(1, false)); diff --git a/Mage.Sets/src/mage/cards/m/MercadianLift.java b/Mage.Sets/src/mage/cards/m/MercadianLift.java index 57cbc2c200f..2820d04314b 100644 --- a/Mage.Sets/src/mage/cards/m/MercadianLift.java +++ b/Mage.Sets/src/mage/cards/m/MercadianLift.java @@ -85,9 +85,9 @@ class MercadianLiftEffect extends OneShotEffect { filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, numberOfCounters)); filter.setMessage("creature card with mana value " + numberOfCounters); TargetCardInHand target = new TargetCardInHand(filter); - if (target.canChoose(source.getSourceId(), controller.getId(), game) + if (target.canChoose(controller.getId(), source, game) && controller.chooseUse(Outcome.PutCardInPlay, "Put " + filter.getMessage() + " from your hand onto the battlefield?", source, game) - && controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { + && controller.choose(Outcome.PutCardInPlay, target, source, game)) { target.setRequired(false); Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/m/MerchantsDockhand.java b/Mage.Sets/src/mage/cards/m/MerchantsDockhand.java index b61b910d7ff..91f8459dd9c 100644 --- a/Mage.Sets/src/mage/cards/m/MerchantsDockhand.java +++ b/Mage.Sets/src/mage/cards/m/MerchantsDockhand.java @@ -74,7 +74,7 @@ class MerchantsDockhandEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } @@ -129,7 +129,7 @@ class TapXTargetCost extends VariableCostImpl { @Override public int getMaxValue(Ability source, Game game) { - return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + return game.getBattlefield().count(filter, source.getControllerId(), source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/m/MercilessEviction.java b/Mage.Sets/src/mage/cards/m/MercilessEviction.java index 0cb8a74dbff..50b27a1f235 100644 --- a/Mage.Sets/src/mage/cards/m/MercilessEviction.java +++ b/Mage.Sets/src/mage/cards/m/MercilessEviction.java @@ -1,19 +1,18 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.ExileAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES; +import mage.filter.StaticFilters; import mage.filter.common.FilterArtifactPermanent; import mage.filter.common.FilterEnchantmentPermanent; import mage.filter.common.FilterPlaneswalkerPermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class MercilessEviction extends CardImpl { @@ -24,17 +23,12 @@ public final class MercilessEviction extends CardImpl { // Choose one - Exile all artifacts this.getSpellAbility().addEffect(new ExileAllEffect(new FilterArtifactPermanent("artifacts"))); // or exile all creatures - Mode mode = new Mode(); - mode.addEffect(new ExileAllEffect(FILTER_PERMANENT_CREATURES)); + Mode mode = new Mode(new ExileAllEffect(StaticFilters.FILTER_PERMANENT_CREATURES)); this.getSpellAbility().addMode(mode); // or exile all enchantments - Mode mode2 = new Mode(); - mode2.addEffect(new ExileAllEffect(new FilterEnchantmentPermanent("enchantments"))); - this.getSpellAbility().addMode(mode2); + this.getSpellAbility().addMode(new Mode(new ExileAllEffect(new FilterEnchantmentPermanent("enchantments")))); // or exile all planeswalkers. - Mode mode3 = new Mode(); - mode3.addEffect(new ExileAllEffect(new FilterPlaneswalkerPermanent("planeswalkers"))); - this.getSpellAbility().addMode(mode3); + this.getSpellAbility().addMode(new Mode(new ExileAllEffect(new FilterPlaneswalkerPermanent("planeswalkers")))); } private MercilessEviction(final MercilessEviction card) { diff --git a/Mage.Sets/src/mage/cards/m/MercyKilling.java b/Mage.Sets/src/mage/cards/m/MercyKilling.java index 26df6d23deb..62988d9aa91 100644 --- a/Mage.Sets/src/mage/cards/m/MercyKilling.java +++ b/Mage.Sets/src/mage/cards/m/MercyKilling.java @@ -1,4 +1,3 @@ - package mage.cards.m; import java.util.UUID; @@ -11,7 +10,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.permanent.token.MercyKillingToken; +import mage.game.permanent.token.GreenWhiteElfWarriorToken; import mage.target.common.TargetCreaturePermanent; /** @@ -59,7 +58,7 @@ class MercyKillingTokenEffect extends OneShotEffect { Permanent permanent = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); if (permanent != null) { int power = permanent.getPower().getValue(); - return new MercyKillingToken().putOntoBattlefield(power, game, source, permanent.getControllerId()); + return new GreenWhiteElfWarriorToken().putOntoBattlefield(power, game, source, permanent.getControllerId()); } return false; } diff --git a/Mage.Sets/src/mage/cards/m/MerfolkWayfinder.java b/Mage.Sets/src/mage/cards/m/MerfolkWayfinder.java index 2d88c82aa58..d0d36179d2d 100644 --- a/Mage.Sets/src/mage/cards/m/MerfolkWayfinder.java +++ b/Mage.Sets/src/mage/cards/m/MerfolkWayfinder.java @@ -19,7 +19,7 @@ import mage.filter.FilterCard; */ public final class MerfolkWayfinder extends CardImpl { - private static final FilterCard filter = new FilterCard("all Island cards"); + private static final FilterCard filter = new FilterCard("Island cards"); static { filter.add(SubType.ISLAND.getPredicate()); diff --git a/Mage.Sets/src/mage/cards/m/MerrowReejerey.java b/Mage.Sets/src/mage/cards/m/MerrowReejerey.java index 61e8d2c1c16..c729be9312d 100644 --- a/Mage.Sets/src/mage/cards/m/MerrowReejerey.java +++ b/Mage.Sets/src/mage/cards/m/MerrowReejerey.java @@ -23,7 +23,7 @@ import mage.target.TargetPermanent; public final class MerrowReejerey extends CardImpl { private static final FilterCreaturePermanent filter1 = new FilterCreaturePermanent("Merfolk creatures you control"); - private static final FilterSpell filter2 = new FilterSpell("Merfolk spell"); + private static final FilterSpell filter2 = new FilterSpell("a Merfolk spell"); static { filter1.add(SubType.MERFOLK.getPredicate()); diff --git a/Mage.Sets/src/mage/cards/m/MessengerJays.java b/Mage.Sets/src/mage/cards/m/MessengerJays.java index 67cbe0eccd0..596b5a35f28 100644 --- a/Mage.Sets/src/mage/cards/m/MessengerJays.java +++ b/Mage.Sets/src/mage/cards/m/MessengerJays.java @@ -8,6 +8,7 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.choices.TwoChoiceVote; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; @@ -36,7 +37,7 @@ public final class MessengerJays extends CardImpl { // Council's dilemma — When Messenger Jays enters the battlefield, starting with you, each player votes for feather or quill. Put a +1/+1 counter on Messenger Jays for each feather vote and draw a card for each quill vote. For each card drawn this way, discard a card. this.addAbility(new EntersBattlefieldTriggeredAbility( new MessengerJaysEffect(), false) - .withFlavorWord("Council's dilemma") + .setAbilityWord(AbilityWord.COUNCILS_DILEMMA) ); } diff --git a/Mage.Sets/src/mage/cards/m/MetallurgicSummonings.java b/Mage.Sets/src/mage/cards/m/MetallurgicSummonings.java index c3916cadfe6..cc1da00503e 100644 --- a/Mage.Sets/src/mage/cards/m/MetallurgicSummonings.java +++ b/Mage.Sets/src/mage/cards/m/MetallurgicSummonings.java @@ -115,8 +115,8 @@ class MetallurgicSummoningsReturnEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - return controller.moveCards(controller.getGraveyard().getCards(new FilterInstantOrSorceryCard(), source.getSourceId(), - source.getControllerId(), game), Zone.HAND, source, game); + return controller.moveCards(controller.getGraveyard().getCards(new FilterInstantOrSorceryCard(), + source.getControllerId(), source, game), Zone.HAND, source, game); } return false; } diff --git a/Mage.Sets/src/mage/cards/m/MetalworkColossus.java b/Mage.Sets/src/mage/cards/m/MetalworkColossus.java index ac9e1e7a841..2f1ccbd1152 100644 --- a/Mage.Sets/src/mage/cards/m/MetalworkColossus.java +++ b/Mage.Sets/src/mage/cards/m/MetalworkColossus.java @@ -72,7 +72,7 @@ class MetalworkColossusCostReductionEffect extends CostModificationEffectImpl { @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { int totalCMC = 0; - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { totalCMC += permanent.getManaValue(); } CardUtil.reduceCost(abilityToModify, totalCMC); diff --git a/Mage.Sets/src/mage/cards/m/Metalworker.java b/Mage.Sets/src/mage/cards/m/Metalworker.java index dbf1542a47d..efb1da4e438 100644 --- a/Mage.Sets/src/mage/cards/m/Metalworker.java +++ b/Mage.Sets/src/mage/cards/m/Metalworker.java @@ -95,7 +95,7 @@ class MetalworkerManaEffect extends ManaEffect { int artifacts = controller.getHand().count(StaticFilters.FILTER_CARD_ARTIFACT, game); if (artifacts > 0) { TargetCardInHand target = new TargetCardInHand(0, Integer.MAX_VALUE, StaticFilters.FILTER_CARD_ARTIFACT); - if (controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.Benefit, target, source, game)) { Cards cards = new CardsImpl(target.getTargets()); controller.revealCards(source, cards, game); return Mana.ColorlessMana(target.getTargets().size() * 2); diff --git a/Mage.Sets/src/mage/cards/m/MetamorphicAlteration.java b/Mage.Sets/src/mage/cards/m/MetamorphicAlteration.java index 0b7805593a6..a03bce8582d 100644 --- a/Mage.Sets/src/mage/cards/m/MetamorphicAlteration.java +++ b/Mage.Sets/src/mage/cards/m/MetamorphicAlteration.java @@ -72,7 +72,7 @@ class ChooseACreature extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getPermanentEntering(source.getSourceId()); if (sourceObject == null) { - sourceObject = game.getObject(source.getSourceId()); + sourceObject = game.getObject(source); } if (controller == null || sourceObject == null) { @@ -80,10 +80,10 @@ class ChooseACreature extends OneShotEffect { } Target target = new TargetCreaturePermanent(); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), controller.getId(), game)) { + if (!target.canChoose(controller.getId(), source, game)) { return true; } - controller.choose(Outcome.Copy, target, source.getSourceId(), game); + controller.choose(Outcome.Copy, target, source, game); Permanent chosenPermanent = game.getPermanent(target.getFirstTarget()); if (chosenPermanent != null) { game.getState().setValue(source.getSourceId().toString() + INFO_KEY, chosenPermanent.copy()); diff --git a/Mage.Sets/src/mage/cards/m/MetropolisAngel.java b/Mage.Sets/src/mage/cards/m/MetropolisAngel.java new file mode 100644 index 00000000000..30d8095dba9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MetropolisAngel.java @@ -0,0 +1,53 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.CounterAnyPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MetropolisAngel extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creatures with counters on them"); + + static { + filter.add(CounterAnyPredicate.instance); + } + + public MetropolisAngel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}"); + + this.subtype.add(SubType.ANGEL); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever you attack with one or more creatures with counters on them, draw a card. + this.addAbility(new AttacksWithCreaturesTriggeredAbility( + new DrawCardSourceControllerEffect(1), 1, filter + ).setTriggerPhrase("Whenever you attack with one or more creatures with counters on them, ")); + } + + private MetropolisAngel(final MetropolisAngel card) { + super(card); + } + + @Override + public MetropolisAngel copy() { + return new MetropolisAngel(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MezzioMugger.java b/Mage.Sets/src/mage/cards/m/MezzioMugger.java new file mode 100644 index 00000000000..226beed5919 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MezzioMugger.java @@ -0,0 +1,92 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.BlitzAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class MezzioMugger extends CardImpl { + + public MezzioMugger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + + this.subtype.add(SubType.VIASHINO); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever Mezzio Mugger attacks, exile the top card of each player's library. You may play those cards this turn, and you may spend mana as though it were mana of any color to cast those spells. + this.addAbility(new AttacksTriggeredAbility(new MezzioMuggerEffect())); + + // Blitz {2}{R} + this.addAbility(new BlitzAbility(this, "{2}{R}")); + } + + private MezzioMugger(final MezzioMugger card) { + super(card); + } + + @Override + public MezzioMugger copy() { + return new MezzioMugger(this); + } +} + +class MezzioMuggerEffect extends OneShotEffect { + + MezzioMuggerEffect() { + super(Outcome.Benefit); + staticText = "exile the top card of each player's library. You may play those cards this turn, " + + "and you may spend mana as though it were mana of any color to cast those spells"; + } + + private MezzioMuggerEffect(final MezzioMuggerEffect effect) { + super(effect); + } + + @Override + public MezzioMuggerEffect copy() { + return new MezzioMuggerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Set cards = game + .getOpponents(source.getControllerId()) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .map(Player::getLibrary) + .map(library -> library.getFromTop(game)) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + if (cards.isEmpty()) { + return false; + } + player.moveCards(cards, Zone.EXILED, source, game); + for (Card card : cards) { + CardUtil.makeCardPlayable(game, source, card, Duration.EndOfTurn, true); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MichikosReignOfTruth.java b/Mage.Sets/src/mage/cards/m/MichikosReignOfTruth.java index d3c4ed1e091..5a51a1f201c 100644 --- a/Mage.Sets/src/mage/cards/m/MichikosReignOfTruth.java +++ b/Mage.Sets/src/mage/cards/m/MichikosReignOfTruth.java @@ -33,12 +33,12 @@ public final class MichikosReignOfTruth extends CardImpl { this.secondSideCardClazz = mage.cards.p.PortraitOfMichiko.class; // (As this Saga enters and after your draw step, add a lore counter.) - SagaAbility sagaAbility = new SagaAbility(this, SagaChapter.CHAPTER_I); + SagaAbility sagaAbility = new SagaAbility(this); // I, II — Target creature gets +1/+1 until end of turn for each artifact and/or enchantment you control. sagaAbility.addChapterEffect( this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, - new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn) + new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn, true) .setText("target creature gets +1/+1 until end of turn " + "for each artifact and/or enchantment you control"), new TargetCreaturePermanent() diff --git a/Mage.Sets/src/mage/cards/m/MidnightArsonist.java b/Mage.Sets/src/mage/cards/m/MidnightArsonist.java index f65ca30b814..2bea621b657 100644 --- a/Mage.Sets/src/mage/cards/m/MidnightArsonist.java +++ b/Mage.Sets/src/mage/cards/m/MidnightArsonist.java @@ -65,7 +65,7 @@ enum MidnightArsonistAdjuster implements TargetAdjuster { @Override public void adjustTargets(Ability ability, Game game) { - int vampires = game.getBattlefield().count(filter, ability.getSourceId(), ability.getControllerId(), game); + int vampires = game.getBattlefield().count(filter, ability.getControllerId(), ability, game); ability.getTargets().clear(); ability.addTarget(new TargetPermanent(0, vampires, filter2)); } diff --git a/Mage.Sets/src/mage/cards/m/MidnightAssassin.java b/Mage.Sets/src/mage/cards/m/MidnightAssassin.java new file mode 100644 index 00000000000..9c1c145415d --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MidnightAssassin.java @@ -0,0 +1,41 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author weirddan455 + */ +public final class MidnightAssassin extends CardImpl { + + public MidnightAssassin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + } + + private MidnightAssassin(final MidnightAssassin card) { + super(card); + } + + @Override + public MidnightAssassin copy() { + return new MidnightAssassin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MidnightCharm.java b/Mage.Sets/src/mage/cards/m/MidnightCharm.java index 05e60609d91..d119f482537 100644 --- a/Mage.Sets/src/mage/cards/m/MidnightCharm.java +++ b/Mage.Sets/src/mage/cards/m/MidnightCharm.java @@ -27,12 +27,10 @@ public final class MidnightCharm extends CardImpl { this.getSpellAbility().addEffect(new DamageTargetEffect(1)); this.getSpellAbility().addEffect(new GainLifeEffect(1).setText("and you gain 1 life")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - Mode mode = new Mode(); - mode.addEffect(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn)); + Mode mode = new Mode(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); - mode = new Mode(); - mode.addEffect(new TapTargetEffect()); + mode = new Mode(new TapTargetEffect()); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/m/MidnightOil.java b/Mage.Sets/src/mage/cards/m/MidnightOil.java index 97280100aea..5e064df5f95 100644 --- a/Mage.Sets/src/mage/cards/m/MidnightOil.java +++ b/Mage.Sets/src/mage/cards/m/MidnightOil.java @@ -38,7 +38,8 @@ public final class MidnightOil extends CardImpl { // At the beginning of your draw step, draw an additional card and remove two hour counters from Midnight Oil. Ability ability = new BeginningOfDrawTriggeredAbility( - new DrawCardSourceControllerEffect(1), + new DrawCardSourceControllerEffect(1) + .setText("draw an additional card"), TargetController.YOU, false ); ability.addEffect(new RemoveCounterSourceEffect( diff --git a/Mage.Sets/src/mage/cards/m/MidnightPathlighter.java b/Mage.Sets/src/mage/cards/m/MidnightPathlighter.java index a4d2c8773ad..8699dbf7eb2 100644 --- a/Mage.Sets/src/mage/cards/m/MidnightPathlighter.java +++ b/Mage.Sets/src/mage/cards/m/MidnightPathlighter.java @@ -1,7 +1,7 @@ package mage.cards.m; import mage.MageInt; -import mage.abilities.common.ControlledCreaturesDealCombatDamagePlayerTriggeredAbility; +import mage.abilities.common.DealCombatDamageControlledTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesAllEffect; import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect; @@ -44,7 +44,7 @@ public final class MidnightPathlighter extends CardImpl { ))); // Whenever one or more creatures you control deal combat damage to a player, venture into the dungeon. - this.addAbility(new ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(new VentureIntoTheDungeonEffect())); + this.addAbility(new DealCombatDamageControlledTriggeredAbility(new VentureIntoTheDungeonEffect())); } private MidnightPathlighter(final MidnightPathlighter card) { diff --git a/Mage.Sets/src/mage/cards/m/MightMakesRight.java b/Mage.Sets/src/mage/cards/m/MightMakesRight.java index 0e6054e7a38..39778cbe061 100644 --- a/Mage.Sets/src/mage/cards/m/MightMakesRight.java +++ b/Mage.Sets/src/mage/cards/m/MightMakesRight.java @@ -65,7 +65,7 @@ enum ControlsEachCreatureWithGreatestPowerCondition implements Condition { public boolean apply(Game game, Ability source) { Integer maxPower = null; boolean result = false; - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); for (Permanent permanent : permanents) { if (permanent == null) { continue; diff --git a/Mage.Sets/src/mage/cards/m/MightOfAlara.java b/Mage.Sets/src/mage/cards/m/MightOfAlara.java index ab22da911f9..09337caf364 100644 --- a/Mage.Sets/src/mage/cards/m/MightOfAlara.java +++ b/Mage.Sets/src/mage/cards/m/MightOfAlara.java @@ -1,30 +1,33 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.dynamicvalue.common.DomainValue; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.hint.common.DomainHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class MightOfAlara extends CardImpl { - public MightOfAlara(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{G}"); + public MightOfAlara(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}"); // Domain - Target creature gets +1/+1 until end of turn for each basic land type among lands you control. - this.getSpellAbility().addEffect(new BoostTargetEffect(new DomainValue(), new DomainValue(), Duration.EndOfTurn, true)); + this.getSpellAbility().addEffect(new BoostTargetEffect( + DomainValue.REGULAR, DomainValue.REGULAR, Duration.EndOfTurn, true + )); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addHint(DomainHint.instance); + this.getSpellAbility().setAbilityWord(AbilityWord.DOMAIN); } private MightOfAlara(final MightOfAlara card) { diff --git a/Mage.Sets/src/mage/cards/m/MightOfTheWild.java b/Mage.Sets/src/mage/cards/m/MightOfTheWild.java index 5cc3018bdb2..b4ba519533b 100644 --- a/Mage.Sets/src/mage/cards/m/MightOfTheWild.java +++ b/Mage.Sets/src/mage/cards/m/MightOfTheWild.java @@ -40,14 +40,12 @@ public final class MightOfTheWild extends CardImpl { this.getSpellAbility().addEffect(new CantBlockAllEffect(filterMode1, Duration.EndOfTurn)); // Destroy target artifact or enchantment. - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetPermanent(filterMode2)); this.getSpellAbility().addMode(mode); // Creatures you control gain indestructible this turn. - mode = new Mode(); - mode.addEffect(new GainAbilityControlledEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES)); + mode = new Mode(new GainAbilityControlledEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/m/MilaCraftyCompanion.java b/Mage.Sets/src/mage/cards/m/MilaCraftyCompanion.java index 26e8c32f14f..37f1b436b97 100644 --- a/Mage.Sets/src/mage/cards/m/MilaCraftyCompanion.java +++ b/Mage.Sets/src/mage/cards/m/MilaCraftyCompanion.java @@ -4,7 +4,6 @@ import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.BecomesTargetControlledPermanentTriggeredAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.delayed.AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -64,7 +63,7 @@ public final class MilaCraftyCompanion extends ModalDoubleFacesCard { // Lukka, Wayward Bonder // Legendary Planeswalker - Lukka this.getRightHalfCard().addSuperType(SuperType.LEGENDARY); - this.getRightHalfCard().addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.getRightHalfCard().setStartingLoyalty(5); // +1: You may discard a card. If you do, draw a card. If a creature card was discarded this way, draw two cards instead. this.getRightHalfCard().addAbility(new LoyaltyAbility(new LukkaWaywardBonderDiscardEffect(), 1)); diff --git a/Mage.Sets/src/mage/cards/m/MilitiaBugler.java b/Mage.Sets/src/mage/cards/m/MilitiaBugler.java index d7802ae4c39..6cdf4d5ecb3 100644 --- a/Mage.Sets/src/mage/cards/m/MilitiaBugler.java +++ b/Mage.Sets/src/mage/cards/m/MilitiaBugler.java @@ -2,15 +2,14 @@ package mage.cards.m; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.PowerPredicate; @@ -38,11 +37,11 @@ public final class MilitiaBugler extends CardImpl { // Vigilance this.addAbility(VigilanceAbility.getInstance()); - // When Militia Bugler enters the battlefield, look at the top four cards of your library. You may reveal a creature card with power 2 or less from among them and put it into your hand. Put the rest on the bottom of your library in a random order. - this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(1), filter, Zone.LIBRARY, false, - true, true, Zone.HAND, false, true, false - ), false)); + // When Militia Bugler enters the battlefield, look at the top four cards of your library. + // You may reveal a creature card with power 2 or less from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new LookLibraryAndPickControllerEffect(4, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM))); } private MilitiaBugler(final MilitiaBugler card) { diff --git a/Mage.Sets/src/mage/cards/m/MilitiasPride.java b/Mage.Sets/src/mage/cards/m/MilitiasPride.java index 6a6723d8fbc..0fddaca3ee7 100644 --- a/Mage.Sets/src/mage/cards/m/MilitiasPride.java +++ b/Mage.Sets/src/mage/cards/m/MilitiasPride.java @@ -62,7 +62,7 @@ class MilitiasPrideTriggerAbility extends TriggeredAbilityImpl { FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); filter.add(TokenPredicate.FALSE); Permanent permanent = game.getPermanent(event.getSourceId()); - return permanent != null && filter.match(permanent, sourceId, controllerId, game); + return permanent != null && filter.match(permanent, controllerId, this, game); } @Override diff --git a/Mage.Sets/src/mage/cards/m/Mimeofacture.java b/Mage.Sets/src/mage/cards/m/Mimeofacture.java index 75fc2b3bb66..11c20adbd7e 100644 --- a/Mage.Sets/src/mage/cards/m/Mimeofacture.java +++ b/Mage.Sets/src/mage/cards/m/Mimeofacture.java @@ -30,7 +30,7 @@ public final class Mimeofacture extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}"); // Replicate {3}{U} - this.addAbility(new ReplicateAbility(this, "{3}{U}")); + this.addAbility(new ReplicateAbility("{3}{U}")); // Choose target permanent an opponent controls. Search that player's library for a card with the same name and put it onto the battlefield under your control. Then that player shuffles their library. this.getSpellAbility().addEffect(new MimeofactureEffect()); diff --git a/Mage.Sets/src/mage/cards/m/MinamosMeddling.java b/Mage.Sets/src/mage/cards/m/MinamosMeddling.java index f7a479c444b..1a0ae290801 100644 --- a/Mage.Sets/src/mage/cards/m/MinamosMeddling.java +++ b/Mage.Sets/src/mage/cards/m/MinamosMeddling.java @@ -56,7 +56,7 @@ class MinamosMeddlingCounterTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/m/MindclawShaman.java b/Mage.Sets/src/mage/cards/m/MindclawShaman.java index ad1cc1ac463..bed6d16c69e 100644 --- a/Mage.Sets/src/mage/cards/m/MindclawShaman.java +++ b/Mage.Sets/src/mage/cards/m/MindclawShaman.java @@ -1,29 +1,25 @@ package mage.cards.m; -import java.util.UUID; -import mage.ApprovingObject; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; import mage.target.common.TargetOpponent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class MindclawShaman extends CardImpl { @@ -55,14 +51,6 @@ public final class MindclawShaman extends CardImpl { class MindclawShamanEffect extends OneShotEffect { - private static final FilterCard filter = new FilterCard("instant or sorcery card"); - - static { - filter.add(Predicates.or( - CardType.INSTANT.getPredicate(), - CardType.SORCERY.getPredicate())); - } - public MindclawShamanEffect() { super(Outcome.PlayForFree); this.staticText = "target opponent reveals their hand. You may cast " @@ -80,34 +68,15 @@ class MindclawShamanEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player targetOpponent = game.getPlayer(source.getFirstTarget()); - MageObject sourceObject = source.getSourceObject(game); - if (targetOpponent != null && sourceObject != null) { - if (!targetOpponent.getHand().isEmpty()) { - targetOpponent.revealCards(sourceObject.getName(), targetOpponent.getHand(), game); - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - TargetCard target = new TargetCard(Zone.HAND, filter); - target.setNotTarget(true); - if (controller.choose(Outcome.PlayForFree, targetOpponent.getHand(), target, game)) { - Card chosenCard = targetOpponent.getHand().get(target.getFirstTarget(), game); - if (chosenCard != null) { - if (controller.chooseUse(Outcome.PlayForFree, "Cast the chosen card without " - + "paying its mana cost?", source, game)) { - game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(chosenCard, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), null); - } else { - game.informPlayers(sourceObject.getLogName() + ": " - + controller.getLogName() + " canceled casting the card."); - } - } - } - return true; - } - } + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(source.getFirstTarget()); + if (controller == null || opponent == null) { + return false; } - return false; + opponent.revealCards(source, opponent.getHand(), game); + return CardUtil.castSpellWithAttributesForFree( + controller, source, game, new CardsImpl(opponent.getHand()), + StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY + ); } } diff --git a/Mage.Sets/src/mage/cards/m/MindleechMass.java b/Mage.Sets/src/mage/cards/m/MindleechMass.java index ed612c25768..1bc43c87c37 100644 --- a/Mage.Sets/src/mage/cards/m/MindleechMass.java +++ b/Mage.Sets/src/mage/cards/m/MindleechMass.java @@ -1,28 +1,24 @@ package mage.cards.m; -import java.util.UUID; -import mage.ApprovingObject; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.TrampleAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterNonlandCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class MindleechMass extends CardImpl { @@ -39,7 +35,9 @@ public final class MindleechMass extends CardImpl { // Whenever Mindleech Mass deals combat damage to a player, you may look at that // player's hand. If you do, you may cast a nonland card in it without paying that card's mana cost. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new MindleechMassEffect(), true, true)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new MindleechMassEffect(), true, true + )); } private MindleechMass(final MindleechMass card) { @@ -56,8 +54,8 @@ class MindleechMassEffect extends OneShotEffect { public MindleechMassEffect() { super(Outcome.PlayForFree); - this.staticText = "you may look at that player's hand. If you do, " - + "you may cast a nonland card in it without paying that card's mana cost"; + this.staticText = "look at that player's hand. If you do, you " + + "may cast a spell from among those cards without paying its mana cost"; } public MindleechMassEffect(final MindleechMassEffect effect) { @@ -71,27 +69,15 @@ class MindleechMassEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); - if (opponent != null && controller != null) { - Cards cardsInHand = new CardsImpl(); - cardsInHand.addAll(opponent.getHand()); - opponent.revealCards("Opponents hand", cardsInHand, game); - if (!cardsInHand.isEmpty() - && !cardsInHand.getCards(new FilterNonlandCard(), game).isEmpty()) { - TargetCard target = new TargetCard(1, Zone.HAND, new FilterNonlandCard()); - if (controller.chooseTarget(Outcome.PlayForFree, cardsInHand, target, source, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - } - } - } - return true; + Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (controller == null || opponent == null) { + return false; } - return false; + controller.lookAtCards(opponent.getName(), opponent.getHand(), game); + return CardUtil.castSpellWithAttributesForFree( + controller, source, game, new CardsImpl(opponent.getHand()), + StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY + ); } } diff --git a/Mage.Sets/src/mage/cards/m/MindlinkMech.java b/Mage.Sets/src/mage/cards/m/MindlinkMech.java new file mode 100644 index 00000000000..38bd0955072 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MindlinkMech.java @@ -0,0 +1,215 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.MageObject; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.MageObjectReferencePredicate; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.util.CardUtil; +import mage.util.functions.CopyApplier; +import mage.watchers.Watcher; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class MindlinkMech extends CardImpl { + + public MindlinkMech(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{U}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Mindlink Mech becomes crewed for the first time each turn, until end of turn, Mindlink Mech becomes a copy of target nonlegendary creature that crewed it this turn, except it's 4/3, it's a Vehicle artifact in addition to its other types, and it has flying. + this.addAbility(new MindlinkMechTriggeredAbility()); + + // Crew 1 + this.addAbility(new CrewAbility(1)); + } + + private MindlinkMech(final MindlinkMech card) { + super(card); + } + + @Override + public MindlinkMech copy() { + return new MindlinkMech(this); + } +} + +class MindlinkMechTriggeredAbility extends TriggeredAbilityImpl { + + MindlinkMechTriggeredAbility() { + super(Zone.BATTLEFIELD, new MindlinkMechEffect()); + this.addWatcher(new MindlinkMechWatcher()); + } + + private MindlinkMechTriggeredAbility(final MindlinkMechTriggeredAbility ability) { + super(ability); + } + + @Override + public MindlinkMechTriggeredAbility copy() { + return new MindlinkMechTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.VEHICLE_CREWED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!event.getSourceId().equals(getSourceId()) || !MindlinkMechWatcher.checkVehicle(this, game)) { + return false; + } + this.getTargets().clear(); + this.addTarget(new TargetPermanent(MindlinkMechWatcher.makeFilter(this, game))); + return true; + } + + @Override + public String getRule() { + return "Whenever {this} becomes crewed for the first time each turn, until end of turn, " + + "{this} becomes a copy of target nonlegendary creature that crewed it this turn, " + + "except it's 4/3, it's a Vehicle artifact in addition to its other types, and it has flying."; + } +} + +class MindlinkMechWatcher extends Watcher { + + private final Map crewCount = new HashMap<>(); + private final Map> crewMap = new HashMap<>(); + private static final FilterPermanent invalidFilter = new FilterPermanent(); + + static { + invalidFilter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, -2)); + } + + MindlinkMechWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + Permanent vehicle; + Permanent crewer; + switch (event.getType()) { + case VEHICLE_CREWED: + vehicle = game.getPermanent(event.getTargetId()); + crewer = null; + break; + case CREWED_VEHICLE: + vehicle = game.getPermanent(event.getSourceId()); + crewer = game.getPermanent(event.getTargetId()); + break; + default: + return; + } + if (vehicle == null) { + return; + } + if (crewer == null) { + crewCount.compute(new MageObjectReference(vehicle, game), (m, i) -> i == null ? 1 : Integer.sum(i, 1)); + return; + } + crewMap.computeIfAbsent(new MageObjectReference(vehicle, game), x -> new HashSet<>()).add(new MageObjectReference(crewer, game)); + } + + @Override + public void reset() { + super.reset(); + crewCount.clear(); + crewMap.clear(); + } + + public static boolean checkVehicle(Ability source, Game game) { + return game + .getState() + .getWatcher(MindlinkMechWatcher.class) + .crewCount + .getOrDefault(new MageObjectReference(source), 0) < 2; + } + + public static FilterPermanent makeFilter(Ability source, Game game) { + Set predicates = game + .getState() + .getWatcher(MindlinkMechWatcher.class) + .crewMap + .computeIfAbsent(new MageObjectReference(source), x -> new HashSet<>()) + .stream() + .filter(mor -> { + Permanent permanent = mor.getPermanent(game); + return permanent != null && !permanent.isLegendary() && permanent.isCreature(game); + }).map(MageObjectReferencePredicate::new) + .collect(Collectors.toSet()); + if (predicates.isEmpty()) { + return invalidFilter; + } + FilterPermanent filterPermanent = new FilterPermanent( + "nonlegendary creature that crewed " + CardUtil.getSourceName(game, source) + " this turn" + ); + filterPermanent.add(Predicates.or(predicates)); + return filterPermanent; + } +} + +class MindlinkMechEffect extends OneShotEffect { + + MindlinkMechEffect() { + super(Outcome.Benefit); + } + + private MindlinkMechEffect(final MindlinkMechEffect effect) { + super(effect); + } + + @Override + public MindlinkMechEffect copy() { + return new MindlinkMechEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null || creature == null) { + return false; + } + game.copyPermanent(Duration.EndOfTurn, creature, permanent.getId(), source, new MindlinkMechApplier()); + return true; + } +} + +class MindlinkMechApplier extends CopyApplier { + @Override + public boolean apply(Game game, MageObject blueprint, Ability source, UUID targetObjectId) { + blueprint.getPower().modifyBaseValue(4); + blueprint.getToughness().modifyBaseValue(3); + blueprint.addCardType(game, CardType.ARTIFACT); + blueprint.addSubType(game, SubType.VEHICLE); + blueprint.getAbilities().add(FlyingAbility.getInstance()); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/MineExcavation.java b/Mage.Sets/src/mage/cards/m/MineExcavation.java index 815f33043ef..34b98505b56 100644 --- a/Mage.Sets/src/mage/cards/m/MineExcavation.java +++ b/Mage.Sets/src/mage/cards/m/MineExcavation.java @@ -3,6 +3,7 @@ package mage.cards.m; import java.util.UUID; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.ConspireAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -17,7 +18,7 @@ import mage.target.common.TargetCardInGraveyard; */ public final class MineExcavation extends CardImpl { - private static final FilterCard filter = new FilterCard("artifact or enchantment card in a graveyard"); + private static final FilterCard filter = new FilterCard("artifact or enchantment card from a graveyard"); static { filter.add(Predicates.or(CardType.ARTIFACT.getPredicate(), @@ -28,11 +29,11 @@ public final class MineExcavation extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{W}"); // Return target artifact or enchantment card from a graveyard to its owner's hand. - this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInGraveyard(filter)); // Conspire - this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE)); + this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.ONE)); } private MineExcavation(final MineExcavation card) { diff --git a/Mage.Sets/src/mage/cards/m/MinionOfTheMighty.java b/Mage.Sets/src/mage/cards/m/MinionOfTheMighty.java index 098e7f691d2..6420b9064e4 100644 --- a/Mage.Sets/src/mage/cards/m/MinionOfTheMighty.java +++ b/Mage.Sets/src/mage/cards/m/MinionOfTheMighty.java @@ -79,7 +79,7 @@ class MinionOfTheMightyEffect extends OneShotEffect { if (controller == null) { return false; } - target.choose(outcome, controller.getId(), source.getSourceId(), game); + target.choose(outcome, controller.getId(), source.getSourceId(), source, game); Card card = controller.getHand().get(target.getFirstTarget(), game); if (card == null) { return false; diff --git a/Mage.Sets/src/mage/cards/m/MinionReflector.java b/Mage.Sets/src/mage/cards/m/MinionReflector.java index 8afbacbcc1d..6d6e84ab961 100644 --- a/Mage.Sets/src/mage/cards/m/MinionReflector.java +++ b/Mage.Sets/src/mage/cards/m/MinionReflector.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; @@ -21,32 +19,31 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author Plopman */ public final class MinionReflector extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a nontoken creature"); static { filter.add(TokenPredicate.FALSE); } public MinionReflector(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{5}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); // Whenever a nontoken creature enters the battlefield under your control, you may pay {2}. If you do, create a token that's a copy of that creature. That token has haste and "At the beginning of the end step, sacrifice this permanent." - Ability ability = new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, new DoIfCostPaid( - new MinionReflectorEffect(), new ManaCostsImpl("{2}"), - "Pay {2} to create a token that's a copy of that creature that " + - "entered the battlefield?"), - filter, false, SetTargetPointer.PERMANENT, - "Whenever a nontoken creature enters the battlefield under your control, " + - "you may pay 2. If you do, create a token that's a copy of that creature, " + - "except it has haste and \"At the beginning of the end step, sacrifice this " + - "permanent.\""); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, + new DoIfCostPaid( + new MinionReflectorEffect(), new ManaCostsImpl<>("{2}"), "Pay {2} " + + "to create a token that's a copy of that creature that entered the battlefield?" + ), + filter, false, SetTargetPointer.PERMANENT, null + )); } private MinionReflector(final MinionReflector card) { @@ -64,7 +61,7 @@ class MinionReflectorEffect extends OneShotEffect { public MinionReflectorEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "create a token that's a copy of that creature, except it has haste and \"At the beginning of the end step, sacrifice this permanent."; + this.staticText = "create a token that's a copy of that creature, except it has haste and \"At the beginning of the end step, sacrifice this permanent.\""; } public MinionReflectorEffect(final MinionReflectorEffect effect) { diff --git a/Mage.Sets/src/mage/cards/m/MinisterOfPain.java b/Mage.Sets/src/mage/cards/m/MinisterOfPain.java index 11c40faeb03..8166fe338a8 100644 --- a/Mage.Sets/src/mage/cards/m/MinisterOfPain.java +++ b/Mage.Sets/src/mage/cards/m/MinisterOfPain.java @@ -1,4 +1,3 @@ - package mage.cards.m; import java.util.UUID; @@ -11,8 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; /** * @@ -20,12 +18,6 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class MinisterOfPain extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public MinisterOfPain(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); this.subtype.add(SubType.HUMAN); @@ -37,7 +29,8 @@ public final class MinisterOfPain extends CardImpl { this.addAbility(new ExploitAbility()); // When Minister of Pain explots a creature, creatures your opponents control get -1/-1 until end of turn. - this.addAbility(new ExploitCreatureTriggeredAbility(new BoostAllEffect(-1,-1, Duration.EndOfTurn, filter, false), false)); + this.addAbility(new ExploitCreatureTriggeredAbility( + new BoostAllEffect(-1, -1, Duration.EndOfTurn, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, false))); } diff --git a/Mage.Sets/src/mage/cards/m/MinscBooTimelessHeroes.java b/Mage.Sets/src/mage/cards/m/MinscBooTimelessHeroes.java new file mode 100644 index 00000000000..3598e26da6c --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MinscBooTimelessHeroes.java @@ -0,0 +1,131 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.CanBeYourCommanderAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.meta.OrTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.BooToken; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MinscBooTimelessHeroes extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creature with trample or haste"); + + static { + filter.add(Predicates.or( + new AbilityPredicate(TrampleAbility.class), + new AbilityPredicate(HasteAbility.class) + )); + } + + public MinscBooTimelessHeroes(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.MINSC); + this.setStartingLoyalty(3); + + // When Minsc & Boo, Timeless Heroes enters the battlefield and at the beginning of your upkeep, you may create Boo, a legendary 1/1 red Hamster creature token with trample and haste. + this.addAbility(new OrTriggeredAbility( + Zone.BATTLEFIELD, new CreateTokenEffect(new BooToken()), true, + "When {this} enters the battlefield and at the beginning of your upkeep, ", + new EntersBattlefieldTriggeredAbility(null, false), + new BeginningOfUpkeepTriggeredAbility(null, TargetController.YOU, false) + )); + + // +1: Put three +1/+1 counters on up to one target creature with trample or haste. + Ability ability = new LoyaltyAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance(3)), 1 + ); + ability.addTarget(new TargetPermanent(0, 1, filter)); + this.addAbility(ability); + + // −2: Sacrifice a creature. When you do, Minsc & Boo, Timeless Heroes deals X damage to any target, where X is that creature's power. If the sacrificed creature was a Hamster, draw X cards. + this.addAbility(new LoyaltyAbility(new MinscBooTimelessHeroesEffect(), -2)); + + // Minsc & Boo, Timeless Heroes can be your commander. + this.addAbility(CanBeYourCommanderAbility.getInstance()); + } + + private MinscBooTimelessHeroes(final MinscBooTimelessHeroes card) { + super(card); + } + + @Override + public MinscBooTimelessHeroes copy() { + return new MinscBooTimelessHeroes(this); + } +} + +class MinscBooTimelessHeroesEffect extends OneShotEffect { + + MinscBooTimelessHeroesEffect() { + super(Outcome.Benefit); + staticText = "sacrifice a creature. When you do, {this} deals X damage to any target, " + + "where X is that creature's power. If the sacrificed creature was a Hamster, draw X cards"; + } + + private MinscBooTimelessHeroesEffect(final MinscBooTimelessHeroesEffect effect) { + super(effect); + } + + @Override + public MinscBooTimelessHeroesEffect copy() { + return new MinscBooTimelessHeroesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null || !game.getBattlefield().contains( + StaticFilters.FILTER_CONTROLLED_CREATURE, source, game, 1 + )) { + return false; + } + TargetPermanent target = new TargetControlledCreaturePermanent(); + target.setNotTarget(true); + player.choose(outcome, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null || !permanent.sacrifice(source, game)) { + return false; + } + int power = permanent.getPower().getValue(); + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( + new DamageTargetEffect(power), false, "deals X damage to any target, " + + "where X is that creature's power. If the sacrificed creature was a Hamster, draw X cards" + ); + if (permanent.hasSubtype(SubType.HAMSTER, game)) { + ability.addEffect(new DrawCardSourceControllerEffect(power)); + } + game.fireReflexiveTriggeredAbility(ability, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MireBlight.java b/Mage.Sets/src/mage/cards/m/MireBlight.java index 3cf62b90219..3e675f06565 100644 --- a/Mage.Sets/src/mage/cards/m/MireBlight.java +++ b/Mage.Sets/src/mage/cards/m/MireBlight.java @@ -33,7 +33,7 @@ public final class MireBlight extends CardImpl { Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); // When enchanted creature is dealt damage, destroy it. - this.addAbility(new DealtDamageAttachedTriggeredAbility(new DestroyAttachedToEffect("it"), false)); + this.addAbility(new DealtDamageAttachedTriggeredAbility(new DestroyAttachedToEffect("it"), false).setTriggerPhrase("When enchanted creature is dealt damage, ")); } private MireBlight(final MireBlight card) { diff --git a/Mage.Sets/src/mage/cards/m/MirrodinBesieged.java b/Mage.Sets/src/mage/cards/m/MirrodinBesieged.java index 7b3b4aa04a8..e1d44f3ec3e 100644 --- a/Mage.Sets/src/mage/cards/m/MirrodinBesieged.java +++ b/Mage.Sets/src/mage/cards/m/MirrodinBesieged.java @@ -92,7 +92,7 @@ class MirrodinBesiegedEffect extends OneShotEffect { if (player == null || opponent == null) { return false; } - if (player.getGraveyard().getCards(StaticFilters.FILTER_CARD_ARTIFACT, source.getSourceId(), source.getControllerId(), game).size() >= 15) { + if (player.getGraveyard().getCards(StaticFilters.FILTER_CARD_ARTIFACT, source.getControllerId(), source, game).size() >= 15) { opponent.lost(game); } return true; diff --git a/Mage.Sets/src/mage/cards/m/MirrorBox.java b/Mage.Sets/src/mage/cards/m/MirrorBox.java new file mode 100644 index 00000000000..e5af340a22f --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MirrorBox.java @@ -0,0 +1,135 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.util.CardUtil; + +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MirrorBox extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("each legendary creature"); + + static { + filter.add(SuperType.LEGENDARY.getPredicate()); + } + + public MirrorBox(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + // The "legend rule" doesn't apply to permanents you control. + this.addAbility(new SimpleStaticAbility(new MirrorBoxLegendEffect())); + + // Each legendary creature you control gets +1/+1. + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 1, Duration.WhileOnBattlefield, filter + ))); + + // Each nontoken creature you control gets +1/+1 for each other creature you control with the same name as that creature. + this.addAbility(new SimpleStaticAbility(new MirrorBoxBoostEffect())); + } + + private MirrorBox(final MirrorBox card) { + super(card); + } + + @Override + public MirrorBox copy() { + return new MirrorBox(this); + } +} + +class MirrorBoxLegendEffect extends ContinuousRuleModifyingEffectImpl { + + MirrorBoxLegendEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment, false, false); + staticText = "the \"legend rule\" doesn't apply to permanents you control"; + } + + private MirrorBoxLegendEffect(final MirrorBoxLegendEffect effect) { + super(effect); + } + + @Override + public MirrorBoxLegendEffect copy() { + return new MirrorBoxLegendEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DESTROY_PERMANENT_BY_LEGENDARY_RULE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent permanent = game.getPermanent(event.getTargetId()); + return permanent != null && permanent.isControlledBy(source.getControllerId()); + } +} + +class MirrorBoxBoostEffect extends ContinuousEffectImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(TokenPredicate.FALSE); + } + + public MirrorBoxBoostEffect() { + super(Duration.WhileOnBattlefield, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.BoostCreature); + this.staticText = "each nontoken creature you control gets +1/+1 for " + + "each other creature you control with the same name as that creature"; + } + + public MirrorBoxBoostEffect(final MirrorBoxBoostEffect effect) { + super(effect); + } + + @Override + public MirrorBoxBoostEffect copy() { + return new MirrorBoxBoostEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + List permanents = game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, + source.getControllerId(), source, game + ); + for (Permanent permanent : game.getBattlefield().getActivePermanents( + filter, source.getControllerId(), source, game + )) { + int amount = getAmount(permanents, permanent, game); + permanent.addPower(amount); + permanent.addToughness(amount); + } + return true; + } + + private int getAmount(List permanents, Permanent target, Game game) { + return permanents + .stream() + .filter(permanent -> !permanent.getId().equals(target.getId()) + && CardUtil.haveSameNames(permanent, target)) + .mapToInt(x -> 1) + .sum(); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MirrorEntity.java b/Mage.Sets/src/mage/cards/m/MirrorEntity.java index 2e616b5b630..1fbc00356a5 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorEntity.java +++ b/Mage.Sets/src/mage/cards/m/MirrorEntity.java @@ -74,7 +74,7 @@ class MirrorEntityEffect extends ContinuousEffectImpl { public void init(Ability source, Game game) { super.init(source, game); for (Permanent perm : game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_CONTROLLED_CREATURES, source.getControllerId(), source.getSourceId(), game + StaticFilters.FILTER_CONTROLLED_CREATURES, source.getControllerId(), source, game )) { affectedObjectList.add(new MageObjectReference(perm, game)); } diff --git a/Mage.Sets/src/mage/cards/m/MirrorGolem.java b/Mage.Sets/src/mage/cards/m/MirrorGolem.java index 9da0c889a95..20a3126d59f 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorGolem.java +++ b/Mage.Sets/src/mage/cards/m/MirrorGolem.java @@ -36,7 +36,7 @@ public final class MirrorGolem extends CardImpl { // Imprint - When Mirror Golem enters the battlefield, you may exile target card from a graveyard. Ability ability = new EntersBattlefieldTriggeredAbility(new MirrorGolemImprintEffect(), true); ability.addTarget(new TargetCardInGraveyard()); - ability.withFlavorWord("Imprint"); + ability.setAbilityWord(AbilityWord.IMPRINT); this.addAbility(ability); // Mirror Golem has protection from each of the exiled card's card types. diff --git a/Mage.Sets/src/mage/cards/m/MirrorOfFate.java b/Mage.Sets/src/mage/cards/m/MirrorOfFate.java index 59a89973f76..129c0b09c4e 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorOfFate.java +++ b/Mage.Sets/src/mage/cards/m/MirrorOfFate.java @@ -73,7 +73,7 @@ class MirrorOfFateEffect extends OneShotEffect { // Choose up to seven face-up exiled cards you own CardsImpl cards = new CardsImpl(); MirrorOfFateTarget targetExile = new MirrorOfFateTarget(); - if (controller.choose(outcome, targetExile, source.getSourceId(), game)) { + if (controller.choose(outcome, targetExile, source, game)) { cards.addAll(targetExile.getTargets()); } // Exile all the cards from your library diff --git a/Mage.Sets/src/mage/cards/m/MirrorhallMimic.java b/Mage.Sets/src/mage/cards/m/MirrorhallMimic.java index 15a77dbb34e..b067aeded81 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorhallMimic.java +++ b/Mage.Sets/src/mage/cards/m/MirrorhallMimic.java @@ -33,8 +33,8 @@ public final class MirrorhallMimic extends CardImpl { // You may have Mirrorhall Mimic enter the battlefield as a copy of any creature on the battlefield, except it's a Spirit in addition to its other types. this.addAbility(new EntersBattlefieldAbility(new CopyPermanentEffect( StaticFilters.FILTER_PERMANENT_CREATURE, new MirrorhallMimicApplier() - ), true, null, "You may have {this} enter the battlefield as a copy of " + - "any creature on the battlefield, except it's a Spirit in addition to its other types.", null)); + ), true, null, "You may have {this} enter the battlefield as a copy of " + + "any creature on the battlefield, except it's a Spirit in addition to its other types.", null)); // Disturb {3}{U}{U} this.addAbility(new DisturbAbility(this, "{3}{U}{U}")); @@ -54,9 +54,7 @@ class MirrorhallMimicApplier extends CopyApplier { @Override public boolean apply(Game game, MageObject blueprint, Ability source, UUID targetObjectId) { - if (!blueprint.hasSubtype(SubType.SPIRIT, game)) { - blueprint.addSubType(game, SubType.SPIRIT); - } + blueprint.addSubType(SubType.SPIRIT); return true; } } diff --git a/Mage.Sets/src/mage/cards/m/MirrorshellCrab.java b/Mage.Sets/src/mage/cards/m/MirrorshellCrab.java index 5f699e5eb48..47d643bd157 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorshellCrab.java +++ b/Mage.Sets/src/mage/cards/m/MirrorshellCrab.java @@ -20,8 +20,8 @@ import mage.target.TargetStackObject; public final class MirrorshellCrab extends CardImpl { public MirrorshellCrab(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE,CardType.ARTIFACT}, "{5}{U}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT,CardType.CREATURE}, "{5}{U}{U}"); + this.subtype.add(SubType.CRAB); this.power = new MageInt(5); this.toughness = new MageInt(7); diff --git a/Mage.Sets/src/mage/cards/m/MirrorwingDragon.java b/Mage.Sets/src/mage/cards/m/MirrorwingDragon.java index 276d36347be..f0a073dcbe5 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorwingDragon.java +++ b/Mage.Sets/src/mage/cards/m/MirrorwingDragon.java @@ -147,7 +147,7 @@ class MirrorwingDragonCopySpellEffect extends CopySpellForEachItCouldTargetEffec return game.getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - player.getId(), source.getSourceId(), game + player.getId(), source, game ).stream() .filter(Objects::nonNull) .filter(p -> !p.equals(permanent)) diff --git a/Mage.Sets/src/mage/cards/m/MischievousQuanar.java b/Mage.Sets/src/mage/cards/m/MischievousQuanar.java index cf44d28acf1..25d1c410901 100644 --- a/Mage.Sets/src/mage/cards/m/MischievousQuanar.java +++ b/Mage.Sets/src/mage/cards/m/MischievousQuanar.java @@ -38,7 +38,7 @@ public final class MischievousQuanar extends CardImpl { this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{3}{U}{U}"))); // Morph {1}{U}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{U}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{U}{U}"))); // When Mischievous Quanar is turned face up, copy target instant or sorcery spell. You may choose new targets for that copy. Effect effect2 = new CopyTargetSpellEffect(); diff --git a/Mage.Sets/src/mage/cards/m/Misdirection.java b/Mage.Sets/src/mage/cards/m/Misdirection.java index 3e56791c854..15f7af28439 100644 --- a/Mage.Sets/src/mage/cards/m/Misdirection.java +++ b/Mage.Sets/src/mage/cards/m/Misdirection.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.costs.AlternativeCostSourceAbility; import mage.abilities.costs.common.ExileFromHandCost; @@ -11,34 +9,33 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.FilterSpell; import mage.filter.common.FilterOwnedCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.other.NumberOfTargetsPredicate; import mage.target.TargetSpell; import mage.target.common.TargetCardInHand; +import java.util.UUID; + /** - * * @author jonubuu */ public final class Misdirection extends CardImpl { + private static final FilterOwnedCard filter + = new FilterOwnedCard("a blue card from your hand"); + private static final FilterSpell filter2 = new FilterSpell("spell with a single target"); + static { + filter.add(new ColorPredicate(ObjectColor.BLUE)); filter2.add(new NumberOfTargetsPredicate(1)); } public Misdirection(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}{U}"); // You may exile a blue card from your hand rather than pay Misdirection's mana cost. - FilterOwnedCard filterCardInHand = new FilterOwnedCard("a blue card from your hand"); - filterCardInHand.add(new ColorPredicate(ObjectColor.BLUE)); - - // the exile cost can never be paid with the card itself - filterCardInHand.add(Predicates.not(new CardIdPredicate(this.getId()))); - this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filterCardInHand)))); + this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter)))); // Change the target of target spell with a single target. this.getSpellAbility().addEffect(new ChooseNewTargetsTargetEffect(true, true)); @@ -54,4 +51,3 @@ public final class Misdirection extends CardImpl { return new Misdirection(this); } } - diff --git a/Mage.Sets/src/mage/cards/m/MiseryCharm.java b/Mage.Sets/src/mage/cards/m/MiseryCharm.java index 199f2d81f23..9122f8d063c 100644 --- a/Mage.Sets/src/mage/cards/m/MiseryCharm.java +++ b/Mage.Sets/src/mage/cards/m/MiseryCharm.java @@ -1,11 +1,9 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -16,34 +14,34 @@ import mage.target.TargetPermanent; import mage.target.TargetPlayer; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author LoneFox */ public final class MiseryCharm extends CardImpl { - private static final FilterPermanent filter1 = new FilterPermanent("Cleric"); + private static final FilterPermanent filter1 = new FilterPermanent(SubType.CLERIC, "Cleric"); private static final FilterCard filter2 = new FilterCard("Cleric card from your graveyard"); static { - filter1.add(SubType.CLERIC.getPredicate()); filter2.add(SubType.CLERIC.getPredicate()); } public MiseryCharm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}"); // Choose one - Destroy target Cleric this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent(filter1)); + // or return target Cleric card from your graveyard to your hand - Mode mode = new Mode(); - mode.addEffect(new ReturnToHandTargetEffect()); + Mode mode = new Mode(new ReturnFromGraveyardToHandTargetEffect()); mode.addTarget(new TargetCardInYourGraveyard(filter2)); this.getSpellAbility().addMode(mode); + // or target player loses 2 life. - mode = new Mode(); - mode.addEffect(new LoseLifeTargetEffect(2)); + mode = new Mode(new LoseLifeTargetEffect(2)); mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/m/Misfortune.java b/Mage.Sets/src/mage/cards/m/Misfortune.java index 6c94dcddd06..18703b68c3e 100644 --- a/Mage.Sets/src/mage/cards/m/Misfortune.java +++ b/Mage.Sets/src/mage/cards/m/Misfortune.java @@ -1,34 +1,42 @@ package mage.cards.m; import mage.abilities.Ability; -import mage.abilities.effects.Effect; +import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.counter.AddCountersAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.TargetController; import mage.counters.CounterType; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.StaticFilters; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetOpponent; import java.util.UUID; /** - * @author jeffwadsworth + * @author TheElk801 */ public final class Misfortune extends CardImpl { public Misfortune(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{R}{G}"); - // An opponent chooses one - You put a +1/+1 counter on each creature you control and gain 4 life; or you put a -1/-1 counter on each creature that player controls and Misfortune deals 4 damage to that player. - this.getSpellAbility().addEffect(new MisfortuneEffect()); - this.getSpellAbility().addTarget(new TargetOpponent(true)); + // An opponent chooses one — + this.getSpellAbility().getModes().setModeChooser(TargetController.OPPONENT); + + // • You put a +1/+1 counter on each creature you control and gain 4 life. + this.getSpellAbility().addEffect(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("you put a +1/+1 counter on each creature you control")); + this.getSpellAbility().addEffect(new GainLifeEffect(4).setText("and gain 4 life")); + + // • You put a -1/-1 counter on each creature that player controls and Misfortune deals 4 damage to that player. + this.getSpellAbility().addMode(new Mode(new MisfortuneEffect())); } private Misfortune(final Misfortune card) { @@ -43,15 +51,13 @@ public final class Misfortune extends CardImpl { class MisfortuneEffect extends OneShotEffect { - public MisfortuneEffect() { - super(Outcome.Neutral); - staticText = "An opponent chooses one - " - + "You put a +1/+1 counter on each creature you control and gain " - + "4 life; or you put a -1/-1 counter on each creature that player " - + "controls and Misfortune deals 4 damage to that player"; + MisfortuneEffect() { + super(Outcome.Benefit); + staticText = "you put a -1/-1 counter on each creature that player controls " + + "and {this} deals 4 damage to that player"; } - public MisfortuneEffect(final MisfortuneEffect effect) { + private MisfortuneEffect(final MisfortuneEffect effect) { super(effect); } @@ -62,27 +68,16 @@ class MisfortuneEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Player chosenOpponent = game.getPlayer(targetPointer.getFirst(game, source)); - if (controller != null - && chosenOpponent != null) { - if (chosenOpponent.chooseUse(Outcome.Neutral, "If you choose Yes, the controller puts a +1/+1 counter" - + "on each creature they control and they gain 4 life. If no, the controller puts a -1/-1 counter" - + "on each creature you control and {this} deals 4 damage to you.", source, game)) { - Effect putP1P1CounterOnEachControlledCreature = new AddCountersAllEffect( - CounterType.P1P1.createInstance(), new FilterControlledCreaturePermanent()); - putP1P1CounterOnEachControlledCreature.apply(game, source); - controller.gainLife(4, game, source); - } else { - FilterCreaturePermanent filterOpponentCreatures = new FilterCreaturePermanent(); - filterOpponentCreatures.add(new ControllerIdPredicate(chosenOpponent.getId())); - Effect putM1M1CounterOnEachOpponentCreature = new AddCountersAllEffect( - CounterType.M1M1.createInstance(), filterOpponentCreatures); - putM1M1CounterOnEachOpponentCreature.apply(game, source); - chosenOpponent.damage(4, source.getSourceId(), source, game); - } - return true; + Player player = game.getPlayer((UUID) getValue("choosingPlayer")); + if (player == null) { + return false; } - return false; + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, player.getId(), source, game + )) { + permanent.addCounters(CounterType.M1M1.createInstance(), source.getControllerId(), source, game); + } + player.damage(4, source, game); + return true; } } diff --git a/Mage.Sets/src/mage/cards/m/MissionBriefing.java b/Mage.Sets/src/mage/cards/m/MissionBriefing.java index ad927f71f81..e35936a7a1a 100644 --- a/Mage.Sets/src/mage/cards/m/MissionBriefing.java +++ b/Mage.Sets/src/mage/cards/m/MissionBriefing.java @@ -73,7 +73,7 @@ class MissionBriefingEffect extends OneShotEffect { player.surveil(2, source, game); Target target = new TargetCardInYourGraveyard( new FilterInstantOrSorceryCard("instant or sorcery card from your graveyard")); - if (!player.choose(outcome, target, source.getSourceId(), game)) { + if (!player.choose(outcome, target, source, game)) { return true; } Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/m/MistbindClique.java b/Mage.Sets/src/mage/cards/m/MistbindClique.java index fa35005954a..0ee7c840823 100644 --- a/Mage.Sets/src/mage/cards/m/MistbindClique.java +++ b/Mage.Sets/src/mage/cards/m/MistbindClique.java @@ -38,7 +38,7 @@ public final class MistbindClique extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Champion a Faerie - this.addAbility(new ChampionAbility(this, SubType.FAERIE, false)); + this.addAbility(new ChampionAbility(this, SubType.FAERIE)); // When a Faerie is championed with Mistbind Clique, tap all lands target player controls. this.addAbility(new MistbindCliqueAbility()); diff --git a/Mage.Sets/src/mage/cards/m/MistfireWeaver.java b/Mage.Sets/src/mage/cards/m/MistfireWeaver.java index b1eba873cfc..9357ac73cd8 100644 --- a/Mage.Sets/src/mage/cards/m/MistfireWeaver.java +++ b/Mage.Sets/src/mage/cards/m/MistfireWeaver.java @@ -35,7 +35,7 @@ public final class MistfireWeaver extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Morph {2}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{U}"))); // When Misfire Weaver is turned face up, target creature you control gains hexproof until end of turn Effect effect = new GainAbilityTargetEffect(HexproofAbility.getInstance(), Duration.EndOfTurn); Ability ability = new TurnedFaceUpSourceTriggeredAbility(effect); diff --git a/Mage.Sets/src/mage/cards/m/Mistfolk.java b/Mage.Sets/src/mage/cards/m/Mistfolk.java index f4b6c58b68b..9d7ad8921d0 100644 --- a/Mage.Sets/src/mage/cards/m/Mistfolk.java +++ b/Mage.Sets/src/mage/cards/m/Mistfolk.java @@ -65,7 +65,7 @@ enum MistfolkPredicate implements ObjectSourcePlayerPredicate { @Override public boolean apply(ObjectSourcePlayer input, Game game) { - Permanent sourceObject = game.getPermanent(input.getSourceId()); + Permanent sourceObject = input.getSource().getSourcePermanentIfItStillExists(game); if (sourceObject == null || input.getObject() == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/m/MistformSeaswift.java b/Mage.Sets/src/mage/cards/m/MistformSeaswift.java index 89dec158f71..1715a6dc129 100644 --- a/Mage.Sets/src/mage/cards/m/MistformSeaswift.java +++ b/Mage.Sets/src/mage/cards/m/MistformSeaswift.java @@ -34,7 +34,7 @@ public final class MistformSeaswift extends CardImpl { this.addAbility(new SimpleActivatedAbility(new BecomesChosenCreatureTypeSourceEffect(), new GenericManaCost(1))); // Morph {1}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{U}"))); } diff --git a/Mage.Sets/src/mage/cards/m/MistformShrieker.java b/Mage.Sets/src/mage/cards/m/MistformShrieker.java index 240625b0798..cbcb87b5429 100644 --- a/Mage.Sets/src/mage/cards/m/MistformShrieker.java +++ b/Mage.Sets/src/mage/cards/m/MistformShrieker.java @@ -35,7 +35,7 @@ public final class MistformShrieker extends CardImpl { this.addAbility(new SimpleActivatedAbility(new BecomesChosenCreatureTypeSourceEffect(), new GenericManaCost(1))); // Morph {3}{U}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{U}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{U}{U}"))); } diff --git a/Mage.Sets/src/mage/cards/m/MistformSliver.java b/Mage.Sets/src/mage/cards/m/MistformSliver.java index 524ef7f7b6e..70f2e7dc2dd 100644 --- a/Mage.Sets/src/mage/cards/m/MistformSliver.java +++ b/Mage.Sets/src/mage/cards/m/MistformSliver.java @@ -1,12 +1,11 @@ package mage.cards.m; -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.costs.mana.GenericManaCost; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.AddCardSubTypeTargetEffect; @@ -15,18 +14,25 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.choices.Choice; import mage.choices.ChoiceCreatureType; -import mage.constants.*; -import mage.filter.StaticFilters; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** * @author cbt33, Plopman (Engineered Plague) */ public final class MistformSliver extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent(SubType.SLIVER, "all Slivers"); + public MistformSliver(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.ILLUSION); @@ -36,8 +42,11 @@ public final class MistformSliver extends CardImpl { this.toughness = new MageInt(1); // All Slivers have "{1}: This permanent becomes the creature type of your choice in addition to its other types until end of turn." - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MistformSliverEffect(), new ManaCostsImpl("{1}")); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS))); + this.addAbility(new SimpleStaticAbility( + new GainAbilityAllEffect(new SimpleActivatedAbility( + new MistformSliverEffect(), new GenericManaCost(1) + ), Duration.WhileOnBattlefield, filter) + )); } private MistformSliver(final MistformSliver card) { diff --git a/Mage.Sets/src/mage/cards/m/MistformWarchief.java b/Mage.Sets/src/mage/cards/m/MistformWarchief.java index bc6260c717f..6a5fc06e793 100644 --- a/Mage.Sets/src/mage/cards/m/MistformWarchief.java +++ b/Mage.Sets/src/mage/cards/m/MistformWarchief.java @@ -62,7 +62,7 @@ class MistformWarchiefPredicate implements ObjectSourcePlayerPredicate { @Override public boolean apply(ObjectSourcePlayer input, Game game) { - MageObject sourceObject = game.getObject(input.getSourceId()); + MageObject sourceObject = input.getSource().getSourceObject(game); return sourceObject != null && sourceObject.shareCreatureTypes(game, input.getObject()); } diff --git a/Mage.Sets/src/mage/cards/m/MisthoofKirin.java b/Mage.Sets/src/mage/cards/m/MisthoofKirin.java index 14acac890e9..ab3f2edec86 100644 --- a/Mage.Sets/src/mage/cards/m/MisthoofKirin.java +++ b/Mage.Sets/src/mage/cards/m/MisthoofKirin.java @@ -31,7 +31,7 @@ public final class MisthoofKirin extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // Megamorph {1}{W} (You may cast this face down as a 2/2 creature for {3}. Turn it face up any time for its megamorph cost and put a +1/+1 counter on it.) - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{W}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{W}"), true)); } private MisthoofKirin(final MisthoofKirin card) { diff --git a/Mage.Sets/src/mage/cards/m/MitoticManipulation.java b/Mage.Sets/src/mage/cards/m/MitoticManipulation.java index 19e57b7565b..c9a6cf9fe2d 100644 --- a/Mage.Sets/src/mage/cards/m/MitoticManipulation.java +++ b/Mage.Sets/src/mage/cards/m/MitoticManipulation.java @@ -80,7 +80,7 @@ class MitoticManipulationEffect extends OneShotEffect { if (!namePredicates.isEmpty() && !cardsFromTop.isEmpty()) { filter.add(Predicates.or(namePredicates)); TargetCard target = new TargetCard(Zone.LIBRARY, filter); - if (cardsFromTop.count(filter, source.getSourceId(), source.getControllerId(), game) > 0 + if (cardsFromTop.count(filter, source.getControllerId(), source, game) > 0 && controller.chooseUse(Outcome.PutCardInPlay, "Put a card on the battlefield?", source, game)) { if (controller.choose(Outcome.PutCardInPlay, cardsFromTop, target, game)) { Card card = cardsFromTop.get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/cards/m/MizzixOfTheIzmagnus.java b/Mage.Sets/src/mage/cards/m/MizzixOfTheIzmagnus.java index b5bc737a42c..93dc1c03861 100644 --- a/Mage.Sets/src/mage/cards/m/MizzixOfTheIzmagnus.java +++ b/Mage.Sets/src/mage/cards/m/MizzixOfTheIzmagnus.java @@ -109,11 +109,11 @@ class MizzixOfTheIzmagnusCostReductionEffect extends CostModificationEffectImpl if (abilityToModify instanceof SpellAbility && abilityToModify.isControlledBy(source.getControllerId())) { Spell spell = (Spell) game.getStack().getStackObject(abilityToModify.getId()); if (spell != null) { - return StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(spell, source.getSourceId(), source.getControllerId(), game); + return StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(spell, source.getControllerId(), source, game); } else if (game.inCheckPlayableState()) { // Spell is not on the stack yet, but possible playable spells are determined Card sourceCard = game.getCard(abilityToModify.getSourceId()); - return sourceCard != null && StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(sourceCard, source.getSourceId(), source.getControllerId(), game); + return sourceCard != null && StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(sourceCard, source.getControllerId(), source, game); } } return false; diff --git a/Mage.Sets/src/mage/cards/m/MizzixsMastery.java b/Mage.Sets/src/mage/cards/m/MizzixsMastery.java index 9dd993e1587..91855af4a0d 100644 --- a/Mage.Sets/src/mage/cards/m/MizzixsMastery.java +++ b/Mage.Sets/src/mage/cards/m/MizzixsMastery.java @@ -118,7 +118,7 @@ class MizzixsMasteryOverloadEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Set cardsToExile = controller.getGraveyard().getCards( - new FilterInstantOrSorceryCard(), source.getId(), source.getControllerId(), game); + new FilterInstantOrSorceryCard(), source.getControllerId(), source, game); if (!cardsToExile.isEmpty()) { if (controller.moveCards(cardsToExile, Zone.EXILED, source, game)) { Cards copiedCards = new CardsImpl(); diff --git a/Mage.Sets/src/mage/cards/m/MnemonicSliver.java b/Mage.Sets/src/mage/cards/m/MnemonicSliver.java index d49bc9e0dad..96304a3864d 100644 --- a/Mage.Sets/src/mage/cards/m/MnemonicSliver.java +++ b/Mage.Sets/src/mage/cards/m/MnemonicSliver.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.Cost; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -14,8 +13,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.StaticFilters; +import mage.filter.FilterPermanent; import java.util.UUID; @@ -24,18 +22,21 @@ import java.util.UUID; */ public final class MnemonicSliver extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent(SubType.SLIVER, "all Slivers"); + public MnemonicSliver(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); this.subtype.add(SubType.SLIVER); this.power = new MageInt(2); this.toughness = new MageInt(2); - Cost cost = new SacrificeSourceCost(); - cost.setText("sacrifice this permanent"); - Ability gainedAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new GenericManaCost(2)); - gainedAbility.addCost(cost); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new GainAbilityAllEffect(gainedAbility, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, false))); + Ability ability = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(1), new GenericManaCost(2) + ); + ability.addCost(new SacrificeSourceCost().setText("sacrifice this permanent")); + this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( + ability, Duration.WhileOnBattlefield, filter, false + ))); } private MnemonicSliver(final MnemonicSliver card) { diff --git a/Mage.Sets/src/mage/cards/m/MnemonicWall.java b/Mage.Sets/src/mage/cards/m/MnemonicWall.java index 921837e17af..f78b5a7b6f2 100644 --- a/Mage.Sets/src/mage/cards/m/MnemonicWall.java +++ b/Mage.Sets/src/mage/cards/m/MnemonicWall.java @@ -1,11 +1,9 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.DefenderAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -15,8 +13,9 @@ import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author North */ public final class MnemonicWall extends CardImpl { @@ -30,14 +29,14 @@ public final class MnemonicWall extends CardImpl { } public MnemonicWall(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); this.subtype.add(SubType.WALL); this.power = new MageInt(0); this.toughness = new MageInt(4); this.addAbility(DefenderAbility.getInstance()); - Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), true); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MobRule.java b/Mage.Sets/src/mage/cards/m/MobRule.java index 66cc3543041..009bb75a9c6 100644 --- a/Mage.Sets/src/mage/cards/m/MobRule.java +++ b/Mage.Sets/src/mage/cards/m/MobRule.java @@ -32,8 +32,7 @@ public final class MobRule extends CardImpl { this.getSpellAbility().addEffect(new MobRuleEffect(ComparisonType.MORE_THAN, 3)); // Gain control of all creatures with power 3 or less until end of turn. Untap those creatures. They gain haste until end of turn. - Mode mode = new Mode(); - mode.addEffect(new MobRuleEffect(ComparisonType.FEWER_THAN, 4)); + Mode mode = new Mode(new MobRuleEffect(ComparisonType.FEWER_THAN, 4)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/m/MobilizerMech.java b/Mage.Sets/src/mage/cards/m/MobilizerMech.java index c6752e963b6..199f37bab0e 100644 --- a/Mage.Sets/src/mage/cards/m/MobilizerMech.java +++ b/Mage.Sets/src/mage/cards/m/MobilizerMech.java @@ -64,7 +64,7 @@ class MobilizerMechTriggeredAbility extends TriggeredAbilityImpl { MobilizerMechTriggeredAbility() { super(Zone.BATTLEFIELD, new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE)); - this.addTarget(new TargetPermanent(0,1,filter)); + this.addTarget(new TargetPermanent(0, 1, filter)); } private MobilizerMechTriggeredAbility(final MobilizerMechTriggeredAbility ability) { @@ -78,7 +78,7 @@ class MobilizerMechTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.CREWED_VEHICLE; + return event.getType() == GameEvent.EventType.VEHICLE_CREWED; } @Override diff --git a/Mage.Sets/src/mage/cards/m/MoggManiac.java b/Mage.Sets/src/mage/cards/m/MoggManiac.java index a94a09fa628..6c9261b277c 100644 --- a/Mage.Sets/src/mage/cards/m/MoggManiac.java +++ b/Mage.Sets/src/mage/cards/m/MoggManiac.java @@ -1,17 +1,15 @@ - package mage.cards.m; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealtDamageToSourceTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Outcome; -import mage.game.Game; import mage.target.common.TargetOpponentOrPlaneswalker; /** @@ -26,8 +24,9 @@ public final class MoggManiac extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - // Whenever Mogg Maniac is dealt damage, it deals that much damage to target opponent. - Ability ability = new DealtDamageToSourceTriggeredAbility(new MoggManiacDealDamageEffect(), false, false); + // Whenever Mogg Maniac is dealt damage, it deals that much damage to target opponent or planeswalker. + Ability ability = new DealtDamageToSourceTriggeredAbility( + new DamageTargetEffect(SavedDamageValue.MUCH, "it"), false); ability.addTarget(new TargetOpponentOrPlaneswalker()); this.addAbility(ability); } @@ -41,30 +40,3 @@ public final class MoggManiac extends CardImpl { return new MoggManiac(this); } } - -class MoggManiacDealDamageEffect extends OneShotEffect { - - public MoggManiacDealDamageEffect() { - super(Outcome.Damage); - this.staticText = "it deals that much damage to target opponent or planeswalker"; - } - - public MoggManiacDealDamageEffect(final MoggManiacDealDamageEffect effect) { - super(effect); - } - - @Override - public MoggManiacDealDamageEffect copy() { - return new MoggManiacDealDamageEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int amount = (Integer) getValue("damage"); - if (amount > 0) { - game.damagePlayerOrPlaneswalker(targetPointer.getFirst(game, source), amount, source.getSourceId(), source, game, false, true); - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/m/MogisGodOfSlaughter.java b/Mage.Sets/src/mage/cards/m/MogisGodOfSlaughter.java index 3911453757e..57eb1ce009e 100644 --- a/Mage.Sets/src/mage/cards/m/MogisGodOfSlaughter.java +++ b/Mage.Sets/src/mage/cards/m/MogisGodOfSlaughter.java @@ -85,9 +85,9 @@ class MogisGodOfSlaughterEffect extends OneShotEffect { } TargetPermanent target = new TargetControlledCreaturePermanent(1); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), player.getId(), game) + if (target.canChoose(player.getId(), source, game) && player.chooseUse(Outcome.Detriment, "Sacrifice a creature to prevent 2 damage?", source, game) - && player.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) { + && player.choose(Outcome.Sacrifice, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null && permanent.sacrifice(source, game)) { return true; diff --git a/Mage.Sets/src/mage/cards/m/MoldAdder.java b/Mage.Sets/src/mage/cards/m/MoldAdder.java index 8c68ca369e2..55483f70adc 100644 --- a/Mage.Sets/src/mage/cards/m/MoldAdder.java +++ b/Mage.Sets/src/mage/cards/m/MoldAdder.java @@ -21,7 +21,7 @@ import mage.filter.predicate.mageobject.ColorPredicate; */ public final class MoldAdder extends CardImpl { - private static final FilterSpell filter = new FilterSpell("blue or black spell"); + private static final FilterSpell filter = new FilterSpell("a blue or black spell"); static { filter.add(Predicates.or( new ColorPredicate(ObjectColor.BLUE), diff --git a/Mage.Sets/src/mage/cards/m/Molder.java b/Mage.Sets/src/mage/cards/m/Molder.java index a4f80e6031e..0a41990d806 100644 --- a/Mage.Sets/src/mage/cards/m/Molder.java +++ b/Mage.Sets/src/mage/cards/m/Molder.java @@ -27,7 +27,7 @@ public final class Molder extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{G}"); // Destroy target artifact or enchantment with converted mana cost X. It can't be regenerated. You gain X life. - this.getSpellAbility().addEffect(new DestroyTargetEffect("Destroy target artifact or enchantment with mana value X", true)); + this.getSpellAbility().addEffect(new DestroyTargetEffect("Destroy target artifact or enchantment with mana value X. It can't be regenerated", true)); this.getSpellAbility().addEffect(new GainLifeEffect(ManacostVariableValue.REGULAR)); this.getSpellAbility().setTargetAdjuster(MolderAdjuster.instance); } diff --git a/Mage.Sets/src/mage/cards/m/MoltensteelDragon.java b/Mage.Sets/src/mage/cards/m/MoltensteelDragon.java index ad9430c080a..141964fa61e 100644 --- a/Mage.Sets/src/mage/cards/m/MoltensteelDragon.java +++ b/Mage.Sets/src/mage/cards/m/MoltensteelDragon.java @@ -1,28 +1,25 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.PhyrexianManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.ColoredManaSymbol; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author North */ public final class MoltensteelDragon extends CardImpl { public MoltensteelDragon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}{R/P}{R/P}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}{R/P}{R/P}"); this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DRAGON); @@ -32,9 +29,9 @@ public final class MoltensteelDragon extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new BoostSourceEffect(1, 0, Duration.EndOfTurn), - new PhyrexianManaCost(ColoredManaSymbol.R))); + this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect( + 1, 0, Duration.EndOfTurn + ), new ManaCostsImpl<>("{R/P}"))); } private MoltensteelDragon(final MoltensteelDragon card) { diff --git a/Mage.Sets/src/mage/cards/m/MomirVigSimicVisionary.java b/Mage.Sets/src/mage/cards/m/MomirVigSimicVisionary.java index fe4eadf03d2..ddd0da64c92 100644 --- a/Mage.Sets/src/mage/cards/m/MomirVigSimicVisionary.java +++ b/Mage.Sets/src/mage/cards/m/MomirVigSimicVisionary.java @@ -88,7 +88,7 @@ class MomirVigSimicVisionaryEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/m/MonasteryFlock.java b/Mage.Sets/src/mage/cards/m/MonasteryFlock.java index f0a2e054cc4..cea30ee5b47 100644 --- a/Mage.Sets/src/mage/cards/m/MonasteryFlock.java +++ b/Mage.Sets/src/mage/cards/m/MonasteryFlock.java @@ -30,7 +30,7 @@ public final class MonasteryFlock extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Morph {U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{U}"))); } private MonasteryFlock(final MonasteryFlock card) { diff --git a/Mage.Sets/src/mage/cards/m/MonasteryLoremaster.java b/Mage.Sets/src/mage/cards/m/MonasteryLoremaster.java index 06cb6ce6d70..d5a352d2ef9 100644 --- a/Mage.Sets/src/mage/cards/m/MonasteryLoremaster.java +++ b/Mage.Sets/src/mage/cards/m/MonasteryLoremaster.java @@ -37,7 +37,7 @@ public final class MonasteryLoremaster extends CardImpl { this.toughness = new MageInt(2); // Megamorph {5}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{5}{U}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{5}{U}"), true)); // When Monastery Loremaster is turned face up, return target noncreature, nonland card from your graveyard to your hand. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/m/MonkIdealist.java b/Mage.Sets/src/mage/cards/m/MonkIdealist.java index 985d86aa2a2..03e8e4b3b51 100644 --- a/Mage.Sets/src/mage/cards/m/MonkIdealist.java +++ b/Mage.Sets/src/mage/cards/m/MonkIdealist.java @@ -1,32 +1,28 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.FilterCard; +import mage.filter.common.FilterEnchantmentCard; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author hanasu */ public final class MonkIdealist extends CardImpl { - private static final FilterCard filter = new FilterCard("enchantment card from your graveyard"); + private static final FilterCard filter = new FilterEnchantmentCard("enchantment card from your graveyard"); - static { - filter.add(CardType.ENCHANTMENT.getPredicate()); - } - public MonkIdealist(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.MONK); this.subtype.add(SubType.CLERIC); @@ -34,7 +30,7 @@ public final class MonkIdealist extends CardImpl { this.toughness = new MageInt(2); // When Monk Idealist enters the battlefield, return target enchantment card from your graveyard to your hand. - Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), true); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MonkeyMonkeyMonkey.java b/Mage.Sets/src/mage/cards/m/MonkeyMonkeyMonkey.java index 03d34fe6123..effffe74819 100644 --- a/Mage.Sets/src/mage/cards/m/MonkeyMonkeyMonkey.java +++ b/Mage.Sets/src/mage/cards/m/MonkeyMonkeyMonkey.java @@ -74,7 +74,7 @@ class ChooseLetterEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } ChoiceImpl choice = new ChoiceImpl(true); @@ -121,7 +121,7 @@ class MonkeyMonkeyMonkeyCount implements DynamicValue { Permanent permanent = game.getPermanentOrLKIBattlefield(sourceAbility.getSourceId()); if (permanent != null && game.getState().getValue(mageObject.getId() + "_letter") != null) { int letters = 0; - for (Permanent p : game.getBattlefield().getActivePermanents(new FilterNonlandPermanent(), sourceAbility.getControllerId(), sourceAbility.getSourceId(), game)) { + for (Permanent p : game.getBattlefield().getActivePermanents(new FilterNonlandPermanent(), sourceAbility.getControllerId(), sourceAbility, game)) { char initial = Character.toUpperCase(p.getName().charAt(0)); if (Character.toString(initial).equals(game.getState().getValue(mageObject.getId() + "_letter"))) { letters++; diff --git a/Mage.Sets/src/mage/cards/m/MonologueTax.java b/Mage.Sets/src/mage/cards/m/MonologueTax.java index 2aece48210d..78d14c97e6d 100644 --- a/Mage.Sets/src/mage/cards/m/MonologueTax.java +++ b/Mage.Sets/src/mage/cards/m/MonologueTax.java @@ -1,16 +1,12 @@ package mage.cards.m; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.CastSecondSpellTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; +import mage.constants.TargetController; import mage.game.permanent.token.TreasureToken; -import mage.players.Player; -import mage.watchers.common.CastSpellLastTurnWatcher; import java.util.UUID; @@ -23,7 +19,11 @@ public final class MonologueTax extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); // Whenever an opponent casts their second spell each turn, you create a Treasure token. - this.addAbility(new MonologueTaxTriggeredAbility()); + this.addAbility(new CastSecondSpellTriggeredAbility( + new CreateTokenEffect(new TreasureToken()) + .setText("you create a Treasure token"), + TargetController.OPPONENT + )); } private MonologueTax(final MonologueTax card) { @@ -35,39 +35,3 @@ public final class MonologueTax extends CardImpl { return new MonologueTax(this); } } - -class MonologueTaxTriggeredAbility extends TriggeredAbilityImpl { - - MonologueTaxTriggeredAbility() { - super(Zone.BATTLEFIELD, new CreateTokenEffect(new TreasureToken())); - } - - private MonologueTaxTriggeredAbility(final MonologueTaxTriggeredAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SPELL_CAST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Player player = game.getPlayer(getControllerId()); - CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); - return player != null - && watcher != null - && player.hasOpponent(event.getPlayerId(), game) - && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) == 2; - } - - @Override - public MonologueTaxTriggeredAbility copy() { - return new MonologueTaxTriggeredAbility(this); - } - - @Override - public String getRule() { - return "Whenever an opponent casts their second spell each turn, you create a Treasure token."; - } -} diff --git a/Mage.Sets/src/mage/cards/m/MoodmarkPainter.java b/Mage.Sets/src/mage/cards/m/MoodmarkPainter.java index e850d17c7f5..a35d98b8040 100644 --- a/Mage.Sets/src/mage/cards/m/MoodmarkPainter.java +++ b/Mage.Sets/src/mage/cards/m/MoodmarkPainter.java @@ -10,6 +10,7 @@ import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.MenaceAbility; +import mage.constants.AbilityWord; import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -49,7 +50,7 @@ public final class MoodmarkPainter extends CardImpl { + "where X is the number of creature cards in your graveyard. " + "(It can't be blocked except by two or more creatures.)")); // Must be here to match Oracle text ability.addTarget(new TargetCreaturePermanent()); - ability.withFlavorWord("Undergrowth"); + ability.setAbilityWord(AbilityWord.UNDERGROWTH); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MoongloveExtract.java b/Mage.Sets/src/mage/cards/m/MoongloveExtract.java index 15acc9c1a76..ebe05d62697 100644 --- a/Mage.Sets/src/mage/cards/m/MoongloveExtract.java +++ b/Mage.Sets/src/mage/cards/m/MoongloveExtract.java @@ -22,7 +22,7 @@ public final class MoongloveExtract extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); // Sacrifice Moonglove Extract: Moonglove Extract deals 2 damage to any target. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new SacrificeSourceCost()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2, "it"), new SacrificeSourceCost()); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/Moonhold.java b/Mage.Sets/src/mage/cards/m/Moonhold.java index de153b6071a..d1d169b00bc 100644 --- a/Mage.Sets/src/mage/cards/m/Moonhold.java +++ b/Mage.Sets/src/mage/cards/m/Moonhold.java @@ -34,7 +34,7 @@ public final class Moonhold extends CardImpl { ContinuousRuleModifyingEffect effect = new MoonholdEffect(); ContinuousRuleModifyingEffect effect2 = new MoonholdEffect2(); effect.setText("Target player can't play lands this turn if {R} was spent to cast this spell"); - effect2.setText("and can't cast creature spells this turn if {W} was spent to cast it."); + effect2.setText("and can't cast creature spells this turn if {W} was spent to cast this spell."); this.getSpellAbility().addEffect(new ConditionalContinuousRuleModifyingEffect( effect, new LockedInCondition(new ManaWasSpentCondition(ColoredManaSymbol.R)))); @@ -77,7 +77,7 @@ class MoonholdEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "you can't play land cards this turn (" + mageObject.getIdName() + ")."; } @@ -120,7 +120,7 @@ class MoonholdEffect2 extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't play creature cards this turn (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/m/MoonsnarePrototype.java b/Mage.Sets/src/mage/cards/m/MoonsnarePrototype.java index 741687662af..a13956b1090 100644 --- a/Mage.Sets/src/mage/cards/m/MoonsnarePrototype.java +++ b/Mage.Sets/src/mage/cards/m/MoonsnarePrototype.java @@ -2,19 +2,15 @@ package mage.cards.m; import mage.abilities.Ability; import mage.abilities.costs.common.TapTargetCost; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; import mage.abilities.keyword.ChannelAbility; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.TappedPredicate; -import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetNonlandPermanent; @@ -45,7 +41,7 @@ public final class MoonsnarePrototype extends CardImpl { this.addAbility(ability); // Channel — {4}{U}, Discard Moonsnare Prototype: The owner of target nonland permanent puts it on the top or bottom of their library. - ability = new ChannelAbility("{4}{U}", new MoonsnarePrototypeEffect()); + ability = new ChannelAbility("{4}{U}", new PutOnTopOrBottomLibraryTargetEffect()); ability.addTarget(new TargetNonlandPermanent()); this.addAbility(ability); } @@ -59,33 +55,3 @@ public final class MoonsnarePrototype extends CardImpl { return new MoonsnarePrototype(this); } } - -class MoonsnarePrototypeEffect extends OneShotEffect { - - MoonsnarePrototypeEffect() { - super(Outcome.Benefit); - staticText = "the owner of target nonland permanent puts it on the top or bottom of their library"; - } - - private MoonsnarePrototypeEffect(final MoonsnarePrototypeEffect effect) { - super(effect); - } - - @Override - public MoonsnarePrototypeEffect copy() { - return new MoonsnarePrototypeEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget())); - if (player == null) { - return false; - } - if (player.chooseUse(Outcome.Detriment, "Put the targeted object on the top or bottom of your library?", - "", "Top", "Bottom", source, game)) { - return new PutOnLibraryTargetEffect(true).apply(game, source); - } - return new PutOnLibraryTargetEffect(false).apply(game, source); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MordantDragon.java b/Mage.Sets/src/mage/cards/m/MordantDragon.java index 6cd888496fa..e1cee271064 100644 --- a/Mage.Sets/src/mage/cards/m/MordantDragon.java +++ b/Mage.Sets/src/mage/cards/m/MordantDragon.java @@ -99,7 +99,7 @@ class MordantDragonTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { return "Whenever {this} deals combat damage to a player, " - + "you may have it deal that much damage to target creature that player controls"; + + "you may have it deal that much damage to target creature that player controls."; } } diff --git a/Mage.Sets/src/mage/cards/m/Mordenkainen.java b/Mage.Sets/src/mage/cards/m/Mordenkainen.java index e55f74548f2..76b69d4501f 100644 --- a/Mage.Sets/src/mage/cards/m/Mordenkainen.java +++ b/Mage.Sets/src/mage/cards/m/Mordenkainen.java @@ -4,7 +4,6 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -27,7 +26,7 @@ public final class Mordenkainen extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.MORDENKAINEN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +2: Draw two cards, then put a card from your hand on the bottom of your library. this.addAbility(new LoyaltyAbility(new MordenkainenDrawEffect(), 2)); diff --git a/Mage.Sets/src/mage/cards/m/MoriokScavenger.java b/Mage.Sets/src/mage/cards/m/MoriokScavenger.java index 3b4c2ef147e..db1253c9881 100644 --- a/Mage.Sets/src/mage/cards/m/MoriokScavenger.java +++ b/Mage.Sets/src/mage/cards/m/MoriokScavenger.java @@ -1,11 +1,9 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -13,8 +11,9 @@ import mage.constants.SubType; import mage.filter.common.FilterCreatureCard; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author LoneFox */ public final class MoriokScavenger extends CardImpl { @@ -26,14 +25,14 @@ public final class MoriokScavenger extends CardImpl { } public MoriokScavenger(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.HUMAN); this.subtype.add(SubType.ROGUE); this.power = new MageInt(2); this.toughness = new MageInt(3); // When Moriok Scavenger enters the battlefield, you may return target artifact creature card from your graveyard to your hand. - Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), true); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MorkrutBehemoth.java b/Mage.Sets/src/mage/cards/m/MorkrutBehemoth.java index 4dd44b8fbbf..48772fd9b2f 100644 --- a/Mage.Sets/src/mage/cards/m/MorkrutBehemoth.java +++ b/Mage.Sets/src/mage/cards/m/MorkrutBehemoth.java @@ -29,9 +29,9 @@ public final class MorkrutBehemoth extends CardImpl { // As an additional cost to cast this spell, sacrifice a creature or pay {1}{B}. this.getSpellAbility().addCost(new OrCost( - new SacrificeTargetCost(new TargetControlledPermanent( + "sacrifice a creature or pay {1}{B}", new SacrificeTargetCost(new TargetControlledPermanent( StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT - )), new ManaCostsImpl<>("{1}{B}"), "sacrifice a creature or pay {1}{B}" + )), new ManaCostsImpl<>("{1}{B}") )); // Menace diff --git a/Mage.Sets/src/mage/cards/m/Morselhoarder.java b/Mage.Sets/src/mage/cards/m/Morselhoarder.java index ab38678b3e5..7ec9d675ca4 100644 --- a/Mage.Sets/src/mage/cards/m/Morselhoarder.java +++ b/Mage.Sets/src/mage/cards/m/Morselhoarder.java @@ -30,7 +30,7 @@ public final class Morselhoarder extends CardImpl { this.toughness = new MageInt(4); // Morselhoarder enters the battlefield with two -1/-1 counters on it. - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance(2), false))); + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance(2)), "with two -1/-1 counters on it")); // Remove a -1/-1 counter from Morselhoarder: Add one mana of any color. this.addAbility(new MorselhoarderAbility()); diff --git a/Mage.Sets/src/mage/cards/m/MossbridgeTroll.java b/Mage.Sets/src/mage/cards/m/MossbridgeTroll.java index 028d0f8ad19..0db551b9830 100644 --- a/Mage.Sets/src/mage/cards/m/MossbridgeTroll.java +++ b/Mage.Sets/src/mage/cards/m/MossbridgeTroll.java @@ -119,7 +119,7 @@ class MossbridgeTrollCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { int sumPower = 0; - if (targets.choose(Outcome.Tap, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.Tap, controllerId, source.getSourceId(), source, game)) { for (UUID targetId : targets.get(0).getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent != null && permanent.tap(source, game)) { diff --git a/Mage.Sets/src/mage/cards/m/MosswortBridge.java b/Mage.Sets/src/mage/cards/m/MosswortBridge.java index 70879f132aa..1e1344c9c86 100644 --- a/Mage.Sets/src/mage/cards/m/MosswortBridge.java +++ b/Mage.Sets/src/mage/cards/m/MosswortBridge.java @@ -1,6 +1,7 @@ package mage.cards.m; import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; @@ -27,7 +28,8 @@ public final class MosswortBridge extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // Hideaway (This land enters the battlefield tapped. When it does, look at the top four cards of your library, exile one face down, then put the rest on the bottom of your library.) - this.addAbility(new HideawayAbility()); + this.addAbility(new HideawayAbility(4)); + this.addAbility(new EntersBattlefieldTappedAbility()); // {T}: Add {G}. this.addAbility(new GreenManaAbility()); @@ -60,7 +62,7 @@ enum MosswortBridgeTotalPowerCondition implements Condition { int totalPower = 0; for (Permanent permanent : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game )) { totalPower += permanent.getPower().getValue(); if (totalPower >= 10) { diff --git a/Mage.Sets/src/mage/cards/m/MostWanted.java b/Mage.Sets/src/mage/cards/m/MostWanted.java new file mode 100644 index 00000000000..cbfd5aba787 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MostWanted.java @@ -0,0 +1,57 @@ +package mage.cards.m; + +import mage.abilities.common.DiesAttachedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.permanent.token.TreasureToken; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MostWanted extends CardImpl { + + public MostWanted(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); + + this.subtype.add(SubType.AURA); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // Enchanted creature gets +2/+1. + this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(2, 1))); + + // When enchanted creature dies, create two Treasure tokens. + this.addAbility(new DiesAttachedTriggeredAbility( + new CreateTokenEffect(new TreasureToken(), 2), "enchanted creature" + )); + } + + private MostWanted(final MostWanted card) { + super(card); + } + + @Override + public MostWanted copy() { + return new MostWanted(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MournersShield.java b/Mage.Sets/src/mage/cards/m/MournersShield.java index 571faa45aee..0eeb80160b7 100644 --- a/Mage.Sets/src/mage/cards/m/MournersShield.java +++ b/Mage.Sets/src/mage/cards/m/MournersShield.java @@ -15,10 +15,7 @@ import mage.abilities.effects.PreventionEffectImpl; 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.constants.*; import mage.filter.FilterObject; import mage.filter.predicate.mageobject.SharesColorPredicate; import mage.game.ExileZone; @@ -43,7 +40,7 @@ public final class MournersShield extends CardImpl { // Imprint - When Mourner's Shield enters the battlefield, you may exile target card from a graveyard. Ability ability = new EntersBattlefieldTriggeredAbility(new MournersShieldImprintEffect(), true); ability.addTarget(new TargetCardInGraveyard()); - ability.withFlavorWord("Imprint"); + ability.setAbilityWord(AbilityWord.IMPRINT); this.addAbility(ability); // {2}, {tap}: Prevent all damage that would be dealt this turn by a source of your choice that shares a color with the exiled card. @@ -144,7 +141,7 @@ class MournersShieldEffect extends PreventionEffectImpl { FilterObject filterObject = new FilterObject("a source of your choice that shares a color with the exiled card"); filterObject.add(new SharesColorPredicate(colorsAmongImprinted)); this.target = new TargetSource(filterObject); - this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); if (target.getFirstTarget() != null) { mageObjectReference = new MageObjectReference(target.getFirstTarget(), game); } else { diff --git a/Mage.Sets/src/mage/cards/m/MrOrfeoTheBoulder.java b/Mage.Sets/src/mage/cards/m/MrOrfeoTheBoulder.java new file mode 100644 index 00000000000..59975e93fb1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MrOrfeoTheBoulder.java @@ -0,0 +1,78 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MrOrfeoTheBoulder extends CardImpl { + + public MrOrfeoTheBoulder(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{R}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.RHINO); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Whenever you attack, double target creature's power until end of turn. + Ability ability = new AttacksWithCreaturesTriggeredAbility(new MrOrfeoTheBoulderEffect(), 1); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private MrOrfeoTheBoulder(final MrOrfeoTheBoulder card) { + super(card); + } + + @Override + public MrOrfeoTheBoulder copy() { + return new MrOrfeoTheBoulder(this); + } +} + +class MrOrfeoTheBoulderEffect extends OneShotEffect { + + MrOrfeoTheBoulderEffect() { + super(Outcome.Benefit); + staticText = "double target creature's power until end of turn"; + } + + private MrOrfeoTheBoulderEffect(final MrOrfeoTheBoulderEffect effect) { + super(effect); + } + + @Override + public MrOrfeoTheBoulderEffect copy() { + return new MrOrfeoTheBoulderEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + return false; + } + game.addEffect(new BoostTargetEffect( + permanent.getPower().getValue(), 0 + ).setTargetPointer(new FixedTarget(permanent, game)), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MuYanling.java b/Mage.Sets/src/mage/cards/m/MuYanling.java index 3ec4c77f521..8da9ea636ac 100644 --- a/Mage.Sets/src/mage/cards/m/MuYanling.java +++ b/Mage.Sets/src/mage/cards/m/MuYanling.java @@ -4,7 +4,6 @@ package mage.cards.m; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; @@ -32,7 +31,7 @@ public final class MuYanling extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.YANLING); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +2: Target creature can't be blocked this turn. LoyaltyAbility ability = new LoyaltyAbility(new CantBeBlockedTargetEffect(), 2); @@ -73,7 +72,7 @@ class MuYanlingEffect extends OneShotEffect { if (player == null) { return false; } - for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, player.getId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, player.getId(), source, game)) { creature.tap(source, game); } return new AddExtraTurnControllerEffect().apply(game, source); diff --git a/Mage.Sets/src/mage/cards/m/MuYanlingCelestialWind.java b/Mage.Sets/src/mage/cards/m/MuYanlingCelestialWind.java index 709b92c774a..1b9abc9ce02 100644 --- a/Mage.Sets/src/mage/cards/m/MuYanlingCelestialWind.java +++ b/Mage.Sets/src/mage/cards/m/MuYanlingCelestialWind.java @@ -2,7 +2,6 @@ package mage.cards.m; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -33,7 +32,7 @@ public final class MuYanlingCelestialWind extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.YANLING); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Until your next turn, up to one target creature gets -5/-0. Ability ability = new LoyaltyAbility(new BoostTargetEffect( diff --git a/Mage.Sets/src/mage/cards/m/MuYanlingSkyDancer.java b/Mage.Sets/src/mage/cards/m/MuYanlingSkyDancer.java index b137052617c..25c122b8709 100644 --- a/Mage.Sets/src/mage/cards/m/MuYanlingSkyDancer.java +++ b/Mage.Sets/src/mage/cards/m/MuYanlingSkyDancer.java @@ -2,7 +2,6 @@ package mage.cards.m; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -30,7 +29,7 @@ public final class MuYanlingSkyDancer extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.YANLING); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(2)); + this.setStartingLoyalty(2); // +2: Until your next turn, up to one target creature gets -2/-0 and loses flying. Ability ability = new LoyaltyAbility(new BoostTargetEffect( diff --git a/Mage.Sets/src/mage/cards/m/MuckDrubb.java b/Mage.Sets/src/mage/cards/m/MuckDrubb.java index 47f4327956f..462f2c62c02 100644 --- a/Mage.Sets/src/mage/cards/m/MuckDrubb.java +++ b/Mage.Sets/src/mage/cards/m/MuckDrubb.java @@ -56,7 +56,7 @@ public final class MuckDrubb extends CardImpl { this.addAbility(ability); // Madness {2}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{2}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{2}{B}"))); } private MuckDrubb(final MuckDrubb card) { diff --git a/Mage.Sets/src/mage/cards/m/Mudslide.java b/Mage.Sets/src/mage/cards/m/Mudslide.java index 7e890bdd832..440c02227fd 100644 --- a/Mage.Sets/src/mage/cards/m/Mudslide.java +++ b/Mage.Sets/src/mage/cards/m/Mudslide.java @@ -87,7 +87,7 @@ class MudslideEffect extends OneShotEffect { int countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size(); while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.Benefit, "Pay {2} and untap a tapped creature without flying under your control?", source, game)) { Target tappedCreatureTarget = new TargetControlledCreaturePermanent(1, 1, filter, true); - if (player.choose(Outcome.Untap, tappedCreatureTarget, source.getSourceId(), game)) { + if (player.choose(Outcome.Untap, tappedCreatureTarget, source, game)) { Cost cost = ManaUtil.createManaCost(2, false); Permanent tappedCreature = game.getPermanent(tappedCreatureTarget.getFirstTarget()); if (tappedCreature != null && cost.pay(source, game, source, player.getId(), false)) { diff --git a/Mage.Sets/src/mage/cards/m/MultanisDecree.java b/Mage.Sets/src/mage/cards/m/MultanisDecree.java index 62c174b36c2..78dde7d0c5a 100644 --- a/Mage.Sets/src/mage/cards/m/MultanisDecree.java +++ b/Mage.Sets/src/mage/cards/m/MultanisDecree.java @@ -57,7 +57,7 @@ class MultanisDecreeDestroyEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); int enchantmentsDestoyed = 0; - for (Permanent permanent: game.getState().getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_ENCHANTMENT, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent: game.getState().getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_ENCHANTMENT, source.getControllerId(), source, game)) { if (permanent.destroy(source, game, false)) { enchantmentsDestoyed++; } diff --git a/Mage.Sets/src/mage/cards/m/MultipleChoice.java b/Mage.Sets/src/mage/cards/m/MultipleChoice.java index bb75538f475..ccf734e83aa 100644 --- a/Mage.Sets/src/mage/cards/m/MultipleChoice.java +++ b/Mage.Sets/src/mage/cards/m/MultipleChoice.java @@ -80,17 +80,17 @@ class MultipleChoiceEffect extends OneShotEffect { return true; } TargetPlayer targetPlayer = new TargetPlayer(0, 1, true); - controller.choose(Outcome.Detriment, targetPlayer, source.getSourceId(), game); + controller.choose(Outcome.Detriment, targetPlayer, source, game); Player player = game.getPlayer(targetPlayer.getFirstTarget()); if (player == null || game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getSourceId(), player.getId(), game + player.getId(), source, game ) <= 0) { return true; } TargetPermanent targetPermanent = new TargetControlledCreaturePermanent(); targetPermanent.setNotTarget(true); - player.choose(Outcome.ReturnToHand, targetPermanent, source.getSourceId(), game); + player.choose(Outcome.ReturnToHand, targetPermanent, source, game); Permanent permanent = game.getPermanent(targetPermanent.getFirstTarget()); return permanent == null || player.moveCards(permanent, Zone.HAND, source, game); } diff --git a/Mage.Sets/src/mage/cards/m/MundaAmbushLeader.java b/Mage.Sets/src/mage/cards/m/MundaAmbushLeader.java index 9e6f03dc56f..644b8144d59 100644 --- a/Mage.Sets/src/mage/cards/m/MundaAmbushLeader.java +++ b/Mage.Sets/src/mage/cards/m/MundaAmbushLeader.java @@ -1,29 +1,31 @@ - package mage.cards.m; import java.util.UUID; import mage.MageInt; -import mage.MageObject; -import mage.abilities.Ability; import mage.abilities.common.AllyEntersBattlefieldTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.FilterCard; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; /** * - * @author LevelX2 + * @author awjackson */ public final class MundaAmbushLeader extends CardImpl { + private static final FilterCard filter = new FilterCard("Ally cards"); + + static { + filter.add(SubType.ALLY.getPredicate()); + } + public MundaAmbushLeader(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}{W}"); addSuperType(SuperType.LEGENDARY); @@ -34,9 +36,13 @@ public final class MundaAmbushLeader extends CardImpl { // Haste this.addAbility(HasteAbility.getInstance()); - // Rally-Whenever Munda, Ambush Leader or another Ally enters the battlefield under your control, you may look at the top four cards of your library. If you do, reveal any number of Ally cards from among them, then put those cards on top of your library in any order and the rest on the bottom in any order. - this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new MundaAmbushLeaderEffect(), true)); - + // Rally-Whenever Munda, Ambush Leader or another Ally enters the battlefield under your control, + // you may look at the top four cards of your library. If you do, reveal any number of Ally cards from among them, + // then put those cards on top of your library in any order and the rest on the bottom in any order. + Effect effect = new LookLibraryAndPickControllerEffect(4, Integer.MAX_VALUE, filter, PutCards.TOP_ANY, PutCards.BOTTOM_ANY, false); + effect.setText("look at the top four cards of your library. If you do, reveal any number of Ally cards from among them, " + + "then put those cards on top of your library in any order and the rest on the bottom in any order"); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility(effect, true)); } private MundaAmbushLeader(final MundaAmbushLeader card) { @@ -48,53 +54,3 @@ public final class MundaAmbushLeader extends CardImpl { return new MundaAmbushLeader(this); } } - -class MundaAmbushLeaderEffect extends OneShotEffect { - - private static final FilterCard filter = new FilterCard("Ally cards to reveal and put on top of your library"); - - static { - filter.add(SubType.ALLY.getPredicate()); - } - - public MundaAmbushLeaderEffect() { - super(Outcome.Benefit); - this.staticText = "you may look at the top four cards of your library. If you do, reveal any number of Ally cards from among them, then put those cards on top of your library in any order and the rest on the bottom in any order"; - } - - public MundaAmbushLeaderEffect(final MundaAmbushLeaderEffect effect) { - super(effect); - } - - @Override - public MundaAmbushLeaderEffect copy() { - return new MundaAmbushLeaderEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller != null && sourceObject != null) { - Cards allCards = new CardsImpl(); - allCards.addAll(controller.getLibrary().getTopCards(game, 4)); - controller.lookAtCards(sourceObject.getIdName(), allCards, game); - if (!allCards.isEmpty()) { - Cards cardsToReveal = new CardsImpl(); - TargetCard target = new TargetCard(0, Integer.MAX_VALUE, Zone.LIBRARY, filter); - controller.chooseTarget(outcome, allCards, target, source, game); - cardsToReveal.addAll(target.getTargets()); - if (!cardsToReveal.isEmpty()) { - controller.revealCards(sourceObject.getIdName(), cardsToReveal, game, true); - allCards.removeAll(cardsToReveal); - } - controller.putCardsOnTopOfLibrary(cardsToReveal, game, source, true); - } - if (!allCards.isEmpty()) { - controller.putCardsOnBottomOfLibrary(allCards, game, source, true); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/m/MurasaBehemoth.java b/Mage.Sets/src/mage/cards/m/MurasaBehemoth.java index bcac144b857..d3303cbecd1 100644 --- a/Mage.Sets/src/mage/cards/m/MurasaBehemoth.java +++ b/Mage.Sets/src/mage/cards/m/MurasaBehemoth.java @@ -21,7 +21,7 @@ import java.util.UUID; */ public final class MurasaBehemoth extends CardImpl { - Condition condition = new CardsInControllerGraveyardCondition(1, StaticFilters.FILTER_CARD_LAND); + private static final Condition condition = new CardsInControllerGraveyardCondition(1, StaticFilters.FILTER_CARD_LAND); public MurasaBehemoth(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); diff --git a/Mage.Sets/src/mage/cards/m/MurasaPyromancer.java b/Mage.Sets/src/mage/cards/m/MurasaPyromancer.java index 2ab4b2bfa81..953c54f6b3e 100644 --- a/Mage.Sets/src/mage/cards/m/MurasaPyromancer.java +++ b/Mage.Sets/src/mage/cards/m/MurasaPyromancer.java @@ -39,7 +39,7 @@ public final class MurasaPyromancer extends CardImpl { Ability ability = new AllyEntersBattlefieldTriggeredAbility(new DamageTargetEffect(new PermanentsOnBattlefieldCount(filter)), true); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(null)); } diff --git a/Mage.Sets/src/mage/cards/m/MurderousCompulsion.java b/Mage.Sets/src/mage/cards/m/MurderousCompulsion.java index 4b40f78d4c7..f261e7951bb 100644 --- a/Mage.Sets/src/mage/cards/m/MurderousCompulsion.java +++ b/Mage.Sets/src/mage/cards/m/MurderousCompulsion.java @@ -32,7 +32,7 @@ public final class MurderousCompulsion extends CardImpl { getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); // Madness {1}{B} (If you discard card, discard it into exile. When you do, cast it for its madness cost or put it into your graveyard.) - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{1}{B}"))); } private MurderousCompulsion(final MurderousCompulsion card) { diff --git a/Mage.Sets/src/mage/cards/m/MurmursFromBeyond.java b/Mage.Sets/src/mage/cards/m/MurmursFromBeyond.java index eb0a0e2ce51..dabb9ab700d 100644 --- a/Mage.Sets/src/mage/cards/m/MurmursFromBeyond.java +++ b/Mage.Sets/src/mage/cards/m/MurmursFromBeyond.java @@ -62,7 +62,7 @@ class MurmursFromBeyondEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && controller != null) { Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 3)); if (!cards.isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/m/MuseVessel.java b/Mage.Sets/src/mage/cards/m/MuseVessel.java index 14f48561338..ce7cbfb70ff 100644 --- a/Mage.Sets/src/mage/cards/m/MuseVessel.java +++ b/Mage.Sets/src/mage/cards/m/MuseVessel.java @@ -80,7 +80,7 @@ class MuseVesselExileEffect extends OneShotEffect { return false; } TargetCardInHand target = new TargetCardInHand(); - if (target.canChoose(source.getSourceId(), player.getId(), game) + if (target.canChoose(player.getId(), source, game) && target.chooseTarget(Outcome.Exile, player.getId(), source, game)) { UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); return player.moveCardsToExile(new CardsImpl(target.getTargets()).getCards(game), source, game, true, exileId, sourceObject.getIdName()); @@ -135,11 +135,11 @@ class TargetCardInMuseVesselExile extends TargetCardInExile { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); - Card sourceCard = game.getCard(sourceId); + Card sourceCard = game.getCard(source.getSourceId()); if (sourceCard != null) { - UUID exileId = CardUtil.getCardExileZoneId(game, sourceId); + UUID exileId = CardUtil.getCardExileZoneId(game, source.getSourceId()); ExileZone exile = game.getExile().getExileZone(exileId); if (exile != null && !exile.isEmpty()) { possibleTargets.addAll(exile); @@ -149,10 +149,10 @@ class TargetCardInMuseVesselExile extends TargetCardInExile { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - Card sourceCard = game.getCard(sourceId); + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + Card sourceCard = game.getCard(source.getSourceId()); if (sourceCard != null) { - UUID exileId = CardUtil.getCardExileZoneId(game, sourceId); + UUID exileId = CardUtil.getCardExileZoneId(game, source.getSourceId()); ExileZone exile = game.getExile().getExileZone(exileId); if (exile != null && !exile.isEmpty()) { return true; diff --git a/Mage.Sets/src/mage/cards/m/MuseVortex.java b/Mage.Sets/src/mage/cards/m/MuseVortex.java index 7545bab7454..dbfd7a95930 100644 --- a/Mage.Sets/src/mage/cards/m/MuseVortex.java +++ b/Mage.Sets/src/mage/cards/m/MuseVortex.java @@ -1,19 +1,22 @@ package mage.cards.m; -import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; +import mage.filter.StaticFilters; import mage.filter.common.FilterInstantOrSorceryCard; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.players.Player; -import mage.target.common.TargetCardInExile; +import mage.util.CardUtil; import java.util.UUID; @@ -60,36 +63,21 @@ class MuseVortexEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { + Player player = game.getPlayer(source.getControllerId()); + int xValue = source.getManaCostsToPay().getX(); + if (player == null || xValue < 1) { return false; } - int xValue = source.getManaCostsToPay().getX(); - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, xValue)); - controller.moveCards(cards, Zone.EXILED, source, game); + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, xValue)); + player.moveCards(cards, Zone.EXILED, source, game); cards.retainZone(Zone.EXILED, game); - FilterCard filter = new FilterInstantOrSorceryCard("an instant or sorcery card with mana value " + xValue + " or less"); + FilterCard filter = new FilterInstantOrSorceryCard(); filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, xValue + 1)); - TargetCardInExile target = new TargetCardInExile(filter); - target.setNotTarget(true); - if (controller.choose(Outcome.Benefit, cards, target, game)) { - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - cards.remove(card); - if (cardWasCast) { - cards.remove(card); - } else { - game.informPlayer(controller, "You're not able to cast " - + card.getIdName() + " or you canceled the casting."); - } - controller.putCardsOnTopOfLibrary(cards, game, source, true); - return true; - } - } - return false; + CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter); + cards.retainZone(Zone.EXILED, game); + player.moveCards(cards.getCards(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, game), Zone.HAND, source, game); + cards.retainZone(Zone.EXILED, game); + player.putCardsOnBottomOfLibrary(cards, game, source, false); + return true; } } diff --git a/Mage.Sets/src/mage/cards/m/Mutiny.java b/Mage.Sets/src/mage/cards/m/Mutiny.java index aef8182e293..f520af56795 100644 --- a/Mage.Sets/src/mage/cards/m/Mutiny.java +++ b/Mage.Sets/src/mage/cards/m/Mutiny.java @@ -119,12 +119,12 @@ class MutinyFirstTarget extends TargetCreaturePermanent { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - if (super.canChoose(sourceId, sourceControllerId, game)) { - UUID controllingPlayerId = game.getControllerId(sourceId); + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + if (super.canChoose(sourceControllerId, source, game)) { + UUID controllingPlayerId = game.getControllerId(source.getSourceId()); for (UUID playerId : game.getOpponents(controllingPlayerId)) { int possibleTargets = 0; - MageObject sourceObject = game.getObject(sourceId); + MageObject sourceObject = game.getObject(source); for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, playerId, game)) { if (permanent.canBeTargetedBy(sourceObject, controllingPlayerId, game)) { possibleTargets++; diff --git a/Mage.Sets/src/mage/cards/m/MuzzioVisionaryArchitect.java b/Mage.Sets/src/mage/cards/m/MuzzioVisionaryArchitect.java index 20944c90d91..9f89f265a20 100644 --- a/Mage.Sets/src/mage/cards/m/MuzzioVisionaryArchitect.java +++ b/Mage.Sets/src/mage/cards/m/MuzzioVisionaryArchitect.java @@ -90,7 +90,7 @@ class MuzzioVisionaryArchitectEffect extends OneShotEffect { controller.lookAtCards(source, null, cards, game); if (!cards.isEmpty()) { TargetCard target = new TargetCard(Zone.LIBRARY, new FilterArtifactCard("artifact card to put onto the battlefield")); - if (target.canChoose(source.getSourceId(), controller.getId(), game) && controller.choose(Outcome.Benefit, cards, target, game)) { + if (target.canChoose(controller.getId(), source, game) && controller.choose(Outcome.Benefit, cards, target, game)) { Card card = cards.get(target.getFirstTarget(), game); if (card != null) { controller.revealCards(source, new CardsImpl(card), game); diff --git a/Mage.Sets/src/mage/cards/m/MyojinOfBloomingDawn.java b/Mage.Sets/src/mage/cards/m/MyojinOfBloomingDawn.java index e4f6112e5b5..873c8850e0a 100644 --- a/Mage.Sets/src/mage/cards/m/MyojinOfBloomingDawn.java +++ b/Mage.Sets/src/mage/cards/m/MyojinOfBloomingDawn.java @@ -5,7 +5,6 @@ import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; import mage.abilities.costs.common.RemoveCountersSourceCost; -import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; @@ -20,6 +19,7 @@ import mage.constants.SuperType; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.permanent.token.SpiritToken; +import mage.watchers.common.CastFromHandWatcher; import java.util.UUID; @@ -40,10 +40,11 @@ public final class MyojinOfBloomingDawn extends CardImpl { this.toughness = new MageInt(6); // Myojin of Blooming Dawn enters the battlefield with an indestructible counter on it if you cast it from your hand. - this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect( + this.addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.INDESTRUCTIBLE.createInstance()), - CastFromHandSourcePermanentCondition.instance, "" - ), "{this} enters the battlefield with an indestructible counter on it if you cast it from your hand")); + CastFromHandSourcePermanentCondition.instance, null, + "with an indestructible counter on it if you cast it from your hand" + ), new CastFromHandWatcher()); // Remove an indestructible counter from Myojin of Blooming Dawn: Create a 1/1 colorless Spirit creature token for each permanent you control. this.addAbility(new SimpleActivatedAbility( diff --git a/Mage.Sets/src/mage/cards/m/MyojinOfCrypticDreams.java b/Mage.Sets/src/mage/cards/m/MyojinOfCrypticDreams.java new file mode 100644 index 00000000000..da089a8c8c3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MyojinOfCrypticDreams.java @@ -0,0 +1,79 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; +import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.effects.common.CopyTargetSpellEffect; +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.SuperType; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.FilterSpell; +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.game.stack.StackObject; +import mage.target.TargetSpell; +import mage.watchers.common.CastFromHandWatcher; + +import java.util.UUID; + +/** + * @author Alex-Vasile + */ +public class MyojinOfCrypticDreams extends CardImpl { + + private static final FilterSpell permanentSpellFilter = new FilterSpell("permanent spell you control"); + static { + permanentSpellFilter.add(TargetController.YOU.getControllerPredicate()); + permanentSpellFilter.add(MyojinOfCrypticDreamsPredicate.instance); + } + + public MyojinOfCrypticDreams(UUID ownderId, CardSetInfo setInfo) { + super(ownderId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Myojin of Cryptic Dreams enters the battlefield with an indestructible counter on it if you cast it from your hand. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.INDESTRUCTIBLE.createInstance()), + CastFromHandSourcePermanentCondition.instance, null, + "with an indestructible counter on it if you cast it from your hand" + ), new CastFromHandWatcher()); + + // Remove an indestructible counter from Myojin of Cryptic Dreams: + // Copy target permanent spell you control three times. (The copies become tokens.) + Ability ability = new SimpleActivatedAbility( + new CopyTargetSpellEffect(false, false, false) + .setText("Copy target permanent spell you control three times. (The copies become tokens.)"), + new RemoveCountersSourceCost(CounterType.INDESTRUCTIBLE.createInstance()) + ); + ability.addEffect(new CopyTargetSpellEffect(false, false, false).setText(" ")); + ability.addEffect(new CopyTargetSpellEffect(false, false, false).setText(" ")); + ability.addTarget(new TargetSpell(permanentSpellFilter)); + this.addAbility(ability); + } + + private MyojinOfCrypticDreams(final MyojinOfCrypticDreams card) { super(card); } + + @Override + public MyojinOfCrypticDreams copy() { return new MyojinOfCrypticDreams(this); } +} + +enum MyojinOfCrypticDreamsPredicate implements Predicate { + instance; + + @Override + public boolean apply(StackObject input, Game game) { + return input.isPermanent(game); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MyojinOfGrimBetrayal.java b/Mage.Sets/src/mage/cards/m/MyojinOfGrimBetrayal.java new file mode 100644 index 00000000000..21cc2a0feb6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MyojinOfGrimBetrayal.java @@ -0,0 +1,101 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; +import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.card.PutIntoGraveFromAnywhereThisTurnPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.watchers.common.CardsPutIntoGraveyardWatcher; +import mage.watchers.common.CastFromHandWatcher; + +import java.util.UUID; + +/** +* @author Alex-Vasile +*/ +public class MyojinOfGrimBetrayal extends CardImpl { + + private static final FilterCreatureCard filter = new FilterCreatureCard(); + static { filter.add(PutIntoGraveFromAnywhereThisTurnPredicate.instance); } + private static final DynamicValue xValue = new CardsInAllGraveyardsCount(filter); + private static final Hint hint = new ValueHint("Permanents put into the graveyard this turn", xValue); + + public MyojinOfGrimBetrayal(UUID ownderId, CardSetInfo setInfo) { + super(ownderId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(5); + this.toughness = new MageInt(2); + + // Myojin of Grim Betrayal enters the battlefield with an indestructible counter on it if you cast it from your hand. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.INDESTRUCTIBLE.createInstance()), + CastFromHandSourcePermanentCondition.instance, null, + "with an indestructible counter on it if you cast it from your hand" + ), new CastFromHandWatcher()); + + // Remove an indestructible counter from Myojin of Grim Betrayal: + // Put onto the battlefield under your control all creature cards in all graveyards that were put there from anywhere this turn. + Ability ability = new SimpleActivatedAbility( + new MyojinOfGrimBetrayalEffect(filter), + new RemoveCountersSourceCost(CounterType.INDESTRUCTIBLE.createInstance()) + ).addHint(hint); + ability.addWatcher(new CardsPutIntoGraveyardWatcher()); + this.addAbility(ability); + } + + private MyojinOfGrimBetrayal(final MyojinOfGrimBetrayal card) { super(card); } + + @Override + public MyojinOfGrimBetrayal copy() {return new MyojinOfGrimBetrayal(this); } +} + +class MyojinOfGrimBetrayalEffect extends OneShotEffect { + + private final FilterCreatureCard filter; + + MyojinOfGrimBetrayalEffect(FilterCreatureCard filter) { + super(Outcome.PutCardInPlay); + this.filter = filter; + this.staticText = "Put onto the battlefield under your control all creature cards in all graveyards " + + "that were put there from anywhere this turn"; + } + + private MyojinOfGrimBetrayalEffect(final MyojinOfGrimBetrayalEffect effect) { + super(effect); + this.filter = effect.filter; + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + CardsPutIntoGraveyardWatcher watcher = game.getState().getWatcher(CardsPutIntoGraveyardWatcher.class); + if (controller == null || watcher == null) { return false; } + + Cards cards = new CardsImpl(watcher.getCardsPutIntoGraveyardFromBattlefield(game)); + cards.removeIf(uuid -> !game.getCard(uuid).isCreature(game)); + + return controller.moveCards(cards, Zone.BATTLEFIELD, source, game); + } + + @Override + public MyojinOfGrimBetrayalEffect copy() { return new MyojinOfGrimBetrayalEffect(this); } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/MyojinOfLifesWeb.java b/Mage.Sets/src/mage/cards/m/MyojinOfLifesWeb.java index 849b1f68fea..a3288e75354 100644 --- a/Mage.Sets/src/mage/cards/m/MyojinOfLifesWeb.java +++ b/Mage.Sets/src/mage/cards/m/MyojinOfLifesWeb.java @@ -88,7 +88,7 @@ class MyojinOfLifesWebPutCreatureOnBattlefieldEffect extends OneShotEffect { } TargetCardInHand target = new TargetCardInHand(0, Integer.MAX_VALUE, new FilterCreatureCard("creature cards from your hand to put onto the battlefield")); - if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCreatureInPlay, target, source, game)) { return controller.moveCards(new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, source, game, false, false, false, null); } diff --git a/Mage.Sets/src/mage/cards/m/MyojinOfRoaringBlades.java b/Mage.Sets/src/mage/cards/m/MyojinOfRoaringBlades.java index 27e2fe9159c..4e44bae6b2d 100644 --- a/Mage.Sets/src/mage/cards/m/MyojinOfRoaringBlades.java +++ b/Mage.Sets/src/mage/cards/m/MyojinOfRoaringBlades.java @@ -6,7 +6,6 @@ import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; import mage.abilities.costs.common.RemoveCountersSourceCost; -import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; @@ -16,6 +15,7 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.counters.CounterType; import mage.target.common.TargetAnyTarget; +import mage.watchers.common.CastFromHandWatcher; import java.util.UUID; @@ -33,10 +33,11 @@ public final class MyojinOfRoaringBlades extends CardImpl { this.toughness = new MageInt(4); // Myojin of Roaring Blades enters the battlefield with an indestructible counter on it if you cast it from your hand. - this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect( + this.addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.INDESTRUCTIBLE.createInstance()), - CastFromHandSourcePermanentCondition.instance, "" - ), "{this} enters the battlefield with an indestructible counter on it if you cast it from your hand")); + CastFromHandSourcePermanentCondition.instance, null, + "with an indestructible counter on it if you cast it from your hand" + ), new CastFromHandWatcher()); // Remove an indestructible counter from Myojin of Roaring Blades: It deals 7 damage to each of up to three targets. Ability ability = new SimpleActivatedAbility( diff --git a/Mage.Sets/src/mage/cards/m/MyojinOfToweringMight.java b/Mage.Sets/src/mage/cards/m/MyojinOfToweringMight.java index 53ee55415a8..3b2234ad016 100644 --- a/Mage.Sets/src/mage/cards/m/MyojinOfToweringMight.java +++ b/Mage.Sets/src/mage/cards/m/MyojinOfToweringMight.java @@ -6,7 +6,6 @@ import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.common.CastFromHandSourcePermanentCondition; import mage.abilities.costs.common.RemoveCountersSourceCost; -import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.DistributeCountersEffect; @@ -20,6 +19,7 @@ import mage.constants.SuperType; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanentAmount; +import mage.watchers.common.CastFromHandWatcher; import java.util.UUID; @@ -37,10 +37,11 @@ public final class MyojinOfToweringMight extends CardImpl { this.toughness = new MageInt(8); // Myojin of Towering Might enters the battlefield with an indestructible counter on it if you cast it from your hand. - this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect( + this.addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.INDESTRUCTIBLE.createInstance()), - CastFromHandSourcePermanentCondition.instance, "" - ), "{this} enters the battlefield with an indestructible counter on it if you cast it from your hand")); + CastFromHandSourcePermanentCondition.instance, null, + "with an indestructible counter on it if you cast it from your hand" + ), new CastFromHandWatcher()); // Remove an indestructible counter from Myojin of Towering Might: Distribute eight +1/+1 counters among any number of target creatures you control. They gain trample until end of turn. Ability ability = new SimpleActivatedAbility(new DistributeCountersEffect( diff --git a/Mage.Sets/src/mage/cards/m/MyrBattlesphere.java b/Mage.Sets/src/mage/cards/m/MyrBattlesphere.java index d47e4bbdde6..852624be951 100644 --- a/Mage.Sets/src/mage/cards/m/MyrBattlesphere.java +++ b/Mage.Sets/src/mage/cards/m/MyrBattlesphere.java @@ -120,10 +120,10 @@ class MyrBattlesphereEffect extends OneShotEffect { TargetPermanent target = new TargetPermanent(0, 1, filter, true); while (controller.canRespond()) { target.clearChosen(); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (target.canChoose(source.getControllerId(), source, game)) { Map options = new HashMap<>(); options.put("UI.right.btn.text", "Myr tapping complete"); - controller.choose(outcome, target, source.getControllerId(), game, options); + controller.choose(outcome, target, source, game, options); if (!target.getTargets().isEmpty()) { UUID creature = target.getFirstTarget(); if (creature != null) { diff --git a/Mage.Sets/src/mage/cards/m/MyrReservoir.java b/Mage.Sets/src/mage/cards/m/MyrReservoir.java index 6f4acfc1036..b7f9be919e1 100644 --- a/Mage.Sets/src/mage/cards/m/MyrReservoir.java +++ b/Mage.Sets/src/mage/cards/m/MyrReservoir.java @@ -1,6 +1,5 @@ package mage.cards.m; -import java.util.UUID; import mage.ConditionalMana; import mage.MageObject; import mage.Mana; @@ -9,18 +8,19 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.abilities.effects.mana.BasicManaEffect; -import mage.abilities.mana.ActivatedManaAbilityImpl; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.mana.ConditionalColorlessManaAbility; +import mage.abilities.mana.builder.ConditionalManaBuilder; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** * @author nantuko */ @@ -36,10 +36,10 @@ public final class MyrReservoir extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // {T}: Add {C}{C}. Spend this mana only to cast Myr spells or activate abilities of Myr. - this.addAbility(new MyrReservoirManaAbility()); + this.addAbility(new ConditionalColorlessManaAbility(2, new MyrReservoirManaBuilder())); // {3}, {T}: Return target Myr card from your graveyard to your hand. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new GenericManaCost(3)); + Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new GenericManaCost(3)); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCardInYourGraveyard(myrCardFilter)); this.addAbility(ability); @@ -55,37 +55,34 @@ public final class MyrReservoir extends CardImpl { } } -class MyrReservoirManaAbility extends ActivatedManaAbilityImpl { +class MyrReservoirManaBuilder extends ConditionalManaBuilder { - MyrReservoirManaAbility() { - super(Zone.BATTLEFIELD, new BasicManaEffect(new MyrConditionalMana()), new TapSourceCost()); - this.netMana.add(Mana.ColorlessMana(2)); - } - - private MyrReservoirManaAbility(MyrReservoirManaAbility ability) { - super(ability); + @Override + public ConditionalMana build(Object... options) { + return new MyrReservoirConditionalMana(this.mana); } @Override - public MyrReservoirManaAbility copy() { - return new MyrReservoirManaAbility(this); + public String getRule() { + return "Spend this mana only to cast Myr spells or activate abilities of Myr"; } } -class MyrConditionalMana extends ConditionalMana { +class MyrReservoirConditionalMana extends ConditionalMana { - MyrConditionalMana() { - super(Mana.ColorlessMana(2)); + MyrReservoirConditionalMana(Mana mana) { + super(mana); staticText = "Spend this mana only to cast Myr spells or activate abilities of Myr"; - addCondition(new MyrManaCondition()); + addCondition(MyrReservoirManaCondition.instance); } } -class MyrManaCondition implements Condition { +enum MyrReservoirManaCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object != null && object.hasSubtype(SubType.MYR, game)) { return true; } diff --git a/Mage.Sets/src/mage/cards/m/MyrRetriever.java b/Mage.Sets/src/mage/cards/m/MyrRetriever.java index 1b7aaa119a6..4bf4eb0840d 100644 --- a/Mage.Sets/src/mage/cards/m/MyrRetriever.java +++ b/Mage.Sets/src/mage/cards/m/MyrRetriever.java @@ -12,7 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterArtifactCard; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.common.TargetCardInYourGraveyard; /** @@ -23,7 +23,7 @@ public final class MyrRetriever extends CardImpl { private static final FilterArtifactCard filter = new FilterArtifactCard("another target artifact card from your graveyard"); static { - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); } public MyrRetriever(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MysteriesOfTheDeep.java b/Mage.Sets/src/mage/cards/m/MysteriesOfTheDeep.java index 001ec588f66..359d48d035b 100644 --- a/Mage.Sets/src/mage/cards/m/MysteriesOfTheDeep.java +++ b/Mage.Sets/src/mage/cards/m/MysteriesOfTheDeep.java @@ -1,28 +1,32 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.condition.common.LandfallCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.watchers.common.LandfallWatcher; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class MysteriesOfTheDeep extends CardImpl { public MysteriesOfTheDeep(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{4}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{U}"); // Draw two cards. // Landfall - If you had a land enter the battlefield under your control this turn, draw three cards instead. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(3), new DrawCardSourceControllerEffect(2), + LandfallCondition.instance, "Draw two cards.
" + AbilityWord.LANDFALL.formatWord() + + "If you had a land enter the battlefield under your control this turn, draw three cards instead" + )); this.getSpellAbility().addWatcher(new LandfallWatcher()); - this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new DrawCardSourceControllerEffect(3), new DrawCardSourceControllerEffect(2), LandfallCondition.instance, "Draw 2 cards. Landfall - If you had a land enter the battlefield under your control this turn, draw three cards instead")); } private MysteriesOfTheDeep(final MysteriesOfTheDeep card) { diff --git a/Mage.Sets/src/mage/cards/m/MysteriousLimousine.java b/Mage.Sets/src/mage/cards/m/MysteriousLimousine.java new file mode 100644 index 00000000000..e266bf2d234 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MysteriousLimousine.java @@ -0,0 +1,108 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.common.delayed.OnLeaveReturnExiledToBattlefieldAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.keyword.CrewAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.ExileZone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MysteriousLimousine extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("other creature"); + + static { + filter.add(AnotherPredicate.instance); + } + + public MysteriousLimousine(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}{W}{W}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever Mysterious Limousine enters the battlefield or attacks, exile up to one other target creature until Mysterious Limousine leaves the battlefield. If a creature is put into exile this way, return each other card exiled with Mysterious Limousine to the battlefield under its owner's control. + Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new MysteriousLimousineEffect()); + ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility())); + ability.addTarget(new TargetPermanent(0, 1, filter)); + this.addAbility(ability); + + // Crew 2 + this.addAbility(new CrewAbility(2)); + } + + private MysteriousLimousine(final MysteriousLimousine card) { + super(card); + } + + @Override + public MysteriousLimousine copy() { + return new MysteriousLimousine(this); + } +} + +class MysteriousLimousineEffect extends OneShotEffect { + + MysteriousLimousineEffect() { + super(Outcome.Benefit); + staticText = "exile up to one other target creature until {this} leaves the battlefield. " + + "If a creature is put into exile this way, return each other card exiled " + + "with {this} to the battlefield under its owner's control"; + } + + private MysteriousLimousineEffect(final MysteriousLimousineEffect effect) { + super(effect); + } + + @Override + public MysteriousLimousineEffect copy() { + return new MysteriousLimousineEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (player == null || permanent == null) { + return false; + } + UUID exileId = CardUtil.getExileZoneId(game, source); + Cards cards = new CardsImpl(); + ExileZone exileZone = game.getExile().getExileZone(exileId); + if (exileZone != null) { + cards.addAll(exileZone); + } + player.moveCardsToExile(permanent, source, game, true, exileId, CardUtil.getSourceName(game, source)); + if (!cards.isEmpty()) { + player.moveCards( + cards.getCards(game), Zone.BATTLEFIELD, source, game, + false, false, true, null + ); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MysticConfluence.java b/Mage.Sets/src/mage/cards/m/MysticConfluence.java index c8193421bc2..41d4d5379ce 100644 --- a/Mage.Sets/src/mage/cards/m/MysticConfluence.java +++ b/Mage.Sets/src/mage/cards/m/MysticConfluence.java @@ -32,14 +32,12 @@ public final class MysticConfluence extends CardImpl { this.getSpellAbility().addTarget(new TargetSpell()); // Return target creature to its owner's hand; - Mode mode = new Mode(); - mode.addEffect(new ReturnToHandTargetEffect()); + Mode mode = new Mode(new ReturnToHandTargetEffect()); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().getModes().addMode(mode); // Draw a card. - mode = new Mode(); - mode.addEffect(new DrawCardSourceControllerEffect(1)); + mode = new Mode(new DrawCardSourceControllerEffect(1)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/m/MysticOfTheHiddenWay.java b/Mage.Sets/src/mage/cards/m/MysticOfTheHiddenWay.java index 4992aa374d2..02054232f23 100644 --- a/Mage.Sets/src/mage/cards/m/MysticOfTheHiddenWay.java +++ b/Mage.Sets/src/mage/cards/m/MysticOfTheHiddenWay.java @@ -28,7 +28,7 @@ public final class MysticOfTheHiddenWay extends CardImpl { // Mystic of the Hidden Way can't be blocked. this.addAbility(new CantBeBlockedSourceAbility()); // Morph {2}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{U}"))); } private MysticOfTheHiddenWay(final MysticOfTheHiddenWay card) { diff --git a/Mage.Sets/src/mage/cards/m/MysticRetrieval.java b/Mage.Sets/src/mage/cards/m/MysticRetrieval.java index 36fd978faf8..36afa6a69d1 100644 --- a/Mage.Sets/src/mage/cards/m/MysticRetrieval.java +++ b/Mage.Sets/src/mage/cards/m/MysticRetrieval.java @@ -1,40 +1,30 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.FlashbackAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.TimingRule; -import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Loki */ public final class MysticRetrieval extends CardImpl { - private static final FilterCard filter = new FilterCard("instant or sorcery card from your graveyard"); - - static { - filter.add(Predicates.or( - CardType.INSTANT.getPredicate(), - CardType.SORCERY.getPredicate())); - } public MysticRetrieval(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}"); // Return target instant or sorcery card from your graveyard to your hand. - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); + // Flashback {2}{R} - this.addAbility(new FlashbackAbility(this, new ManaCostsImpl("{2}{R}"))); + this.addAbility(new FlashbackAbility(this, new ManaCostsImpl<>("{2}{R}"))); } private MysticRetrieval(final MysticRetrieval card) { diff --git a/Mage.Sets/src/mage/cards/m/MythosOfSnapdax.java b/Mage.Sets/src/mage/cards/m/MythosOfSnapdax.java index c45bcb4a917..faef852fea0 100644 --- a/Mage.Sets/src/mage/cards/m/MythosOfSnapdax.java +++ b/Mage.Sets/src/mage/cards/m/MythosOfSnapdax.java @@ -98,15 +98,15 @@ class MythosOfSnapdaxEffect extends OneShotEffect { FilterPermanent filter = new FilterNonlandPermanent(message); filter.add(cardType.getPredicate()); filter.add(new ControllerIdPredicate(player.getId())); - if (game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) == 0) { + if (game.getBattlefield().count(filter, source.getControllerId(), source, game) == 0) { continue; } TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); if (conditionMet) { - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); } else { - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); } toKeep.add(target.getFirstTarget()); } diff --git a/Mage.Sets/src/mage/cards/n/NagaOracle.java b/Mage.Sets/src/mage/cards/n/NagaOracle.java index e8d771134e5..1f57bd3d922 100644 --- a/Mage.Sets/src/mage/cards/n/NagaOracle.java +++ b/Mage.Sets/src/mage/cards/n/NagaOracle.java @@ -1,18 +1,14 @@ - package mage.cards.n; import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.FilterCard; /** * @@ -30,21 +26,8 @@ public final class NagaOracle extends CardImpl { // When Naga Oracle enters the battlefield, look at the top three cards of your library. Put any number of them into your graveyard // and the rest back on top of your library in any order. - Effect effect = new LookLibraryAndPickControllerEffect( - /* oh god, Microsoft looks conservative with their function parameters in comparison */ - StaticValue.get(3), - false, - StaticValue.get(3), - new FilterCard("cards"), - Zone.LIBRARY, - true, - false, - true, - Zone.GRAVEYARD, - false); - effect.setText("look at the top three cards of your library. Put any number of them into your graveyard " - + "and the rest back on top of your library in any order"); - addAbility(new EntersBattlefieldTriggeredAbility(effect)); + addAbility(new EntersBattlefieldTriggeredAbility( + new LookLibraryAndPickControllerEffect(3, Integer.MAX_VALUE, PutCards.GRAVEYARD, PutCards.TOP_ANY))); } private NagaOracle(final NagaOracle card) { diff --git a/Mage.Sets/src/mage/cards/n/NaggingThoughts.java b/Mage.Sets/src/mage/cards/n/NaggingThoughts.java index 554573a6e47..c7d95dac3a8 100644 --- a/Mage.Sets/src/mage/cards/n/NaggingThoughts.java +++ b/Mage.Sets/src/mage/cards/n/NaggingThoughts.java @@ -1,16 +1,13 @@ - package mage.cards.n; import java.util.UUID; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.MadnessAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.FilterCard; /** * @@ -22,10 +19,10 @@ public final class NaggingThoughts extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{U}"); // Look at the top two cards of your library. Put one of them into your hand and the other into your graveyard. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(2), false, StaticValue.get(1), new FilterCard(), Zone.GRAVEYARD, false, false)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(2, 1, PutCards.HAND, PutCards.GRAVEYARD)); // Madness {1}{U} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{U}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{1}{U}"))); } private NaggingThoughts(final NaggingThoughts card) { diff --git a/Mage.Sets/src/mage/cards/n/NahiriHeirOfTheAncients.java b/Mage.Sets/src/mage/cards/n/NahiriHeirOfTheAncients.java index 4a8981a596f..969bc16a968 100644 --- a/Mage.Sets/src/mage/cards/n/NahiriHeirOfTheAncients.java +++ b/Mage.Sets/src/mage/cards/n/NahiriHeirOfTheAncients.java @@ -3,13 +3,12 @@ package mage.cards.n; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -36,7 +35,7 @@ import java.util.stream.Collectors; */ public final class NahiriHeirOfTheAncients extends CardImpl { - private static final FilterCard filter = new FilterCard("Warrior or Equipment card"); + private static final FilterCard filter = new FilterCard("a Warrior or Equipment card"); static { filter.add(Predicates.or( @@ -53,20 +52,15 @@ public final class NahiriHeirOfTheAncients extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NAHIRI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Create a 1/1 white Kor Warrior creature token. You may attach an Equipment you control to it. this.addAbility(new LoyaltyAbility(new NahiriHeirOfTheAncientsEffect(), 1)); - // −2: Look at the top six cards of your library. You may reveal a Warrior or Equipment card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. - this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(6), false, StaticValue.get(1), filter, - Zone.LIBRARY, false, true, false, Zone.HAND, - true, false, false - ).setBackInRandomOrder(true).setText("Look at the top six cards of your library. " + - "You may reveal a Warrior or Equipment card from among them and put it into your hand. " + - "Put the rest on the bottom of your library in a random order." - ), -2)); + // −2: Look at the top six cards of your library. + // You may reveal a Warrior or Equipment card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. + this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect(6, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM), -2)); // −3: Nahiri, Heir of the Ancients deals damage to target creature or planeswalker equal to twice the number of Equipment you control. Ability ability = new LoyaltyAbility(new DamageTargetEffect(xValue) @@ -117,7 +111,7 @@ class NahiriHeirOfTheAncientsEffect extends OneShotEffect { .map(game::getPermanent) .filter(Objects::nonNull) .collect(Collectors.toList()); - int equipCount = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int equipCount = game.getBattlefield().count(filter, source.getControllerId(), source, game); if (tokens.isEmpty() || equipCount == 0 || !player.chooseUse(outcome, "Attach an equipment to the token?", source, game)) { @@ -134,12 +128,12 @@ class NahiriHeirOfTheAncientsEffect extends OneShotEffect { )); TargetPermanent target = new TargetPermanent(tokenFilter); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); tokenCreature = game.getPermanent(target.getFirstTarget()); } TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); tokenCreature.addAttachment(target.getFirstTarget(), source, game); return true; } diff --git a/Mage.Sets/src/mage/cards/n/NahiriStormOfStone.java b/Mage.Sets/src/mage/cards/n/NahiriStormOfStone.java index ace6fe386a6..0270fe1df37 100644 --- a/Mage.Sets/src/mage/cards/n/NahiriStormOfStone.java +++ b/Mage.Sets/src/mage/cards/n/NahiriStormOfStone.java @@ -2,7 +2,6 @@ package mage.cards.n; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.decorator.ConditionalContinuousEffect; @@ -44,7 +43,7 @@ public final class NahiriStormOfStone extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NAHIRI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(6)); + this.setStartingLoyalty(6); // As long as it's your turn, creatures you control have first strike and equip abilities you activate cost {1} less to activate. Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( diff --git a/Mage.Sets/src/mage/cards/n/NahiriTheHarbinger.java b/Mage.Sets/src/mage/cards/n/NahiriTheHarbinger.java index 934edb37f7a..3d718744644 100644 --- a/Mage.Sets/src/mage/cards/n/NahiriTheHarbinger.java +++ b/Mage.Sets/src/mage/cards/n/NahiriTheHarbinger.java @@ -4,7 +4,6 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.effects.ContinuousEffect; @@ -57,7 +56,7 @@ public final class NahiriTheHarbinger extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NAHIRI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +2: You may discard a card. If you do, draw a card. this.addAbility(new LoyaltyAbility(new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new DiscardCardCost()), 2)); diff --git a/Mage.Sets/src/mage/cards/n/NahiriTheLithomancer.java b/Mage.Sets/src/mage/cards/n/NahiriTheLithomancer.java index 0ae039061f5..344805c873e 100644 --- a/Mage.Sets/src/mage/cards/n/NahiriTheLithomancer.java +++ b/Mage.Sets/src/mage/cards/n/NahiriTheLithomancer.java @@ -5,7 +5,6 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; @@ -41,7 +40,7 @@ public final class NahiriTheLithomancer extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NAHIRI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +2: Create a 1/1 white Kor Soldier creature token. You may attach an Equipment you control to it. this.addAbility(new LoyaltyAbility(new NahiriTheLithomancerFirstAbilityEffect(), 2)); @@ -101,9 +100,9 @@ class NahiriTheLithomancerFirstAbilityEffect extends OneShotEffect { if (tokenPermanent != null) { //TODO: Make sure the Equipment can legally enchant the token, preferably on targetting. Target target = new TargetControlledPermanent(0, 1, filter, true); - if (target.canChoose(source.getSourceId(), controller.getId(), game) + if (target.canChoose(controller.getId(), source, game) && controller.chooseUse(outcome, "Attach an Equipment you control to the created " + tokenPermanent.getIdName() + '?', source, game)) { - if (target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), game)) { + if (target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), source, game)) { Permanent equipmentPermanent = game.getPermanent(target.getFirstTarget()); if (equipmentPermanent != null) { Permanent attachedTo = game.getPermanent(equipmentPermanent.getAttachedTo()); @@ -152,14 +151,14 @@ class NahiriTheLithomancerSecondAbilityEffect extends OneShotEffect { if (controller != null) { if (controller.chooseUse(Outcome.PutCardInPlay, "Put an Equipment from hand? (No = from graveyard)", source, game)) { Target target = new TargetCardInHand(0, 1, filter); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); Card card = controller.getHand().get(target.getFirstTarget(), game); if (card != null) { controller.moveCards(card, Zone.BATTLEFIELD, source, game); } } else { Target target = new TargetCardInYourGraveyard(0, 1, filter); - target.choose(Outcome.PutCardInPlay, source.getControllerId(), source.getSourceId(), game); + target.choose(Outcome.PutCardInPlay, source.getControllerId(), source.getSourceId(), source, game); Card card = controller.getGraveyard().get(target.getFirstTarget(), game); if (card != null) { controller.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/n/NahirisLithoforming.java b/Mage.Sets/src/mage/cards/n/NahirisLithoforming.java index ce13960799a..f20d10a4255 100644 --- a/Mage.Sets/src/mage/cards/n/NahirisLithoforming.java +++ b/Mage.Sets/src/mage/cards/n/NahirisLithoforming.java @@ -67,13 +67,13 @@ class NahirisLithoformingSacrificeEffect extends OneShotEffect { } int landCount = game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_LAND_SHORT_TEXT, - source.getSourceId(), source.getControllerId(), game + source.getControllerId(), source, game ); landCount = Math.min(source.getManaCostsToPay().getX(), landCount); TargetPermanent target = new TargetPermanent( landCount, landCount, StaticFilters.FILTER_CONTROLLED_LAND_SHORT_TEXT, true ); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); int counter = 0; for (UUID permanentId : target.getTargets()) { Permanent permanent = game.getPermanent(permanentId); diff --git a/Mage.Sets/src/mage/cards/n/NamelessOne.java b/Mage.Sets/src/mage/cards/n/NamelessOne.java index a742d3ab21b..bcb025383a0 100644 --- a/Mage.Sets/src/mage/cards/n/NamelessOne.java +++ b/Mage.Sets/src/mage/cards/n/NamelessOne.java @@ -38,7 +38,7 @@ public final class NamelessOne extends CardImpl { // Nameless One's power and toughness are each equal to the number of Wizards on the battlefield. this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new PermanentsOnBattlefieldCount(filter), Duration.EndOfGame))); // Morph {2}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{U}"))); } private NamelessOne(final NamelessOne card) { diff --git a/Mage.Sets/src/mage/cards/n/NantukoVigilante.java b/Mage.Sets/src/mage/cards/n/NantukoVigilante.java index 1d01f9be348..9a0eced886b 100644 --- a/Mage.Sets/src/mage/cards/n/NantukoVigilante.java +++ b/Mage.Sets/src/mage/cards/n/NantukoVigilante.java @@ -32,7 +32,7 @@ public final class NantukoVigilante extends CardImpl { this.toughness = new MageInt(2); // Morph {1}{G} - this.addAbility(new MorphAbility(this,new ManaCostsImpl("{1}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{G}"))); // When Nantuko Vigilante is turned face up, destroy target artifact or enchantment. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new DestroyTargetEffect()); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); diff --git a/Mage.Sets/src/mage/cards/n/NarnamRenegade.java b/Mage.Sets/src/mage/cards/n/NarnamRenegade.java index a105199e1a5..1a7f53b57af 100644 --- a/Mage.Sets/src/mage/cards/n/NarnamRenegade.java +++ b/Mage.Sets/src/mage/cards/n/NarnamRenegade.java @@ -1,7 +1,5 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.common.RevoltCondition; @@ -14,8 +12,9 @@ import mage.constants.SubType; import mage.counters.CounterType; import mage.watchers.common.RevoltWatcher; +import java.util.UUID; + /** - * * @author fireshoes */ public final class NarnamRenegade extends CardImpl { @@ -32,13 +31,11 @@ public final class NarnamRenegade extends CardImpl { this.addAbility(DeathtouchAbility.getInstance()); // Revolt — Narnam Renegade enters the battlefield with a +1/+1 counter on it if a permanent you controlled left this battlefield this turn. - this.addAbility( - new EntersBattlefieldAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()), - false, RevoltCondition.instance, - "Revolt — {this} enters the battlefield with a +1/+1 counter on it if a permanent you controlled left the battlefield this turn", null), - new RevoltWatcher() - ); + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, + RevoltCondition.instance, "Revolt — {this} enters the battlefield with " + + "a +1/+1 counter on it if a permanent you controlled left the battlefield this turn.", null + ), new RevoltWatcher()); } private NarnamRenegade(final NarnamRenegade card) { diff --git a/Mage.Sets/src/mage/cards/n/NarsetEnlightenedMaster.java b/Mage.Sets/src/mage/cards/n/NarsetEnlightenedMaster.java index b13e8422610..232cf793349 100644 --- a/Mage.Sets/src/mage/cards/n/NarsetEnlightenedMaster.java +++ b/Mage.Sets/src/mage/cards/n/NarsetEnlightenedMaster.java @@ -67,7 +67,7 @@ class NarsetEnlightenedMasterExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (player != null && sourceObject != null) { Set cards = player.getLibrary().getTopCards(game, 4); player.moveCards(cards, Zone.EXILED, source, game); diff --git a/Mage.Sets/src/mage/cards/n/NarsetOfTheAncientWay.java b/Mage.Sets/src/mage/cards/n/NarsetOfTheAncientWay.java index b69562ce7ec..857d423dd33 100644 --- a/Mage.Sets/src/mage/cards/n/NarsetOfTheAncientWay.java +++ b/Mage.Sets/src/mage/cards/n/NarsetOfTheAncientWay.java @@ -5,7 +5,6 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.SpellAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.Cost; @@ -38,7 +37,7 @@ public final class NarsetOfTheAncientWay extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NARSET); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: You gain 2 life. Add {U}, {R}, or {W}. Spend this mana only to cast a noncreature spell. this.addAbility(new LoyaltyAbility(new NarsetOfTheAncientWayManaEffect(), 1)); @@ -101,7 +100,7 @@ class NarsetOfTheAncientWayManaCondition extends ManaCondition implements Condit if (!(source instanceof SpellAbility)) { return false; } - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && !object.isCreature(game); } diff --git a/Mage.Sets/src/mage/cards/n/NarsetParterOfVeils.java b/Mage.Sets/src/mage/cards/n/NarsetParterOfVeils.java index 20996fe8a01..19fde5784e0 100644 --- a/Mage.Sets/src/mage/cards/n/NarsetParterOfVeils.java +++ b/Mage.Sets/src/mage/cards/n/NarsetParterOfVeils.java @@ -2,11 +2,10 @@ package mage.cards.n; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -24,7 +23,7 @@ import java.util.UUID; */ public final class NarsetParterOfVeils extends CardImpl { - private static final FilterCard filter = new FilterCard("noncreature, nonland card"); + private static final FilterCard filter = new FilterCard("a noncreature, nonland card"); static { filter.add(Predicates.not(CardType.CREATURE.getPredicate())); @@ -36,20 +35,15 @@ public final class NarsetParterOfVeils extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NARSET); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Each opponent can't draw more than one card each turn. this.addAbility(new SimpleStaticAbility(new NarsetParterOfVeilsEffect()), new CardsAmountDrawnThisTurnWatcher()); - // -2: Look at the top four cards of your library. You may reveal a noncreature, nonland card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. - this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(1), filter, - Zone.LIBRARY, false, true, false, Zone.HAND, - true, false, false - ).setBackInRandomOrder(true).setText("Look at the top four cards of your library. " + - "You may reveal a noncreature, nonland card from among them and put it into your hand. " + - "Put the rest on the bottom of your library in a random order." - ), -2)); + // -2: Look at the top four cards of your library. + // You may reveal a noncreature, nonland card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. + this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect(4, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM), -2)); } private NarsetParterOfVeils(final NarsetParterOfVeils card) { diff --git a/Mage.Sets/src/mage/cards/n/NarsetTranscendent.java b/Mage.Sets/src/mage/cards/n/NarsetTranscendent.java index 17813fe54b1..a47d27c528c 100644 --- a/Mage.Sets/src/mage/cards/n/NarsetTranscendent.java +++ b/Mage.Sets/src/mage/cards/n/NarsetTranscendent.java @@ -5,7 +5,6 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -42,7 +41,7 @@ public final class NarsetTranscendent extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NARSET); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(6)); + this.setStartingLoyalty(6); // +1: Look at the top card of your library. If it's a noncreature, nonland card, you may reveal it and put it into your hand. this.addAbility(new LoyaltyAbility(new NarsetTranscendentEffect1(), 1)); diff --git a/Mage.Sets/src/mage/cards/n/NashiMoonSagesScion.java b/Mage.Sets/src/mage/cards/n/NashiMoonSagesScion.java new file mode 100644 index 00000000000..076116e003d --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NashiMoonSagesScion.java @@ -0,0 +1,200 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.Costs; +import mage.abilities.costs.CostsImpl; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.asthought.CanPlayCardControllerEffect; +import mage.abilities.keyword.NinjutsuAbility; +import mage.cards.*; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class NashiMoonSagesScion extends CardImpl { + + public NashiMoonSagesScion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.RAT); + this.subtype.add(SubType.NINJA); + + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Ninjutsu {3}{B} + this.addAbility(new NinjutsuAbility("{3}{B}")); + + // Whenever Nashi, Moon Sage's Scion deals combat damage to a player, exile the top card of each player's library. Until end of turn, you may play one of those cards. If you cast a spell this way, pay life equal to its mana value rather than paying its mana cost. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new NashiMoonSagesScionEffect(), false + ), new NashiMoonSagesScionWatcher()); + } + + private NashiMoonSagesScion(final NashiMoonSagesScion card) { + super(card); + } + + @Override + public NashiMoonSagesScion copy() { + return new NashiMoonSagesScion(this); + } +} + +class NashiMoonSagesScionEffect extends OneShotEffect { + + public NashiMoonSagesScionEffect() { + super(Outcome.Benefit); + this.staticText = "exile the top card of each player's library. Until end of turn, " + + "you may play one of those cards. If you cast a spell this way, " + + "pay life equal to its mana value rather than paying its mana cost"; + } + + public NashiMoonSagesScionEffect(final NashiMoonSagesScionEffect effect) { + super(effect); + } + + @Override + public NashiMoonSagesScionEffect copy() { + return new NashiMoonSagesScionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Cards cards = new CardsImpl(); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + cards.add(player.getLibrary().getFromTop(game)); + } + } + Set cardSet = cards.getCards(game); + controller.moveCardsToExile( + cardSet, source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + NashiMoonSagesScionWatcher.addCards(source, cardSet, game); + for (Card card : cardSet) { + game.addEffect(new NashiMoonSagesScionPlayEffect(game, card), source); + } + return true; + } +} + +class NashiMoonSagesScionWatcher extends Watcher { + + private final Map>> morMap = new HashMap<>(); + + public NashiMoonSagesScionWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.CLEANUP_STEP_POST) { + morMap.entrySet().removeIf(e -> !e.getKey().zoneCounterIsCurrent(game)); + morMap.values() + .stream() + .flatMap(Collection::stream) + .map(set -> set.removeIf(mor -> !mor.zoneCounterIsCurrent(game))); + morMap.values().removeIf(Set::isEmpty); + return; + } + if (event.getType() != GameEvent.EventType.SPELL_CAST || event.getAdditionalReference() == null) { + return; + } + Spell spell = game.getSpell(event.getTargetId()); + if (spell == null) { + return; + } + morMap.getOrDefault( + event.getAdditionalReference().getApprovingMageObjectReference(), Collections.emptySet() + ).removeIf(set -> set + .stream() + .anyMatch(mor -> mor.getSourceId().equals(spell.getMainCard().getId()) + && mor.getZoneChangeCounter() + 1 == spell.getZoneChangeCounter(game))); + } + + @Override + public void reset() { + super.reset(); + morMap.clear(); + } + + static void addCards(Ability source, Set cards, Game game) { + game.getState() + .getWatcher(NashiMoonSagesScionWatcher.class) + .morMap + .computeIfAbsent(new MageObjectReference(source), x -> new HashSet<>()) + .add(cards + .stream() + .map(card -> new MageObjectReference(card, game)) + .collect(Collectors.toSet())); + } + + static boolean checkCard(Game game, Ability source, MageObjectReference mor) { + return game.getState() + .getWatcher(NashiMoonSagesScionWatcher.class) + .morMap + .getOrDefault(new MageObjectReference(source), Collections.emptySet()) + .stream() + .flatMap(Collection::stream) + .anyMatch(mor::equals); + } +} + +class NashiMoonSagesScionPlayEffect extends CanPlayCardControllerEffect { + + NashiMoonSagesScionPlayEffect(Game game, Card card) { + super(game, card.getMainCard().getId(), card.getZoneChangeCounter(game), Duration.EndOfTurn); + } + + private NashiMoonSagesScionPlayEffect(final NashiMoonSagesScionPlayEffect effect) { + super(effect); + } + + @Override + public NashiMoonSagesScionPlayEffect copy() { + return new NashiMoonSagesScionPlayEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + if (!super.applies(objectId, source, affectedControllerId, game) + || !NashiMoonSagesScionWatcher.checkCard(game, source, mor)) { + return false; + } + Card cardToCheck = mor.getCard(game); + if (cardToCheck.isLand(game)) { + return true; + } + // allows to play/cast with alternative life cost + Player controller = game.getPlayer(source.getControllerId()); + PayLifeCost lifeCost = new PayLifeCost(cardToCheck.getSpellAbility().getManaCosts().manaValue()); + Costs newCosts = new CostsImpl<>(); + newCosts.add(lifeCost); + newCosts.addAll(cardToCheck.getSpellAbility().getCosts()); + controller.setCastSourceIdWithAlternateMana(cardToCheck.getId(), null, newCosts); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/n/NaturalBalance.java b/Mage.Sets/src/mage/cards/n/NaturalBalance.java index 93617912995..e7c4c274812 100644 --- a/Mage.Sets/src/mage/cards/n/NaturalBalance.java +++ b/Mage.Sets/src/mage/cards/n/NaturalBalance.java @@ -71,7 +71,7 @@ public final class NaturalBalance extends CardImpl { if (landCount > 5) { // chooses five lands they control and sacrifices the rest TargetControlledPermanent target = new TargetControlledPermanent(5, 5, new FilterControlledLandPermanent("lands to keep"), true); - if (target.choose(Outcome.Sacrifice, player.getId(), source.getSourceId(), game)) { + if (target.choose(Outcome.Sacrifice, player.getId(), source.getSourceId(), source, game)) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterLandPermanent(), player.getId(), game)) { if (!target.getTargets().contains(permanent.getId())) { permanent.sacrifice(source, game); diff --git a/Mage.Sets/src/mage/cards/n/NaturesKiss.java b/Mage.Sets/src/mage/cards/n/NaturesKiss.java index 4ba50dcd6e5..7c235419058 100644 --- a/Mage.Sets/src/mage/cards/n/NaturesKiss.java +++ b/Mage.Sets/src/mage/cards/n/NaturesKiss.java @@ -1,32 +1,30 @@ - package mage.cards.n; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.ExileTopCardOfGraveyardCost; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.keyword.EnchantAbility; 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.constants.SubType; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class NaturesKiss extends CardImpl { public NaturesKiss(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -34,10 +32,12 @@ public final class NaturesKiss extends CardImpl { this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); - + // {1}, Exile the top card of your graveyard: Enchanted creature gets +1/+1 until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 1, Duration.EndOfTurn), new ManaCostsImpl("{1}")); - ability.addCost(new ExileTopCardOfGraveyardCost(1)); + Ability ability = new SimpleActivatedAbility(new BoostEnchantedEffect( + 1, 1, Duration.EndOfTurn + ), new GenericManaCost(1)); + ability.addCost(new ExileTopCardOfGraveyardCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NaturesSpiral.java b/Mage.Sets/src/mage/cards/n/NaturesSpiral.java index 722c5d5b36c..226172a9100 100644 --- a/Mage.Sets/src/mage/cards/n/NaturesSpiral.java +++ b/Mage.Sets/src/mage/cards/n/NaturesSpiral.java @@ -1,26 +1,27 @@ - - package mage.cards.n; -import java.util.UUID; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.filter.FilterCard; import mage.filter.common.FilterPermanentCard; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public final class NaturesSpiral extends CardImpl { - public NaturesSpiral(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{G}"); + private static final FilterCard filter = new FilterPermanentCard("permanent card from your graveyard"); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterPermanentCard("permanent card from your graveyard"))); - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + public NaturesSpiral(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); + + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); } private NaturesSpiral(final NaturesSpiral card) { diff --git a/Mage.Sets/src/mage/cards/n/NaturesWill.java b/Mage.Sets/src/mage/cards/n/NaturesWill.java index c3adad17554..5014d39fc58 100644 --- a/Mage.Sets/src/mage/cards/n/NaturesWill.java +++ b/Mage.Sets/src/mage/cards/n/NaturesWill.java @@ -3,7 +3,7 @@ package mage.cards.n; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.ControlledCreaturesDealCombatDamagePlayerTriggeredAbility; +import mage.abilities.common.DealCombatDamageControlledTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.TapAllTargetPlayerControlsEffect; import mage.abilities.effects.common.UntapAllEffect; @@ -26,7 +26,7 @@ public final class NaturesWill extends CardImpl { // Whenever one or more creatures you control deal combat damage to a player, tap all lands that player controls and untap all lands you control. Effect tapAllEffect = new TapAllTargetPlayerControlsEffect(new FilterLandPermanent()); tapAllEffect.setText("tap all lands that player controls"); - Ability ability = new ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Zone.BATTLEFIELD, tapAllEffect, true); + Ability ability = new DealCombatDamageControlledTriggeredAbility(Zone.BATTLEFIELD, tapAllEffect, true); ability.addEffect(new UntapAllEffect(new FilterControlledLandPermanent())); addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NavigatorsRuin.java b/Mage.Sets/src/mage/cards/n/NavigatorsRuin.java index 225e1238808..63ae105dcf7 100644 --- a/Mage.Sets/src/mage/cards/n/NavigatorsRuin.java +++ b/Mage.Sets/src/mage/cards/n/NavigatorsRuin.java @@ -28,7 +28,7 @@ public final class NavigatorsRuin extends CardImpl { Ability ability = new ConditionalInterveningIfTriggeredAbility(new BeginningOfEndStepTriggeredAbility( new PutLibraryIntoGraveTargetEffect(4), TargetController.YOU, false), RaidCondition.instance, - "Raid — At the beginning of your end step, " + + "At the beginning of your end step, " + "if you attacked this turn, target opponent mills four cards." ); ability.addTarget(new TargetOpponent()); diff --git a/Mage.Sets/src/mage/cards/n/NayaCharm.java b/Mage.Sets/src/mage/cards/n/NayaCharm.java index 1db7628a2f1..70731cd31c9 100644 --- a/Mage.Sets/src/mage/cards/n/NayaCharm.java +++ b/Mage.Sets/src/mage/cards/n/NayaCharm.java @@ -27,13 +27,11 @@ public final class NayaCharm extends CardImpl { this.getSpellAbility().addEffect(new DamageTargetEffect(3)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // or return target card from a graveyard to its owner's hand; - Mode mode = new Mode(); - mode.addEffect(new ReturnToHandTargetEffect()); + Mode mode = new Mode(new ReturnToHandTargetEffect()); mode.addTarget(new TargetCardInGraveyard()); this.getSpellAbility().addMode(mode); // or tap all creatures target player controls. - mode = new Mode(); - mode.addEffect(new TapAllTargetPlayerControlsEffect(FILTER_PERMANENT_CREATURES)); + mode = new Mode(new TapAllTargetPlayerControlsEffect(FILTER_PERMANENT_CREATURES)); mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/n/NayaSojourners.java b/Mage.Sets/src/mage/cards/n/NayaSojourners.java index 78236fa56c9..3cd8c9b8e3b 100644 --- a/Mage.Sets/src/mage/cards/n/NayaSojourners.java +++ b/Mage.Sets/src/mage/cards/n/NayaSojourners.java @@ -1,7 +1,5 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.CycleTriggeredAbility; @@ -9,40 +7,42 @@ import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.CyclingAbility; +import mage.abilities.meta.OrTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.Zone; import mage.counters.CounterType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class NayaSojourners extends CardImpl { public NayaSojourners(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}{G}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}{W}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.SHAMAN); - - - - this.power = new MageInt(5); this.toughness = new MageInt(3); // When you cycle Naya Sojourners or it dies, you may put a +1/+1 counter on target creature. - Ability ability1 = new CycleTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); - Ability ability2 = new DiesSourceTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); - ability1.addTarget(new TargetCreaturePermanent()); - ability2.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability1); - this.addAbility(ability2); - + Ability ability = new OrTriggeredAbility(Zone.ALL, + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), + true, + "When you cycle {this} or it dies, ", + new CycleTriggeredAbility(null, true), + new DiesSourceTriggeredAbility(null, true) + ); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + // Cycling {2}{G} - this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}{G}"))); + this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{2}{G}"))); } private NayaSojourners(final NayaSojourners card) { diff --git a/Mage.Sets/src/mage/cards/n/Nebuchadnezzar.java b/Mage.Sets/src/mage/cards/n/Nebuchadnezzar.java index 20004e4f676..e5f75dc6404 100644 --- a/Mage.Sets/src/mage/cards/n/Nebuchadnezzar.java +++ b/Mage.Sets/src/mage/cards/n/Nebuchadnezzar.java @@ -64,7 +64,7 @@ class NebuchadnezzarEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player opponent = game.getPlayer(targetPointer.getFirst(game, source)); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); if (opponent == null || sourceObject == null || cardName.isEmpty()) { return false; diff --git a/Mage.Sets/src/mage/cards/n/Necrogoyf.java b/Mage.Sets/src/mage/cards/n/Necrogoyf.java index 70434c06f7a..84e59fb821d 100644 --- a/Mage.Sets/src/mage/cards/n/Necrogoyf.java +++ b/Mage.Sets/src/mage/cards/n/Necrogoyf.java @@ -42,7 +42,7 @@ public final class Necrogoyf extends CardImpl { )); // Madness {1}{B}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{1}{B}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{1}{B}{B}"))); } private Necrogoyf(final Necrogoyf card) { diff --git a/Mage.Sets/src/mage/cards/n/NecromancersStockpile.java b/Mage.Sets/src/mage/cards/n/NecromancersStockpile.java index b321e53b4b0..0dc9e8bc0e0 100644 --- a/Mage.Sets/src/mage/cards/n/NecromancersStockpile.java +++ b/Mage.Sets/src/mage/cards/n/NecromancersStockpile.java @@ -64,7 +64,7 @@ class NecromancersStockpileDiscardTargetCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - if (targets.choose(Outcome.Discard, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.Discard, controllerId, source.getSourceId(), source, game)) { Player player = game.getPlayer(controllerId); if (player != null) { for (UUID targetId : targets.get(0).getTargets()) { @@ -83,7 +83,7 @@ class NecromancersStockpileDiscardTargetCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/n/NecromanticSelection.java b/Mage.Sets/src/mage/cards/n/NecromanticSelection.java index b2fec3f42bc..17e543848e7 100644 --- a/Mage.Sets/src/mage/cards/n/NecromanticSelection.java +++ b/Mage.Sets/src/mage/cards/n/NecromanticSelection.java @@ -71,11 +71,11 @@ class NecromanticSelectionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && controller != null) { Cards cards = new CardsImpl(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), source, game)) { permanent.destroy(source, game, false); game.checkStateAndTriggered(); // Meren of the Clan Nel Toth bug #8515 if (game.getState().getZone(permanent.getId()) == Zone.GRAVEYARD) { diff --git a/Mage.Sets/src/mage/cards/n/Necroplasm.java b/Mage.Sets/src/mage/cards/n/Necroplasm.java index e8c870c903e..43352ee983c 100644 --- a/Mage.Sets/src/mage/cards/n/Necroplasm.java +++ b/Mage.Sets/src/mage/cards/n/Necroplasm.java @@ -80,7 +80,7 @@ class NecroplasmEffect extends OneShotEffect { int numCounters = sourcePermanent.getCounters(game).getCount(CounterType.P1P1); FilterCreaturePermanent filter = new FilterCreaturePermanent(); filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, numCounters)); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if(permanent != null) { permanent.destroy(source, game, false); } diff --git a/Mage.Sets/src/mage/cards/n/Necrosynthesis.java b/Mage.Sets/src/mage/cards/n/Necrosynthesis.java index e3338e09093..5059b112918 100644 --- a/Mage.Sets/src/mage/cards/n/Necrosynthesis.java +++ b/Mage.Sets/src/mage/cards/n/Necrosynthesis.java @@ -5,10 +5,10 @@ import mage.abilities.common.DiesAttachedTriggeredAbility; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.EnchantAbility; @@ -16,7 +16,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.counters.CounterType; -import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; @@ -47,12 +46,10 @@ public final class Necrosynthesis extends CardImpl { effect.setText("Enchanted creature has \"Whenever another creature dies, put a +1/+1 counter on this creature.\""); this.addAbility(new SimpleStaticAbility(effect)); - // When enchanted creature dies, look at the top X cards of your library, where X is its power. Put one of those cards into your hand and the rest on the bottom of your library in a random order. + // When enchanted creature dies, look at the top X cards of your library, where X is its power. + // Put one of those cards into your hand and the rest on the bottom of your library in a random order. DynamicValue attachedPower = new NecrosynthesisAttachedPermanentPowerCount(); - effect = new LookLibraryAndPickControllerEffect( - attachedPower, false, StaticValue.get(1), StaticFilters.FILTER_CARD, false, - false - ).setBackInRandomOrder(true); + effect = new LookLibraryAndPickControllerEffect(attachedPower, 1, PutCards.HAND, PutCards.BOTTOM_RANDOM); effect.setText("look at the top X cards of your library, where X is its power. " + "Put one of those cards into your hand and the rest on the bottom of your library in a random order"); ability = new DiesAttachedTriggeredAbility(effect, "enchanted creature"); diff --git a/Mage.Sets/src/mage/cards/n/NecroticSliver.java b/Mage.Sets/src/mage/cards/n/NecroticSliver.java index a8940b0a6ad..d14976817d7 100644 --- a/Mage.Sets/src/mage/cards/n/NecroticSliver.java +++ b/Mage.Sets/src/mage/cards/n/NecroticSliver.java @@ -38,7 +38,7 @@ public final class NecroticSliver extends CardImpl { ability.addTarget(new TargetPermanent()); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(ability, - Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, + Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS, "All Slivers have \"{3}, Sacrifice this permanent: Destroy target permanent.\""))); } diff --git a/Mage.Sets/src/mage/cards/n/NeedleDrop.java b/Mage.Sets/src/mage/cards/n/NeedleDrop.java index 549659c588a..7f7cb3f0680 100644 --- a/Mage.Sets/src/mage/cards/n/NeedleDrop.java +++ b/Mage.Sets/src/mage/cards/n/NeedleDrop.java @@ -39,7 +39,7 @@ public final class NeedleDrop extends CardImpl { this.getSpellAbility().addTarget(new TargetAnyTarget(1, 1, filer)); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private NeedleDrop(final NeedleDrop card) { diff --git a/Mage.Sets/src/mage/cards/n/NeedleSpecter.java b/Mage.Sets/src/mage/cards/n/NeedleSpecter.java index bc00276dd67..514dff2e594 100644 --- a/Mage.Sets/src/mage/cards/n/NeedleSpecter.java +++ b/Mage.Sets/src/mage/cards/n/NeedleSpecter.java @@ -1,20 +1,17 @@ - package mage.cards.n; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.WitherAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Outcome; -import mage.game.Game; -import mage.players.Player; /** * @@ -31,13 +28,14 @@ public final class NeedleSpecter extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // Wither this.addAbility(WitherAbility.getInstance()); - + // Whenever Needle Specter deals combat damage to a player, that player discards that many cards. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new NeedleSpecterEffect(), false, true)); - + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DiscardTargetEffect(SavedDamageValue.MANY), + false, true)); } private NeedleSpecter(final NeedleSpecter card) { @@ -49,33 +47,3 @@ public final class NeedleSpecter extends CardImpl { return new NeedleSpecter(this); } } - -class NeedleSpecterEffect extends OneShotEffect { - - public NeedleSpecterEffect() { - super(Outcome.Discard); - this.staticText = "that player discards that many cards"; - } - - public NeedleSpecterEffect(final NeedleSpecterEffect effect) { - super(effect); - } - - @Override - public NeedleSpecterEffect copy() { - return new NeedleSpecterEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); - if (targetPlayer != null) { - int damage = (Integer)getValue("damage"); - targetPlayer.discard(damage, false, false, source, game); - game.informPlayers(targetPlayer.getLogName() + "discards " + damage + " card(s)"); - return true; - } - return false; - } - -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/n/NeedlebiteTrap.java b/Mage.Sets/src/mage/cards/n/NeedlebiteTrap.java index 5c52c0502f4..35a7a7b5bd5 100644 --- a/Mage.Sets/src/mage/cards/n/NeedlebiteTrap.java +++ b/Mage.Sets/src/mage/cards/n/NeedlebiteTrap.java @@ -31,7 +31,7 @@ public final class NeedlebiteTrap extends CardImpl { // Target player loses 5 life and you gain 5 life. this.getSpellAbility().addEffect(new LoseLifeTargetEffect(5)); - this.getSpellAbility().addEffect(new GainLifeEffect(5)); + this.getSpellAbility().addEffect(new GainLifeEffect(5).concatBy("and")); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Sets/src/mage/cards/n/NefariousLich.java b/Mage.Sets/src/mage/cards/n/NefariousLich.java index 0d30b3c2d88..0a6673ba957 100644 --- a/Mage.Sets/src/mage/cards/n/NefariousLich.java +++ b/Mage.Sets/src/mage/cards/n/NefariousLich.java @@ -19,7 +19,6 @@ import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; @@ -77,8 +76,8 @@ class NefariousLichDamageReplacementEffect extends ReplacementEffectImpl { Player controller = game.getPlayer(event.getPlayerId()); if (controller != null) { Target target = new TargetCardInYourGraveyard(amount, new FilterCard("card in your graveyard")); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - if (controller.choose(Outcome.Exile, target, source.getSourceId(), game)) { + if (target.canChoose(controller.getId(), source, game)) { + if (controller.choose(Outcome.Exile, target, source, game)) { Set cards = new HashSet<>(amount); for (UUID targetId : target.getTargets()) { Card card = controller.getGraveyard().get(targetId, game); diff --git a/Mage.Sets/src/mage/cards/n/NeganTheColdBlooded.java b/Mage.Sets/src/mage/cards/n/NeganTheColdBlooded.java index bc812c21a67..0fcbfd29c43 100644 --- a/Mage.Sets/src/mage/cards/n/NeganTheColdBlooded.java +++ b/Mage.Sets/src/mage/cards/n/NeganTheColdBlooded.java @@ -90,16 +90,16 @@ class NeganTheColdBloodedEffect extends OneShotEffect { filter.add(new ControllerIdPredicate(opponent.getId())); TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (!target.canChoose(source.getControllerId(), source, game)) { return false; } Set choices = new HashSet<>(); - controller.choose(Outcome.DestroyPermanent, target, source.getSourceId(), game); + controller.choose(Outcome.DestroyPermanent, target, source, game); UUID controllerChoice = target.getFirstTarget(); choices.add(controllerChoice); target.clearChosen(); - opponent.choose(Outcome.DestroyPermanent, target, source.getSourceId(), game); + opponent.choose(Outcome.DestroyPermanent, target, source, game); UUID opponentChoice = target.getFirstTarget(); choices.add(opponentChoice); diff --git a/Mage.Sets/src/mage/cards/n/NessianGameWarden.java b/Mage.Sets/src/mage/cards/n/NessianGameWarden.java index 27847b82700..63a4aca5c46 100644 --- a/Mage.Sets/src/mage/cards/n/NessianGameWarden.java +++ b/Mage.Sets/src/mage/cards/n/NessianGameWarden.java @@ -1,34 +1,33 @@ - package mage.cards.n; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; -import mage.filter.common.FilterCreatureCard; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.TargetCard; /** * - * @author LevelX2 + * @author awjackson */ public final class NessianGameWarden extends CardImpl { + private static final FilterControlledPermanent filter = new FilterControlledPermanent("Forests you control"); + + static { + filter.add(SubType.FOREST.getPredicate()); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter, null); + public NessianGameWarden(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); this.subtype.add(SubType.BEAST); @@ -36,8 +35,10 @@ public final class NessianGameWarden extends CardImpl { this.power = new MageInt(4); this.toughness = new MageInt(5); - // When Nessian Game Warden enters the battlefield, look at the top X cards of your library, where X is the number of forests you control. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in any order. - this.addAbility(new EntersBattlefieldTriggeredAbility(new NessianGameWardenEffect(), false)); + // When Nessian Game Warden enters the battlefield, look at the top X cards of your library, where X is the number of forests you control. + // You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in any order. + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + xValue, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_ANY))); } private NessianGameWarden(final NessianGameWarden card) { @@ -49,55 +50,3 @@ public final class NessianGameWarden extends CardImpl { return new NessianGameWarden(this); } } - -class NessianGameWardenEffect extends OneShotEffect { - - private static final FilterControlledPermanent filter = new FilterControlledPermanent("forests you control"); - - static { - filter.add(SubType.FOREST.getPredicate()); - } - - public NessianGameWardenEffect() { - super(Outcome.DrawCard); - this.staticText = "look at the top X cards of your library, where X is the number of Forests you control. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in any order"; - } - - public NessianGameWardenEffect(final NessianGameWardenEffect effect) { - super(effect); - } - - @Override - public NessianGameWardenEffect copy() { - return new NessianGameWardenEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (controller == null || sourcePermanent == null) { - return false; - } - - int count = new PermanentsOnBattlefieldCount(filter).calculate(game, source, this); - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, count)); - controller.lookAtCards(sourcePermanent.getIdName(), cards, game); - - if (!cards.isEmpty()) { - TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCreatureCard("creature card to put into your hand")); - if (target.canChoose(source.getSourceId(), controller.getId(), game) && controller.choose(Outcome.DrawCard, cards, target, game)) { - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - controller.revealCards(sourcePermanent.getName(), new CardsImpl(card), game); - cards.remove(card); - controller.moveCards(card, Zone.HAND, source, game); - } - } - } - - controller.putCardsOnBottomOfLibrary(cards, game, source, true); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/n/NessianWanderer.java b/Mage.Sets/src/mage/cards/n/NessianWanderer.java index 1ca21b900c2..9cd28428e9b 100644 --- a/Mage.Sets/src/mage/cards/n/NessianWanderer.java +++ b/Mage.Sets/src/mage/cards/n/NessianWanderer.java @@ -2,13 +2,12 @@ package mage.cards.n; import mage.MageInt; import mage.abilities.abilityword.ConstellationAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import java.util.UUID; @@ -26,15 +25,14 @@ public final class NessianWanderer extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(3); - // Constellation — Whenever an enchantment enters the battelfield under your control, look at the top three cards of your library. You may reveal a land card from among them and put that card into your hand. Put the rest on the bottom of your library in a random order. - this.addAbility(new ConstellationAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(3), false, StaticValue.get(1), - StaticFilters.FILTER_CARD_LAND_A, Zone.LIBRARY, false, - true, false, Zone.HAND, true, false, false - ).setBackInRandomOrder(true).setText("look at the top three cards of your library. " + - "You may reveal a land card from among them and put that card into your hand. " + - "Put the rest on the bottom of your library in a random order"), false, false - )); + // Constellation — Whenever an enchantment enters the battelfield under your control, look at the top three cards of your library. + // You may reveal a land card from among them and put that card into your hand. Put the rest on the bottom of your library in a random order. + this.addAbility(new ConstellationAbility( + new LookLibraryAndPickControllerEffect(3, 1, StaticFilters.FILTER_CARD_LAND_A, PutCards.HAND, PutCards.BOTTOM_RANDOM) + .setText("look at the top three cards of your library. " + + "You may reveal a land card from among them and put that card into your hand. " + + "Put the rest on the bottom of your library in a random order"), + false, false)); } private NessianWanderer(final NessianWanderer card) { diff --git a/Mage.Sets/src/mage/cards/n/NetcasterSpider.java b/Mage.Sets/src/mage/cards/n/NetcasterSpider.java index 1443330dcb0..067d8e48f87 100644 --- a/Mage.Sets/src/mage/cards/n/NetcasterSpider.java +++ b/Mage.Sets/src/mage/cards/n/NetcasterSpider.java @@ -3,8 +3,7 @@ package mage.cards.n; import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.ReachAbility; @@ -13,10 +12,8 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; /** * @@ -24,6 +21,12 @@ import mage.game.events.GameEvent.EventType; */ public final class NetcasterSpider extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + public NetcasterSpider(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); this.subtype.add(SubType.SPIDER); @@ -33,8 +36,9 @@ public final class NetcasterSpider extends CardImpl { // Reach this.addAbility(ReachAbility.getInstance()); + // Whenever Netcaster Spider blocks a creature with flying, Netcaster Spider gets +2/+0 until end of turn. - this.addAbility(new BlocksCreatureWithFlyingTriggeredAbility(new BoostSourceEffect(2, 0, Duration.EndOfTurn), false)); + this.addAbility(new BlocksCreatureTriggeredAbility(new BoostSourceEffect(2, 0, Duration.EndOfTurn), filter, false)); } private NetcasterSpider(final NetcasterSpider card) { @@ -45,36 +49,4 @@ public final class NetcasterSpider extends CardImpl { public NetcasterSpider copy() { return new NetcasterSpider(this); } -} - -class BlocksCreatureWithFlyingTriggeredAbility extends TriggeredAbilityImpl { - - public BlocksCreatureWithFlyingTriggeredAbility(Effect effect, boolean optional) { - super(Zone.BATTLEFIELD, effect, optional); - } - - public BlocksCreatureWithFlyingTriggeredAbility(final BlocksCreatureWithFlyingTriggeredAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.BLOCKER_DECLARED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return event.getSourceId().equals(this.getSourceId()) - && game.getPermanent(event.getTargetId()).getAbilities().containsKey(FlyingAbility.getInstance().getId()); - } - - @Override - public String getTriggerPhrase() { - return "Whenever {this} blocks a creature with flying, " ; - } - - @Override - public BlocksCreatureWithFlyingTriggeredAbility copy() { - return new BlocksCreatureWithFlyingTriggeredAbility(this); - } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/n/NettlevineBlight.java b/Mage.Sets/src/mage/cards/n/NettlevineBlight.java index 69587f98ab1..0d6d013e193 100644 --- a/Mage.Sets/src/mage/cards/n/NettlevineBlight.java +++ b/Mage.Sets/src/mage/cards/n/NettlevineBlight.java @@ -99,8 +99,8 @@ class NettlevineBlightEffect extends OneShotEffect { filter.add(new CanBeEnchantedByPredicate(nettlevineBlight)); Target target = new TargetPermanent(filter); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), newController.getId(), game) - && newController.choose(outcome, target, source.getSourceId(), game)) { + if (target.canChoose(newController.getId(), source, game) + && newController.choose(outcome, target, source, game)) { Permanent chosenPermanent = game.getPermanent(target.getFirstTarget()); if (chosenPermanent != null) { Card nettlevineBlightCard = game.getCard(source.getSourceId()); diff --git a/Mage.Sets/src/mage/cards/n/NettlingImp.java b/Mage.Sets/src/mage/cards/n/NettlingImp.java index c9c98e3f4b2..881c20ef962 100644 --- a/Mage.Sets/src/mage/cards/n/NettlingImp.java +++ b/Mage.Sets/src/mage/cards/n/NettlingImp.java @@ -103,7 +103,7 @@ class NettlingImpDelayedDestroyEffect extends OneShotEffect { DestroyTargetEffect effect = new DestroyTargetEffect(); effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game)); AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility - = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone.ALL, effect, TargetController.ANY, new InvertCondition(TargetAttackedThisTurnCondition.instance)); + = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect, TargetController.ANY, new InvertCondition(TargetAttackedThisTurnCondition.instance)); delayedAbility.getDuration(); delayedAbility.getTargets().addAll(source.getTargets()); game.addDelayedTriggeredAbility(delayedAbility, source); diff --git a/Mage.Sets/src/mage/cards/n/NewBlood.java b/Mage.Sets/src/mage/cards/n/NewBlood.java index e4c75ebc8b0..5f811d96ef7 100644 --- a/Mage.Sets/src/mage/cards/n/NewBlood.java +++ b/Mage.Sets/src/mage/cards/n/NewBlood.java @@ -1,7 +1,5 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; @@ -10,38 +8,39 @@ import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; -import mage.abilities.text.TextPartSubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.choices.Choice; import mage.choices.ChoiceCreatureType; import mage.constants.*; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.mageobject.TextPartSubtypePredicate; +import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class NewBlood extends CardImpl { + private static final FilterControlledPermanent filter + = new FilterControlledPermanent(SubType.VAMPIRE, "an untapped Vampire you control"); + + static { + filter.add(TappedPredicate.UNTAPPED); + } + public NewBlood(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}{B}"); - TextPartSubType textPartVampire = (TextPartSubType) addTextPart(new TextPartSubType(SubType.VAMPIRE)); - FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an untapped Vampire you control"); - filter.add(new TextPartSubtypePredicate(textPartVampire)); - filter.add(TappedPredicate.UNTAPPED); // As an additional cost to cast New Blood, tap an untapped Vampire you control. - this.getSpellAbility().addCost(new TapTargetCost( - new TargetControlledCreaturePermanent(1, 1, filter, true))); + this.getSpellAbility().addCost(new TapTargetCost(new TargetControlledPermanent(filter))); // Gain control of target creature. Change the text of that creature by replacing all instances of one creature type with Vampire. getSpellAbility().addEffect(new NewBloodEffect()); @@ -115,7 +114,7 @@ class ChangeCreatureTypeTargetEffect extends ContinuousEffectImpl { return; } if (fromSubType == null) { - Choice typeChoice = new ChoiceCreatureType(game.getObject(source.getSourceId())); + Choice typeChoice = new ChoiceCreatureType(game.getObject(source)); typeChoice.setMessage("Choose creature type to change to Vampire"); if (!controller.choose(outcome, typeChoice, game)) { discard(); @@ -136,36 +135,26 @@ class ChangeCreatureTypeTargetEffect extends ContinuousEffectImpl { if (controller == null) { return false; } - if (fromSubType != null) { - boolean objectFound = false; - for (UUID targetId : targetPointer.getTargets(game, source)) { - MageObject targetObject = game.getObject(targetId); - if (targetObject != null) { - objectFound = true; - switch (layer) { - case TextChangingEffects_3: - targetObject.changeSubType(fromSubType, toSubType); - break; - case TypeChangingEffects_4: - if (sublayer == SubLayer.NA) { - if (targetObject.hasSubtype(fromSubType, game)) { - targetObject.removeSubType(game, fromSubType); - if (!targetObject.hasSubtype(toSubType, game)) { - targetObject.addSubType(game, toSubType); - } - } - break; - } - } - } - if (!objectFound && this.getDuration() == Duration.Custom) { - this.discard(); - } - } - return true; - } else { + if (fromSubType == null) { throw new UnsupportedOperationException("No subtype to change set"); } + boolean objectFound = false; + for (UUID targetId : targetPointer.getTargets(game, source)) { + MageObject targetObject = game.getObject(targetId); + if (targetObject != null) { + objectFound = true; + if (targetObject.hasSubtype(fromSubType, game)) { + targetObject.removeSubType(game, fromSubType); + if (!targetObject.hasSubtype(toSubType, game)) { + targetObject.addSubType(game, toSubType); + } + } + } + if (!objectFound && this.getDuration() == Duration.Custom) { + this.discard(); + } + } + return true; } @Override @@ -175,8 +164,7 @@ class ChangeCreatureTypeTargetEffect extends ContinuousEffectImpl { @Override public boolean hasLayer(Layer layer) { - return layer == Layer.TextChangingEffects_3 - || layer == Layer.TypeChangingEffects_4; + return layer == Layer.TypeChangingEffects_4; } @Override diff --git a/Mage.Sets/src/mage/cards/n/NezahalPrimalTide.java b/Mage.Sets/src/mage/cards/n/NezahalPrimalTide.java index 9ad28f9576d..d1eae780649 100644 --- a/Mage.Sets/src/mage/cards/n/NezahalPrimalTide.java +++ b/Mage.Sets/src/mage/cards/n/NezahalPrimalTide.java @@ -58,7 +58,7 @@ public final class NezahalPrimalTide extends CardImpl { new DrawCardSourceControllerEffect(1), filter, false, SetTargetPointer.NONE)); // Discard three cards: Exile Nezahal. Return it to the battlefield tapped under its owner's control at the beginning of the next end step. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true, true), + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true), new DiscardTargetCost(new TargetCardInHand(3, new FilterCard("three cards"))))); } diff --git a/Mage.Sets/src/mage/cards/n/NicolBolasDragonGod.java b/Mage.Sets/src/mage/cards/n/NicolBolasDragonGod.java index fb6d6a6fd58..ac3dc25563b 100644 --- a/Mage.Sets/src/mage/cards/n/NicolBolasDragonGod.java +++ b/Mage.Sets/src/mage/cards/n/NicolBolasDragonGod.java @@ -3,7 +3,6 @@ package mage.cards.n; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; @@ -37,7 +36,7 @@ public final class NicolBolasDragonGod extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.BOLAS); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // Nicol Bolas, Dragon-God has all loyalty abilities of all other planeswalkers on the battlefield. this.addAbility(new SimpleStaticAbility(new NicolBolasDragonGodGainAbilitiesEffect())); @@ -88,7 +87,7 @@ class NicolBolasDragonGodGainAbilitiesEffect extends ContinuousEffectImpl { return true; } for (Permanent permanent : game.getState().getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game )) { for (Ability ability : permanent.getAbilities()) { if (ability instanceof LoyaltyAbility) { @@ -174,7 +173,7 @@ class NicolBolasDragonGodPlusOneEffect extends OneShotEffect { } // permanent if (target.equals(targetPermanent)) { - if (opponent.choose(Outcome.Exile, targetPermanent, source.getSourceId(), game)) { + if (opponent.choose(Outcome.Exile, targetPermanent, source, game)) { MageObject mageObject = game.getObject(targetPermanent.getFirstTarget()); if (mageObject instanceof Permanent) { cardsOnBattlefield.add((Card) mageObject); diff --git a/Mage.Sets/src/mage/cards/n/NicolBolasGodPharaoh.java b/Mage.Sets/src/mage/cards/n/NicolBolasGodPharaoh.java index a496767a99c..b61ac321907 100644 --- a/Mage.Sets/src/mage/cards/n/NicolBolasGodPharaoh.java +++ b/Mage.Sets/src/mage/cards/n/NicolBolasGodPharaoh.java @@ -2,7 +2,6 @@ package mage.cards.n; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; @@ -47,7 +46,7 @@ public final class NicolBolasGodPharaoh extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.BOLAS); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(7)); + this.setStartingLoyalty(7); // +2: Target opponent exiles cards from the top of their library until they exile a nonland card. Until end of turn, you may cast that card without paying its mana cost. LoyaltyAbility ability = new LoyaltyAbility(new NicolBolasGodPharaohPlusTwoEffect(), 2); diff --git a/Mage.Sets/src/mage/cards/n/NicolBolasPlaneswalker.java b/Mage.Sets/src/mage/cards/n/NicolBolasPlaneswalker.java index c7a0fd8f8d4..0f4bb25363c 100644 --- a/Mage.Sets/src/mage/cards/n/NicolBolasPlaneswalker.java +++ b/Mage.Sets/src/mage/cards/n/NicolBolasPlaneswalker.java @@ -3,7 +3,6 @@ package mage.cards.n; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.SacrificeEffect; @@ -38,7 +37,7 @@ public final class NicolBolasPlaneswalker extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.BOLAS); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +3: Destroy target noncreature permanent. LoyaltyAbility ability = new LoyaltyAbility(new DestroyTargetEffect(), 3); @@ -55,7 +54,7 @@ public final class NicolBolasPlaneswalker extends CardImpl { .setText("That player or that planeswalker's controller discards seven cards") ); ability.addEffect(new SacrificeEffect(new FilterPermanent(), 7, "then") - .setText("then sacrifices seven permanents") + .setText(", then sacrifices seven permanents") ); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NicolBolasTheArisen.java b/Mage.Sets/src/mage/cards/n/NicolBolasTheArisen.java index de5f1adbe81..3c5ca837b9d 100644 --- a/Mage.Sets/src/mage/cards/n/NicolBolasTheArisen.java +++ b/Mage.Sets/src/mage/cards/n/NicolBolasTheArisen.java @@ -3,7 +3,6 @@ package mage.cards.n; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -49,7 +48,7 @@ public final class NicolBolasTheArisen extends CardImpl { this.color.setRed(true); this.nightCard = true; - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(7)); + this.setStartingLoyalty(7); // +2: Draw two cards. this.addAbility(new LoyaltyAbility(new DrawCardSourceControllerEffect(2), 2)); diff --git a/Mage.Sets/src/mage/cards/n/NicolBolasTheDeceiver.java b/Mage.Sets/src/mage/cards/n/NicolBolasTheDeceiver.java index 40e68414f29..2a027a549c4 100644 --- a/Mage.Sets/src/mage/cards/n/NicolBolasTheDeceiver.java +++ b/Mage.Sets/src/mage/cards/n/NicolBolasTheDeceiver.java @@ -4,7 +4,6 @@ package mage.cards.n; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.DestroyTargetEffect; @@ -34,7 +33,7 @@ public final class NicolBolasTheDeceiver extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{5}{U}{B}{R}"); this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.BOLAS); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +3: Each opponent loses 3 life unless that player sacrifices a nonland permanent or discards a card. this.addAbility(new LoyaltyAbility(new NicolBolasTheDeceiverFirstEffect(), 3)); @@ -87,7 +86,7 @@ class NicolBolasTheDeceiverFirstEffect extends OneShotEffect { if (permanents > 0 && opponent.chooseUse(outcome, "Sacrifices a nonland permanent?", "Otherwise you have to discard a card or lose 3 life.", "Sacrifice", "Discard or life loss", source, game)) { Target target = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_NON_LAND); - if (opponent.choose(outcome, target, source.getSourceId(), game)) { + if (opponent.choose(outcome, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.sacrifice(source, game); diff --git a/Mage.Sets/src/mage/cards/n/NightClubber.java b/Mage.Sets/src/mage/cards/n/NightClubber.java new file mode 100644 index 00000000000..a5157981ebb --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NightClubber.java @@ -0,0 +1,46 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.keyword.BlitzAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NightClubber extends CardImpl { + + public NightClubber(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Night Clubber enters the battlefield, creatures your opponents control get -1/-1 until end of turn. + this.addAbility(new EntersBattlefieldTriggeredAbility(new BoostAllEffect( + -1, -1, Duration.EndOfTurn, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, false + ))); + + // Blitz {2}{B} + this.addAbility(new BlitzAbility(this, "{2}{B}")); + } + + private NightClubber(final NightClubber card) { + super(card); + } + + @Override + public NightClubber copy() { + return new NightClubber(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NightMarketAeronaut.java b/Mage.Sets/src/mage/cards/n/NightMarketAeronaut.java index 9c0819d902f..7a2a91fd8d8 100644 --- a/Mage.Sets/src/mage/cards/n/NightMarketAeronaut.java +++ b/Mage.Sets/src/mage/cards/n/NightMarketAeronaut.java @@ -1,10 +1,6 @@ - - package mage.cards.n; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.common.RevoltCondition; import mage.abilities.effects.common.counter.AddCountersSourceEffect; @@ -16,6 +12,8 @@ import mage.constants.SubType; import mage.counters.CounterType; import mage.watchers.common.RevoltWatcher; +import java.util.UUID; + /** * @author JRHerlehy */ @@ -34,11 +32,11 @@ public final class NightMarketAeronaut extends CardImpl { // Revolt — Night Market Aeronaut enters the battlefield with a +1/+1 counter on it if // a permanent you controlled left the battlefield this turn. - Ability ability = new EntersBattlefieldAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, RevoltCondition.instance, - "Revolt — {this} enters the battlefield with a +1/+1 counter on it if a permanent you controlled left the battlefield this turn", null); - ability.addWatcher(new RevoltWatcher()); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, + RevoltCondition.instance, "Revolt — {this} enters the battlefield with " + + "a +1/+1 counter on it if a permanent you controlled left the battlefield this turn.", null + ), new RevoltWatcher()); } private NightMarketAeronaut(final NightMarketAeronaut card) { diff --git a/Mage.Sets/src/mage/cards/n/Nightcreep.java b/Mage.Sets/src/mage/cards/n/Nightcreep.java index 9b2fb714d0d..0f60154c43b 100644 --- a/Mage.Sets/src/mage/cards/n/Nightcreep.java +++ b/Mage.Sets/src/mage/cards/n/Nightcreep.java @@ -55,7 +55,7 @@ class NightcreepLandEffect extends BecomesBasicLandTargetEffect { @Override public void init(Ability source, Game game) { super.init(source, game); - List targets = new ArrayList<>(game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), source.getSourceId(), game)); + List targets = new ArrayList<>(game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), source, game)); this.setTargetPointer(new FixedTargets(targets, game)); } @@ -79,7 +79,7 @@ class NightcreepCreatureEffect extends BecomesColorTargetEffect { @Override public void init(Ability source, Game game) { super.init(source, game); - List targets = new ArrayList<>(game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)); + List targets = new ArrayList<>(game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)); this.setTargetPointer(new FixedTargets(targets, game)); } diff --git a/Mage.Sets/src/mage/cards/n/Nighthaze.java b/Mage.Sets/src/mage/cards/n/Nighthaze.java index 7be5e8daade..3fcf36ad2ec 100644 --- a/Mage.Sets/src/mage/cards/n/Nighthaze.java +++ b/Mage.Sets/src/mage/cards/n/Nighthaze.java @@ -22,7 +22,7 @@ public final class Nighthaze extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{B}"); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(new SwampwalkAbility(), Duration.EndOfTurn)); - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/n/NightmareIncursion.java b/Mage.Sets/src/mage/cards/n/NightmareIncursion.java index 9152d18758e..9ae95cc0376 100644 --- a/Mage.Sets/src/mage/cards/n/NightmareIncursion.java +++ b/Mage.Sets/src/mage/cards/n/NightmareIncursion.java @@ -70,7 +70,7 @@ class NightmareIncursionEffect extends OneShotEffect { if (controller == null || targetPlayer == null) { return false; } - int amount = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int amount = game.getBattlefield().count(filter, source.getControllerId(), source, game); TargetCardInLibrary target = new TargetCardInLibrary(0, amount, StaticFilters.FILTER_CARD); if (controller.searchLibrary(target, source, game, targetPlayer.getId())) { Cards cards = new CardsImpl(target.getTargets()); diff --git a/Mage.Sets/src/mage/cards/n/NightshadeAssassin.java b/Mage.Sets/src/mage/cards/n/NightshadeAssassin.java index 64577809c04..e162bc012d1 100644 --- a/Mage.Sets/src/mage/cards/n/NightshadeAssassin.java +++ b/Mage.Sets/src/mage/cards/n/NightshadeAssassin.java @@ -49,7 +49,7 @@ public final class NightshadeAssassin extends CardImpl { this.addAbility(ability); // Madness {1}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{1}{B}"))); } private NightshadeAssassin(final NightshadeAssassin card) { @@ -87,12 +87,12 @@ class NightshadeAssassinEffect extends OneShotEffect { } FilterCard filter = new FilterCard(); filter.add(new ColorPredicate(ObjectColor.BLACK)); - int blackCards = controller.getHand().count(filter, source.getSourceId(), source.getControllerId(), game); + int blackCards = controller.getHand().count(filter, source.getControllerId(), source, game); int cardsToReveal = controller.getAmount(0, blackCards, "Reveal how many black cards?", game); game.informPlayers(controller.getLogName() + " chooses to reveal " + cardsToReveal + " black cards."); if (cardsToReveal > 0) { TargetCardInHand target = new TargetCardInHand(cardsToReveal, cardsToReveal, filter); - if (controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.Benefit, target, source, game)) { controller.revealCards(sourceObject.getIdName(), new CardsImpl(target.getTargets()), game); int unboost = target.getTargets().size() * -1; ContinuousEffect effect = new BoostTargetEffect(unboost, unboost, Duration.EndOfTurn); diff --git a/Mage.Sets/src/mage/cards/n/NightskyMimic.java b/Mage.Sets/src/mage/cards/n/NightskyMimic.java index e6caf289c39..d2491c53289 100644 --- a/Mage.Sets/src/mage/cards/n/NightskyMimic.java +++ b/Mage.Sets/src/mage/cards/n/NightskyMimic.java @@ -32,7 +32,7 @@ public final class NightskyMimic extends CardImpl { filter.add(new ColorPredicate(ObjectColor.BLACK)); } - private String rule = "Whenever you cast a spell that's both white and black, {this} has base power and toughness 4/4 until end of turn and gains flying until end of turn."; + private static final String rule = "Whenever you cast a spell that's both white and black, {this} has base power and toughness 4/4 until end of turn and gains flying until end of turn."; public NightskyMimic(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W/B}"); diff --git a/Mage.Sets/src/mage/cards/n/NightsquadCommando.java b/Mage.Sets/src/mage/cards/n/NightsquadCommando.java index 8ae8c016bc7..90943a1c836 100644 --- a/Mage.Sets/src/mage/cards/n/NightsquadCommando.java +++ b/Mage.Sets/src/mage/cards/n/NightsquadCommando.java @@ -8,7 +8,6 @@ import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.common.RaidHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; import mage.game.permanent.token.HumanSoldierToken; @@ -31,12 +30,10 @@ public final class NightsquadCommando extends CardImpl { // When Nightsquad Commando enters the battlefield, if you attacked this turn, create a 1/1 white Human Soldier creature token. this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new HumanSoldierToken())), - RaidCondition.instance, "When {this} enters the battlefield, " + - "if you attacked this turn, create a 1/1 white Human Soldier creature token.") - .setAbilityWord(AbilityWord.RAID) - .addHint(RaidHint.instance), - new PlayerAttackedWatcher()); + new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new HumanSoldierToken())), + RaidCondition.instance, "When {this} enters the battlefield, " + + "if you attacked this turn, create a 1/1 white Human Soldier creature token." + ).addHint(RaidHint.instance), new PlayerAttackedWatcher()); } private NightsquadCommando(final NightsquadCommando card) { diff --git a/Mage.Sets/src/mage/cards/n/Nihiloor.java b/Mage.Sets/src/mage/cards/n/Nihiloor.java index 72623718818..66735e34fea 100644 --- a/Mage.Sets/src/mage/cards/n/Nihiloor.java +++ b/Mage.Sets/src/mage/cards/n/Nihiloor.java @@ -120,7 +120,7 @@ class NihiloorControlEffect extends OneShotEffect { } TargetPermanent target = new TargetPermanent(0, 1, filter, true); target.withChooseHint("tapping a creature controlled by " + opponent.getName()); - controller.choose(outcome, target, source.getControllerId(), game); + controller.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent == null || !permanent.tap(source, game)) { continue; diff --git a/Mage.Sets/src/mage/cards/n/NikoAris.java b/Mage.Sets/src/mage/cards/n/NikoAris.java index 5f2871f4b55..84c23b95cb2 100644 --- a/Mage.Sets/src/mage/cards/n/NikoAris.java +++ b/Mage.Sets/src/mage/cards/n/NikoAris.java @@ -4,7 +4,6 @@ import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.MultipliedValue; import mage.abilities.dynamicvalue.common.CardsDrawnThisTurnDynamicValue; @@ -52,7 +51,7 @@ public final class NikoAris extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NIKO); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // When Niko Aris enters the battlefield, create X Shard tokens. this.addAbility(new EntersBattlefieldTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/n/NikoDefiesDestiny.java b/Mage.Sets/src/mage/cards/n/NikoDefiesDestiny.java index aff6ac2688b..98b25572cac 100644 --- a/Mage.Sets/src/mage/cards/n/NikoDefiesDestiny.java +++ b/Mage.Sets/src/mage/cards/n/NikoDefiesDestiny.java @@ -167,7 +167,7 @@ class NikoDefiesDestinyManaCondition extends ManaCondition implements Condition @Override public boolean apply(Game game, Ability source) { if (source instanceof SpellAbility) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && object.getAbilities().containsClass(ForetellAbility.class); } return source instanceof ForetellAbility; diff --git a/Mage.Sets/src/mage/cards/n/NimDevourer.java b/Mage.Sets/src/mage/cards/n/NimDevourer.java index fafc11ca966..42b282d22f1 100644 --- a/Mage.Sets/src/mage/cards/n/NimDevourer.java +++ b/Mage.Sets/src/mage/cards/n/NimDevourer.java @@ -82,7 +82,7 @@ class NimDevourerEffect extends OneShotEffect { if (player != null) { Target target = new TargetControlledPermanent(new FilterControlledCreaturePermanent()); - if (target.canChoose(source.getSourceId(), player.getId(), game) && player.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) { + if (target.canChoose(player.getId(), source, game) && player.choose(Outcome.Sacrifice, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { return permanent.sacrifice(source, game); diff --git a/Mage.Sets/src/mage/cards/n/NimanaSellSword.java b/Mage.Sets/src/mage/cards/n/NimanaSellSword.java index 0b007bce435..52864bec84c 100644 --- a/Mage.Sets/src/mage/cards/n/NimanaSellSword.java +++ b/Mage.Sets/src/mage/cards/n/NimanaSellSword.java @@ -26,7 +26,7 @@ public final class NimanaSellSword extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); - this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true)); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true).setAbilityWord(null)); } private NimanaSellSword(final NimanaSellSword card) { diff --git a/Mage.Sets/src/mage/cards/n/NimbleLarcenist.java b/Mage.Sets/src/mage/cards/n/NimbleLarcenist.java new file mode 100644 index 00000000000..1d4aa607ef5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NimbleLarcenist.java @@ -0,0 +1,58 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.ExileCardYouChooseTargetOpponentEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NimbleLarcenist extends CardImpl { + + private static final FilterCard filter = new FilterCard("an artifact, instant, or sorcery card"); + + static { + filter.add(Predicates.or( + CardType.ARTIFACT.getPredicate(), + CardType.INSTANT.getPredicate(), + CardType.SORCERY.getPredicate() + )); + } + + public NimbleLarcenist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}{B}"); + + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Nimble Larcenist enters the battlefield, target opponent reveals their hand. You choose an artifact, instant, or sorcery card from it and exile that card. + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileCardYouChooseTargetOpponentEffect(filter)); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + private NimbleLarcenist(final NimbleLarcenist card) { + super(card); + } + + @Override + public NimbleLarcenist copy() { + return new NimbleLarcenist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NimbusWings.java b/Mage.Sets/src/mage/cards/n/NimbusWings.java index 39af8670ec3..7dfbee6d766 100644 --- a/Mage.Sets/src/mage/cards/n/NimbusWings.java +++ b/Mage.Sets/src/mage/cards/n/NimbusWings.java @@ -38,7 +38,7 @@ public final class NimbusWings extends CardImpl { this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Enchanted creature gets +1/+2 and has flying. SimpleStaticAbility ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 2, Duration.WhileOnBattlefield)); - ability.addEffect(new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA)); + ability.addEffect(new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA).setText("and has flying")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NinjasKunai.java b/Mage.Sets/src/mage/cards/n/NinjasKunai.java index 7f6c8b3e673..55275ef79a1 100644 --- a/Mage.Sets/src/mage/cards/n/NinjasKunai.java +++ b/Mage.Sets/src/mage/cards/n/NinjasKunai.java @@ -33,7 +33,7 @@ public final class NinjasKunai extends CardImpl { // Equipped creature has "{1}, {T}, Sacrifice Ninja's Kunai: Ninja's Kunai deals 3 damage to any target." this.addAbility(new SimpleStaticAbility(new GainAbilityWithAttachmentEffect( - "equipped creature has \"{1}, {T}, Sacrifice {this}: {this} deals 2 damage to any target.\"", + "equipped creature has \"{1}, {T}, Sacrifice {this}: {this} deals 3 damage to any target.\"", new NinjasKunaiEffect(), new TargetAnyTarget(), new SacrificeAttachmentCost(), new GenericManaCost(1), new TapSourceCost() ))); diff --git a/Mage.Sets/src/mage/cards/n/NissaGenesisMage.java b/Mage.Sets/src/mage/cards/n/NissaGenesisMage.java index c1c242dedcc..d3d255eff1f 100644 --- a/Mage.Sets/src/mage/cards/n/NissaGenesisMage.java +++ b/Mage.Sets/src/mage/cards/n/NissaGenesisMage.java @@ -1,12 +1,11 @@ - package mage.cards.n; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; -import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; @@ -15,12 +14,12 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.predicate.Predicates; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetLandPermanent; +import mage.target.targetpointer.EachTargetPointer; /** * @@ -28,7 +27,7 @@ import mage.target.common.TargetLandPermanent; */ public final class NissaGenesisMage extends CardImpl { - private static final FilterCard filter = new FilterCard("any number of creature and/or land cards"); + private static final FilterCard filter = new FilterCard("creature and/or land cards"); static { filter.add(Predicates.or( @@ -42,10 +41,12 @@ public final class NissaGenesisMage extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NISSA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); //+2: Untap up to two target creatures and up to two target lands. - Ability ability = new LoyaltyAbility(new UntapTargetEffect(false).setText("Untap up to two target creatures and up to two target lands"), +2); + Effect effect = new UntapTargetEffect("untap up to two target creatures and up to two target lands"); + effect.setTargetPointer(new EachTargetPointer()); + Ability ability = new LoyaltyAbility(effect, +2); ability.addTarget(new TargetCreaturePermanent(0, 2, StaticFilters.FILTER_PERMANENT_CREATURES, false)); ability.addTarget(new TargetLandPermanent(0, 2, StaticFilters.FILTER_LANDS, false)); this.addAbility(ability); @@ -55,10 +56,11 @@ public final class NissaGenesisMage extends CardImpl { ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); - //-10: Look at the top ten cards of your library. You may put any number of creature and/or land cards from among them onto the battlefield. Put the rest on the bottom of your library in a random order.); + //-10: Look at the top ten cards of your library. + //You may put any number of creature and/or land cards from among them onto the battlefield. + //Put the rest on the bottom of your library in a random order.); this.addAbility(new LoyaltyAbility( - new LookLibraryAndPickControllerEffect(StaticValue.get(10), false, StaticValue.get(10), filter, - Zone.LIBRARY, true, false, true, Zone.BATTLEFIELD, true, true, false).setBackInRandomOrder(true), + new LookLibraryAndPickControllerEffect(10, Integer.MAX_VALUE, filter, PutCards.BATTLEFIELD, PutCards.BOTTOM_RANDOM), -10)); } diff --git a/Mage.Sets/src/mage/cards/n/NissaNaturesArtisan.java b/Mage.Sets/src/mage/cards/n/NissaNaturesArtisan.java index e8ad1de5d8d..bd2aa84f94a 100644 --- a/Mage.Sets/src/mage/cards/n/NissaNaturesArtisan.java +++ b/Mage.Sets/src/mage/cards/n/NissaNaturesArtisan.java @@ -1,35 +1,24 @@ package mage.cards.n; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.TrampleAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.cards.*; +import mage.constants.*; import mage.filter.common.FilterLandCard; import mage.game.Game; import mage.players.Player; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author fireshoes */ public final class NissaNaturesArtisan extends CardImpl { @@ -39,7 +28,7 @@ public final class NissaNaturesArtisan extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NISSA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +3: You gain 3 life. this.addAbility(new LoyaltyAbility(new GainLifeEffect(3), 3)); @@ -49,13 +38,12 @@ public final class NissaNaturesArtisan extends CardImpl { this.addAbility(new LoyaltyAbility(new NissaNaturesArtisanEffect(), -4)); // -12: Creatures you control get +5/+5 and gain trample until end of turn. - Effect effect = new BoostControlledEffect(5, 5, Duration.EndOfTurn); - effect.setText("Creature you control get +5/+5"); - LoyaltyAbility ability = new LoyaltyAbility(effect, -12); - Effect effect2 = new GainAbilityControlledEffect( - TrampleAbility.getInstance(), Duration.EndOfTurn); - effect2.setText("and gain trample until end of turn"); - ability.addEffect(effect2); + LoyaltyAbility ability = new LoyaltyAbility(new BoostControlledEffect( + 5, 5, Duration.EndOfTurn + ).setText("creatures you control get +5/+5"), -12); + ability.addEffect(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + ).setText("and gain trample until end of turn")); this.addAbility(ability); } @@ -84,7 +72,7 @@ class NissaNaturesArtisanEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } @@ -93,7 +81,7 @@ class NissaNaturesArtisanEffect extends OneShotEffect { controller.revealCards(sourceObject.getIdName(), cards, game); Set toBattlefield = new LinkedHashSet<>(); for (Card card : cards.getCards(new FilterLandCard(), - source.getSourceId(), source.getControllerId(), game)) { + source.getControllerId(), source, game)) { cards.remove(card); toBattlefield.add(card); } diff --git a/Mage.Sets/src/mage/cards/n/NissaOfShadowedBoughs.java b/Mage.Sets/src/mage/cards/n/NissaOfShadowedBoughs.java index 1b3a3667d46..a2d85dbe5fe 100644 --- a/Mage.Sets/src/mage/cards/n/NissaOfShadowedBoughs.java +++ b/Mage.Sets/src/mage/cards/n/NissaOfShadowedBoughs.java @@ -3,7 +3,6 @@ package mage.cards.n; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.LandfallAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; @@ -42,7 +41,7 @@ public final class NissaOfShadowedBoughs extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NISSA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // Landfall — Whenever a land enters the battlefield under your control, put a loyalty counter on Nissa of Shadowed Boughs. this.addAbility(new LandfallAbility(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance()))); @@ -127,7 +126,7 @@ class NissaOfShadowedBoughsCreatureEffect extends OneShotEffect { } int lands = game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, - source.getSourceId(), source.getControllerId(), game + source.getControllerId(), source, game ); FilterCard filter = new FilterCreatureCard("creature card with mana value " + lands + " or less"); filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, lands + 1)); @@ -145,7 +144,7 @@ class NissaOfShadowedBoughsCreatureEffect extends OneShotEffect { } else { target = new TargetCardInHand(filter); } - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card == null) { return false; diff --git a/Mage.Sets/src/mage/cards/n/NissaRevane.java b/Mage.Sets/src/mage/cards/n/NissaRevane.java index 794f46ea940..d5680732c4e 100644 --- a/Mage.Sets/src/mage/cards/n/NissaRevane.java +++ b/Mage.Sets/src/mage/cards/n/NissaRevane.java @@ -4,7 +4,6 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.cards.CardImpl; @@ -14,7 +13,6 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.SuperType; import mage.filter.FilterCard; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; @@ -38,7 +36,7 @@ public final class NissaRevane extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{G}{G}"); this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NISSA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(2)); + this.setStartingLoyalty(2); LoyaltyAbility ability1 = new LoyaltyAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(1, nissasChosenFilter)), 1); this.addAbility(ability1); @@ -81,7 +79,7 @@ class NissaRevaneGainLifeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - int life = 2 * game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int life = 2 * game.getBattlefield().count(filter, source.getControllerId(), source, game); if (player != null) { player.gainLife(life, game, source); } diff --git a/Mage.Sets/src/mage/cards/n/NissaSageAnimist.java b/Mage.Sets/src/mage/cards/n/NissaSageAnimist.java index 0d50bfa2ba0..6c2afa68a13 100644 --- a/Mage.Sets/src/mage/cards/n/NissaSageAnimist.java +++ b/Mage.Sets/src/mage/cards/n/NissaSageAnimist.java @@ -4,7 +4,6 @@ import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; @@ -38,7 +37,7 @@ public final class NissaSageAnimist extends CardImpl { this.nightCard = true; - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Reveal the top card of your library. If it's a land card, put it onto the battlefield. Otherwise, put it into your hand. this.addAbility(new LoyaltyAbility(new NissaSageAnimistPlusOneEffect(), 1)); @@ -82,7 +81,7 @@ class NissaSageAnimistPlusOneEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && controller != null && controller.getLibrary().hasCards()) { Card card = controller.getLibrary().getFromTop(game); if (card == null) { diff --git a/Mage.Sets/src/mage/cards/n/NissaStewardOfElements.java b/Mage.Sets/src/mage/cards/n/NissaStewardOfElements.java index 60717a9fbcc..b5f975d4060 100644 --- a/Mage.Sets/src/mage/cards/n/NissaStewardOfElements.java +++ b/Mage.Sets/src/mage/cards/n/NissaStewardOfElements.java @@ -1,21 +1,21 @@ package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.dynamicvalue.common.CountersSourceCount; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; import mage.abilities.effects.keyword.ScryEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; -import mage.cards.*; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.*; import mage.counters.CounterType; import mage.filter.common.FilterControlledLandPermanent; @@ -27,8 +27,9 @@ import mage.game.permanent.token.TokenImpl; import mage.players.Player; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class NissaStewardOfElements extends CardImpl { @@ -38,9 +39,7 @@ public final class NissaStewardOfElements extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NISSA); - Ability abilityETB = new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.LOYALTY.createInstance())); - abilityETB.setRuleVisible(false); - this.addAbility(abilityETB); + this.setStartingLoyalty(-2); // -2 loyalty means X // +2: Scry 2. this.addAbility(new LoyaltyAbility(new ScryEffect(2), 2)); diff --git a/Mage.Sets/src/mage/cards/n/NissaVitalForce.java b/Mage.Sets/src/mage/cards/n/NissaVitalForce.java index 5150a71ecc7..6ad1c2decec 100644 --- a/Mage.Sets/src/mage/cards/n/NissaVitalForce.java +++ b/Mage.Sets/src/mage/cards/n/NissaVitalForce.java @@ -1,22 +1,17 @@ package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.GetEmblemEffect; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; import mage.abilities.keyword.HasteAbility; 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.TargetController; +import mage.constants.*; +import mage.filter.FilterCard; import mage.filter.common.FilterLandPermanent; import mage.filter.common.FilterPermanentCard; import mage.game.command.emblems.NissaVitalForceEmblem; @@ -24,13 +19,15 @@ import mage.game.permanent.token.TokenImpl; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetLandPermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class NissaVitalForce extends CardImpl { private static final FilterLandPermanent filter = new FilterLandPermanent("land you control"); + private static final FilterCard filter2 = new FilterPermanentCard("permanent card from your graveyard"); static { filter.add(TargetController.YOU.getControllerPredicate()); @@ -41,17 +38,19 @@ public final class NissaVitalForce extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NISSA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Untap target land you control. Until your next turn, it becomes a 5/5 Elemental creature with haste. It's still a land. LoyaltyAbility ability = new LoyaltyAbility(new UntapTargetEffect(), 1); - ability.addEffect(new BecomesCreatureTargetEffect(new NissaVitalForceToken(), false, true, Duration.UntilYourNextTurn)); + ability.addEffect(new BecomesCreatureTargetEffect( + new NissaVitalForceToken(), false, true, Duration.UntilYourNextTurn + ).setText("Until your next turn, it becomes a 5/5 Elemental creature with haste. It's still a land")); ability.addTarget(new TargetLandPermanent(filter)); this.addAbility(ability); // -3: Return target permanent card from your graveyard to your hand. - ability = new LoyaltyAbility(new ReturnToHandTargetEffect(), -3); - ability.addTarget(new TargetCardInYourGraveyard(new FilterPermanentCard("permanent card from your graveyard"))); + ability = new LoyaltyAbility(new ReturnFromGraveyardToHandTargetEffect(), -3); + ability.addTarget(new TargetCardInYourGraveyard(filter2)); this.addAbility(ability); // -6: You get an emblem with "Whenever a land enters the battlefield under your control, you may draw a card." @@ -79,6 +78,7 @@ class NissaVitalForceToken extends TokenImpl { this.toughness = new MageInt(5); this.addAbility(HasteAbility.getInstance()); } + public NissaVitalForceToken(final NissaVitalForceToken token) { super(token); } diff --git a/Mage.Sets/src/mage/cards/n/NissaVoiceOfZendikar.java b/Mage.Sets/src/mage/cards/n/NissaVoiceOfZendikar.java index 65d034ef764..b3e25056c9e 100644 --- a/Mage.Sets/src/mage/cards/n/NissaVoiceOfZendikar.java +++ b/Mage.Sets/src/mage/cards/n/NissaVoiceOfZendikar.java @@ -3,7 +3,6 @@ package mage.cards.n; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; @@ -38,7 +37,7 @@ public final class NissaVoiceOfZendikar extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NISSA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Create a 0/1 green Plant creature token. this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new PlantToken()), 1)); diff --git a/Mage.Sets/src/mage/cards/n/NissaWhoShakesTheWorld.java b/Mage.Sets/src/mage/cards/n/NissaWhoShakesTheWorld.java index 3f85834cac9..2ff7174e0f5 100644 --- a/Mage.Sets/src/mage/cards/n/NissaWhoShakesTheWorld.java +++ b/Mage.Sets/src/mage/cards/n/NissaWhoShakesTheWorld.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; @@ -52,7 +51,7 @@ public final class NissaWhoShakesTheWorld extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NISSA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Whenever you tap a Forest for mana, add an additional {G}. this.addAbility(new NissaWhoShakesTheWorldTriggeredAbility()); diff --git a/Mage.Sets/src/mage/cards/n/NissaWorldwaker.java b/Mage.Sets/src/mage/cards/n/NissaWorldwaker.java index 9eab0f0dfd1..3318c4d700c 100644 --- a/Mage.Sets/src/mage/cards/n/NissaWorldwaker.java +++ b/Mage.Sets/src/mage/cards/n/NissaWorldwaker.java @@ -4,7 +4,6 @@ package mage.cards.n; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.UntapTargetEffect; @@ -40,7 +39,7 @@ public final class NissaWorldwaker extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NISSA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Target land you control becomes a 4/4 Elemental creature with trample. It's still a land. LoyaltyAbility ability = new LoyaltyAbility(new BecomesCreatureTargetEffect(new NissaWorldwakerToken(), false, true, Duration.Custom), 1); diff --git a/Mage.Sets/src/mage/cards/n/NiveousWisps.java b/Mage.Sets/src/mage/cards/n/NiveousWisps.java index cd0912ad909..acdec41970c 100644 --- a/Mage.Sets/src/mage/cards/n/NiveousWisps.java +++ b/Mage.Sets/src/mage/cards/n/NiveousWisps.java @@ -25,9 +25,9 @@ public final class NiveousWisps extends CardImpl { // Target creature becomes white until end of turn. Tap that creature. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new BecomesColorTargetEffect(ObjectColor.WHITE, Duration.EndOfTurn)); - this.getSpellAbility().addEffect(new TapTargetEffect()); + this.getSpellAbility().addEffect(new TapTargetEffect("tap that creature")); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } public NiveousWisps (final NiveousWisps card) { diff --git a/Mage.Sets/src/mage/cards/n/NivixGuildmage.java b/Mage.Sets/src/mage/cards/n/NivixGuildmage.java index e04068bd74c..6e6c4ad78bb 100644 --- a/Mage.Sets/src/mage/cards/n/NivixGuildmage.java +++ b/Mage.Sets/src/mage/cards/n/NivixGuildmage.java @@ -24,7 +24,7 @@ import mage.target.TargetSpell; */ public final class NivixGuildmage extends CardImpl { - private static final FilterSpell filter = new FilterSpell("instant or sorcery spell"); + private static final FilterSpell filter = new FilterSpell("instant or sorcery spell you control"); static { filter.add(Predicates.or( diff --git a/Mage.Sets/src/mage/cards/n/NivmagusElemental.java b/Mage.Sets/src/mage/cards/n/NivmagusElemental.java index daf54a843ce..566feaa6143 100644 --- a/Mage.Sets/src/mage/cards/n/NivmagusElemental.java +++ b/Mage.Sets/src/mage/cards/n/NivmagusElemental.java @@ -91,7 +91,7 @@ class NivmagusElementalCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/n/NoContest.java b/Mage.Sets/src/mage/cards/n/NoContest.java index 9fa1ad68dab..94dc34e86ac 100644 --- a/Mage.Sets/src/mage/cards/n/NoContest.java +++ b/Mage.Sets/src/mage/cards/n/NoContest.java @@ -55,9 +55,9 @@ class TargetCreatureWithLessPowerPermanent extends TargetPermanent { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { int maxPower = Integer.MIN_VALUE; // get the most powerful controlled creature that can be targeted - Card sourceCard = game.getCard(sourceId); + Card sourceCard = game.getCard(source.getSourceId()); if (sourceCard == null) { return false; } @@ -69,7 +69,7 @@ class TargetCreatureWithLessPowerPermanent extends TargetPermanent { // now check, if another creature has less power and can be targeted FilterCreaturePermanent checkFilter = new FilterCreaturePermanent(); checkFilter.add(new PowerPredicate(ComparisonType.FEWER_THAN, maxPower)); - for (Permanent permanent : game.getBattlefield().getActivePermanents(checkFilter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(checkFilter, sourceControllerId, source, game)) { if (permanent.canBeTargetedBy(sourceCard, sourceControllerId, game)) { return true; } @@ -78,8 +78,8 @@ class TargetCreatureWithLessPowerPermanent extends TargetPermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Spell spell = game.getStack().getSpell(sourceId); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Spell spell = game.getStack().getSpell(source.getSourceId()); if (spell != null) { Permanent firstTarget = getPermanentFromFirstTarget(spell.getSpellAbility(), game); if (firstTarget != null) { @@ -89,7 +89,7 @@ class TargetCreatureWithLessPowerPermanent extends TargetPermanent { filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, power)); } } - return super.possibleTargets(sourceId, sourceControllerId, game); + return super.possibleTargets(sourceControllerId, source, game); } private Permanent getPermanentFromFirstTarget(Ability source, Game game) { diff --git a/Mage.Sets/src/mage/cards/n/NobleStand.java b/Mage.Sets/src/mage/cards/n/NobleStand.java index 4070b715592..4ecb286a742 100644 --- a/Mage.Sets/src/mage/cards/n/NobleStand.java +++ b/Mage.Sets/src/mage/cards/n/NobleStand.java @@ -57,7 +57,7 @@ class NobleStandAbility extends TriggeredAbilityImpl { FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); filter.add(TokenPredicate.FALSE); Permanent permanent = game.getPermanent(event.getSourceId()); - return permanent != null && filter.match(permanent, sourceId, controllerId, game); + return permanent != null && filter.match(permanent, controllerId, this, game); } @Override diff --git a/Mage.Sets/src/mage/cards/n/NoeticScales.java b/Mage.Sets/src/mage/cards/n/NoeticScales.java index a00ab107977..8a79f87634e 100644 --- a/Mage.Sets/src/mage/cards/n/NoeticScales.java +++ b/Mage.Sets/src/mage/cards/n/NoeticScales.java @@ -75,7 +75,7 @@ class NoeticScalesEffect extends OneShotEffect { } Cards cards = new CardsImpl(); game.getBattlefield().getActivePermanents( - filter, game.getActivePlayerId(), source.getSourceId(), game + filter, game.getActivePlayerId(), source, game ).stream().filter(Objects::nonNull).forEach(cards::add); return player.moveCards(cards, Zone.HAND, source, game); } diff --git a/Mage.Sets/src/mage/cards/n/NoggleHedgeMage.java b/Mage.Sets/src/mage/cards/n/NoggleHedgeMage.java index 38da0be2459..dc876fe2a81 100644 --- a/Mage.Sets/src/mage/cards/n/NoggleHedgeMage.java +++ b/Mage.Sets/src/mage/cards/n/NoggleHedgeMage.java @@ -34,8 +34,8 @@ public final class NoggleHedgeMage extends CardImpl { filter2.add(SubType.MOUNTAIN.getPredicate()); } - private String rule = "When {this} enters the battlefield, if you control two or more Islands, you may tap two target permanents."; - private String rule2 = "When {this} enters the battlefield, if you control two or more Mountains, you may have {this} deal 2 damage to target player or planeswalker."; + private static final String rule = "When {this} enters the battlefield, if you control two or more Islands, you may tap two target permanents."; + private static final String rule2 = "When {this} enters the battlefield, if you control two or more Mountains, you may have {this} deal 2 damage to target player or planeswalker."; public NoggleHedgeMage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U/R}"); diff --git a/Mage.Sets/src/mage/cards/n/NoggleRansacker.java b/Mage.Sets/src/mage/cards/n/NoggleRansacker.java index 2ef8897903a..95e7a458f7e 100644 --- a/Mage.Sets/src/mage/cards/n/NoggleRansacker.java +++ b/Mage.Sets/src/mage/cards/n/NoggleRansacker.java @@ -28,7 +28,7 @@ public final class NoggleRansacker extends CardImpl { // When Noggle Ransacker enters the battlefield, each player draws two cards, then discards a card at random. Ability ability = new EntersBattlefieldTriggeredAbility(new DrawCardAllEffect(2)); - ability.addEffect(new DiscardEachPlayerEffect(1, true)); + ability.addEffect(new DiscardEachPlayerEffect(1, true).setText(", then discards a card at random")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NomadMythmaker.java b/Mage.Sets/src/mage/cards/n/NomadMythmaker.java index a699cbdfca6..9ac931b86f2 100644 --- a/Mage.Sets/src/mage/cards/n/NomadMythmaker.java +++ b/Mage.Sets/src/mage/cards/n/NomadMythmaker.java @@ -87,7 +87,7 @@ class NomadMythmakerEffect extends OneShotEffect { FilterControlledCreaturePermanent FILTER = new FilterControlledCreaturePermanent("Choose a creature you control"); TargetControlledPermanent target = new TargetControlledPermanent(FILTER); target.setNotTarget(true); - if (controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCardInPlay, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null && !permanent.cantBeAttachedBy(aura, source, game, false)) { diff --git a/Mage.Sets/src/mage/cards/n/NorinTheWary.java b/Mage.Sets/src/mage/cards/n/NorinTheWary.java index dd19ec242e5..6778ecf1a86 100644 --- a/Mage.Sets/src/mage/cards/n/NorinTheWary.java +++ b/Mage.Sets/src/mage/cards/n/NorinTheWary.java @@ -13,7 +13,6 @@ import mage.constants.SuperType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; /** * @@ -48,7 +47,7 @@ public final class NorinTheWary extends CardImpl { class NorinTheWaryTriggeredAbility extends TriggeredAbilityImpl { public NorinTheWaryTriggeredAbility() { - super(Zone.BATTLEFIELD, new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true), false); + super(Zone.BATTLEFIELD, new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(), false); } public NorinTheWaryTriggeredAbility(final NorinTheWaryTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/n/Norritt.java b/Mage.Sets/src/mage/cards/n/Norritt.java index 7dd4f67886d..21cff23e104 100644 --- a/Mage.Sets/src/mage/cards/n/Norritt.java +++ b/Mage.Sets/src/mage/cards/n/Norritt.java @@ -104,7 +104,7 @@ class NorrittDelayedDestroyEffect extends OneShotEffect { DestroyTargetEffect effect = new DestroyTargetEffect(); effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game)); AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility - = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone.ALL, effect, TargetController.ANY, new InvertCondition(TargetAttackedThisTurnCondition.instance)); + = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect, TargetController.ANY, new InvertCondition(TargetAttackedThisTurnCondition.instance)); delayedAbility.getDuration(); delayedAbility.getTargets().addAll(source.getTargets()); game.addDelayedTriggeredAbility(delayedAbility, source); diff --git a/Mage.Sets/src/mage/cards/n/NotOfThisWorld.java b/Mage.Sets/src/mage/cards/n/NotOfThisWorld.java index 6dd0c14a325..a9bb1965ebe 100644 --- a/Mage.Sets/src/mage/cards/n/NotOfThisWorld.java +++ b/Mage.Sets/src/mage/cards/n/NotOfThisWorld.java @@ -89,7 +89,7 @@ enum NotOfThisWorldCondition implements Condition { .flatMap(Collection::stream) .map(game::getPermanentOrLKIBattlefield) .anyMatch(permanent -> permanent != null && filter.match( - permanent, sourceSpell.getSourceId(), sourceSpell.getControllerId(), game + permanent, sourceSpell.getControllerId(), source, game )); } diff --git a/Mage.Sets/src/mage/cards/n/NourishingShoal.java b/Mage.Sets/src/mage/cards/n/NourishingShoal.java index 4e0885a8689..67444f4b9e0 100644 --- a/Mage.Sets/src/mage/cards/n/NourishingShoal.java +++ b/Mage.Sets/src/mage/cards/n/NourishingShoal.java @@ -1,4 +1,3 @@ - package mage.cards.n; import mage.ObjectColor; @@ -11,33 +10,34 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterOwnedCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetCardInHand; import java.util.UUID; /** - * * @author LevelX2 */ public final class NourishingShoal extends CardImpl { + private static final FilterOwnedCard filter + = new FilterOwnedCard("a red card with mana value X from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.GREEN)); + } + public NourishingShoal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{G}{G}"); this.subtype.add(SubType.ARCANE); - // You may exile a green card with converted mana cost X from your hand rather than pay Nourishing Shoal's mana cost. - FilterOwnedCard filter = new FilterOwnedCard("a green card with mana value X from your hand"); - filter.add(new ColorPredicate(ObjectColor.GREEN)); - filter.add(Predicates.not(new CardIdPredicate(this.getId()))); // the exile cost can never be paid with the card itself - this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter), true))); + this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost( + new TargetCardInHand(filter), true + ))); // You gain X life. this.getSpellAbility().addEffect(new GainLifeEffect(ExileFromHandCostCardConvertedMana.instance)); - } private NourishingShoal(final NourishingShoal card) { @@ -48,4 +48,4 @@ public final class NourishingShoal extends CardImpl { public NourishingShoal copy() { return new NourishingShoal(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/n/NovaChaser.java b/Mage.Sets/src/mage/cards/n/NovaChaser.java index 40cafdb4bbe..bab7d5850e8 100644 --- a/Mage.Sets/src/mage/cards/n/NovaChaser.java +++ b/Mage.Sets/src/mage/cards/n/NovaChaser.java @@ -27,7 +27,7 @@ public final class NovaChaser extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Champion an Elemental - this.addAbility(new ChampionAbility(this, SubType.ELEMENTAL, false)); + this.addAbility(new ChampionAbility(this, SubType.ELEMENTAL)); } private NovaChaser(final NovaChaser card) { diff --git a/Mage.Sets/src/mage/cards/n/NovaPentacle.java b/Mage.Sets/src/mage/cards/n/NovaPentacle.java index 4ca999f98d2..ed0e2de38b0 100644 --- a/Mage.Sets/src/mage/cards/n/NovaPentacle.java +++ b/Mage.Sets/src/mage/cards/n/NovaPentacle.java @@ -69,7 +69,7 @@ class NovaPentacleEffect extends RedirectionEffect { @Override public void init(Ability source, Game game) { - this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.damageSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); super.init(source, game); } diff --git a/Mage.Sets/src/mage/cards/n/NovijenHeartOfProgress.java b/Mage.Sets/src/mage/cards/n/NovijenHeartOfProgress.java index c3f1810b0ec..557abfcbedc 100644 --- a/Mage.Sets/src/mage/cards/n/NovijenHeartOfProgress.java +++ b/Mage.Sets/src/mage/cards/n/NovijenHeartOfProgress.java @@ -67,7 +67,7 @@ class NovijenHeartOfProgressEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), game)) { if (permanent.getTurnsOnBattlefield() == 0) { diff --git a/Mage.Sets/src/mage/cards/n/NoxiousVapors.java b/Mage.Sets/src/mage/cards/n/NoxiousVapors.java index def20a07d17..1ba8d834ef4 100644 --- a/Mage.Sets/src/mage/cards/n/NoxiousVapors.java +++ b/Mage.Sets/src/mage/cards/n/NoxiousVapors.java @@ -98,7 +98,7 @@ class NoxiousVaporsEffect extends OneShotEffect { FilterCard filter = new FilterCard(); filter.add(new ColorPredicate(color)); TargetCardInHand target = new TargetCardInHand(filter); - if (player.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + if (player.choose(Outcome.Benefit, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { chosenCards.add(card); diff --git a/Mage.Sets/src/mage/cards/n/Nucklavee.java b/Mage.Sets/src/mage/cards/n/Nucklavee.java index b509892c208..8aa78bb7547 100644 --- a/Mage.Sets/src/mage/cards/n/Nucklavee.java +++ b/Mage.Sets/src/mage/cards/n/Nucklavee.java @@ -1,12 +1,10 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -15,8 +13,9 @@ import mage.filter.FilterCard; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Loki */ public final class Nucklavee extends CardImpl { @@ -31,18 +30,18 @@ public final class Nucklavee extends CardImpl { } public Nucklavee(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U/R}{U/R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U/R}{U/R}"); this.subtype.add(SubType.BEAST); this.power = new MageInt(4); this.toughness = new MageInt(4); // When Nucklavee enters the battlefield, you may return target red sorcery card from your graveyard to your hand. - Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), true); ability.addTarget(new TargetCardInYourGraveyard(filterRed)); this.addAbility(ability); // When Nucklavee enters the battlefield, you may return target blue instant card from your graveyard to your hand. - ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); + ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), true); ability.addTarget(new TargetCardInYourGraveyard(filterBlue)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NullChamber.java b/Mage.Sets/src/mage/cards/n/NullChamber.java index 41202c8d10d..e1d6b53add6 100644 --- a/Mage.Sets/src/mage/cards/n/NullChamber.java +++ b/Mage.Sets/src/mage/cards/n/NullChamber.java @@ -71,7 +71,7 @@ class NullChamberChooseEffect extends OneShotEffect { if (controller == null || sourceObject == null) { return false; } - controller.choose(Outcome.Neutral, chosenOpponent, source.getSourceId(), game); + controller.choose(Outcome.Neutral, chosenOpponent, source, game); Player opponent = game.getPlayer(chosenOpponent.getFirstTarget()); String cardName = ChooseACardNameEffect.TypeOfName.NOT_BASIC_LAND_NAME.getChoice(controller, game, source, false); if (cardName != null) { @@ -123,7 +123,7 @@ class NullChamberReplacementEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast a spell with that name (" + mageObject.getName() + " in play)."; } diff --git a/Mage.Sets/src/mage/cards/n/NulltreadGargantuan.java b/Mage.Sets/src/mage/cards/n/NulltreadGargantuan.java index 27c9618f335..285a83dca3a 100644 --- a/Mage.Sets/src/mage/cards/n/NulltreadGargantuan.java +++ b/Mage.Sets/src/mage/cards/n/NulltreadGargantuan.java @@ -1,42 +1,39 @@ - - package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SubType; -import mage.target.Target; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class NulltreadGargantuan extends CardImpl { - public NulltreadGargantuan (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{U}"); + public NulltreadGargantuan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{U}"); this.subtype.add(SubType.BEAST); - - this.power = new MageInt(5); this.toughness = new MageInt(6); // When Nulltread Gargantuan enters the battlefield, put a creature you control on top of its owner's library. - Ability ability = new EntersBattlefieldTriggeredAbility(new PutOnLibraryTargetEffect(true), false); - Target target = new TargetControlledCreaturePermanent(); - target.setNotTarget(true); - ability.addTarget(target); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldTriggeredAbility(new NulltreadGargantuanEffect())); } - public NulltreadGargantuan (final NulltreadGargantuan card) { + public NulltreadGargantuan(final NulltreadGargantuan card) { super(card); } @@ -44,5 +41,36 @@ public final class NulltreadGargantuan extends CardImpl { public NulltreadGargantuan copy() { return new NulltreadGargantuan(this); } - +} + +class NulltreadGargantuanEffect extends OneShotEffect { + + NulltreadGargantuanEffect() { + super(Outcome.UnboostCreature); + staticText = "put a creature you control on top of its owner's library"; + } + + private NulltreadGargantuanEffect(final NulltreadGargantuanEffect effect) { + super(effect); + } + + @Override + public NulltreadGargantuanEffect copy() { + return new NulltreadGargantuanEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null || !game.getState().getBattlefield().contains( + StaticFilters.FILTER_CONTROLLED_CREATURE, source, game, 1 + )) { + return false; + } + TargetPermanent target = new TargetControlledCreaturePermanent(); + target.setNotTarget(true); + player.choose(outcome, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + return permanent != null && player.putCardsOnTopOfLibrary(permanent, game, source, false); + } } diff --git a/Mage.Sets/src/mage/cards/n/NykthosParagon.java b/Mage.Sets/src/mage/cards/n/NykthosParagon.java index 73027ff59e4..39160b8e5d6 100644 --- a/Mage.Sets/src/mage/cards/n/NykthosParagon.java +++ b/Mage.Sets/src/mage/cards/n/NykthosParagon.java @@ -1,27 +1,24 @@ package mage.cards.n; -import java.util.UUID; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; +import mage.abilities.common.GainLifeControllerTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.constants.Outcome; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; +import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class NykthosParagon extends CardImpl { @@ -35,7 +32,7 @@ public final class NykthosParagon extends CardImpl { this.toughness = new MageInt(6); // Whenever you gain life, you may put that many +1/+1 counters on each creature you control. Do this only once each turn. - this.addAbility(new NykthosParagonTriggeredAbility()); + this.addAbility(new GainLifeControllerTriggeredAbility(new NykthosParagonEffect()).setDoOnlyOnce(true)); } private NykthosParagon(final NykthosParagon card) { @@ -48,65 +45,11 @@ public final class NykthosParagon extends CardImpl { } } -class NykthosParagonTriggeredAbility extends TriggeredAbilityImpl { - - public NykthosParagonTriggeredAbility() { - super(Zone.BATTLEFIELD, new NykthosParagonEffect(), true); - } - - private NykthosParagonTriggeredAbility(final NykthosParagonTriggeredAbility ability) { - super(ability); - } - - @Override - public NykthosParagonTriggeredAbility copy() { - return new NykthosParagonTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.GAINED_LIFE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (abilityAvailableThisTurn(game) && event.getPlayerId().equals(this.getControllerId())) { - for (Effect effect : this.getEffects()) { - effect.setValue("gainedLife", event.getAmount()); - } - return true; - } - return false; - } - - @Override - public boolean resolve(Game game) { - if (abilityAvailableThisTurn(game) && super.resolve(game)) { - game.getState().setValue(CardUtil.getCardZoneString( - "lastTurnResolved" + originalId, sourceId, game - ), game.getTurnNum()); - return true; - } - return false; - } - - private boolean abilityAvailableThisTurn(Game game) { - Integer lastTurnResolved = (Integer) game.getState().getValue( - CardUtil.getCardZoneString("lastTurnResolved" + originalId, sourceId, game) - ); - return lastTurnResolved == null || lastTurnResolved != game.getTurnNum(); - } - - @Override - public String getRule() { - return "Whenever you gain life, you may put that many +1/+1 counters on each creature you control. Do this only once each turn."; - } -} - class NykthosParagonEffect extends OneShotEffect { public NykthosParagonEffect() { super(Outcome.BoostCreature); + staticText = "put that many +1/+1 counters on each creature you control"; } private NykthosParagonEffect(final NykthosParagonEffect effect) { @@ -119,22 +62,26 @@ class NykthosParagonEffect extends OneShotEffect { } @Override - public boolean apply (Game game, Ability source) { + public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); Integer life = (Integer) this.getValue("gainedLife"); - if (controller != null && sourceObject != null && life != null) { - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) { - if (permanent != null && permanent.isCreature(game)) { - permanent.addCounters(CounterType.P1P1.createInstance(life), source.getControllerId(), source, game); - if (!game.isSimulation()) { - game.informPlayers(sourceObject.getLogName() + ": " + controller.getLogName() + " puts " + life - + " +1/+1 counters on " + permanent.getLogName()); - } - } - } - return true; + if (controller == null || life == null || life < 1) { + return false; } - return false; + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURES, + source.getControllerId(), source, game + )) { + permanent.addCounters( + CounterType.P1P1.createInstance(life), + source.getControllerId(), source, game + ); + game.informPlayers( + CardUtil.getSourceLogName(game, source) + ": " + + controller.getLogName() + " puts " + life + + " +1/+1 counters on " + permanent.getLogName() + ); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/n/NymrisOonasTrickster.java b/Mage.Sets/src/mage/cards/n/NymrisOonasTrickster.java index 424adf5aea2..06b8ee0f064 100644 --- a/Mage.Sets/src/mage/cards/n/NymrisOonasTrickster.java +++ b/Mage.Sets/src/mage/cards/n/NymrisOonasTrickster.java @@ -2,8 +2,8 @@ package mage.cards.n; import mage.MageInt; import mage.abilities.common.FirstSpellOpponentsTurnTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -11,8 +11,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import java.util.UUID; @@ -36,13 +34,11 @@ public final class NymrisOonasTrickster extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - // Whenever you cast your first spell during each opponent's turn, look at the top two cards of your library. Put one of those cards into your hand and the other into your graveyard. + // Whenever you cast your first spell during each opponent's turn, look at the top two cards of your library. + // Put one of those cards into your hand and the other into your graveyard. this.addAbility(new FirstSpellOpponentsTurnTriggeredAbility( - new LookLibraryAndPickControllerEffect( - StaticValue.get(2), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.GRAVEYARD, false, false - ), false - )); + new LookLibraryAndPickControllerEffect(2, 1, PutCards.HAND, PutCards.GRAVEYARD), + false)); } private NymrisOonasTrickster(final NymrisOonasTrickster card) { diff --git a/Mage.Sets/src/mage/cards/n/Nyxathid.java b/Mage.Sets/src/mage/cards/n/Nyxathid.java index c145d368e84..2b460eacaaa 100644 --- a/Mage.Sets/src/mage/cards/n/Nyxathid.java +++ b/Mage.Sets/src/mage/cards/n/Nyxathid.java @@ -74,7 +74,7 @@ class CardsInChosenPlayerHandCount implements DynamicValue { @Override public String getMessage() { - return "card in chosen opponents hand"; + return "card in the chosen player's hand"; } @Override diff --git a/Mage.Sets/src/mage/cards/o/OKagachiMadeManifest.java b/Mage.Sets/src/mage/cards/o/OKagachiMadeManifest.java new file mode 100644 index 00000000000..ad16a1600fb --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OKagachiMadeManifest.java @@ -0,0 +1,120 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OKagachiMadeManifest extends CardImpl { + + public OKagachiMadeManifest(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); + + this.subtype.add(SubType.DRAGON); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + this.nightCard = true; + + // O-Kagachi Made Manifest is all colors. + this.color.setWhite(true); + this.color.setBlue(true); + this.color.setBlack(true); + this.color.setRed(true); + this.color.setGreen(true); + this.addAbility(new SimpleStaticAbility(new InfoEffect("{this} is all colors"))); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever O-Kagachi Made Manifest attacks, defending player chooses a nonland card in your graveyard. Return that card to your hand. O-Kagachi Made Manifest gets +X/+0 until end of turn, where X is the mana value of that card. + this.addAbility(new AttacksTriggeredAbility( + new OKagachiMadeManifestEffect(), false, null, SetTargetPointer.PLAYER + )); + } + + private OKagachiMadeManifest(final OKagachiMadeManifest card) { + super(card); + } + + @Override + public OKagachiMadeManifest copy() { + return new OKagachiMadeManifest(this); + } +} + +class OKagachiMadeManifestEffect extends OneShotEffect { + + OKagachiMadeManifestEffect() { + super(Outcome.Benefit); + staticText = "defending player chooses a nonland card in your graveyard. Return that card to your hand. " + + "{this} gets +X/+0 until end of turn, where X is the mana value of that card"; + } + + private OKagachiMadeManifestEffect(final OKagachiMadeManifestEffect effect) { + super(effect); + } + + @Override + public OKagachiMadeManifestEffect copy() { + return new OKagachiMadeManifestEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (controller == null || player == null) { + return false; + } + Card card; + switch (controller.getGraveyard().count(StaticFilters.FILTER_CARD_A_NON_LAND, game)) { + case 0: + return false; + case 1: + card = controller + .getGraveyard() + .getCards(StaticFilters.FILTER_CARD_A_NON_LAND, game) + .stream() + .findFirst() + .orElse(null); + break; + default: + TargetCard target = new TargetCardInGraveyard(StaticFilters.FILTER_CARD_A_NON_LAND); + target.setNotTarget(true); + player.choose(Outcome.ReturnToHand, controller.getGraveyard(), target, game); + card = game.getCard(target.getFirstTarget()); + } + if (card == null) { + return false; + } + int manaValue = card.getManaValue(); + player.moveCards(card, Zone.HAND, source, game); + if (manaValue > 0) { + game.addEffect(new BoostSourceEffect(manaValue, 0, Duration.EndOfTurn), source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/o/OathOfGhouls.java b/Mage.Sets/src/mage/cards/o/OathOfGhouls.java index dc1552060aa..2f45b501b9f 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfGhouls.java +++ b/Mage.Sets/src/mage/cards/o/OathOfGhouls.java @@ -108,7 +108,7 @@ class OathOfGhoulsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Player firstPlayer = game.getPlayer(game.getActivePlayerId()); if (sourceObject == null || firstPlayer == null) { return false; @@ -117,7 +117,7 @@ class OathOfGhoulsEffect extends OneShotEffect { filter.add(new OwnerIdPredicate(firstPlayer.getId())); Target target = new TargetCardInGraveyard(filter); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), firstPlayer.getId(), game) + if (target.canChoose(firstPlayer.getId(), source, game) && firstPlayer.chooseUse(outcome, "Return a creature card from your graveyard to your hand?", source, game) && firstPlayer.chooseTarget(Outcome.ReturnToHand, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/o/OathOfLimDul.java b/Mage.Sets/src/mage/cards/o/OathOfLimDul.java index 89699582bcf..d81ffe08b27 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfLimDul.java +++ b/Mage.Sets/src/mage/cards/o/OathOfLimDul.java @@ -114,7 +114,7 @@ class OathOfLimDulEffect extends OneShotEffect { && controller != null) { TargetControlledPermanent target = new TargetControlledPermanent(0, numberOfControlledPermanents, filter, true); target.setNotTarget(true); - if (controller.choose(Outcome.Detriment, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.Detriment, target, source, game)) { for (UUID targetPermanentId : target.getTargets()) { Permanent permanent = game.getPermanent(targetPermanentId); if (permanent != null diff --git a/Mage.Sets/src/mage/cards/o/OathOfMages.java b/Mage.Sets/src/mage/cards/o/OathOfMages.java index 6d6efdef132..2c6319d1b8c 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfMages.java +++ b/Mage.Sets/src/mage/cards/o/OathOfMages.java @@ -104,7 +104,7 @@ class OathOfMagesEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Player firstPlayer = game.getPlayer(game.getActivePlayerId()); Player secondPlayer = game.getPlayer(source.getFirstTarget()); if (sourceObject == null || firstPlayer == null) { diff --git a/Mage.Sets/src/mage/cards/o/OathOfNissa.java b/Mage.Sets/src/mage/cards/o/OathOfNissa.java index 83381439d6f..7a2efc70754 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfNissa.java +++ b/Mage.Sets/src/mage/cards/o/OathOfNissa.java @@ -6,18 +6,18 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.AsThoughManaEffect; -import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.game.Game; import mage.players.ManaPoolItem; import mage.players.Player; -import mage.target.TargetCard; import mage.util.CardUtil; -import java.util.Set; import java.util.UUID; /** @@ -25,12 +25,23 @@ import java.util.UUID; */ public final class OathOfNissa extends CardImpl { + private static final FilterCard filter = new FilterCard("a creature, land, or planeswalker card"); + + static { + filter.add(Predicates.or(CardType.CREATURE.getPredicate(), + CardType.LAND.getPredicate(), + CardType.PLANESWALKER.getPredicate())); + } + public OathOfNissa(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}"); addSuperType(SuperType.LEGENDARY); - // When Oath of Nissa enters the battlefield, look at the top three cards of your library. You may reveal a creature, land, or planeswalker card from among them and put it into your hand. Put the rest on the bottom of your library in any order. - this.addAbility(new EntersBattlefieldTriggeredAbility(new OathOfNissaEffect())); + // When Oath of Nissa enters the battlefield, look at the top three cards of your library. + // You may reveal a creature, land, or planeswalker card from among them and put it into your hand. + // Put the rest on the bottom of your library in any order. + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 3, 1, filter, PutCards.HAND, PutCards.BOTTOM_ANY))); // You may spend mana as though it were mana of any color to cast planeswalker spells. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new OathOfNissaSpendAnyManaEffect())); @@ -46,66 +57,6 @@ public final class OathOfNissa extends CardImpl { } } -class OathOfNissaEffect extends OneShotEffect { - - private static final FilterCard filter = new FilterCard("a creature, land, or planeswalker card"); - - static { - filter.add(Predicates.or(CardType.CREATURE.getPredicate(), - CardType.PLANESWALKER.getPredicate(), - CardType.LAND.getPredicate())); - } - - public OathOfNissaEffect() { - super(Outcome.DrawCard); - this.staticText = "look at the top three cards of your library. You may reveal a creature, land, or planeswalker card from among them and put it into your hand. Put the rest on the bottom of your library in any order"; - } - - public OathOfNissaEffect(final OathOfNissaEffect effect) { - super(effect); - } - - @Override - public OathOfNissaEffect copy() { - return new OathOfNissaEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller != null && sourceObject != null) { - Cards topCards = new CardsImpl(); - topCards.addAll(controller.getLibrary().getTopCards(game, 3)); - if (!topCards.isEmpty()) { - controller.lookAtCards(sourceObject.getIdName(), topCards, game); - int number = topCards.count(filter, source.getSourceId(), source.getControllerId(), game); - if (number > 0) { - if (controller.chooseUse(outcome, "Reveal a creature, land, or planeswalker card from the looked at cards and put it into your hand?", source, game)) { - Card card; - if (number == 1) { - Set cards = topCards.getCards(filter, source.getSourceId(), source.getControllerId(), game); - card = cards.isEmpty() ? null : cards.iterator().next(); - } else { - TargetCard target = new TargetCard(Zone.LIBRARY, filter); - controller.choose(outcome, topCards, target, game); - card = topCards.get(target.getFirstTarget(), game); - } - if (card != null) { - controller.moveCards(card, Zone.HAND, source, game); - controller.revealCards(sourceObject.getIdName(), new CardsImpl(card), game); - topCards.remove(card); - } - } - } - controller.putCardsOnBottomOfLibrary(topCards, game, source, true); - } - return true; - } - return false; - } -} - class OathOfNissaSpendAnyManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { public OathOfNissaSpendAnyManaEffect() { diff --git a/Mage.Sets/src/mage/cards/o/OathOfScholars.java b/Mage.Sets/src/mage/cards/o/OathOfScholars.java index 194a5709b92..3f76a1c9ac7 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfScholars.java +++ b/Mage.Sets/src/mage/cards/o/OathOfScholars.java @@ -100,7 +100,7 @@ class OathOfScholarsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Player firstPlayer = game.getPlayer(game.getActivePlayerId()); if (sourceObject == null || firstPlayer == null) { return false; diff --git a/Mage.Sets/src/mage/cards/o/OathkeeperTakenosDaisho.java b/Mage.Sets/src/mage/cards/o/OathkeeperTakenosDaisho.java index 6aecd7bc72c..43204e2efca 100644 --- a/Mage.Sets/src/mage/cards/o/OathkeeperTakenosDaisho.java +++ b/Mage.Sets/src/mage/cards/o/OathkeeperTakenosDaisho.java @@ -121,7 +121,7 @@ class OathkeeperEquippedMatchesFilterCondition implements Condition { } } if (attachedTo != null) { - return filter.match(attachedTo, attachedTo.getId(), attachedTo.getControllerId(), game); + return filter.match(attachedTo, attachedTo.getControllerId(), source, game); } } diff --git a/Mage.Sets/src/mage/cards/o/ObNixilisOfTheBlackOath.java b/Mage.Sets/src/mage/cards/o/ObNixilisOfTheBlackOath.java index 6bd31e361d5..71fcec21b88 100644 --- a/Mage.Sets/src/mage/cards/o/ObNixilisOfTheBlackOath.java +++ b/Mage.Sets/src/mage/cards/o/ObNixilisOfTheBlackOath.java @@ -5,7 +5,6 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -32,7 +31,7 @@ public final class ObNixilisOfTheBlackOath extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NIXILIS); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +2: Each opponent loses 1 life. You gain life equal to the life lost this way. this.addAbility(new LoyaltyAbility(new ObNixilisOfTheBlackOathEffect1(), 2)); diff --git a/Mage.Sets/src/mage/cards/o/ObNixilisReignited.java b/Mage.Sets/src/mage/cards/o/ObNixilisReignited.java index 3a59579b594..3c96f68cb0a 100644 --- a/Mage.Sets/src/mage/cards/o/ObNixilisReignited.java +++ b/Mage.Sets/src/mage/cards/o/ObNixilisReignited.java @@ -1,7 +1,6 @@ package mage.cards.o; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -28,7 +27,7 @@ public final class ObNixilisReignited extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NIXILIS); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: You draw a card and you lose 1 life. Effect effect = new DrawCardSourceControllerEffect(1, "you"); diff --git a/Mage.Sets/src/mage/cards/o/ObNixilisTheAdversary.java b/Mage.Sets/src/mage/cards/o/ObNixilisTheAdversary.java new file mode 100644 index 00000000000..7516f32be3e --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/ObNixilisTheAdversary.java @@ -0,0 +1,225 @@ +package mage.cards.o; + +import java.util.List; +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.StaticAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardTargetEffect; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.cards.Card; +import mage.constants.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.MageObjectReferencePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.DevilToken; +import mage.game.stack.Spell; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.common.TargetControlledPermanent; +import mage.util.functions.StackObjectCopyApplier; + +/** + * + * @author weirddan455 + */ +public final class ObNixilisTheAdversary extends CardImpl { + + public ObNixilisTheAdversary(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{B}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.NIXILIS); + this.setStartingLoyalty(3); + + // Casualty X. The copy isn't legendary and has starting loyalty X. + this.addAbility(new ObNixilisTheAdversaryCasualtyAbility(this)); + + // +1: Each opponent loses 2 life unless they discard a card. If you control a Demon or Devil, you gain 2 life. + this.addAbility(new LoyaltyAbility(new ObNixilisTheAdversaryDiscardEffect(), 1)); + + // −2: Create a 1/1 red Devil creature token with "When this creature dies, it deals 1 damage to any target." + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new DevilToken()), -2)); + + // −7: Target player draws seven cards and loses 7 life. + Ability ability = new LoyaltyAbility(new DrawCardTargetEffect(7), -7); + ability.addEffect(new LoseLifeTargetEffect(7).setText("and loses 7 life")); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + private ObNixilisTheAdversary(final ObNixilisTheAdversary card) { + super(card); + } + + @Override + public ObNixilisTheAdversary copy() { + return new ObNixilisTheAdversary(this); + } +} + +class ObNixilisTheAdversaryCasualtyAbility extends StaticAbility { + + public ObNixilisTheAdversaryCasualtyAbility(Card card) { + super(Zone.ALL, new InfoEffect( + "Casualty X. The copy isn't legendary and has starting loyalty X. (As you cast this spell, " + + "you may sacrifice a creature with power X. " + + "When you do, copy this spell. The copy becomes a token.)" + )); + card.getSpellAbility().addCost(new ObNixilisTheAdversaryCost()); + this.setRuleAtTheTop(true); + } + + private ObNixilisTheAdversaryCasualtyAbility(final ObNixilisTheAdversaryCasualtyAbility ability) { + super(ability); + } + + @Override + public ObNixilisTheAdversaryCasualtyAbility copy() { + return new ObNixilisTheAdversaryCasualtyAbility(this); + } +} + +class ObNixilisTheAdversaryCost extends SacrificeTargetCost { + + public ObNixilisTheAdversaryCost() { + super(new TargetControlledPermanent(0, 1, StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT, true)); + this.text = ""; + } + + private ObNixilisTheAdversaryCost(final ObNixilisTheAdversaryCost cost) { + super(cost); + } + + @Override + public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { + if (!super.pay(ability, game, source, controllerId, noMana, costToPay)) { + return false; + } + List sacrificedPermanents = getPermanents(); + if (!sacrificedPermanents.isEmpty()) { + StackObjectCopyApplier applier = new ObNixilisTheAdversaryApplier(sacrificedPermanents.get(0).getPower().getValue()); + game.fireReflexiveTriggeredAbility(new ReflexiveTriggeredAbility( + new ObNixilisTheAdversaryCopyEffect(applier), false, "when you do, copy this spell" + ), source); + } + return true; + } + + @Override + public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { + return true; + } + + @Override + public ObNixilisTheAdversaryCost copy() { + return new ObNixilisTheAdversaryCost(this); + } +} + +class ObNixilisTheAdversaryCopyEffect extends OneShotEffect { + + private final StackObjectCopyApplier applier; + + public ObNixilisTheAdversaryCopyEffect(StackObjectCopyApplier applier) { + super(Outcome.Copy); + this.applier = applier; + this.staticText = "copy {this}"; + } + + private ObNixilisTheAdversaryCopyEffect(final ObNixilisTheAdversaryCopyEffect effect) { + super(effect); + this.applier = effect.applier; + } + + @Override + public ObNixilisTheAdversaryCopyEffect copy() { + return new ObNixilisTheAdversaryCopyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = game.getSpellOrLKIStack(source.getSourceId()); + if (spell == null) { + return false; + } + spell.createCopyOnStack(game, source, source.getControllerId(), true, 1, applier); + return true; + } +} + +class ObNixilisTheAdversaryApplier implements StackObjectCopyApplier { + + private final int loyalty; + + public ObNixilisTheAdversaryApplier(int loyalty) { + this.loyalty = loyalty; + } + + @Override + public void modifySpell(StackObject stackObject, Game game) { + stackObject.getSuperType().remove(SuperType.LEGENDARY); + stackObject.setStartingLoyalty(loyalty); + } + + @Override + public MageObjectReferencePredicate getNextNewTargetType(int copyNumber) { + return null; + } +} + +class ObNixilisTheAdversaryDiscardEffect extends OneShotEffect { + + public ObNixilisTheAdversaryDiscardEffect() { + super(Outcome.LoseLife); + this.staticText = "Each opponent loses 2 life unless they discard a card. If you control a Demon or Devil, you gain 2 life"; + } + + private ObNixilisTheAdversaryDiscardEffect(final ObNixilisTheAdversaryDiscardEffect effect) { + super(effect); + } + + @Override + public ObNixilisTheAdversaryDiscardEffect copy() { + return new ObNixilisTheAdversaryDiscardEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + UUID controllerId = source.getControllerId(); + Player controller = game.getPlayer(controllerId); + if (controller == null) { + return false; + } + for (UUID opponentId : game.getOpponents(controllerId)) { + Player opponent = game.getPlayer(opponentId); + if (opponent == null) { + continue; + } + if (opponent.getHand().isEmpty() || !opponent.chooseUse( + Outcome.Discard, "Discard a card or lose 2 life?", + null, "Discard Card", "Lose 2 Life", source, game) + || opponent.discard(1, false, false, source, game).isEmpty()) { + opponent.loseLife(2, game, source, false); + } + } + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(controllerId)) { + if (permanent.hasSubtype(SubType.DEMON, game) || permanent.hasSubtype(SubType.DEVIL, game)) { + controller.gainLife(2, game, source); + break; + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/o/ObNixilisTheFallen.java b/Mage.Sets/src/mage/cards/o/ObNixilisTheFallen.java index 3a68864fa39..90e5af83b5e 100644 --- a/Mage.Sets/src/mage/cards/o/ObNixilisTheFallen.java +++ b/Mage.Sets/src/mage/cards/o/ObNixilisTheFallen.java @@ -31,7 +31,7 @@ public final class ObNixilisTheFallen extends CardImpl { // Landfall - Whenever a land enters the battlefield under your control, you may have target player lose 3 life. // If you do, put three +1/+1 counters on Ob Nixilis, the Fallen. - Ability ability = new LandfallAbility(new LoseLifeTargetEffect(3), true); + Ability ability = new LandfallAbility(new LoseLifeTargetEffect(3).setText("target player lose 3 life"), true); ability.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(3)).concatBy("If you do,")); ability.addTarget(new TargetPlayer()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/o/ObNixilisTheHateTwisted.java b/Mage.Sets/src/mage/cards/o/ObNixilisTheHateTwisted.java index 71d1cbf9ee5..4a592ad3856 100644 --- a/Mage.Sets/src/mage/cards/o/ObNixilisTheHateTwisted.java +++ b/Mage.Sets/src/mage/cards/o/ObNixilisTheHateTwisted.java @@ -3,7 +3,6 @@ package mage.cards.o; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.DrawCardOpponentTriggeredAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; @@ -29,11 +28,11 @@ public final class ObNixilisTheHateTwisted extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NIXILIS); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Whenever an opponent draws a card, Ob Nixilis, the Hate-Twisted deals 1 damage to that player. this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect( - 1, "that player" + 1, true, "that player" ), false, true)); // -2: Destroy target creature. Its controller draws two cards. diff --git a/Mage.Sets/src/mage/cards/o/ObiWanKenobi.java b/Mage.Sets/src/mage/cards/o/ObiWanKenobi.java index 0ad5ca8a1ca..383dcae1362 100644 --- a/Mage.Sets/src/mage/cards/o/ObiWanKenobi.java +++ b/Mage.Sets/src/mage/cards/o/ObiWanKenobi.java @@ -4,7 +4,6 @@ package mage.cards.o; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.TapTargetEffect; @@ -31,7 +30,7 @@ public final class ObiWanKenobi extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.OBI_WAN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1:Up to one target creature you control gains vigilance and protection from color of your choice until end of turn. Effect effect = new GainAbilityTargetEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn); diff --git a/Mage.Sets/src/mage/cards/o/OblivionSower.java b/Mage.Sets/src/mage/cards/o/OblivionSower.java index 0a09125e602..9d03512f857 100644 --- a/Mage.Sets/src/mage/cards/o/OblivionSower.java +++ b/Mage.Sets/src/mage/cards/o/OblivionSower.java @@ -85,7 +85,7 @@ class OblivionSowerEffect extends OneShotEffect { Cards exiledCards = new CardsImpl(); exiledCards.addAll(game.getExile().getAllCards(game)); Cards exiledLands = new CardsImpl(); - exiledLands.addAll(exiledCards.getCards(filter, source.getSourceId(), controller.getId(), game)); + exiledLands.addAll(exiledCards.getCards(filter, controller.getId(), source, game)); if (!exiledLands.isEmpty() && controller.chooseUse(outcome, "Put lands into play?", source, game)) { FilterCard filterToPlay = new FilterCard("land" + (exiledLands.size() > 1 ? "s" : "") + " from exile owned by " diff --git a/Mage.Sets/src/mage/cards/o/ObscuraAscendancy.java b/Mage.Sets/src/mage/cards/o/ObscuraAscendancy.java new file mode 100644 index 00000000000..de99ac113b5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/ObscuraAscendancy.java @@ -0,0 +1,81 @@ +package mage.cards.o; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.Effects; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.Spirit22Token; +import mage.game.stack.Spell; + +/** + * + * @author weirddan455 + */ +public final class ObscuraAscendancy extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.SPIRIT, "Spirits"); + + public ObscuraAscendancy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}{U}{B}"); + + // Whenever you cast a spell, if its mana value is equal to the number of soul counters on Obscura Ascendancy plus one, put a soul counter on Obscura Ascendancy, then create a 2/2 white Spirit creature token with flying. + SpellCastControllerTriggeredAbility triggeredAbility = new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.SOUL.createInstance()), false); + triggeredAbility.addEffect(new CreateTokenEffect(new Spirit22Token())); + this.addAbility(new ConditionalInterveningIfTriggeredAbility(triggeredAbility, ObscuraAscendancyCondition.instance, + "Whenever you cast a spell, if its mana value is equal to 1 plus the number of soul counters on {this}, put a soul counter on {this}, then create a 2/2 white Spirit creature token with flying." + )); + + // As long as Obscura Ascendancy has five or more soul counters on it, Spirits you control get +3/+3. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostControlledEffect(3, 3, Duration.WhileOnBattlefield, filter), + new SourceHasCounterCondition(CounterType.SOUL, 5), + "as long as there are five or more soul counters on {this}, Spirits you control get +3/+3" + ))); + } + + private ObscuraAscendancy(final ObscuraAscendancy card) { + super(card); + } + + @Override + public ObscuraAscendancy copy() { + return new ObscuraAscendancy(this); + } +} + +enum ObscuraAscendancyCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentOrLKI(game); + if (permanent != null) { + Effects effects = source.getEffects(); + if (!effects.isEmpty()) { + Object spellCast = effects.get(0).getValue("spellCast"); + if (spellCast instanceof Spell) { + return ((Spell) spellCast).getManaValue() == permanent.getCounters(game).getCount(CounterType.SOUL) + 1; + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/o/ObscuraCharm.java b/Mage.Sets/src/mage/cards/o/ObscuraCharm.java new file mode 100644 index 00000000000..ccf994dfb10 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/ObscuraCharm.java @@ -0,0 +1,64 @@ +package mage.cards.o; + +import mage.abilities.Mode; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.filter.predicate.mageobject.MulticoloredPredicate; +import mage.target.TargetPermanent; +import mage.target.TargetSpell; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ObscuraCharm extends CardImpl { + + private static final FilterCard filter + = new FilterPermanentCard("multicolored permanent card with mana value 3 or less from your graveyard"); + private static final FilterPermanent filter2 + = new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker with mana value 3 or less"); + + static { + filter.add(MulticoloredPredicate.instance); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); + filter2.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); + } + + public ObscuraCharm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}{U}{B}"); + + // Choose one — + // • Return target multicolored permanent card with mana value 3 or less from your graveyard to the battlefield tapped. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect(true)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); + + // • Counter target instant or sorcery spell. + this.getSpellAbility().addMode(new Mode(new CounterTargetEffect()) + .addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY))); + + // • Destroy target creature or planeswalker with mana value 3 or less. + this.getSpellAbility().addMode(new Mode(new DestroyTargetEffect()).addTarget(new TargetPermanent(filter2))); + } + + private ObscuraCharm(final ObscuraCharm card) { + super(card); + } + + @Override + public ObscuraCharm copy() { + return new ObscuraCharm(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/ObscuraConfluence.java b/Mage.Sets/src/mage/cards/o/ObscuraConfluence.java new file mode 100644 index 00000000000..dcd33e0d971 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/ObscuraConfluence.java @@ -0,0 +1,116 @@ +package mage.cards.o; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.LoseAllAbilitiesTargetEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessTargetEffect; +import mage.abilities.effects.keyword.ConniveSourceEffect; +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.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ObscuraConfluence extends CardImpl { + + public ObscuraConfluence(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}{U}{B}"); + + // 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); + + // • Until end of turn, target creature loses all abilities and has base power and toughness 1/1. + this.getSpellAbility().addEffect(new LoseAllAbilitiesTargetEffect(Duration.EndOfTurn) + .setText("until end of turn, target creature loses all abilities")); + this.getSpellAbility().addEffect(new SetPowerToughnessTargetEffect(1, 1, Duration.EndOfTurn) + .setText("and has base power and toughness 1/1")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // • Target creature connives. + this.getSpellAbility().addMode(new Mode(new ObscuraConfluenceConniveEffect()).addTarget(new TargetCreaturePermanent())); + + // • Target player returns a creature card from their graveyard to their hand. + this.getSpellAbility().addMode(new Mode(new ObscuraConfluenceReturnEffect()).addTarget(new TargetPlayer())); + } + + private ObscuraConfluence(final ObscuraConfluence card) { + super(card); + } + + @Override + public ObscuraConfluence copy() { + return new ObscuraConfluence(this); + } +} + +class ObscuraConfluenceConniveEffect extends OneShotEffect { + + ObscuraConfluenceConniveEffect() { + super(Outcome.Benefit); + staticText = "target creature connives. (Draw a card, then discard a card. " + + "If you discarded a nonland card, put a +1/+1 counter on that creature.)"; + } + + private ObscuraConfluenceConniveEffect(final ObscuraConfluenceConniveEffect effect) { + super(effect); + } + + @Override + public ObscuraConfluenceConniveEffect copy() { + return new ObscuraConfluenceConniveEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + return permanent != null && ConniveSourceEffect.connive(permanent, 1, source, game); + } +} + +class ObscuraConfluenceReturnEffect extends OneShotEffect { + + ObscuraConfluenceReturnEffect() { + super(Outcome.Benefit); + staticText = "target player returns a creature card from their graveyard to their hand"; + } + + private ObscuraConfluenceReturnEffect(final ObscuraConfluenceReturnEffect effect) { + super(effect); + } + + @Override + public ObscuraConfluenceReturnEffect copy() { + return new ObscuraConfluenceReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (player == null || player.getGraveyard().count( + StaticFilters.FILTER_CARD_CREATURE, game + ) < 1) { + return false; + } + TargetCard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE); + target.setNotTarget(true); + player.choose(outcome, target, source, game); + return player.moveCards(game.getCard(target.getFirstTarget()), Zone.HAND, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/o/ObscuraInitiate.java b/Mage.Sets/src/mage/cards/o/ObscuraInitiate.java new file mode 100644 index 00000000000..2886cdcddf1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/ObscuraInitiate.java @@ -0,0 +1,47 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ObscuraInitiate extends CardImpl { + + public ObscuraInitiate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {1}{W/B}: Obscura Initiate gains lifelink until end of turn. + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + LifelinkAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl<>("{1}{W/B}"))); + } + + private ObscuraInitiate(final ObscuraInitiate card) { + super(card); + } + + @Override + public ObscuraInitiate copy() { + return new ObscuraInitiate(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/ObscuraInterceptor.java b/Mage.Sets/src/mage/cards/o/ObscuraInterceptor.java new file mode 100644 index 00000000000..196dbed2823 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/ObscuraInterceptor.java @@ -0,0 +1,52 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ObscuraInterceptor extends CardImpl { + + public ObscuraInterceptor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}{B}"); + + this.subtype.add(SubType.CEPHALID); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // When Obscura Interceptor enters the battlefield, it connives. When it connives this way, return up to one target spell to its owner's hand. + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new ReturnToHandTargetEffect(), false); + ability.addTarget(new TargetSpell(0, 1, StaticFilters.FILTER_SPELL)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new ConniveSourceEffect("it", ability))); + } + + private ObscuraInterceptor(final ObscuraInterceptor card) { + super(card); + } + + @Override + public ObscuraInterceptor copy() { + return new ObscuraInterceptor(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/ObscuraStorefront.java b/Mage.Sets/src/mage/cards/o/ObscuraStorefront.java new file mode 100644 index 00000000000..0c4175e5a04 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/ObscuraStorefront.java @@ -0,0 +1,57 @@ +package mage.cards.o; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.effects.common.DoWhenCostPaid; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ObscuraStorefront extends CardImpl { + + private static final FilterCard filter = new FilterCard("a basic Plains, Island, or Swamp card"); + + static { + filter.add(SuperType.BASIC.getPredicate()); + filter.add(Predicates.or( + SubType.PLAINS.getPredicate(), + SubType.ISLAND.getPredicate(), + SubType.SWAMP.getPredicate() + )); + } + + public ObscuraStorefront(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // When Obscura Storefront enters the battlefield, sacrifice it. When you do, search your library for a basic Plains, Island, or Swamp card, put it onto the battlefield tapped, then shuffle and you gain 1 life. + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new SearchLibraryPutInPlayEffect( + new TargetCardInLibrary(filter), true, true + ), false); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DoWhenCostPaid( + ability, new SacrificeSourceCost().setText("sacrifice it"), null, false + ))); + } + + private ObscuraStorefront(final ObscuraStorefront card) { + super(card); + } + + @Override + public ObscuraStorefront copy() { + return new ObscuraStorefront(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/ObscuringHaze.java b/Mage.Sets/src/mage/cards/o/ObscuringHaze.java index f9a8e3d4161..feda12621eb 100644 --- a/Mage.Sets/src/mage/cards/o/ObscuringHaze.java +++ b/Mage.Sets/src/mage/cards/o/ObscuringHaze.java @@ -2,24 +2,21 @@ package mage.cards.o; import mage.abilities.condition.common.ControlACommanderCondition; import mage.abilities.costs.AlternativeCostSourceAbility; +import mage.abilities.effects.common.PreventAllDamageByAllPermanentsEffect; import mage.abilities.hint.common.ControlACommanderHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.common.FilterOpponentsCreaturePermanent; +import mage.filter.StaticFilters; import java.util.UUID; -import mage.abilities.effects.common.PreventAllDamageByAllPermanentsEffect; /** * @author TheElk801 */ public final class ObscuringHaze extends CardImpl { - private static final FilterOpponentsCreaturePermanent filter - = new FilterOpponentsCreaturePermanent("creatures your opponents control"); - public ObscuringHaze(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); @@ -30,7 +27,7 @@ public final class ObscuringHaze extends CardImpl { // Prevent all damage that would be dealt this turn by creatures your opponents control. this.getSpellAbility().addEffect(new PreventAllDamageByAllPermanentsEffect( - filter, Duration.EndOfTurn, false + StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, Duration.EndOfTurn, false )); } diff --git a/Mage.Sets/src/mage/cards/o/ObsessiveCollector.java b/Mage.Sets/src/mage/cards/o/ObsessiveCollector.java new file mode 100644 index 00000000000..622f82af119 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/ObsessiveCollector.java @@ -0,0 +1,92 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.WardAbility; +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.filter.FilterCard; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ObsessiveCollector extends CardImpl { + + public ObsessiveCollector(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Ward {2} + this.addAbility(new WardAbility(new ManaCostsImpl<>("{2}"))); + + // Whenever Obsessive Collector deals combat damage to a player, seek a card with mana value equal to the number of cards in your hand. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new ObsessiveCollectorEffect(), false)); + } + + private ObsessiveCollector(final ObsessiveCollector card) { + super(card); + } + + @Override + public ObsessiveCollector copy() { + return new ObsessiveCollector(this); + } +} + +enum ObsessiveCollectorPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return game.getPlayer(input.getPlayerId()).getHand().size() == input.getObject().getManaValue(); + } +} + +class ObsessiveCollectorEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterCard(); + + static { + filter.add(ObsessiveCollectorPredicate.instance); + } + + ObsessiveCollectorEffect() { + super(Outcome.Benefit); + staticText = "seek a card with mana value equal to the number of cards in your hand"; + } + + private ObsessiveCollectorEffect(final ObsessiveCollectorEffect effect) { + super(effect); + } + + @Override + public ObsessiveCollectorEffect copy() { + return new ObsessiveCollectorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + return player != null && player.seekCard(filter, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/o/ObsessiveSearch.java b/Mage.Sets/src/mage/cards/o/ObsessiveSearch.java index 48907421e6a..971c40a788b 100644 --- a/Mage.Sets/src/mage/cards/o/ObsessiveSearch.java +++ b/Mage.Sets/src/mage/cards/o/ObsessiveSearch.java @@ -23,7 +23,7 @@ public final class ObsessiveSearch extends CardImpl { this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); // Madness {U} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{U}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{U}"))); } private ObsessiveSearch(final ObsessiveSearch card) { diff --git a/Mage.Sets/src/mage/cards/o/ObsidianBattleAxe.java b/Mage.Sets/src/mage/cards/o/ObsidianBattleAxe.java index 0be91b97d56..2b7fd091e3c 100644 --- a/Mage.Sets/src/mage/cards/o/ObsidianBattleAxe.java +++ b/Mage.Sets/src/mage/cards/o/ObsidianBattleAxe.java @@ -1,4 +1,3 @@ - package mage.cards.o; import java.util.UUID; @@ -23,10 +22,7 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class ObsidianBattleAxe extends CardImpl { - private static final FilterPermanent filter = new FilterCreaturePermanent("a Warrior creature"); - static { - filter.add(SubType.WARRIOR.getPredicate()); - } + private static final FilterPermanent filter = new FilterCreaturePermanent(SubType.WARRIOR, "a Warrior creature"); public ObsidianBattleAxe(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.TRIBAL,CardType.ARTIFACT},"{3}"); @@ -35,7 +31,7 @@ public final class ObsidianBattleAxe extends CardImpl { // Equipped creature gets +2/+1 and has haste. Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(2, 1)); - ability.addEffect(new GainAbilityAttachedEffect(HasteAbility.getInstance(), AttachmentType.EQUIPMENT)); + ability.addEffect(new GainAbilityAttachedEffect(HasteAbility.getInstance(), AttachmentType.EQUIPMENT).setText("and has haste")); this.addAbility(ability); // Whenever a Warrior creature enters the battlefield, you may attach Obsidian Battle-Axe to it. this.addAbility(new EntersBattlefieldAllTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/o/ObsidianCharmaw.java b/Mage.Sets/src/mage/cards/o/ObsidianCharmaw.java index 753e468e5bd..eb02e1811a8 100644 --- a/Mage.Sets/src/mage/cards/o/ObsidianCharmaw.java +++ b/Mage.Sets/src/mage/cards/o/ObsidianCharmaw.java @@ -80,7 +80,7 @@ enum ObsidianCharmawValue implements DynamicValue { .getBattlefield() .getActivePermanents( StaticFilters.FILTER_OPPONENTS_PERMANENT, - sourceAbility.getControllerId(), sourceAbility.getSourceId(), game + sourceAbility.getControllerId(), sourceAbility, game ).stream() .filter(Objects::nonNull) .filter(permanent1 -> permanent1.isLand(game)) diff --git a/Mage.Sets/src/mage/cards/o/OddlyUneven.java b/Mage.Sets/src/mage/cards/o/OddlyUneven.java index b432c32a14c..bbce80d54da 100644 --- a/Mage.Sets/src/mage/cards/o/OddlyUneven.java +++ b/Mage.Sets/src/mage/cards/o/OddlyUneven.java @@ -27,8 +27,7 @@ public final class OddlyUneven extends CardImpl { // * Destroy each creature with an odd number of words in its name. (Hyphenated words are one word.) this.getSpellAbility().addEffect(new OddOrEvenEffect(true)); // * Destroy each creature with an even number of words in its name. - Mode mode = new Mode(); - mode.addEffect(new OddOrEvenEffect(false)); + Mode mode = new Mode(new OddOrEvenEffect(false)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/o/OgnisTheDragonsLash.java b/Mage.Sets/src/mage/cards/o/OgnisTheDragonsLash.java new file mode 100644 index 00000000000..16a5b38d995 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OgnisTheDragonsLash.java @@ -0,0 +1,56 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.common.AttacksCreatureYouControlTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OgnisTheDragonsLash extends CardImpl { + + private static final FilterControlledCreaturePermanent filter + = new FilterControlledCreaturePermanent("a creature you control with haste"); + + static { + filter.add(new AbilityPredicate(HasteAbility.class)); + } + + public OgnisTheDragonsLash(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B/R}{R}{R/G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.VIASHINO); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Whenever a creature you control with haste attacks, create a tapped Treasure token. + this.addAbility(new AttacksCreatureYouControlTriggeredAbility( + new CreateTokenEffect(new TreasureToken(), 1, true, false), false, filter + )); + } + + private OgnisTheDragonsLash(final OgnisTheDragonsLash card) { + super(card); + } + + @Override + public OgnisTheDragonsLash copy() { + return new OgnisTheDragonsLash(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OgreMarauder.java b/Mage.Sets/src/mage/cards/o/OgreMarauder.java index 6aabe66f59b..0d8d67d3dd8 100644 --- a/Mage.Sets/src/mage/cards/o/OgreMarauder.java +++ b/Mage.Sets/src/mage/cards/o/OgreMarauder.java @@ -69,7 +69,7 @@ class OgreMarauderEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { UUID defendingPlayerId = game.getCombat().getDefendingPlayerId(source.getSourceId(), game); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Player defender = game.getPlayer(defendingPlayerId); if (defender != null && sourceObject != null) { Cost cost = new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT)); diff --git a/Mage.Sets/src/mage/cards/o/OjutaiInterceptor.java b/Mage.Sets/src/mage/cards/o/OjutaiInterceptor.java index f038b4f071e..730947fa6ce 100644 --- a/Mage.Sets/src/mage/cards/o/OjutaiInterceptor.java +++ b/Mage.Sets/src/mage/cards/o/OjutaiInterceptor.java @@ -28,7 +28,7 @@ public final class OjutaiInterceptor extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Megamorph {3}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{U}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{U}"), true)); } diff --git a/Mage.Sets/src/mage/cards/o/OjutaisCommand.java b/Mage.Sets/src/mage/cards/o/OjutaisCommand.java index e31d447dbc8..008d143fcb9 100644 --- a/Mage.Sets/src/mage/cards/o/OjutaisCommand.java +++ b/Mage.Sets/src/mage/cards/o/OjutaisCommand.java @@ -1,7 +1,5 @@ - package mage.cards.o; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.CounterTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -18,8 +16,9 @@ import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.target.TargetSpell; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class OjutaisCommand extends CardImpl { @@ -42,20 +41,15 @@ public final class OjutaisCommand extends CardImpl { this.getSpellAbility().getTargets().add(new TargetCardInYourGraveyard(filter)); // or You gain 4 life; - Mode mode = new Mode(); - mode.addEffect(new GainLifeEffect(4)); - this.getSpellAbility().getModes().addMode(mode); + this.getSpellAbility().getModes().addMode(new Mode(new GainLifeEffect(4))); // or Counter target creature spell; - mode = new Mode(); + Mode mode = new Mode(new CounterTargetEffect()); mode.addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_CREATURE)); - mode.addEffect(new CounterTargetEffect()); this.getSpellAbility().getModes().addMode(mode); // or Draw a card - mode = new Mode(); - mode.addEffect(new DrawCardSourceControllerEffect(1)); - this.getSpellAbility().getModes().addMode(mode); + this.getSpellAbility().getModes().addMode(new Mode(new DrawCardSourceControllerEffect(1))); } private OjutaisCommand(final OjutaisCommand card) { diff --git a/Mage.Sets/src/mage/cards/o/OketraTheTrue.java b/Mage.Sets/src/mage/cards/o/OketraTheTrue.java index 493cd408fbf..cbea6bc7233 100644 --- a/Mage.Sets/src/mage/cards/o/OketraTheTrue.java +++ b/Mage.Sets/src/mage/cards/o/OketraTheTrue.java @@ -90,7 +90,7 @@ class OketraTheTrueRestrictionEffect extends RestrictionEffect { if (permanent.getId().equals(source.getSourceId())) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - int permanentsOnBattlefield = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int permanentsOnBattlefield = game.getBattlefield().count(filter, source.getControllerId(), source, game); return (ComparisonType.compare(permanentsOnBattlefield, ComparisonType.FEWER_THAN, 4)); } return true; diff --git a/Mage.Sets/src/mage/cards/o/OkibaSalvage.java b/Mage.Sets/src/mage/cards/o/OkibaSalvage.java new file mode 100644 index 00000000000..7fc74ead283 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OkibaSalvage.java @@ -0,0 +1,88 @@ +package mage.cards.o; + +import mage.abilities.Ability; +import mage.abilities.condition.common.ControlArtifactAndEnchantmentCondition; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.hint.common.ControlArtifactAndEnchantmentHint; +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.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OkibaSalvage extends CardImpl { + + private static final FilterCard filter = new FilterCard("creature or Vehicle card from your graveyard"); + + static { + filter.add(Predicates.or( + CardType.CREATURE.getPredicate(), + SubType.VEHICLE.getPredicate() + )); + } + + public OkibaSalvage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); + + // Return target creature or Vehicle card from your graveyard to the battlefield. Then put two +1/+1 counters on that permanent if you control an artifact and an enchantment. + this.getSpellAbility().addEffect(new OkibaSalvageEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); + this.getSpellAbility().addHint(ControlArtifactAndEnchantmentHint.instance); + } + + private OkibaSalvage(final OkibaSalvage card) { + super(card); + } + + @Override + public OkibaSalvage copy() { + return new OkibaSalvage(this); + } +} + +class OkibaSalvageEffect extends OneShotEffect { + + OkibaSalvageEffect() { + super(Outcome.Benefit); + staticText = "return target creature or Vehicle card from your graveyard to the battlefield. " + + "Then put two +1/+1 counters on that permanent if you control an artifact and an enchantment"; + } + + private OkibaSalvageEffect(final OkibaSalvageEffect effect) { + super(effect); + } + + @Override + public OkibaSalvageEffect copy() { + return new OkibaSalvageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(source.getFirstTarget()); + if (player == null || card == null) { + return false; + } + player.moveCards(card, Zone.BATTLEFIELD, source, game); + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null && ControlArtifactAndEnchantmentCondition.instance.apply(game, source)) { + permanent.addCounters(CounterType.P1P1.createInstance(2), source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/o/Okk.java b/Mage.Sets/src/mage/cards/o/Okk.java index d7191e37e20..ede068e8e23 100644 --- a/Mage.Sets/src/mage/cards/o/Okk.java +++ b/Mage.Sets/src/mage/cards/o/Okk.java @@ -72,7 +72,7 @@ class OkkAttackEffect extends RestrictionEffect { public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(source.getSourceId())) { // Search for an attacking creature with greater power - for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (creature.getPower().getValue() > permanent.getPower().getValue()) { return false; } @@ -110,7 +110,7 @@ class OkkBlockEffect extends RestrictionEffect { public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(source.getSourceId())) { // Search for a blocking creature with greater power - for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (creature.getPower().getValue() > permanent.getPower().getValue()) { return false; } diff --git a/Mage.Sets/src/mage/cards/o/OkoTheTrickster.java b/Mage.Sets/src/mage/cards/o/OkoTheTrickster.java index 86e1ed6c1b4..cb98c9ec02f 100644 --- a/Mage.Sets/src/mage/cards/o/OkoTheTrickster.java +++ b/Mage.Sets/src/mage/cards/o/OkoTheTrickster.java @@ -2,7 +2,6 @@ package mage.cards.o; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.PreventAllDamageToSourceEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; @@ -31,7 +30,7 @@ public final class OkoTheTrickster extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.OKO); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Put two +1/+1 counters on up to one target creature you control. Ability ability = new LoyaltyAbility( diff --git a/Mage.Sets/src/mage/cards/o/OkoThiefOfCrowns.java b/Mage.Sets/src/mage/cards/o/OkoThiefOfCrowns.java index f2b391b7a14..57804a64654 100644 --- a/Mage.Sets/src/mage/cards/o/OkoThiefOfCrowns.java +++ b/Mage.Sets/src/mage/cards/o/OkoThiefOfCrowns.java @@ -2,7 +2,6 @@ package mage.cards.o; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.ExchangeControlTargetEffect; @@ -37,7 +36,7 @@ public final class OkoThiefOfCrowns extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.OKO); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +2: Create a Food token. this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new FoodToken()), 2)); diff --git a/Mage.Sets/src/mage/cards/o/OlagLudevicsHubris.java b/Mage.Sets/src/mage/cards/o/OlagLudevicsHubris.java index b3cf3cd498a..dc76a1e359f 100644 --- a/Mage.Sets/src/mage/cards/o/OlagLudevicsHubris.java +++ b/Mage.Sets/src/mage/cards/o/OlagLudevicsHubris.java @@ -98,7 +98,7 @@ class OlagLudevicsHubrisEffect extends ReplacementEffectImpl { return cards.getRandom(game); } TargetCard target = new TargetCardInExile(StaticFilters.FILTER_CARD); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); return cards.get(target.getFirstTarget(), game); } diff --git a/Mage.Sets/src/mage/cards/o/OldGnawbone.java b/Mage.Sets/src/mage/cards/o/OldGnawbone.java index 86770749d72..2b83bf460f0 100644 --- a/Mage.Sets/src/mage/cards/o/OldGnawbone.java +++ b/Mage.Sets/src/mage/cards/o/OldGnawbone.java @@ -2,10 +2,8 @@ package mage.cards.o; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.effects.Effect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.CreateTokenEffect; import mage.constants.SetTargetPointer; import mage.constants.SubType; @@ -15,7 +13,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; -import mage.game.Game; import mage.game.permanent.token.TreasureToken; /** @@ -37,7 +34,7 @@ public final class OldGnawbone extends CardImpl { // Whenever a creature you control deals combat damage to a player, create that many Treasure tokens. this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility( - new CreateTokenEffect(new TreasureToken(), OldGnawboneValue.instance), + new CreateTokenEffect(new TreasureToken(), SavedDamageValue.MANY), StaticFilters.FILTER_CONTROLLED_A_CREATURE, false, SetTargetPointer.NONE, true )); @@ -52,31 +49,3 @@ public final class OldGnawbone extends CardImpl { return new OldGnawbone(this); } } - -enum OldGnawboneValue implements DynamicValue { - instance; - - @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - Integer damage = (Integer) effect.getValue("damage"); - if (damage != null) { - return damage; - } - return 0; - } - - @Override - public String toString() { - return "that many"; - } - - @Override - public String getMessage() { - return ""; - } - - @Override - public OldGnawboneValue copy() { - return OldGnawboneValue.instance; - } -} diff --git a/Mage.Sets/src/mage/cards/o/OldGrowthTroll.java b/Mage.Sets/src/mage/cards/o/OldGrowthTroll.java index 20d851174a3..942c5bdc151 100644 --- a/Mage.Sets/src/mage/cards/o/OldGrowthTroll.java +++ b/Mage.Sets/src/mage/cards/o/OldGrowthTroll.java @@ -111,7 +111,7 @@ class OldGrowthTrollReturnEffect extends OneShotEffect { } TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); - if (controller.choose(outcome, target, source.getSourceId(), game) + if (controller.choose(outcome, target, source, game) && game.getPermanent(target.getFirstTarget()) != null) { game.getState().setValue("attachTo:" + source.getSourceId(), target.getFirstTarget()); } diff --git a/Mage.Sets/src/mage/cards/o/OldManOfTheSea.java b/Mage.Sets/src/mage/cards/o/OldManOfTheSea.java index ca370189566..18e1a3801fb 100644 --- a/Mage.Sets/src/mage/cards/o/OldManOfTheSea.java +++ b/Mage.Sets/src/mage/cards/o/OldManOfTheSea.java @@ -1,41 +1,38 @@ - package mage.cards.o; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.StateTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SkipUntapOptionalAbility; -import mage.abilities.condition.CompoundCondition; -import mage.abilities.condition.Condition; -import mage.abilities.condition.common.SourceTappedCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.effects.common.InfoEffect; -import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.effects.ContinuousEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.*; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * - * @author LevelX2 + * @author TheElk801 */ public final class OldManOfTheSea extends CardImpl { + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature with less than or equal power"); + + static { + filter.add(OldManOfTheSeaPredicate.instance); + } + public OldManOfTheSea(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.DJINN); this.power = new MageInt(2); @@ -45,16 +42,9 @@ public final class OldManOfTheSea extends CardImpl { this.addAbility(new SkipUntapOptionalAbility()); // {tap}: Gain control of target creature with power less than or equal to Old Man of the Sea's power for as long as Old Man of the Sea remains tapped and that creature's power remains less than or equal to Old Man of the Sea's power. - FilterCreaturePermanent controllableCreatures = new FilterCreaturePermanent("creature with power less than or equal to Old Man of the Sea's power"); - controllableCreatures.add(new PowerLowerEqualSourcePredicate(this.getId())); - ConditionalContinuousEffect effect = new ConditionalContinuousEffect( - new OldManOfTheSeaGainControlTargetEffect(Duration.Custom, true), new CompoundCondition(SourceTappedCondition.TAPPED, new SourcePowerGreaterEqualTargetCondition()), - "Gain control of target creature with power less than or equal to {this}'s power for as long as {this} remains tapped and that creature's power remains less than or equal to {this}'s power"); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(controllableCreatures)); + Ability ability = new SimpleActivatedAbility(new OldManOfTheSeaEffect(), new TapSourceCost()); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); - // internal ability to check condition - this.addAbility(new OldManOfTheSeaStateBasedTriggeredAbility()); } private OldManOfTheSea(final OldManOfTheSea card) { @@ -67,109 +57,61 @@ public final class OldManOfTheSea extends CardImpl { } } -class OldManOfTheSeaGainControlTargetEffect extends GainControlTargetEffect { +enum OldManOfTheSeaPredicate implements ObjectSourcePlayerPredicate { + instance; - public OldManOfTheSeaGainControlTargetEffect(Duration duration, boolean fixedControl) { - super(duration, fixedControl); + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + Permanent sourcePermanent = input.getSource().getSourcePermanentOrLKI(game); + return sourcePermanent != null + && input.getObject().getPower().getValue() <= sourcePermanent.getPower().getValue(); + } +} + +class OldManOfTheSeaEffect extends ContinuousEffectImpl { + + OldManOfTheSeaEffect() { + super(Duration.Custom, Outcome.GainControl); + staticText = "gain control of target creature with power less than or equal to {this}'s power for as long as {this} remains tapped and that creature's power remains less than or equal to {this}'s power"; } - public OldManOfTheSeaGainControlTargetEffect(final OldManOfTheSeaGainControlTargetEffect effect) { + private OldManOfTheSeaEffect(final OldManOfTheSeaEffect effect) { super(effect); } @Override - public void init(Ability source, Game game) { - super.init(source, game); - // save target id to be available for hidden state based triggered effect - game.getState().setValue("target" + source.getSourceId(), getTargetPointer().getFirst(game, source)); + public OldManOfTheSeaEffect copy() { + return new OldManOfTheSeaEffect(this); } @Override - public OldManOfTheSeaGainControlTargetEffect copy() { - return new OldManOfTheSeaGainControlTargetEffect(this); - } -} - -/* -used a state based triggered effect here (not going to stack, so running hidden) to compare power of the controlled -creature to Old Man of the seas power. It's not possible to do this as condition of continuous effect, because the -time the effect checks its condition, the layered effects that modify power are not applied yet. -result is save to a state value to be available for the condition of the continuous effect -*/ -class OldManOfTheSeaStateBasedTriggeredAbility extends StateTriggeredAbility { - - public OldManOfTheSeaStateBasedTriggeredAbility() { - super(Zone.BATTLEFIELD, new InfoEffect("")); - this.setRuleVisible(false); - this.usesStack = false; - } - - public OldManOfTheSeaStateBasedTriggeredAbility(final OldManOfTheSeaStateBasedTriggeredAbility ability) { - super(ability); - } - - @Override - public OldManOfTheSeaStateBasedTriggeredAbility copy() { - return new OldManOfTheSeaStateBasedTriggeredAbility(this); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Permanent sourcePermanent = game.getPermanent(getSourceId()); - if (sourcePermanent != null && sourcePermanent.isTapped()) { - UUID controlledCreatureId = (UUID) game.getState().getValue("target" + getSourceId()); - if (controlledCreatureId != null) { - Permanent controlledCreature = game.getPermanent(controlledCreatureId); - if (controlledCreature != null) { - if (controlledCreature.getPower().getValue() > sourcePermanent.getPower().getValue()) { - game.getState().setValue("powerCondition" + getSourceId(), Boolean.TRUE); - } + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (sourcePermanent == null || permanent == null || !sourcePermanent.isTapped()) { + discard(); + return false; + } + switch (layer) { + case ControlChangingEffects_2: + permanent.changeControllerId(source.getControllerId(), game, source); + return true; + case RulesEffects: + if (permanent.getPower().getValue() > sourcePermanent.getPower().getValue()) { + discard(); + return false; } - } } return false; } -} - -class SourcePowerGreaterEqualTargetCondition implements Condition { - @Override public boolean apply(Game game, Ability source) { - Object object = game.getState().getValue("powerCondition" + source.getSourceId()); - if (object != null && (Boolean) object) { - // reset the values - game.getState().setValue("powerCondition" + source.getSourceId(), Boolean.FALSE); - game.getState().setValue("target" + source.getSourceId(), null); - // stop controlling target - return false; - } return true; } -} - -class PowerLowerEqualSourcePredicate implements ObjectSourcePlayerPredicate { - - UUID sourceId; - - public PowerLowerEqualSourcePredicate(UUID sourceId) { - this.sourceId = sourceId; - } @Override - public boolean apply(ObjectSourcePlayer input, Game game) { - Permanent sourcePermanent = game.getPermanent(sourceId); - Permanent permanent = input.getObject(); - if (permanent != null && sourcePermanent != null) { - if (permanent.getPower().getValue() <= sourcePermanent.getPower().getValue()) { - return true; - } - } - return false; - } - - @Override - public String toString() { - return "creature with power less than or equal to {this}'s power"; + public boolean hasLayer(Layer layer) { + return layer == Layer.ControlChangingEffects_2 || layer == Layer.RulesEffects; } } diff --git a/Mage.Sets/src/mage/cards/o/OliviaCrimsonBride.java b/Mage.Sets/src/mage/cards/o/OliviaCrimsonBride.java index d0ec11c3163..9f6cb112201 100644 --- a/Mage.Sets/src/mage/cards/o/OliviaCrimsonBride.java +++ b/Mage.Sets/src/mage/cards/o/OliviaCrimsonBride.java @@ -124,7 +124,7 @@ class OliviaCrimsonBrideAbility extends StateTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - return game.getBattlefield().count(filter, getSourceId(), getControllerId(), game) < 1; + return game.getBattlefield().count(filter, getControllerId(), this, game) < 1; } @Override diff --git a/Mage.Sets/src/mage/cards/o/OliviaVoldaren.java b/Mage.Sets/src/mage/cards/o/OliviaVoldaren.java index 250b50b08d5..fa6868dc958 100644 --- a/Mage.Sets/src/mage/cards/o/OliviaVoldaren.java +++ b/Mage.Sets/src/mage/cards/o/OliviaVoldaren.java @@ -12,12 +12,13 @@ import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.counters.CounterType; -import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -43,12 +44,6 @@ public final class OliviaVoldaren extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(3); - String rule = "Gain control of target Vampire for as long as you control {this}"; - - FilterPermanent filter2 = new FilterPermanent(); - filter2.add(TargetController.YOU.getControllerPredicate()); - filter2.add(new CardIdPredicate(this.getId())); - this.addAbility(FlyingAbility.getInstance()); // {1}{R}: Olivia Voldaren deals 1 damage to another target creature. That creature becomes a Vampire in addition to its other types. Put a +1/+1 counter on Olivia Voldaren. diff --git a/Mage.Sets/src/mage/cards/o/Omen.java b/Mage.Sets/src/mage/cards/o/Omen.java index 0b1ab731f96..9811470dbb3 100644 --- a/Mage.Sets/src/mage/cards/o/Omen.java +++ b/Mage.Sets/src/mage/cards/o/Omen.java @@ -1,9 +1,9 @@ - package mage.cards.o; import java.util.UUID; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LookLibraryControllerEffect; +import mage.abilities.effects.common.ShuffleLibrarySourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -17,11 +17,12 @@ public final class Omen extends CardImpl { public Omen(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{U}"); - // Look at the top three cards of your library, then put them back in any order. You may shuffle your library. - this.getSpellAbility().addEffect(new LookLibraryControllerEffect(3, true)); - + // Look at the top three cards of your library, then put them back in any order. + this.getSpellAbility().addEffect(new LookLibraryControllerEffect(3)); + // You may shuffle. + this.getSpellAbility().addEffect(new ShuffleLibrarySourceEffect(true)); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private Omen(final Omen card) { diff --git a/Mage.Sets/src/mage/cards/o/OminousParcel.java b/Mage.Sets/src/mage/cards/o/OminousParcel.java new file mode 100644 index 00000000000..534151ac745 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OminousParcel.java @@ -0,0 +1,54 @@ +package mage.cards.o; + +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.GenericManaCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OminousParcel extends CardImpl { + + public OminousParcel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + + // {2}, {T}, Sacrifice Ominous Parcel: Search your library for a basic land card, reveal it, put it into your hand, then shuffle. + Ability ability = new SimpleActivatedAbility(new SearchLibraryPutInHandEffect( + new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true + ), + new GenericManaCost(2)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + + // {5}, {T}, Sacrifice Ominous Parcel: It deals 4 damage to target creature. + ability = new SimpleActivatedAbility( + new DamageTargetEffect(4, "it"), new GenericManaCost(5) + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private OminousParcel(final OminousParcel card) { + super(card); + } + + @Override + public OminousParcel copy() { + return new OminousParcel(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OmnispellAdept.java b/Mage.Sets/src/mage/cards/o/OmnispellAdept.java index d012b3739a7..a11cb39da4a 100644 --- a/Mage.Sets/src/mage/cards/o/OmnispellAdept.java +++ b/Mage.Sets/src/mage/cards/o/OmnispellAdept.java @@ -5,30 +5,23 @@ 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.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.cost.CastFromHandForFreeEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.common.FilterInstantOrSorceryCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; -import mage.game.Game; -import mage.players.Player; -import mage.target.Target; -import mage.target.common.TargetCardInHand; import java.util.UUID; -import mage.ApprovingObject; /** * @author TheElk801 */ public final class OmnispellAdept extends CardImpl { + private static final FilterCard filter = new FilterInstantOrSorceryCard("an instant or sorcery spell"); + public OmnispellAdept(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); @@ -40,7 +33,7 @@ public final class OmnispellAdept extends CardImpl { // {2}{U}, {T}: You may cast an instant or sorcery card from your hand // without paying its mana cost. Ability ability = new SimpleActivatedAbility( - new OmnispellAdeptEffect(), new ManaCostsImpl("{2}{U}") + new CastFromHandForFreeEffect(filter), new ManaCostsImpl<>("{2}{U}") ); ability.addCost(new TapSourceCost()); this.addAbility(ability); @@ -55,65 +48,3 @@ public final class OmnispellAdept extends CardImpl { return new OmnispellAdept(this); } } - -class OmnispellAdeptEffect extends OneShotEffect { - - private static final FilterCard filter = new FilterInstantOrSorceryCard( - "instant or sorcery card from your hand"); - - public OmnispellAdeptEffect() { - super(Outcome.PlayForFree); - this.staticText = "you may cast an instant or sorcery card from your hand " - + "without paying its mana cost"; - } - - public OmnispellAdeptEffect(final OmnispellAdeptEffect effect) { - super(effect); - } - - @Override - public OmnispellAdeptEffect copy() { - return new OmnispellAdeptEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - FilterCard realFilter = filter.copy(); - Target target = new TargetCardInHand(realFilter); - // choose one card until it possible to cast - if (target.canChoose(source.getSourceId(), controller.getId(), game) - && controller.chooseUse(Outcome.PlayForFree, "Cast an instant or sorcery " - + "card from your hand without paying its mana cost?", source, game)) { - Card cardToCast; - while (controller.canRespond() - && controller.chooseTarget(Outcome.PlayForFree, target, source, game)) { - cardToCast = game.getCard(target.getFirstTarget()); - if (cardToCast == null) { - break; - } - realFilter.add(Predicates.not(new CardIdPredicate(cardToCast.getId()))); // remove card from choose dialog (infinite fix) - - if (!cardToCast.getSpellAbility().canChooseTarget(game, controller.getId())) { - continue; - } - - game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(cardToCast, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), null); - - if (cardWasCast) { - break; - } else { - game.informPlayer(controller, "You're not able to cast " - + cardToCast.getIdName() + " or you canceled the casting."); - } - } - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/o/OnceUponATime.java b/Mage.Sets/src/mage/cards/o/OnceUponATime.java index 52ef52fb3b8..041e220c258 100644 --- a/Mage.Sets/src/mage/cards/o/OnceUponATime.java +++ b/Mage.Sets/src/mage/cards/o/OnceUponATime.java @@ -3,15 +3,13 @@ package mage.cards.o; import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.costs.AlternativeCostSourceAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.WatcherScope; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.watchers.Watcher; @@ -25,15 +23,6 @@ import java.util.UUID; */ public final class OnceUponATime extends CardImpl { - private static final FilterCard filter = new FilterCard("a creature or land card"); - - static { - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.LAND.getPredicate() - )); - } - public OnceUponATime(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); @@ -45,13 +34,7 @@ public final class OnceUponATime extends CardImpl { // Look at the top five cards of your library. You may reveal a creature or land card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), filter, - Zone.LIBRARY, false, true, false, Zone.HAND, - true, false, false - ).setBackInRandomOrder(true).setText("Look at the top five cards of your library. " + - "You may reveal a creature or land card from among them and put it into your hand. " + - "Put the rest on the bottom of your library in a random order." - )); + 5, 1, StaticFilters.FILTER_CARD_CREATURE_OR_LAND, PutCards.HAND, PutCards.BOTTOM_RANDOM)); } private OnceUponATime(final OnceUponATime card) { diff --git a/Mage.Sets/src/mage/cards/o/OnduCleric.java b/Mage.Sets/src/mage/cards/o/OnduCleric.java index 76d9878aff1..9c0069c83d7 100644 --- a/Mage.Sets/src/mage/cards/o/OnduCleric.java +++ b/Mage.Sets/src/mage/cards/o/OnduCleric.java @@ -35,7 +35,7 @@ public final class OnduCleric extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new GainLifeEffect(new PermanentsOnBattlefieldCount(filter)), true)); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new GainLifeEffect(new PermanentsOnBattlefieldCount(filter)), true).setAbilityWord(null)); } private OnduCleric(final OnduCleric card) { diff --git a/Mage.Sets/src/mage/cards/o/OneDozenEyes.java b/Mage.Sets/src/mage/cards/o/OneDozenEyes.java index 6f095f5e18e..ca8abe5e624 100644 --- a/Mage.Sets/src/mage/cards/o/OneDozenEyes.java +++ b/Mage.Sets/src/mage/cards/o/OneDozenEyes.java @@ -26,8 +26,7 @@ public final class OneDozenEyes extends CardImpl { // Create a 5/5 green Beast creature token; this.getSpellAbility().addEffect(new CreateTokenEffect(new OneDozenEyesBeastToken())); // or create five 1/1 green Insect creature tokens. - Mode mode = new Mode(); - mode.addEffect(new CreateTokenEffect(new InsectToken(), 5)); + Mode mode = new Mode(new CreateTokenEffect(new InsectToken(), 5)); this.getSpellAbility().addMode(mode); // Entwine {G}{G}{G} this.addAbility(new EntwineAbility("{G}{G}{G}")); diff --git a/Mage.Sets/src/mage/cards/o/OneWithTheKami.java b/Mage.Sets/src/mage/cards/o/OneWithTheKami.java new file mode 100644 index 00000000000..b8b699132e9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OneWithTheKami.java @@ -0,0 +1,92 @@ +package mage.cards.o; + +import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.ModifiedPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.SpiritToken; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OneWithTheKami extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("enchanted creature or another modified creature you control"); + + static { + filter.add(ModifiedPredicate.instance); + } + + public OneWithTheKami(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); + + this.subtype.add(SubType.AURA); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Enchant creature you control + TargetPermanent auraTarget = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_CREATURE); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // Whenever enchanted creature or another modified creature you control dies, create X 1/1 colorless Spirit creature tokens, where X is that creature's power. + this.addAbility(new DiesCreatureTriggeredAbility(new CreateTokenEffect( + new SpiritToken(), OneWithTheKamiValue.instance + ), false, filter)); + } + + private OneWithTheKami(final OneWithTheKami card) { + super(card); + } + + @Override + public OneWithTheKami copy() { + return new OneWithTheKami(this); + } +} + +enum OneWithTheKamiValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Permanent permanent = (Permanent) effect.getValue("creatureDied"); + return permanent != null ? permanent.getPower().getValue() : 0; + } + + @Override + public OneWithTheKamiValue copy() { + return this; + } + + @Override + public String getMessage() { + return "that creature's power"; + } + + @Override + public String toString() { + return "X"; + } +} diff --git a/Mage.Sets/src/mage/cards/o/OngoingInvestigation.java b/Mage.Sets/src/mage/cards/o/OngoingInvestigation.java index 3b9c1214980..d11567603b0 100644 --- a/Mage.Sets/src/mage/cards/o/OngoingInvestigation.java +++ b/Mage.Sets/src/mage/cards/o/OngoingInvestigation.java @@ -3,7 +3,7 @@ package mage.cards.o; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.ControlledCreaturesDealCombatDamagePlayerTriggeredAbility; +import mage.abilities.common.DealCombatDamageControlledTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.ExileFromGraveCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -26,7 +26,7 @@ public final class OngoingInvestigation extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); // Whenever one or more creatures you control deal combat damage to a player, investigate. - this.addAbility(new ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(new InvestigateEffect())); + this.addAbility(new DealCombatDamageControlledTriggeredAbility(new InvestigateEffect())); // {1}{G}, Exile a creature card from your graveyard: Investigate. You gain 2 life. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new InvestigateEffect(), new ManaCostsImpl("{1}{G}")); diff --git a/Mage.Sets/src/mage/cards/o/OozeGarden.java b/Mage.Sets/src/mage/cards/o/OozeGarden.java index 8444d4d2bb1..6dc7166349a 100644 --- a/Mage.Sets/src/mage/cards/o/OozeGarden.java +++ b/Mage.Sets/src/mage/cards/o/OozeGarden.java @@ -92,7 +92,7 @@ class OozeToken extends TokenImpl { } public OozeToken(int x) { - super("Ooze", "X/X green Ooze creature token, where X is the sacrificed creature's power"); + super("Ooze Token", "X/X green Ooze creature token, where X is the sacrificed creature's power"); this.cardType.add(CardType.CREATURE); this.color.addColor(ObjectColor.GREEN); this.subtype.add(SubType.OOZE); diff --git a/Mage.Sets/src/mage/cards/o/OpalEyeKondasYojimbo.java b/Mage.Sets/src/mage/cards/o/OpalEyeKondasYojimbo.java index 012724a3cc6..82f581e8fcb 100644 --- a/Mage.Sets/src/mage/cards/o/OpalEyeKondasYojimbo.java +++ b/Mage.Sets/src/mage/cards/o/OpalEyeKondasYojimbo.java @@ -77,7 +77,7 @@ class OpalEyeKondasYojimboRedirectionEffect extends ReplacementEffectImpl { @Override public void init(Ability source, Game game) { - this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); super.init(source, game); } diff --git a/Mage.Sets/src/mage/cards/o/Opalescence.java b/Mage.Sets/src/mage/cards/o/Opalescence.java index 633f335bc21..8c8cf57b5c2 100644 --- a/Mage.Sets/src/mage/cards/o/Opalescence.java +++ b/Mage.Sets/src/mage/cards/o/Opalescence.java @@ -71,7 +71,7 @@ public final class Opalescence extends CardImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, - source.getControllerId(), source.getSourceId(), game)) { + source.getControllerId(), source, game)) { switch (layer) { case TypeChangingEffects_4: if (sublayer == SubLayer.NA) { diff --git a/Mage.Sets/src/mage/cards/o/OpalineSliver.java b/Mage.Sets/src/mage/cards/o/OpalineSliver.java index ae353054e00..fe1762b8427 100644 --- a/Mage.Sets/src/mage/cards/o/OpalineSliver.java +++ b/Mage.Sets/src/mage/cards/o/OpalineSliver.java @@ -14,11 +14,9 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterPermanent; -import mage.filter.FilterSpell; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.stack.StackObject; /** @@ -84,7 +82,7 @@ class OpalineSliverTriggeredAbility extends TriggeredAbilityImpl { } else { return event.getTargetId().equals(this.getSourceId()) && game.getOpponents(this.controllerId).contains(event.getPlayerId()) - && StaticFilters.FILTER_SPELL_A.match(spell, getSourceId(), getControllerId(), game); + && StaticFilters.FILTER_SPELL_A.match(spell, getControllerId(), this, game); } } diff --git a/Mage.Sets/src/mage/cards/o/OpenTheOmenpaths.java b/Mage.Sets/src/mage/cards/o/OpenTheOmenpaths.java index 3b72e24161f..f4fce2bcd96 100644 --- a/Mage.Sets/src/mage/cards/o/OpenTheOmenpaths.java +++ b/Mage.Sets/src/mage/cards/o/OpenTheOmenpaths.java @@ -87,7 +87,7 @@ class OpenTheOmenpathsCondition extends ManaCondition implements Condition { if (!(source instanceof SpellAbility)) { return false; } - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && (object.isCreature(game) || object.isEnchantment(game)); } diff --git a/Mage.Sets/src/mage/cards/o/Oppression.java b/Mage.Sets/src/mage/cards/o/Oppression.java index b1b169bd65b..01cb9f8e186 100644 --- a/Mage.Sets/src/mage/cards/o/Oppression.java +++ b/Mage.Sets/src/mage/cards/o/Oppression.java @@ -49,7 +49,7 @@ class OppressionTriggeredAbility extends SpellCastAllTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.SPELL_CAST) { Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null && filter.match(spell, getSourceId(), getControllerId(), game)) { + if (spell != null && filter.match(spell, getControllerId(), this, game)) { this.getEffects().get(0).setTargetPointer(new FixedTarget(event.getPlayerId())); return true; } diff --git a/Mage.Sets/src/mage/cards/o/OppressiveWill.java b/Mage.Sets/src/mage/cards/o/OppressiveWill.java index f242e56bb24..73a6bcb5a18 100644 --- a/Mage.Sets/src/mage/cards/o/OppressiveWill.java +++ b/Mage.Sets/src/mage/cards/o/OppressiveWill.java @@ -58,7 +58,7 @@ class SpellSyphonEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { StackObject spell = game.getStack().getStackObject(targetPointer.getFirst(game, source)); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && spell != null) { Player player = game.getPlayer(spell.getControllerId()); Player controller = game.getPlayer(source.getControllerId()); diff --git a/Mage.Sets/src/mage/cards/o/OracleEnVec.java b/Mage.Sets/src/mage/cards/o/OracleEnVec.java index 2a4658c0f3a..85c3d420b2b 100644 --- a/Mage.Sets/src/mage/cards/o/OracleEnVec.java +++ b/Mage.Sets/src/mage/cards/o/OracleEnVec.java @@ -85,8 +85,8 @@ class OracleEnVecEffect extends OneShotEffect { Player opponent = game.getPlayer(this.getTargetPointer().getFirst(game, source)); if (opponent != null) { Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, new FilterControlledCreaturePermanent(), true); - if (target.choose(Outcome.Neutral, opponent.getId(), source.getSourceId(), game)) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), opponent.getId(), source.getSourceId(), game)) { + if (target.choose(Outcome.Neutral, opponent.getId(), source.getSourceId(), source, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), opponent.getId(), source, game)) { if (target.getTargets().contains(permanent.getId())) { RequirementEffect effect = new OracleEnVecMustAttackRequirementEffect(); effect.setTargetPointer(new FixedTarget(permanent, game)); diff --git a/Mage.Sets/src/mage/cards/o/OracleOfBones.java b/Mage.Sets/src/mage/cards/o/OracleOfBones.java index e101d727b32..595d90c4739 100644 --- a/Mage.Sets/src/mage/cards/o/OracleOfBones.java +++ b/Mage.Sets/src/mage/cards/o/OracleOfBones.java @@ -1,31 +1,21 @@ package mage.cards.o; -import java.util.UUID; -import mage.ApprovingObject; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.TributeNotPaidCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.cost.CastFromHandForFreeEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.TributeAbility; -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.filter.FilterCard; -import mage.filter.common.FilterInstantOrSorceryCard; -import mage.game.Game; -import mage.players.Player; -import mage.target.Target; -import mage.target.common.TargetCardInHand; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class OracleOfBones extends CardImpl { @@ -44,10 +34,14 @@ public final class OracleOfBones extends CardImpl { this.addAbility(new TributeAbility(2)); // When Oracle of Bones enters the battlefield, if tribute wasn't paid, // you may cast an instant or sorcery card from your hand without paying its mana cost. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new OracleOfBonesCastEffect(), false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, TributeNotPaidCondition.instance, - "When {this} enters the battlefield, if its tribute wasn't paid, " - + "you may cast an instant or sorcery card from your hand without paying its mana cost.")); + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new CastFromHandForFreeEffect( + StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY + ), false), + TributeNotPaidCondition.instance, "When {this} enters the battlefield, " + + "if its tribute wasn't paid, you may cast an instant or " + + "sorcery spell from your hand without paying its mana cost." + )); } private OracleOfBones(final OracleOfBones card) { @@ -59,58 +53,3 @@ public final class OracleOfBones extends CardImpl { return new OracleOfBones(this); } } - -class OracleOfBonesCastEffect extends OneShotEffect { - - private static final FilterCard filter = new FilterInstantOrSorceryCard( - "instant or sorcery card from your hand"); - - public OracleOfBonesCastEffect() { - super(Outcome.PlayForFree); - this.staticText = "you may cast an instant or sorcery card " - + "from your hand without paying its mana cost"; - } - - public OracleOfBonesCastEffect(final OracleOfBonesCastEffect effect) { - super(effect); - } - - @Override - public OracleOfBonesCastEffect copy() { - return new OracleOfBonesCastEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Target target = new TargetCardInHand(filter); - if (target.canChoose(source.getSourceId(), controller.getId(), game) - && controller.chooseUse(outcome, "Cast an instant or sorcery " - + "card from your hand without paying its mana cost?", source, game)) { - Card cardToCast = null; - boolean cancel = false; - while (controller.canRespond() - && !cancel) { - if (controller.chooseTarget(outcome, target, source, game)) { - cardToCast = game.getCard(target.getFirstTarget()); - if (cardToCast != null - && cardToCast.getSpellAbility().canChooseTarget(game, controller.getId())) { - cancel = true; - } - } else { - cancel = true; - } - } - if (cardToCast != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(cardToCast, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), null); - } - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/o/OraclesAttendants.java b/Mage.Sets/src/mage/cards/o/OraclesAttendants.java index b0dca23a9e7..68247da7cf3 100644 --- a/Mage.Sets/src/mage/cards/o/OraclesAttendants.java +++ b/Mage.Sets/src/mage/cards/o/OraclesAttendants.java @@ -74,7 +74,7 @@ class OraclesAttendantsReplacementEffect extends ReplacementEffectImpl { @Override public void init(Ability source, Game game) { - this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/o/OranRiefSurvivalist.java b/Mage.Sets/src/mage/cards/o/OranRiefSurvivalist.java index 3cf336dfe83..4ca05bfee6b 100644 --- a/Mage.Sets/src/mage/cards/o/OranRiefSurvivalist.java +++ b/Mage.Sets/src/mage/cards/o/OranRiefSurvivalist.java @@ -26,7 +26,7 @@ public final class OranRiefSurvivalist extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true)); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true).setAbilityWord(null)); } private OranRiefSurvivalist(final OranRiefSurvivalist card) { diff --git a/Mage.Sets/src/mage/cards/o/OrbOfDragonkind.java b/Mage.Sets/src/mage/cards/o/OrbOfDragonkind.java index 54f38b0d2d0..089f8a0ae62 100644 --- a/Mage.Sets/src/mage/cards/o/OrbOfDragonkind.java +++ b/Mage.Sets/src/mage/cards/o/OrbOfDragonkind.java @@ -9,16 +9,16 @@ import mage.abilities.condition.Condition; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.costs.mana.ColoredManaCost; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.mana.ConditionalAnyColorManaAbility; import mage.abilities.mana.builder.ConditionalManaBuilder; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; @@ -45,12 +45,9 @@ public final class OrbOfDragonkind extends CardImpl { // {R}, {T}, Sacrifice Orb of Dragonkind: Look at the top seven cards of your library. // You may reveal a Dragon card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. - ability = new SimpleActivatedAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(7), false, StaticValue.get(1), filter, - Zone.LIBRARY, false, true, false, Zone.HAND, - true, false, false).setBackInRandomOrder(true), - new ManaCostsImpl<>("{R}") - ); + ability = new SimpleActivatedAbility( + new LookLibraryAndPickControllerEffect(7, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM), + new ColoredManaCost(ColoredManaSymbol.R)); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); @@ -93,7 +90,7 @@ enum OrbOfDragonkindManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && object.hasSubtype(SubType.DRAGON, game); } } diff --git a/Mage.Sets/src/mage/cards/o/OrchardElemental.java b/Mage.Sets/src/mage/cards/o/OrchardElemental.java index adbb36ae999..4f687547f34 100644 --- a/Mage.Sets/src/mage/cards/o/OrchardElemental.java +++ b/Mage.Sets/src/mage/cards/o/OrchardElemental.java @@ -7,6 +7,7 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.choices.TwoChoiceVote; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; @@ -32,7 +33,7 @@ public final class OrchardElemental extends CardImpl { // Council's dilemma &mdash When Orchard Elemental enters the battlefield, starting with you, each player votes for sprout or harvest. Put two +1/+1 counters on Orchard Elemental for each sprout vote. You gain 3 life for each harvest vote. this.addAbility(new EntersBattlefieldTriggeredAbility( new OrchardElementalEffect(), false) - .withFlavorWord("Council's dilemma") + .setAbilityWord(AbilityWord.COUNCILS_DILEMMA) ); } diff --git a/Mage.Sets/src/mage/cards/o/OrcishCannonade.java b/Mage.Sets/src/mage/cards/o/OrcishCannonade.java index f83d0fe652c..fe965ea9193 100644 --- a/Mage.Sets/src/mage/cards/o/OrcishCannonade.java +++ b/Mage.Sets/src/mage/cards/o/OrcishCannonade.java @@ -27,7 +27,7 @@ public final class OrcishCannonade extends CardImpl { effect.setText("and 3 damage to you"); this.getSpellAbility().addEffect(effect); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private OrcishCannonade(final OrcishCannonade card) { diff --git a/Mage.Sets/src/mage/cards/o/OrcishSettlers.java b/Mage.Sets/src/mage/cards/o/OrcishSettlers.java index 086060c93d2..4bbdbeaacbd 100644 --- a/Mage.Sets/src/mage/cards/o/OrcishSettlers.java +++ b/Mage.Sets/src/mage/cards/o/OrcishSettlers.java @@ -77,8 +77,8 @@ class OrcishSettlersEffect extends OneShotEffect { TargetLandPermanent target = new TargetLandPermanent(amount); Player controller = game.getPlayer(source.getControllerId()); if (controller != null - && target.canChoose(source.getSourceId(), controller.getId(), game) - && controller.choose(Outcome.DestroyPermanent, target, source.getSourceId(), game)) { + && target.canChoose(controller.getId(), source, game) + && controller.choose(Outcome.DestroyPermanent, target, source, game)) { List targets = target.getTargets(); targets.forEach((landId) -> { Permanent land = game.getPermanent(landId); diff --git a/Mage.Sets/src/mage/cards/o/OrcusPrinceOfUndeath.java b/Mage.Sets/src/mage/cards/o/OrcusPrinceOfUndeath.java index 4c5fc0b3583..9af8435040b 100644 --- a/Mage.Sets/src/mage/cards/o/OrcusPrinceOfUndeath.java +++ b/Mage.Sets/src/mage/cards/o/OrcusPrinceOfUndeath.java @@ -117,7 +117,7 @@ class OrcusPrinceOfUndeathTarget extends TargetCardInYourGraveyard { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); int maxManaValue = this.xValue; for (UUID targetId : this.getTargets()) { @@ -126,7 +126,7 @@ class OrcusPrinceOfUndeathTarget extends TargetCardInYourGraveyard { maxManaValue -= card.getManaValue(); } } - for (UUID possibleTargetId : super.possibleTargets(sourceId, sourceControllerId, game)) { + for (UUID possibleTargetId : super.possibleTargets(sourceControllerId, source, game)) { Card card = game.getCard(possibleTargetId); if (card != null && card.getManaValue() <= maxManaValue) { possibleTargets.add(possibleTargetId); diff --git a/Mage.Sets/src/mage/cards/o/OrderOfSuccession.java b/Mage.Sets/src/mage/cards/o/OrderOfSuccession.java index 6534644522b..3d94f3a69f9 100644 --- a/Mage.Sets/src/mage/cards/o/OrderOfSuccession.java +++ b/Mage.Sets/src/mage/cards/o/OrderOfSuccession.java @@ -100,7 +100,7 @@ class OrderOfSuccessionEffect extends OneShotEffect { filter.add(new ControllerIdPredicate(nextPlayer.getId())); Target target = new TargetCreaturePermanent(filter); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), currentPlayer.getId(), game)) { + if (target.canChoose(currentPlayer.getId(), source, game)) { if (currentPlayer.chooseTarget(outcome, target, source, game)) { playerCreature.put(currentPlayer.getId(), target.getFirstTarget()); } diff --git a/Mage.Sets/src/mage/cards/o/OrderedMigration.java b/Mage.Sets/src/mage/cards/o/OrderedMigration.java index 9076afaa5c1..0e704ee790a 100644 --- a/Mage.Sets/src/mage/cards/o/OrderedMigration.java +++ b/Mage.Sets/src/mage/cards/o/OrderedMigration.java @@ -1,4 +1,3 @@ - package mage.cards.o; import java.util.UUID; @@ -9,7 +8,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.game.permanent.token.OrderedMigrationBirdToken; +import mage.game.permanent.token.BlueBirdToken; /** * @@ -22,7 +21,7 @@ public final class OrderedMigration extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{W}{U}"); // Domain - Create a 1/1 blue Bird creature token with flying for each basic land type among lands you control. - this.getSpellAbility().addEffect(new CreateTokenEffect(new OrderedMigrationBirdToken(), new DomainValue())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new BlueBirdToken(), DomainValue.REGULAR)); this.getSpellAbility().setAbilityWord(AbilityWord.DOMAIN); this.getSpellAbility().addHint(DomainHint.instance); } diff --git a/Mage.Sets/src/mage/cards/o/OrganHoarder.java b/Mage.Sets/src/mage/cards/o/OrganHoarder.java index e72aad0f934..02f6c9468bd 100644 --- a/Mage.Sets/src/mage/cards/o/OrganHoarder.java +++ b/Mage.Sets/src/mage/cards/o/OrganHoarder.java @@ -2,14 +2,12 @@ package mage.cards.o; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import java.util.UUID; @@ -27,8 +25,7 @@ public final class OrganHoarder extends CardImpl { // When Organ Hoarder enters the battlefield, look at the top three cards of your library, then put one of them into your hand and the rest into you graveyard. this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(3), false, StaticValue.get(1), StaticFilters.FILTER_CARD, - Zone.GRAVEYARD, false, false, false, Zone.HAND, false + 3, 1, PutCards.HAND, PutCards.GRAVEYARD ).setText("look at the top three cards of your library, then put one of them into your hand and the rest into your graveyard"))); } diff --git a/Mage.Sets/src/mage/cards/o/OrganicExtinction.java b/Mage.Sets/src/mage/cards/o/OrganicExtinction.java new file mode 100644 index 00000000000..b4464f0bfb3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OrganicExtinction.java @@ -0,0 +1,43 @@ +package mage.cards.o; + +import mage.abilities.effects.common.DestroyAllEffect; +import mage.abilities.keyword.ImproviseAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OrganicExtinction extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("nonartifact creatures"); + + static { + filter.add(Predicates.not(CardType.ARTIFACT.getPredicate())); + } + + public OrganicExtinction(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{8}{W}{W}"); + + // Improvise + this.addAbility(new ImproviseAbility()); + + // Destroy all nonartifact creatures. + this.getSpellAbility().addEffect(new DestroyAllEffect(filter)); + } + + private OrganicExtinction(final OrganicExtinction card) { + super(card); + } + + @Override + public OrganicExtinction copy() { + return new OrganicExtinction(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OrmosArchiveKeeper.java b/Mage.Sets/src/mage/cards/o/OrmosArchiveKeeper.java index a6d04407530..c7be77ddf48 100644 --- a/Mage.Sets/src/mage/cards/o/OrmosArchiveKeeper.java +++ b/Mage.Sets/src/mage/cards/o/OrmosArchiveKeeper.java @@ -130,8 +130,8 @@ class OrmosArchiveKeeperTarget extends TargetCardInHand { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set possibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); Set names = this.getTargets() .stream() .map(game::getCard) diff --git a/Mage.Sets/src/mage/cards/o/OrnateKanzashi.java b/Mage.Sets/src/mage/cards/o/OrnateKanzashi.java index 544fc9ed50d..85bc8afe8e8 100644 --- a/Mage.Sets/src/mage/cards/o/OrnateKanzashi.java +++ b/Mage.Sets/src/mage/cards/o/OrnateKanzashi.java @@ -72,7 +72,7 @@ class OrnateKanzashiEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player opponent = game.getPlayer(targetPointer.getFirst(game, source)); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && opponent != null) { if (opponent.getLibrary().hasCards()) { Library library = opponent.getLibrary(); diff --git a/Mage.Sets/src/mage/cards/o/Ornithopter.java b/Mage.Sets/src/mage/cards/o/Ornithopter.java index 9389184b2d1..227d67cbd54 100644 --- a/Mage.Sets/src/mage/cards/o/Ornithopter.java +++ b/Mage.Sets/src/mage/cards/o/Ornithopter.java @@ -17,7 +17,7 @@ import mage.constants.SubType; public final class Ornithopter extends CardImpl { public Ornithopter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE,CardType.ARTIFACT},"{0}"); + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{0}"); this.subtype.add(SubType.THOPTER); this.power = new MageInt(0); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/o/OrvarTheAllForm.java b/Mage.Sets/src/mage/cards/o/OrvarTheAllForm.java index 56f1772fe7a..061a70752e8 100644 --- a/Mage.Sets/src/mage/cards/o/OrvarTheAllForm.java +++ b/Mage.Sets/src/mage/cards/o/OrvarTheAllForm.java @@ -156,7 +156,7 @@ class OrvarTheAllFormEffect extends OneShotEffect { filter.add(Predicates.not(new MageObjectReferencePredicate(new MageObjectReference(source)))); TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); return new CreateTokenCopyTargetEffect() .setTargetPointer(new FixedTarget(target.getFirstTarget(), game)) .apply(game, source); diff --git a/Mage.Sets/src/mage/cards/o/OrzhovAdvokist.java b/Mage.Sets/src/mage/cards/o/OrzhovAdvokist.java index 6f58f1588aa..2c54bafed9c 100644 --- a/Mage.Sets/src/mage/cards/o/OrzhovAdvokist.java +++ b/Mage.Sets/src/mage/cards/o/OrzhovAdvokist.java @@ -84,7 +84,7 @@ class OrzhovAdvokistEffect extends OneShotEffect { if (player != null) { if (player.chooseUse(outcome, "Put two +1/+1 counters on a creature you control?", source, game)) { Target target = new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("a creature you control (to add two +1/+1 counters on it)")); - if (player.choose(outcome, target, playerId, game)) { + if (player.choose(outcome, target, source, game)) { creatures.add(target.getFirstTarget()); players.add(player.getId()); } diff --git a/Mage.Sets/src/mage/cards/o/OrzhovPontiff.java b/Mage.Sets/src/mage/cards/o/OrzhovPontiff.java index edc0af22d38..fbd720ad83b 100644 --- a/Mage.Sets/src/mage/cards/o/OrzhovPontiff.java +++ b/Mage.Sets/src/mage/cards/o/OrzhovPontiff.java @@ -39,8 +39,7 @@ public final class OrzhovPontiff extends CardImpl { // Haunt // When Orzhov Pontiff enters the battlefield or the creature it haunts dies, choose one - Creatures you control get +1/+1 until end of turn; or creatures you don't control get -1/-1 until end of turn. Ability ability = new HauntAbility(this, new BoostAllEffect(1,1, Duration.EndOfTurn, filterControlled, false)); - Mode mode = new Mode(); - mode.addEffect(new BoostAllEffect(-1,-1, Duration.EndOfTurn, filterNotControlled, false)); + Mode mode = new Mode(new BoostAllEffect(-1,-1, Duration.EndOfTurn, filterNotControlled, false)); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/o/OtawaraSoaringCity.java b/Mage.Sets/src/mage/cards/o/OtawaraSoaringCity.java index 5fe267e0fd2..fcb9ad463e7 100644 --- a/Mage.Sets/src/mage/cards/o/OtawaraSoaringCity.java +++ b/Mage.Sets/src/mage/cards/o/OtawaraSoaringCity.java @@ -46,7 +46,7 @@ public final class OtawaraSoaringCity extends CardImpl { ability.addEffect(new InfoEffect("This ability costs {1} less to activate for each legendary creature you control")); ability.addTarget(new TargetPermanent(filter)); ability.setCostAdjuster(LegendaryCreatureCostAdjuster.instance); - this.addAbility(ability); + this.addAbility(ability.addHint(LegendaryCreatureCostAdjuster.getHint())); } private OtawaraSoaringCity(final OtawaraSoaringCity card) { diff --git a/Mage.Sets/src/mage/cards/m/MikeTheDungeonMaster.java b/Mage.Sets/src/mage/cards/o/OthelmSigardianOutcast.java similarity index 87% rename from Mage.Sets/src/mage/cards/m/MikeTheDungeonMaster.java rename to Mage.Sets/src/mage/cards/o/OthelmSigardianOutcast.java index 44c5e11beda..362dfe73c08 100644 --- a/Mage.Sets/src/mage/cards/m/MikeTheDungeonMaster.java +++ b/Mage.Sets/src/mage/cards/o/OthelmSigardianOutcast.java @@ -1,4 +1,4 @@ -package mage.cards.m; +package mage.cards.o; import mage.MageInt; import mage.abilities.Ability; @@ -23,7 +23,7 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class MikeTheDungeonMaster extends CardImpl { +public final class OthelmSigardianOutcast extends CardImpl { private static final FilterCard filter = new FilterCreatureCard( "creature card in your graveyard that was put there from the battlefield this turn" @@ -33,7 +33,7 @@ public final class MikeTheDungeonMaster extends CardImpl { filter.add(PutIntoGraveFromBattlefieldThisTurnPredicate.instance); } - public MikeTheDungeonMaster(UUID ownerId, CardSetInfo setInfo) { + public OthelmSigardianOutcast(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}"); this.addSuperType(SuperType.LEGENDARY); @@ -57,12 +57,12 @@ public final class MikeTheDungeonMaster extends CardImpl { this.addAbility(FriendsForeverAbility.getInstance()); } - private MikeTheDungeonMaster(final MikeTheDungeonMaster card) { + private OthelmSigardianOutcast(final OthelmSigardianOutcast card) { super(card); } @Override - public MikeTheDungeonMaster copy() { - return new MikeTheDungeonMaster(this); + public OthelmSigardianOutcast copy() { + return new OthelmSigardianOutcast(this); } } diff --git a/Mage.Sets/src/mage/cards/o/OtherworldlyGaze.java b/Mage.Sets/src/mage/cards/o/OtherworldlyGaze.java index 687b1aa3ef5..7cbb0193113 100644 --- a/Mage.Sets/src/mage/cards/o/OtherworldlyGaze.java +++ b/Mage.Sets/src/mage/cards/o/OtherworldlyGaze.java @@ -1,14 +1,12 @@ package mage.cards.o; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.FlashbackAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import java.util.UUID; @@ -21,10 +19,7 @@ public final class OtherworldlyGaze extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); // Look at the top three cards of your library. Put any number of them into your graveyard and the rest back on top of your library in any order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(3), false, StaticValue.get(5), StaticFilters.FILTER_CARD_CARDS, - Zone.LIBRARY, true, false, true, Zone.GRAVEYARD, false - ).setText("look at the top three cards of your library. Put any number of them into your graveyard and the rest back on top of your library in any order")); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(3, Integer.MAX_VALUE, PutCards.GRAVEYARD, PutCards.TOP_ANY)); // Flashback {1}{U} this.addAbility(new FlashbackAbility(this, new ManaCostsImpl<>("{1}{U}"))); diff --git a/Mage.Sets/src/mage/cards/o/Oubliette.java b/Mage.Sets/src/mage/cards/o/Oubliette.java index 804776d4734..3de70b1b995 100644 --- a/Mage.Sets/src/mage/cards/o/Oubliette.java +++ b/Mage.Sets/src/mage/cards/o/Oubliette.java @@ -47,7 +47,7 @@ public final class Oubliette extends CardImpl { class OubliettePhaseOutEffect extends OneShotEffect { OubliettePhaseOutEffect() { - super(Outcome.Benefit); + super(Outcome.Detriment); staticText = "target creature phases out until {this} leaves the battlefield. " + "Tap that creature as it phases in this way."; } @@ -68,11 +68,12 @@ class OubliettePhaseOutEffect extends OneShotEffect { if (sourcePermanent == null || permanent == null) { return false; } + MageObjectReference mor = new MageObjectReference(permanent, game); - permanent.tap(source, game); permanent.phaseOut(game); game.addEffect(new OubliettePhasePreventEffect(mor), source); game.addDelayedTriggeredAbility(new OublietteDelayedTriggeredAbility(mor), source); + return true; } } @@ -136,13 +137,11 @@ class OublietteDelayedTriggeredAbility extends DelayedTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getTargetId().equals(this.getSourceId())) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD) { - return true; - } + if (!event.getTargetId().equals(this.getSourceId())) { + return false; } - return false; + + return ((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD; } } @@ -168,6 +167,12 @@ class OubliettePhaseInEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = mor.getPermanent(game); - return permanent != null && permanent.phaseIn(game); + if (permanent == null) { + return false; + } + + permanent.setTapped(true); // Used instead of .tap so that tapped triggered abilities don't trigger + + return permanent.phaseIn(game); } } diff --git a/Mage.Sets/src/mage/cards/o/OutOfTheWay.java b/Mage.Sets/src/mage/cards/o/OutOfTheWay.java new file mode 100644 index 00000000000..9441095c47a --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OutOfTheWay.java @@ -0,0 +1,63 @@ +package mage.cards.o; + +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceTargetsPermanentCondition; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OutOfTheWay extends CardImpl { + + private static final FilterPermanent filter + = new FilterPermanent("a green permanent"); + private static final FilterPermanent filter2 + = new FilterNonlandPermanent("nonland permanent an opponent controls"); + + static { + filter.add(new ColorPredicate(ObjectColor.GREEN)); + filter2.add(TargetController.OPPONENT.getControllerPredicate()); + } + + private static final Condition condition = new SourceTargetsPermanentCondition(filter); + + public OutOfTheWay(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}"); + + // This spell costs {2} less to cast if it targets a green permanent. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SpellCostReductionSourceEffect(2, condition).setCanWorksOnStackOnly(true) + ).setRuleAtTheTop(true)); + + // Return target nonland permanent an opponent controls to its owner's hand. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter2)); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); + } + + private OutOfTheWay(final OutOfTheWay card) { + super(card); + } + + @Override + public OutOfTheWay copy() { + return new OutOfTheWay(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OutOfTime.java b/Mage.Sets/src/mage/cards/o/OutOfTime.java index bc0bd0fca97..e28d782450b 100644 --- a/Mage.Sets/src/mage/cards/o/OutOfTime.java +++ b/Mage.Sets/src/mage/cards/o/OutOfTime.java @@ -72,7 +72,7 @@ class OutOfTimePhaseOutEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { List creatures = game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game); + StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game); int numCreatures = creatures.size(); if (numCreatures > 0) { Set creatureIds = new HashSet<>(numCreatures); diff --git a/Mage.Sets/src/mage/cards/o/Outbreak.java b/Mage.Sets/src/mage/cards/o/Outbreak.java index dbdfba0f03a..57f9b2294d3 100644 --- a/Mage.Sets/src/mage/cards/o/Outbreak.java +++ b/Mage.Sets/src/mage/cards/o/Outbreak.java @@ -67,7 +67,7 @@ class OutbreakEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Choice typeChoice = new ChoiceCreatureType(game.getObject(source.getSourceId())); + Choice typeChoice = new ChoiceCreatureType(game.getObject(source)); if (player != null && player.choose(outcome, typeChoice, game)) { game.informPlayers(player.getLogName() + " has chosen " + typeChoice.getChoice()); FilterCreaturePermanent filter = new FilterCreaturePermanent("All creatures of the chosen type"); diff --git a/Mage.Sets/src/mage/cards/o/OutrageShaman.java b/Mage.Sets/src/mage/cards/o/OutrageShaman.java index cd3cb957014..fee429e60e7 100644 --- a/Mage.Sets/src/mage/cards/o/OutrageShaman.java +++ b/Mage.Sets/src/mage/cards/o/OutrageShaman.java @@ -10,6 +10,7 @@ import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.hint.ValueHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.ManaType; import mage.constants.SubType; @@ -36,7 +37,7 @@ public final class OutrageShaman extends CardImpl { effect.setText("it deals damage to target creature equal to the number of red mana symbols in the mana costs of permanents you control"); Ability ability = new EntersBattlefieldTriggeredAbility(effect, false); ability.addTarget(new TargetCreaturePermanent()); - ability.withFlavorWord("Chroma"); + ability.setAbilityWord(AbilityWord.CHROMA); ability.addHint(new ValueHint("Red mana symbols in your permanents", xValue)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/o/Outwit.java b/Mage.Sets/src/mage/cards/o/Outwit.java index 0c9d7feb4c4..5d149df7767 100644 --- a/Mage.Sets/src/mage/cards/o/Outwit.java +++ b/Mage.Sets/src/mage/cards/o/Outwit.java @@ -78,12 +78,12 @@ public final class Outwit extends CardImpl { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { return canChoose(sourceControllerId, game); } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { return possibleTargets(sourceControllerId, game); } diff --git a/Mage.Sets/src/mage/cards/o/OvalchaseDaredevil.java b/Mage.Sets/src/mage/cards/o/OvalchaseDaredevil.java index 0d8275d6092..f6b336afc4d 100644 --- a/Mage.Sets/src/mage/cards/o/OvalchaseDaredevil.java +++ b/Mage.Sets/src/mage/cards/o/OvalchaseDaredevil.java @@ -1,22 +1,17 @@ - package mage.cards.o; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SetTargetPointer; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterArtifactPermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class OvalchaseDaredevil extends CardImpl { @@ -35,7 +30,10 @@ public final class OvalchaseDaredevil extends CardImpl { this.toughness = new MageInt(2); // Whenever an artifact enters the battlefield under your control, you may return Ovalchase Daredevil from your graveyard to your hand. - this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.GRAVEYARD, new ReturnToHandSourceEffect(), filter, true, SetTargetPointer.NONE, null, true)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), filter, + true, SetTargetPointer.NONE, null, true + )); } private OvalchaseDaredevil(final OvalchaseDaredevil card) { diff --git a/Mage.Sets/src/mage/cards/o/OverbeingOfMyth.java b/Mage.Sets/src/mage/cards/o/OverbeingOfMyth.java index f5ab080f9fd..4f4a10b7e50 100644 --- a/Mage.Sets/src/mage/cards/o/OverbeingOfMyth.java +++ b/Mage.Sets/src/mage/cards/o/OverbeingOfMyth.java @@ -37,7 +37,7 @@ public final class OverbeingOfMyth extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(number, Duration.EndOfGame))); // 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)); } diff --git a/Mage.Sets/src/mage/cards/o/Overmaster.java b/Mage.Sets/src/mage/cards/o/Overmaster.java index 0dd8c73c6c2..e25de75cc66 100644 --- a/Mage.Sets/src/mage/cards/o/Overmaster.java +++ b/Mage.Sets/src/mage/cards/o/Overmaster.java @@ -80,7 +80,7 @@ class OvermasterEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null) { return "This spell can't be countered (" + sourceObject.getName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/o/OverrideCard.java b/Mage.Sets/src/mage/cards/o/OverrideCard.java index 6da4a194b31..26d9400ea31 100644 --- a/Mage.Sets/src/mage/cards/o/OverrideCard.java +++ b/Mage.Sets/src/mage/cards/o/OverrideCard.java @@ -59,7 +59,7 @@ class OverrideEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { StackObject spell = game.getStack().getStackObject(targetPointer.getFirst(game, source)); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && spell != null) { Player player = game.getPlayer(spell.getControllerId()); Player controller = game.getPlayer(source.getControllerId()); diff --git a/Mage.Sets/src/mage/cards/o/Oversimplify.java b/Mage.Sets/src/mage/cards/o/Oversimplify.java index 0c4c2a03ee8..c787abafc07 100644 --- a/Mage.Sets/src/mage/cards/o/Oversimplify.java +++ b/Mage.Sets/src/mage/cards/o/Oversimplify.java @@ -71,7 +71,7 @@ class OversimplifyEffect extends OneShotEffect { } List permanents = game.getBattlefield().getActivePermanents( StaticFilters.FILTER_PERMANENT_CREATURE, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game ); Map playerMap = permanents .stream() diff --git a/Mage.Sets/src/mage/cards/o/OverwhelmingSplendor.java b/Mage.Sets/src/mage/cards/o/OverwhelmingSplendor.java index 6669b410532..75303eba78f 100644 --- a/Mage.Sets/src/mage/cards/o/OverwhelmingSplendor.java +++ b/Mage.Sets/src/mage/cards/o/OverwhelmingSplendor.java @@ -139,7 +139,7 @@ class OverwhelmingSplendorCantActivateEffect extends ContinuousRuleModifyingEffe @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't activate abilities that aren't mana abilities or loyalty abilities (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/p/PacksDisdain.java b/Mage.Sets/src/mage/cards/p/PacksDisdain.java index 176e990b421..5ac2813ae6f 100644 --- a/Mage.Sets/src/mage/cards/p/PacksDisdain.java +++ b/Mage.Sets/src/mage/cards/p/PacksDisdain.java @@ -64,7 +64,7 @@ class PacksDisdainEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Choice typeChoice = new ChoiceCreatureType(game.getObject(source.getSourceId())); + Choice typeChoice = new ChoiceCreatureType(game.getObject(source)); if (player != null && player.choose(Outcome.UnboostCreature, typeChoice, game)) { FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); diff --git a/Mage.Sets/src/mage/cards/p/PactOfTheSerpent.java b/Mage.Sets/src/mage/cards/p/PactOfTheSerpent.java index dcaed81c8f3..e434fa6abac 100644 --- a/Mage.Sets/src/mage/cards/p/PactOfTheSerpent.java +++ b/Mage.Sets/src/mage/cards/p/PactOfTheSerpent.java @@ -69,7 +69,7 @@ class PactOfTheSerpentEffect extends OneShotEffect { if (player == null) { return false; } - int permCount = game.getBattlefield().count(filter, source.getSourceId(), player.getId(), game); + int permCount = game.getBattlefield().count(filter, player.getId(), source, game); if (permCount > 0) { player.drawCards(permCount, source, game); player.loseLife(permCount, game, source, false); diff --git a/Mage.Sets/src/mage/cards/p/PadeemConsulOfInnovation.java b/Mage.Sets/src/mage/cards/p/PadeemConsulOfInnovation.java index 61bdbaf9c56..5811908ffe7 100644 --- a/Mage.Sets/src/mage/cards/p/PadeemConsulOfInnovation.java +++ b/Mage.Sets/src/mage/cards/p/PadeemConsulOfInnovation.java @@ -35,7 +35,7 @@ public final class PadeemConsulOfInnovation extends CardImpl { // Artifacts you control have hexproof. this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( HexproofAbility.getInstance(), Duration.WhileOnBattlefield, - StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACTS, false + StaticFilters.FILTER_PERMANENT_ARTIFACTS, false ))); // At the beginning of your upkeep, if you control the artifact with the highest converted mana cost or tied for the highest converted mana cost, draw a card. diff --git a/Mage.Sets/src/mage/cards/p/PaladinOfPrahv.java b/Mage.Sets/src/mage/cards/p/PaladinOfPrahv.java index 83773fbae30..ff3bb29742c 100644 --- a/Mage.Sets/src/mage/cards/p/PaladinOfPrahv.java +++ b/Mage.Sets/src/mage/cards/p/PaladinOfPrahv.java @@ -7,20 +7,19 @@ import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.DealsDamageGainLifeSourceTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.keyword.ForecastAbility; 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.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetCreaturePermanent; /** @@ -59,13 +58,12 @@ public final class PaladinOfPrahv extends CardImpl { class PaladinOfPrahvTriggeredAbility extends DelayedTriggeredAbility { public PaladinOfPrahvTriggeredAbility() { - super(new PaladinOfPrahvEffect(), Duration.EndOfTurn, false); + super(new GainLifeEffect(SavedDamageValue.MUCH), Duration.EndOfTurn, false); } - + public PaladinOfPrahvTriggeredAbility(final PaladinOfPrahvTriggeredAbility ability) { super(ability); } - @Override public PaladinOfPrahvTriggeredAbility copy() { @@ -93,40 +91,9 @@ class PaladinOfPrahvTriggeredAbility extends DelayedTriggeredAbility { } return false; } - + @Override public String getTriggerPhrase() { return "Whenever target creature deals damage this turn, " ; } } - -class PaladinOfPrahvEffect extends OneShotEffect { - - public PaladinOfPrahvEffect() { - super(Outcome.GainLife); - this.staticText = "you gain that much life"; - } - - public PaladinOfPrahvEffect(final PaladinOfPrahvEffect effect) { - super(effect); - } - - @Override - public PaladinOfPrahvEffect copy() { - return new PaladinOfPrahvEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - int amount = (Integer) getValue("damage"); - if (amount > 0) { - controller.gainLife(amount, game, source); - return true; - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/p/PalliationAccord.java b/Mage.Sets/src/mage/cards/p/PalliationAccord.java index 923d3d22ea2..908593c3fba 100644 --- a/Mage.Sets/src/mage/cards/p/PalliationAccord.java +++ b/Mage.Sets/src/mage/cards/p/PalliationAccord.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.abilities.common.BecomesTappedTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.RemoveCountersSourceCost; @@ -11,12 +9,12 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author fireshoes */ public final class PalliationAccord extends CardImpl { @@ -25,12 +23,16 @@ public final class PalliationAccord extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}{U}"); // Whenever a creature an opponent controls becomes tapped, put a shield counter on Palliation Accord. - this.addAbility(new BecomesTappedTriggeredAbility(new AddCountersSourceEffect(CounterType.SHIELD.createInstance()), false, StaticFilters.FILTER_OPPONENTS_PERMANENT_A_CREATURE)); + this.addAbility(new BecomesTappedTriggeredAbility( + new AddCountersSourceEffect(CounterType.PALLIATION.createInstance()), + false, StaticFilters.FILTER_OPPONENTS_PERMANENT_A_CREATURE + )); // Remove a shield counter from Palliation Accord: Prevent the next 1 damage that would be dealt to you this turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, + this.addAbility(new SimpleActivatedAbility( new PreventDamageToControllerEffect(Duration.EndOfTurn, 1), - new RemoveCountersSourceCost(CounterType.SHIELD.createInstance()))); + new RemoveCountersSourceCost(CounterType.PALLIATION.createInstance()) + )); } private PalliationAccord(final PalliationAccord card) { diff --git a/Mage.Sets/src/mage/cards/p/Pallimud.java b/Mage.Sets/src/mage/cards/p/Pallimud.java index 73d6beb69a5..9b75b84921c 100644 --- a/Mage.Sets/src/mage/cards/p/Pallimud.java +++ b/Mage.Sets/src/mage/cards/p/Pallimud.java @@ -63,7 +63,7 @@ class AnathemancerCount implements DynamicValue { FilterLandPermanent filter = new FilterLandPermanent("tapped lands the chosen player controls"); filter.add(TappedPredicate.TAPPED); filter.add(new ControllerIdPredicate(playerId)); - return game.getBattlefield().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + return game.getBattlefield().count(filter, sourceAbility.getControllerId(), sourceAbility, game); } } return 0; diff --git a/Mage.Sets/src/mage/cards/p/PanopticMirror.java b/Mage.Sets/src/mage/cards/p/PanopticMirror.java index 34e7bc91e81..8eace8b92cc 100644 --- a/Mage.Sets/src/mage/cards/p/PanopticMirror.java +++ b/Mage.Sets/src/mage/cards/p/PanopticMirror.java @@ -80,7 +80,7 @@ class PanopticMirrorExileEffect extends OneShotEffect { } TargetCardInHand target = new TargetCardInHand(filter); - if (player.choose(Outcome.PlayForFree, target, source.getSourceId(), game)) { + if (player.choose(Outcome.PlayForFree, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { card.moveToExile(CardUtil.getCardExileZoneId(game, source), "Panoptic Mirror", source, game); diff --git a/Mage.Sets/src/mage/cards/p/ParadisePlume.java b/Mage.Sets/src/mage/cards/p/ParadisePlume.java index 38f7d0347b2..110f069faba 100644 --- a/Mage.Sets/src/mage/cards/p/ParadisePlume.java +++ b/Mage.Sets/src/mage/cards/p/ParadisePlume.java @@ -74,7 +74,7 @@ class ParadisePlumeSpellCastTriggeredAbility extends TriggeredAbilityImpl { filter.add(new ColorPredicate(color)); Spell spell = game.getStack().getSpell(event.getTargetId()); return (spell != null - && filter.match(spell, getSourceId(), getControllerId(), game)); + && filter.match(spell, getControllerId(), this, game)); } return false; } diff --git a/Mage.Sets/src/mage/cards/p/ParadoxEngine.java b/Mage.Sets/src/mage/cards/p/ParadoxEngine.java index 7f0757b8684..f93b153a515 100644 --- a/Mage.Sets/src/mage/cards/p/ParadoxEngine.java +++ b/Mage.Sets/src/mage/cards/p/ParadoxEngine.java @@ -1,28 +1,31 @@ package mage.cards.p; -import java.util.UUID; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.common.UntapAllControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SuperType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterNonlandPermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class ParadoxEngine extends CardImpl { + private static final FilterPermanent filter = new FilterNonlandPermanent("nonland permanents"); + public ParadoxEngine(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); this.addSuperType(SuperType.LEGENDARY); // Whenever you cast a spell, untap all nonland permanents you control. - this.addAbility(new SpellCastControllerTriggeredAbility(new UntapAllControllerEffect(new FilterNonlandPermanent()), false)); + this.addAbility(new SpellCastControllerTriggeredAbility(new UntapAllControllerEffect(filter), false)); } private ParadoxEngine(final ParadoxEngine card) { diff --git a/Mage.Sets/src/mage/cards/p/ParadoxHaze.java b/Mage.Sets/src/mage/cards/p/ParadoxHaze.java index 19885717afc..7ccf2f5db66 100644 --- a/Mage.Sets/src/mage/cards/p/ParadoxHaze.java +++ b/Mage.Sets/src/mage/cards/p/ParadoxHaze.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.OneShotEffect; @@ -9,29 +7,26 @@ import mage.abilities.effects.common.AttachEffect; 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.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.game.turn.TurnMod; import mage.game.turn.UpkeepStep; -import mage.players.Player; import mage.target.TargetPlayer; import mage.target.targetpointer.FixedTarget; -import mage.watchers.common.FirstTimeStepWatcher; +import mage.watchers.Watcher; + +import java.util.UUID; /** - * * @author emerald000 */ public final class ParadoxHaze extends CardImpl { public ParadoxHaze(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); this.subtype.add(SubType.AURA); // Enchant player @@ -41,7 +36,7 @@ public final class ParadoxHaze extends CardImpl { this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // At the beginning of enchanted player's first upkeep each turn, that player gets an additional upkeep step after this step. - this.addAbility(new ParadoxHazeTriggeredAbility(), new FirstTimeStepWatcher(EventType.UPKEEP_STEP_POST)); + this.addAbility(new ParadoxHazeTriggeredAbility(), new ParadoxHazeWatcher()); } private ParadoxHaze(final ParadoxHaze card) { @@ -60,7 +55,7 @@ class ParadoxHazeTriggeredAbility extends TriggeredAbilityImpl { super(Zone.BATTLEFIELD, new ParadoxHazeEffect(), false); } - ParadoxHazeTriggeredAbility(final ParadoxHazeTriggeredAbility ability) { + private ParadoxHazeTriggeredAbility(final ParadoxHazeTriggeredAbility ability) { super(ability); } @@ -77,17 +72,13 @@ class ParadoxHazeTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanent(getSourceId()); - if (permanent != null) { - Player player = game.getPlayer(permanent.getAttachedTo()); - if (player != null && game.isActivePlayer(player.getId())) { - FirstTimeStepWatcher watcher = game.getState().getWatcher(FirstTimeStepWatcher.class, EventType.UPKEEP_STEP_POST.toString()); - if (watcher != null && !watcher.conditionMet()) { - this.getEffects().get(0).setTargetPointer(new FixedTarget(player.getId())); - return true; - } - } + if (permanent == null + || !game.isActivePlayer(permanent.getAttachedTo()) + || game.getState().getWatcher(ParadoxHazeWatcher.class).conditionMet()) { + return false; } - return false; + this.getEffects().setTargetPointer(new FixedTarget(permanent.getAttachedTo())); + return true; } @Override @@ -103,7 +94,7 @@ class ParadoxHazeEffect extends OneShotEffect { this.staticText = "that player gets an additional upkeep step after this step"; } - ParadoxHazeEffect(final ParadoxHazeEffect effect) { + private ParadoxHazeEffect(final ParadoxHazeEffect effect) { super(effect); } @@ -118,3 +109,17 @@ class ParadoxHazeEffect extends OneShotEffect { return true; } } + +class ParadoxHazeWatcher extends Watcher { + + ParadoxHazeWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == EventType.UPKEEP_STEP_POST) { + condition = true; + } + } +} diff --git a/Mage.Sets/src/mage/cards/p/ParagonOfModernity.java b/Mage.Sets/src/mage/cards/p/ParagonOfModernity.java new file mode 100644 index 00000000000..4c5b681162d --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ParagonOfModernity.java @@ -0,0 +1,65 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.AddContinuousEffectToGame; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +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.counters.CounterType; +import mage.game.Game; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ParagonOfModernity extends CardImpl { + + public ParagonOfModernity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); + + this.subtype.add(SubType.ANGEL); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {3}: Paragon of Modernity gets +1/+1 until end of turn. If exactly three colors of mana were spent to activate this ability, put a +1/+1 counter on it instead. + this.addAbility(new SimpleActivatedAbility(new ConditionalOneShotEffect( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + new AddContinuousEffectToGame(new BoostSourceEffect(1, 1, Duration.EndOfTurn)), + ParagonOfModernityCondition.instance, "{this} gets +1/+1 until end of turn. If exactly three " + + "colors of mana were spent to activate this ability, put a +1/+1 counter on it instead" + ), new GenericManaCost(3))); + } + + private ParagonOfModernity(final ParagonOfModernity card) { + super(card); + } + + @Override + public ParagonOfModernity copy() { + return new ParagonOfModernity(this); + } +} + +enum ParagonOfModernityCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return source.getManaCostsToPay().getUsedManaToPay().getDifferentColors() == 3; + } +} diff --git a/Mage.Sets/src/mage/cards/p/Paralyze.java b/Mage.Sets/src/mage/cards/p/Paralyze.java index 08d23301f3d..781c9ac6ea7 100644 --- a/Mage.Sets/src/mage/cards/p/Paralyze.java +++ b/Mage.Sets/src/mage/cards/p/Paralyze.java @@ -18,6 +18,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; /** * @@ -81,6 +82,6 @@ class ParalyzeEffect extends DoIfCostPaid { @Override public String getText(Mode mode) { - return "that player may " + getCostText() + ". If they do, " + executingEffects.getText(mode); + return "that player may " + CardUtil.addCostVerb(cost.getText()) + ". If they do, " + executingEffects.getText(mode); } } diff --git a/Mage.Sets/src/mage/cards/p/Paraselene.java b/Mage.Sets/src/mage/cards/p/Paraselene.java index 457fe3ef54d..df4e7607f14 100644 --- a/Mage.Sets/src/mage/cards/p/Paraselene.java +++ b/Mage.Sets/src/mage/cards/p/Paraselene.java @@ -51,7 +51,7 @@ class ParaseleneEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int count = 0; - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_ENCHANTMENT, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_ENCHANTMENT, source.getControllerId(), source, game)) { if (permanent.destroy(source, game, false)) { count++; } diff --git a/Mage.Sets/src/mage/cards/p/ParasiticImpetus.java b/Mage.Sets/src/mage/cards/p/ParasiticImpetus.java index 9a0dad6d1e8..1967a6ffcc4 100644 --- a/Mage.Sets/src/mage/cards/p/ParasiticImpetus.java +++ b/Mage.Sets/src/mage/cards/p/ParasiticImpetus.java @@ -2,10 +2,11 @@ package mage.cards.p; import mage.abilities.Ability; import mage.abilities.common.AttacksAttachedTriggeredAbility; -import mage.abilities.common.GoadAttachedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeControllerAttachedEffect; +import mage.abilities.effects.common.combat.GoadAttachedEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; @@ -37,7 +38,9 @@ public final class ParasiticImpetus extends CardImpl { this.addAbility(ability); // Enchanted creature gets +2/+2 and is goaded. - this.addAbility(new GoadAttachedAbility(new BoostEnchantedEffect(2, 2))); + ability = new SimpleStaticAbility(new BoostEnchantedEffect(2, 2)); + ability.addEffect(new GoadAttachedEffect()); + this.addAbility(ability); // Whenever enchanted creature attacks, its controller loses 2 life and you gain 2 life. ability = new AttacksAttachedTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/p/Parch.java b/Mage.Sets/src/mage/cards/p/Parch.java index 8704166c1b3..ce4752cb4e9 100644 --- a/Mage.Sets/src/mage/cards/p/Parch.java +++ b/Mage.Sets/src/mage/cards/p/Parch.java @@ -32,8 +32,7 @@ public final class Parch extends CardImpl { // Choose one - Parch deals 2 damage to any target; or Parch deals 4 damage to target blue creature. this.getSpellAbility().addEffect(new DamageTargetEffect(2)); this.getSpellAbility().addTarget(new TargetAnyTarget()); - Mode mode = new Mode(); - mode.addEffect(new DamageTargetEffect(4)); + Mode mode = new Mode(new DamageTargetEffect(4)); mode.addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/p/PardicMiner.java b/Mage.Sets/src/mage/cards/p/PardicMiner.java index bfd991f3bc9..ed645495ec7 100644 --- a/Mage.Sets/src/mage/cards/p/PardicMiner.java +++ b/Mage.Sets/src/mage/cards/p/PardicMiner.java @@ -71,7 +71,7 @@ class PardicMinerEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't play lands this turn (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/p/ParkHeightsMaverick.java b/Mage.Sets/src/mage/cards/p/ParkHeightsMaverick.java new file mode 100644 index 00000000000..dcb5a76889a --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ParkHeightsMaverick.java @@ -0,0 +1,54 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.abilities.keyword.DauntAbility; +import mage.abilities.keyword.DethroneAbility; +import mage.abilities.meta.OrTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ParkHeightsMaverick extends CardImpl { + + public ParkHeightsMaverick(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Dethrone + this.addAbility(new DethroneAbility()); + + // Park Heights Maverick can't be blocked by creatures with power 2 or less. + this.addAbility(new DauntAbility()); + + // Whenever Park Heights Maverick deals combat damage to a player or dies, proliferate. + this.addAbility(new OrTriggeredAbility( + Zone.ALL, new ProliferateEffect(), false, + "Whenever {this} deals combat damage to a player or dies, ", + new DealsCombatDamageToAPlayerTriggeredAbility(null, false), + new DiesSourceTriggeredAbility(null, false) + )); + } + + private ParkHeightsMaverick(final ParkHeightsMaverick card) { + super(card); + } + + @Override + public ParkHeightsMaverick copy() { + return new ParkHeightsMaverick(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/ParkHeightsPegasus.java b/Mage.Sets/src/mage/cards/p/ParkHeightsPegasus.java new file mode 100644 index 00000000000..2a2cf3f9b74 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ParkHeightsPegasus.java @@ -0,0 +1,92 @@ +package mage.cards.p; + +import java.util.List; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.watchers.common.PermanentsEnteredBattlefieldWatcher; + +/** + * + * @author weirddan455 + */ +public final class ParkHeightsPegasus extends CardImpl { + + public ParkHeightsPegasus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}"); + + this.subtype.add(SubType.PEGASUS); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever Park Heights Pegasus deals combat damage to a player, draw a card if two or more creatures entered the battlefield under your control this turn. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new ParkHeightsPegasusEffect(), false), new PermanentsEnteredBattlefieldWatcher()); + } + + private ParkHeightsPegasus(final ParkHeightsPegasus card) { + super(card); + } + + @Override + public ParkHeightsPegasus copy() { + return new ParkHeightsPegasus(this); + } +} + +class ParkHeightsPegasusEffect extends OneShotEffect { + + public ParkHeightsPegasusEffect() { + super(Outcome.DrawCard); + this.staticText = "draw a card if you had two or more creatures enter the battlefield under your control this turn"; + } + + private ParkHeightsPegasusEffect(final ParkHeightsPegasusEffect effect) { + super(effect); + } + + @Override + public ParkHeightsPegasusEffect copy() { + return new ParkHeightsPegasusEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + PermanentsEnteredBattlefieldWatcher watcher = game.getState().getWatcher(PermanentsEnteredBattlefieldWatcher.class); + UUID controllerId = source.getControllerId(); + Player controller = game.getPlayer(controllerId); + if (watcher != null && controller != null) { + List permanents = watcher.getThisTurnEnteringPermanents(controllerId); + if (permanents != null) { + int creatures = 0; + for (Permanent permanent : permanents) { + if (permanent.isCreature(game)) { + creatures++; + if (creatures >= 2) { + controller.drawCards(1, source, game); + return true; + } + } + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PatchUp.java b/Mage.Sets/src/mage/cards/p/PatchUp.java new file mode 100644 index 00000000000..1055cf663d0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PatchUp.java @@ -0,0 +1,76 @@ +package mage.cards.p; + +import mage.abilities.Ability; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PatchUp extends CardImpl { + + public PatchUp(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}"); + + // Return up to three target creature cards with total mana value 3 or less from your graveyard to the battlefield. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); + this.getSpellAbility().addTarget(new PatchUpTarget()); + } + + private PatchUp(final PatchUp card) { + super(card); + } + + @Override + public PatchUp copy() { + return new PatchUp(this); + } +} + +class PatchUpTarget extends TargetCardInYourGraveyard { + + private static final FilterCard filter + = new FilterCreatureCard("creature cards with total mana value 3 or less from your graveyard"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); + } + + PatchUpTarget() { + super(0, 3, filter, false); + } + + private PatchUpTarget(final PatchUpTarget target) { + super(target); + } + + @Override + public PatchUpTarget copy() { + return new PatchUpTarget(this); + } + + @Override + public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { + if (!super.canTarget(controllerId, id, source, game)) { + return false; + } + Card card = game.getCard(id); + return card != null && + this.getTargets() + .stream() + .map(game::getCard) + .mapToInt(Card::getManaValue) + .sum() + card.getManaValue() <= 3; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PathOfAncestry.java b/Mage.Sets/src/mage/cards/p/PathOfAncestry.java index fd248b9970c..f825b9bbd0a 100644 --- a/Mage.Sets/src/mage/cards/p/PathOfAncestry.java +++ b/Mage.Sets/src/mage/cards/p/PathOfAncestry.java @@ -120,7 +120,7 @@ class PathOfAncestryTriggeredAbility extends DelayedTriggeredAbility { @Override public String getRule() { - return "When that mana is spent to cast a creature spell that shares a creature type with your commander," + + return "When that mana is spent to cast a creature spell that shares a creature type with your commander, " + "scry 1. " + "(Look at the top card of your library. You may put that card on the bottom of your library.)"; } diff --git a/Mage.Sets/src/mage/cards/p/PathToTheFestival.java b/Mage.Sets/src/mage/cards/p/PathToTheFestival.java index 58cd3c1babb..aff8d2a0116 100644 --- a/Mage.Sets/src/mage/cards/p/PathToTheFestival.java +++ b/Mage.Sets/src/mage/cards/p/PathToTheFestival.java @@ -4,7 +4,6 @@ import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.DomainValue; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.abilities.effects.keyword.ScryEffect; @@ -13,7 +12,6 @@ import mage.abilities.keyword.FlashbackAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.TimingRule; import mage.filter.StaticFilters; import mage.game.Game; import mage.target.common.TargetCardInLibrary; @@ -56,10 +54,9 @@ public final class PathToTheFestival extends CardImpl { enum PathToTheFestivalCondition implements Condition { instance; - private static final DynamicValue xValue = new DomainValue(); @Override public boolean apply(Game game, Ability source) { - return xValue.calculate(game, source, null) >= 3; + return DomainValue.REGULAR.calculate(game, source, null) >= 3; } } diff --git a/Mage.Sets/src/mage/cards/p/PatriarchsBidding.java b/Mage.Sets/src/mage/cards/p/PatriarchsBidding.java index 19752823852..153a1f80265 100644 --- a/Mage.Sets/src/mage/cards/p/PatriarchsBidding.java +++ b/Mage.Sets/src/mage/cards/p/PatriarchsBidding.java @@ -60,7 +60,7 @@ class PatriarchsBiddingEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { Set chosenTypes = new HashSet<>(); for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { diff --git a/Mage.Sets/src/mage/cards/p/PatriciansScorn.java b/Mage.Sets/src/mage/cards/p/PatriciansScorn.java index 3cbb5106cda..fc62084e7a5 100644 --- a/Mage.Sets/src/mage/cards/p/PatriciansScorn.java +++ b/Mage.Sets/src/mage/cards/p/PatriciansScorn.java @@ -33,7 +33,7 @@ public final class PatriciansScorn extends CardImpl { // If you've cast another white spell this turn, you may cast this spell without paying its mana cost. this.addAbility(new AlternativeCostSourceAbility(new CastWhiteSpellThisTurnCondition()), new PatriciansScornWatcher()); // Destroy all enchantments. - this.getSpellAbility().addEffect(new DestroyAllEffect(StaticFilters.FILTER_PERMANENT_ENCHANTMENT)); + this.getSpellAbility().addEffect(new DestroyAllEffect(StaticFilters.FILTER_PERMANENT_ENCHANTMENTS)); } private PatriciansScorn(final PatriciansScorn card) { diff --git a/Mage.Sets/src/mage/cards/p/PatronOfTheOrochi.java b/Mage.Sets/src/mage/cards/p/PatronOfTheOrochi.java index cd23c54c398..e76e169bc80 100644 --- a/Mage.Sets/src/mage/cards/p/PatronOfTheOrochi.java +++ b/Mage.Sets/src/mage/cards/p/PatronOfTheOrochi.java @@ -76,7 +76,7 @@ class PatronOfTheOrochiEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanent.untap(game); } return true; diff --git a/Mage.Sets/src/mage/cards/p/PatronOfTheWild.java b/Mage.Sets/src/mage/cards/p/PatronOfTheWild.java index 8ea524d56f6..db5bedc0e9a 100644 --- a/Mage.Sets/src/mage/cards/p/PatronOfTheWild.java +++ b/Mage.Sets/src/mage/cards/p/PatronOfTheWild.java @@ -28,7 +28,7 @@ public final class PatronOfTheWild extends CardImpl { this.toughness = new MageInt(1); // Morph {2}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{G}"))); // When Patron of the Wild is turned face up, target creature gets +3/+3 until end of turn. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new BoostTargetEffect(3, 3, Duration.EndOfTurn)); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/p/PatternMatcher.java b/Mage.Sets/src/mage/cards/p/PatternMatcher.java index 6bac73e92c4..7ff91538d38 100644 --- a/Mage.Sets/src/mage/cards/p/PatternMatcher.java +++ b/Mage.Sets/src/mage/cards/p/PatternMatcher.java @@ -77,7 +77,7 @@ class RegularExpression extends OneShotEffect { .getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game ).stream() .map(Permanent::getName) .filter(Objects::nonNull) diff --git a/Mage.Sets/src/mage/cards/p/PearlShard.java b/Mage.Sets/src/mage/cards/p/PearlShard.java index 80ff4d9bea0..5d8d64eb0b2 100644 --- a/Mage.Sets/src/mage/cards/p/PearlShard.java +++ b/Mage.Sets/src/mage/cards/p/PearlShard.java @@ -29,9 +29,8 @@ public final class PearlShard extends CardImpl { Ability ability = new SimpleActivatedAbility( new PreventDamageToTargetEffect(Duration.EndOfTurn, 2), new OrCost( - new CompositeCost(new GenericManaCost(3), new TapSourceCost(), "{3}, {T}"), - new CompositeCost(new ManaCostsImpl<>("{W}"), new TapSourceCost(), "{W}, {T}"), - "{3}, {T} or {W}, {T}" + "{3}, {T} or {W}, {T}", new CompositeCost(new GenericManaCost(3), new TapSourceCost(), "{3}, {T}"), + new CompositeCost(new ManaCostsImpl<>("{W}"), new TapSourceCost(), "{W}, {T}") ) ); ability.addTarget(new TargetAnyTarget()); diff --git a/Mage.Sets/src/mage/cards/p/PeerPressure.java b/Mage.Sets/src/mage/cards/p/PeerPressure.java index 607a50661b5..a69e227b40a 100644 --- a/Mage.Sets/src/mage/cards/p/PeerPressure.java +++ b/Mage.Sets/src/mage/cards/p/PeerPressure.java @@ -65,7 +65,7 @@ class PeerPressureEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Choice choice = new ChoiceCreatureType(game.getObject(source.getSourceId())); + Choice choice = new ChoiceCreatureType(game.getObject(source)); if (controller != null && controller.choose(Outcome.GainControl, choice, game)) { String chosenType = choice.getChoice(); game.informPlayers(controller.getLogName() + " has chosen " + chosenType); @@ -83,7 +83,7 @@ class PeerPressureEffect extends OneShotEffect { } } if (playerWithMost != null && playerWithMost.equals(controller.getId())) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(SubType.byDescription(chosenType), chosenType), controller.getId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterCreaturePermanent(SubType.byDescription(chosenType), chosenType), controller.getId(), source, game)) { ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfGame); effect.setTargetPointer(new FixedTarget(permanent, game)); game.addEffect(effect, source); diff --git a/Mage.Sets/src/mage/cards/p/PeerThroughDepths.java b/Mage.Sets/src/mage/cards/p/PeerThroughDepths.java index 70f82788391..3213b29761c 100644 --- a/Mage.Sets/src/mage/cards/p/PeerThroughDepths.java +++ b/Mage.Sets/src/mage/cards/p/PeerThroughDepths.java @@ -1,9 +1,7 @@ - - package mage.cards.p; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -31,10 +29,9 @@ public final class PeerThroughDepths extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); this.subtype.add(SubType.ARCANE); - // Look at the top five cards of your library. You may reveal an instant or sorcery card from among them and put it into your hand. // Put the rest on the bottom of your library in any order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(5), false, StaticValue.get(1), filter, false)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(5, 1, filter, PutCards.HAND, PutCards.BOTTOM_ANY)); } public PeerThroughDepths (final PeerThroughDepths card) { @@ -45,6 +42,4 @@ public final class PeerThroughDepths extends CardImpl { public PeerThroughDepths copy() { return new PeerThroughDepths(this); } - } - diff --git a/Mage.Sets/src/mage/cards/p/Penance.java b/Mage.Sets/src/mage/cards/p/Penance.java index 090a100378f..77abfcd09e4 100644 --- a/Mage.Sets/src/mage/cards/p/Penance.java +++ b/Mage.Sets/src/mage/cards/p/Penance.java @@ -63,7 +63,7 @@ class PenanceEffect extends PreventionEffectImpl { @Override public void init(Ability source, Game game) { - this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); super.init(source, game); } diff --git a/Mage.Sets/src/mage/cards/p/Peregrination.java b/Mage.Sets/src/mage/cards/p/Peregrination.java index e8a9de463c3..c3b288f7323 100644 --- a/Mage.Sets/src/mage/cards/p/Peregrination.java +++ b/Mage.Sets/src/mage/cards/p/Peregrination.java @@ -65,7 +65,7 @@ class PeregrinationEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/p/PerilousPredicament.java b/Mage.Sets/src/mage/cards/p/PerilousPredicament.java index bad01d2beab..2769bd4908c 100644 --- a/Mage.Sets/src/mage/cards/p/PerilousPredicament.java +++ b/Mage.Sets/src/mage/cards/p/PerilousPredicament.java @@ -71,14 +71,14 @@ class PerilousPredicamentSacrificeOpponentsEffect extends OneShotEffect { filterNonArtifact.add(new ControllerIdPredicate(player.getId())); if (game.getBattlefield().countAll(filterArtifact, player.getId(), game) > 0) { TargetPermanent target = new TargetPermanent(1, 1, filterArtifact, true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Sacrifice, target, source, game); perms.addAll(target.getTargets()); } } if (game.getBattlefield().countAll(filterNonArtifact, player.getId(), game) > 0) { TargetPermanent target = new TargetPermanent(1, 1, filterNonArtifact, true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Sacrifice, target, source, game); perms.addAll(target.getTargets()); } diff --git a/Mage.Sets/src/mage/cards/p/PerilousResearch.java b/Mage.Sets/src/mage/cards/p/PerilousResearch.java index 337b5ad5ab8..2ac08f26c1d 100644 --- a/Mage.Sets/src/mage/cards/p/PerilousResearch.java +++ b/Mage.Sets/src/mage/cards/p/PerilousResearch.java @@ -62,7 +62,7 @@ class PerilousResearchEffect extends OneShotEffect { if (player != null) { Target target = new TargetControlledPermanent(); - if (target.canChoose(source.getSourceId(), player.getId(), game) && player.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) { + if (target.canChoose(player.getId(), source, game) && player.choose(Outcome.Sacrifice, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { return permanent.sacrifice(source, game); diff --git a/Mage.Sets/src/mage/cards/p/PermafrostTrap.java b/Mage.Sets/src/mage/cards/p/PermafrostTrap.java index 0403f4a8162..2ce72d0925b 100644 --- a/Mage.Sets/src/mage/cards/p/PermafrostTrap.java +++ b/Mage.Sets/src/mage/cards/p/PermafrostTrap.java @@ -35,7 +35,7 @@ public final class PermafrostTrap extends CardImpl { // Tap up to two target creatures. Those creatures don't untap during their controller's next untap step. this.getSpellAbility().addEffect(new TapTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); - this.getSpellAbility().addEffect(new DontUntapInControllersNextUntapStepTargetEffect()); + this.getSpellAbility().addEffect(new DontUntapInControllersNextUntapStepTargetEffect("Those creatures")); } private PermafrostTrap(final PermafrostTrap card) { diff --git a/Mage.Sets/src/mage/cards/p/PerrieThePulverizer.java b/Mage.Sets/src/mage/cards/p/PerrieThePulverizer.java new file mode 100644 index 00000000000..20daff0fec7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PerrieThePulverizer.java @@ -0,0 +1,104 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.TrampleAbility; +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.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.Collection; +import java.util.HashMap; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PerrieThePulverizer extends CardImpl { + + private static final Hint hint = new ValueHint( + "Different kinds of counters among permanents you control", PerrieThePulverizerValue.instance + ); + + public PerrieThePulverizer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{U}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.RHINO); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Perrie enters the battlefield, put a shield counter on target creature. + Ability ability = new EntersBattlefieldTriggeredAbility( + new AddCountersTargetEffect(CounterType.SHIELD.createInstance()) + ); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + // Whenever Perrie attacks, target creature you control gains trample and gets +X/+X, where X is the number of different kinds of counters among permanents you control. + ability = new AttacksTriggeredAbility(new GainAbilityTargetEffect(TrampleAbility.getInstance()) + .setText("target creature you control gains trample")); + ability.addEffect(new BoostTargetEffect( + PerrieThePulverizerValue.instance, PerrieThePulverizerValue.instance, Duration.EndOfTurn + ).setText("and gets +X/+X, where X is the number of different kinds of counters among permanents you control")); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private PerrieThePulverizer(final PerrieThePulverizer card) { + super(card); + } + + @Override + public PerrieThePulverizer copy() { + return new PerrieThePulverizer(this); + } +} + +enum PerrieThePulverizerValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_PERMANENT, + sourceAbility.getControllerId(), sourceAbility, game + ).stream() + .map(p -> p.getCounters(game)) + .map(HashMap::keySet) + .flatMap(Collection::stream) + .distinct() + .mapToInt(x -> 1) + .sum(); + } + + @Override + public PerrieThePulverizerValue copy() { + return this; + } + + @Override + public String getMessage() { + return ""; + } +} diff --git a/Mage.Sets/src/mage/cards/p/Persecute.java b/Mage.Sets/src/mage/cards/p/Persecute.java index 5e46d347235..a919d88211a 100644 --- a/Mage.Sets/src/mage/cards/p/Persecute.java +++ b/Mage.Sets/src/mage/cards/p/Persecute.java @@ -59,7 +59,7 @@ class PersecuteEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); ChoiceColor choice = new ChoiceColor(); if (controller == null diff --git a/Mage.Sets/src/mage/cards/p/PestilenceRats.java b/Mage.Sets/src/mage/cards/p/PestilenceRats.java index b671d6cca76..8cc8f423997 100644 --- a/Mage.Sets/src/mage/cards/p/PestilenceRats.java +++ b/Mage.Sets/src/mage/cards/p/PestilenceRats.java @@ -13,7 +13,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterPermanent; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; /** * @@ -24,7 +24,7 @@ public final class PestilenceRats extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("other Rats on the battlefield"); static{ filter.add(SubType.RAT.getPredicate()); - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); } public PestilenceRats(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/PestilentHaze.java b/Mage.Sets/src/mage/cards/p/PestilentHaze.java index 13e92c8ff58..98397956749 100644 --- a/Mage.Sets/src/mage/cards/p/PestilentHaze.java +++ b/Mage.Sets/src/mage/cards/p/PestilentHaze.java @@ -62,7 +62,7 @@ class PestilentHazeEffect extends OneShotEffect { game.getBattlefield() .getActivePermanents( StaticFilters.FILTER_PERMANENT_PLANESWALKER, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game ).stream() .forEach(permanent -> permanent.removeCounters(CounterType.LOYALTY.createInstance(2), source, game)); return true; diff --git a/Mage.Sets/src/mage/cards/p/PestilentSouleater.java b/Mage.Sets/src/mage/cards/p/PestilentSouleater.java index d9b448d4428..7f631d8a1a4 100644 --- a/Mage.Sets/src/mage/cards/p/PestilentSouleater.java +++ b/Mage.Sets/src/mage/cards/p/PestilentSouleater.java @@ -1,37 +1,34 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.PhyrexianManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.InfectAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.ColoredManaSymbol; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author North */ public final class PestilentSouleater extends CardImpl { public PestilentSouleater(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{5}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{5}"); this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.INSECT); this.power = new MageInt(3); this.toughness = new MageInt(3); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new GainAbilitySourceEffect(InfectAbility.getInstance(), Duration.EndOfTurn), - new PhyrexianManaCost(ColoredManaSymbol.B))); + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + InfectAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl<>("{B/P}"))); } private PestilentSouleater(final PestilentSouleater card) { diff --git a/Mage.Sets/src/mage/cards/p/PetalmaneBaku.java b/Mage.Sets/src/mage/cards/p/PetalmaneBaku.java index 0b521c0049a..6bf0e934267 100644 --- a/Mage.Sets/src/mage/cards/p/PetalmaneBaku.java +++ b/Mage.Sets/src/mage/cards/p/PetalmaneBaku.java @@ -1,4 +1,3 @@ - package mage.cards.p; import java.util.UUID; @@ -7,7 +6,7 @@ import mage.Mana; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.costs.common.RemoveVariableCountersSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.dynamicvalue.common.CountersSourceCount; import mage.abilities.dynamicvalue.common.RemovedCountersForCostValue; import mage.abilities.effects.common.counter.AddCountersSourceEffect; @@ -31,18 +30,17 @@ public final class PetalmaneBaku extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(2); - // Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Skullmane Baku. + // Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Petalmane Baku. this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true)); // {1}, Remove X ki counters from Petalmane Baku: Add X mana of any one color. Ability ability = new DynamicManaAbility( new Mana(0, 0, 0, 0, 0, 0, 1, 0), RemovedCountersForCostValue.instance, - new ManaCostsImpl<>("{1}"), + new GenericManaCost(1), "Add X mana of any one color", true, new CountersSourceCount(CounterType.KI)); - ability.addCost(new RemoveVariableCountersSourceCost(CounterType.KI.createInstance(), - "Remove X ki counters from {this}")); + ability.addCost(new RemoveVariableCountersSourceCost(CounterType.KI.createInstance())); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/PetalsOfInsight.java b/Mage.Sets/src/mage/cards/p/PetalsOfInsight.java index 73d5b7a2973..e6cd389cb72 100644 --- a/Mage.Sets/src/mage/cards/p/PetalsOfInsight.java +++ b/Mage.Sets/src/mage/cards/p/PetalsOfInsight.java @@ -57,7 +57,7 @@ class PetalsOfInsightEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/p/PhantasmalAbomination.java b/Mage.Sets/src/mage/cards/p/PhantasmalAbomination.java index 3aab19dda54..3d0631eb238 100644 --- a/Mage.Sets/src/mage/cards/p/PhantasmalAbomination.java +++ b/Mage.Sets/src/mage/cards/p/PhantasmalAbomination.java @@ -25,7 +25,7 @@ public final class PhantasmalAbomination extends CardImpl { this.toughness = new MageInt(5); this.addAbility(DefenderAbility.getInstance()); - this.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect())); + this.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect().setText("sacrifice it"))); } private PhantasmalAbomination(final PhantasmalAbomination card) { diff --git a/Mage.Sets/src/mage/cards/p/PhantasmalSphere.java b/Mage.Sets/src/mage/cards/p/PhantasmalSphere.java index 689becf0c8e..dee5c767021 100644 --- a/Mage.Sets/src/mage/cards/p/PhantasmalSphere.java +++ b/Mage.Sets/src/mage/cards/p/PhantasmalSphere.java @@ -102,7 +102,7 @@ class PhantasmalSphereEffect extends OneShotEffect { class PhantasmalSphereToken extends TokenImpl { public PhantasmalSphereToken(int xValue) { - super("Orb", "X/X blue Orb creature token with flying"); + super("Orb Token", "X/X blue Orb creature token with flying"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.ORB); diff --git a/Mage.Sets/src/mage/cards/p/PhosphorescentFeast.java b/Mage.Sets/src/mage/cards/p/PhosphorescentFeast.java index 55a2bb9fd83..b66088424d1 100644 --- a/Mage.Sets/src/mage/cards/p/PhosphorescentFeast.java +++ b/Mage.Sets/src/mage/cards/p/PhosphorescentFeast.java @@ -62,7 +62,7 @@ class PhosphorescentFeastEffect extends OneShotEffect { } if (player.getHand().count(new FilterCard(), game) > 0) { TargetCardInHand target = new TargetCardInHand(0, Integer.MAX_VALUE, new FilterCard()); - if (player.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + if (player.choose(Outcome.Benefit, target, source, game)) { Cards cards = new CardsImpl(); for (UUID uuid : target.getTargets()) { diff --git a/Mage.Sets/src/mage/cards/p/PhylacteryLich.java b/Mage.Sets/src/mage/cards/p/PhylacteryLich.java index 05794d5e5d9..3bfe3601195 100644 --- a/Mage.Sets/src/mage/cards/p/PhylacteryLich.java +++ b/Mage.Sets/src/mage/cards/p/PhylacteryLich.java @@ -111,8 +111,8 @@ class PhylacteryLichEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null) { TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { - if (player.choose(Outcome.Neutral, target, source.getSourceId(), game)) { + if (target.canChoose(source.getControllerId(), source, game)) { + if (player.choose(Outcome.Neutral, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.addCounters(CounterType.PHYLACTERY.createInstance(), source.getControllerId(), source, game); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianDreadnought.java b/Mage.Sets/src/mage/cards/p/PhyrexianDreadnought.java index a036ab16ca5..5ae10fe9b60 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianDreadnought.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianDreadnought.java @@ -72,7 +72,7 @@ class PhyrexianDreadnoughtSacrificeCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { int sumPower = 0; - if (targets.choose(Outcome.Sacrifice, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.Sacrifice, controllerId, source.getSourceId(), source, game)) { for (UUID targetId : targets.get(0).getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent != null && permanent.sacrifice(source, game)) { diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianHydra.java b/Mage.Sets/src/mage/cards/p/PhyrexianHydra.java index 9618dc9ec0e..9295156fb90 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianHydra.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianHydra.java @@ -53,11 +53,11 @@ class PhyrexianHydraEffect extends PreventionEffectImpl { public PhyrexianHydraEffect() { super(Duration.WhileOnBattlefield); + staticText = "If damage would be dealt to {this}, prevent that damage. Put a -1/-1 counter on {this} for each 1 damage prevented this way"; } public PhyrexianHydraEffect(final PhyrexianHydraEffect effect) { super(effect); - staticText = "If damage would be dealt to {this}, prevent that damage. Put a -1/-1 counter on {this} for each 1 damage prevented this way"; } @Override diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianMetamorph.java b/Mage.Sets/src/mage/cards/p/PhyrexianMetamorph.java index 8acb010d794..a6509f1a5a0 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianMetamorph.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianMetamorph.java @@ -1,4 +1,3 @@ - package mage.cards.p; import java.util.UUID; @@ -44,9 +43,7 @@ public final class PhyrexianMetamorph extends CardImpl { CopyApplier phyrexianMetamorphCopyApplier = new CopyApplier() { @Override public boolean apply(Game game, MageObject blueprint, Ability source, UUID copyToObjectId) { - if (!blueprint.isArtifact(game)) { - blueprint.addCardType(game, CardType.ARTIFACT); - } + blueprint.addCardType(CardType.ARTIFACT); return true; } }; diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianReclamation.java b/Mage.Sets/src/mage/cards/p/PhyrexianReclamation.java index fd20cddbe57..589f153890b 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianReclamation.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianReclamation.java @@ -1,21 +1,19 @@ - package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Plopman */ public final class PhyrexianReclamation extends CardImpl { @@ -24,7 +22,7 @@ public final class PhyrexianReclamation extends CardImpl { 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 ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl<>("{1}{B}")); ability.addCost(new PayLifeCost(2)); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianRevoker.java b/Mage.Sets/src/mage/cards/p/PhyrexianRevoker.java index 0f8cec5c36b..ee3c8a96093 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianRevoker.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianRevoker.java @@ -69,7 +69,7 @@ class PhyrexianRevokerEffect2 extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't activate abilities of sources with that name (" + mageObject.getName() + " in play)."; } diff --git a/Mage.Sets/src/mage/cards/p/PiasRevolution.java b/Mage.Sets/src/mage/cards/p/PiasRevolution.java index 9785a5a756e..7826ac4b3a1 100644 --- a/Mage.Sets/src/mage/cards/p/PiasRevolution.java +++ b/Mage.Sets/src/mage/cards/p/PiasRevolution.java @@ -117,7 +117,7 @@ class PiasRevolutionTriggeredAbility extends TriggeredAbilityImpl { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; if (zEvent.isDiesEvent()) { Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); - if (permanent != null && filter.match(permanent, sourceId, controllerId, game)) { + if (permanent != null && filter.match(permanent, controllerId, this, game)) { for (Effect effect : this.getEffects()) { effect.setValue("permanentId", event.getTargetId()); } diff --git a/Mage.Sets/src/mage/cards/p/PiecesOfThePuzzle.java b/Mage.Sets/src/mage/cards/p/PiecesOfThePuzzle.java index 51eb1ca084e..af1bc7a5c5f 100644 --- a/Mage.Sets/src/mage/cards/p/PiecesOfThePuzzle.java +++ b/Mage.Sets/src/mage/cards/p/PiecesOfThePuzzle.java @@ -1,14 +1,12 @@ - package mage.cards.p; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; -import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.effects.common.RevealLibraryPickControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; @@ -18,18 +16,19 @@ import mage.filter.predicate.Predicates; */ public final class PiecesOfThePuzzle extends CardImpl { - private static final FilterCard FILTER = new FilterCard("up to two instant and/or sorcery cards"); + private static final FilterCard filter = new FilterCard("instant and/or sorcery cards"); static { - FILTER.add(Predicates.or(CardType.INSTANT.getPredicate(), CardType.SORCERY.getPredicate())); + filter.add(Predicates.or(CardType.INSTANT.getPredicate(), CardType.SORCERY.getPredicate())); } public PiecesOfThePuzzle(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{U}"); // Reveal the top five cards of your library. Put up to two instant and/or sorcery cards from among them into your hand and the rest into your graveyard. - Effect effect = new LookLibraryAndPickControllerEffect(StaticValue.get(5), false, StaticValue.get(2), FILTER, Zone.GRAVEYARD, false, true, true, Zone.HAND, false); - effect.setText("Reveal the top five cards of your library. Put up to two instant and/or sorcery cards from among them into your hand and the rest into your graveyard"); + Effect effect = new RevealLibraryPickControllerEffect(5, 2, filter, PutCards.HAND, PutCards.GRAVEYARD, false); + effect.setText("reveal the top five cards of your library. " + + "Put up to two instant and/or sorcery cards from among them into your hand and the rest into your graveyard"); this.getSpellAbility().addEffect(effect); } diff --git a/Mage.Sets/src/mage/cards/p/PietyCharm.java b/Mage.Sets/src/mage/cards/p/PietyCharm.java index 7f9df2e9135..83478fd8b6a 100644 --- a/Mage.Sets/src/mage/cards/p/PietyCharm.java +++ b/Mage.Sets/src/mage/cards/p/PietyCharm.java @@ -41,13 +41,11 @@ public final class PietyCharm extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent(filter1)); // or target Soldier creature gets +2/+2 until end of turn - Mode mode = new Mode(); - mode.addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn)); + Mode mode = new Mode(new BoostTargetEffect(2, 2, Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent(filter2)); this.getSpellAbility().addMode(mode); // or creatures you control gain vigilance until end of turn. - mode = new Mode(); - mode.addEffect(new GainAbilityAllEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES)); + mode = new Mode(new GainAbilityAllEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/p/PilgrimOfJustice.java b/Mage.Sets/src/mage/cards/p/PilgrimOfJustice.java index 13d2ef5310f..4567105d0de 100644 --- a/Mage.Sets/src/mage/cards/p/PilgrimOfJustice.java +++ b/Mage.Sets/src/mage/cards/p/PilgrimOfJustice.java @@ -87,7 +87,7 @@ class PilgrimOfJusticeEffect extends PreventionEffectImpl { @Override public void init(Ability source, Game game) { - this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/p/PilgrimOfVirtue.java b/Mage.Sets/src/mage/cards/p/PilgrimOfVirtue.java index 6b6a1344cac..3d32b9de466 100644 --- a/Mage.Sets/src/mage/cards/p/PilgrimOfVirtue.java +++ b/Mage.Sets/src/mage/cards/p/PilgrimOfVirtue.java @@ -87,7 +87,7 @@ class PilgrimOfVirtueEffect extends PreventionEffectImpl { @Override public void init(Ability source, Game game) { - this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/p/PillarOfOrigins.java b/Mage.Sets/src/mage/cards/p/PillarOfOrigins.java index b64fd74f636..28cee80e143 100644 --- a/Mage.Sets/src/mage/cards/p/PillarOfOrigins.java +++ b/Mage.Sets/src/mage/cards/p/PillarOfOrigins.java @@ -55,7 +55,7 @@ class PillarOfOriginsManaBuilder extends ConditionalManaBuilder { public ConditionalManaBuilder setMana(Mana mana, Ability source, Game game) { creatureType = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game); Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null && mana.getAny() == 0) { game.informPlayers(controller.getLogName() + " produces " + mana.toString() + " with " + sourceObject.getLogName() + " (can only be spent to cast creatures of type " + creatureType + ")"); @@ -96,7 +96,7 @@ class PillarOfOriginsManaCondition extends CreatureCastManaCondition { // check: ... to cast a creature spell if (super.apply(game, source)) { // check: ... of the chosen type - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (creatureType != null && object != null && object.hasSubtype(creatureType, game)) { return true; } diff --git a/Mage.Sets/src/mage/cards/p/PineWalker.java b/Mage.Sets/src/mage/cards/p/PineWalker.java index 2543d269a08..cf408f2214e 100644 --- a/Mage.Sets/src/mage/cards/p/PineWalker.java +++ b/Mage.Sets/src/mage/cards/p/PineWalker.java @@ -28,7 +28,7 @@ public final class PineWalker extends CardImpl { this.toughness = new MageInt(5); // Morph {4}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{G}"))); // Whenever Pine Walker or another creature you control is turned face up, untap that creature. Effect effect = new UntapTargetEffect(); effect.setText("untap that creature"); diff --git a/Mage.Sets/src/mage/cards/p/PiousKitsune.java b/Mage.Sets/src/mage/cards/p/PiousKitsune.java index 588758d7cff..5c0c79f819f 100644 --- a/Mage.Sets/src/mage/cards/p/PiousKitsune.java +++ b/Mage.Sets/src/mage/cards/p/PiousKitsune.java @@ -83,7 +83,7 @@ class PiousKitsuneEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { boolean result; result = new AddCountersSourceEffect(CounterType.DEVOTION.createInstance()).apply(game, source); - if (game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0) { + if (game.getBattlefield().count(filter, source.getControllerId(), source, game) > 0) { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { int life = permanent.getCounters(game).getCount(CounterType.DEVOTION); diff --git a/Mage.Sets/src/mage/cards/p/PiracyCharm.java b/Mage.Sets/src/mage/cards/p/PiracyCharm.java index 8cbce042598..8bfbdddd925 100644 --- a/Mage.Sets/src/mage/cards/p/PiracyCharm.java +++ b/Mage.Sets/src/mage/cards/p/PiracyCharm.java @@ -28,13 +28,11 @@ public final class PiracyCharm extends CardImpl { this.getSpellAbility().addEffect(new GainAbilityTargetEffect(new IslandwalkAbility(), Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // or target creature gets +2/-1 until end of turn; - Mode mode = new Mode(); - mode.addEffect(new BoostTargetEffect(2, -1, Duration.EndOfTurn)); + Mode mode = new Mode(new BoostTargetEffect(2, -1, Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or target player discards a card. - mode = new Mode(); - mode.addEffect(new DiscardTargetEffect(1)); + mode = new Mode(new DiscardTargetEffect(1)); mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/p/PitilessHorde.java b/Mage.Sets/src/mage/cards/p/PitilessHorde.java index fd24f8b681c..3fddaf25800 100644 --- a/Mage.Sets/src/mage/cards/p/PitilessHorde.java +++ b/Mage.Sets/src/mage/cards/p/PitilessHorde.java @@ -29,7 +29,7 @@ public final class PitilessHorde extends CardImpl { this.addAbility(new BeginningOfUpkeepTriggeredAbility(new LoseLifeSourceControllerEffect(2), TargetController.YOU, false)); // Dash {2}{B}{B} - this.addAbility(new DashAbility(this, "{2}{B}{B}")); + this.addAbility(new DashAbility("{2}{B}{B}")); } private PitilessHorde(final PitilessHorde card) { diff --git a/Mage.Sets/src/mage/cards/p/PlagueReaver.java b/Mage.Sets/src/mage/cards/p/PlagueReaver.java index d3c1801198f..a09f62eabfc 100644 --- a/Mage.Sets/src/mage/cards/p/PlagueReaver.java +++ b/Mage.Sets/src/mage/cards/p/PlagueReaver.java @@ -87,7 +87,7 @@ class PlagueReaverSacrificeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { for (Permanent permanent : game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game )) { if (permanent == null) { continue; diff --git a/Mage.Sets/src/mage/cards/p/Plaguecrafter.java b/Mage.Sets/src/mage/cards/p/Plaguecrafter.java index aa1215b050b..2baf7d8d832 100644 --- a/Mage.Sets/src/mage/cards/p/Plaguecrafter.java +++ b/Mage.Sets/src/mage/cards/p/Plaguecrafter.java @@ -90,9 +90,9 @@ class PlaguecrafterEffect extends OneShotEffect { CardType.PLANESWALKER.getPredicate() )); TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { while (!target.isChosen() && player.canRespond()) { - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + player.choose(Outcome.Sacrifice, target, source, game); } perms.addAll(target.getTargets()); } else { diff --git a/Mage.Sets/src/mage/cards/p/PlanarBirth.java b/Mage.Sets/src/mage/cards/p/PlanarBirth.java index 7e460dfb6ab..a8f5318252b 100644 --- a/Mage.Sets/src/mage/cards/p/PlanarBirth.java +++ b/Mage.Sets/src/mage/cards/p/PlanarBirth.java @@ -62,7 +62,7 @@ class PlanarBirthEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - toBattlefield.addAll(player.getGraveyard().getCards(StaticFilters.FILTER_CARD_BASIC_LAND, source.getSourceId(), controller.getId(), game)); + toBattlefield.addAll(player.getGraveyard().getCards(StaticFilters.FILTER_CARD_BASIC_LAND, controller.getId(), source, game)); } } controller.moveCards(toBattlefield.getCards(game), Zone.BATTLEFIELD, source, game, true, false, true, null); diff --git a/Mage.Sets/src/mage/cards/p/PlanarCollapse.java b/Mage.Sets/src/mage/cards/p/PlanarCollapse.java index 77709aa0b35..79e5e08c402 100644 --- a/Mage.Sets/src/mage/cards/p/PlanarCollapse.java +++ b/Mage.Sets/src/mage/cards/p/PlanarCollapse.java @@ -46,7 +46,7 @@ public final class PlanarCollapse extends CardImpl { @Override public boolean apply(Game game, Ability source) { - return game.getBattlefield().count(StaticFilters.FILTER_PERMANENT_CREATURE, source.getSourceId(), source.getControllerId(), game) >= 4; + return game.getBattlefield().count(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game) >= 4; } } } diff --git a/Mage.Sets/src/mage/cards/p/PlanarDespair.java b/Mage.Sets/src/mage/cards/p/PlanarDespair.java index 65bdb3dcf5d..a84b5d799a7 100644 --- a/Mage.Sets/src/mage/cards/p/PlanarDespair.java +++ b/Mage.Sets/src/mage/cards/p/PlanarDespair.java @@ -1,8 +1,7 @@ - package mage.cards.p; import java.util.UUID; -import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.LockedInDynamicValue; import mage.abilities.dynamicvalue.common.DomainValue; import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; import mage.abilities.effects.Effect; @@ -16,15 +15,17 @@ import mage.constants.Duration; /** * * @author LoneFox - + * */ public final class PlanarDespair extends CardImpl { + // rule 608.2h + private static final LockedInDynamicValue dv = new LockedInDynamicValue(new SignInversionDynamicValue(DomainValue.REGULAR)); + public PlanarDespair(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}{B}"); // Domain - All creatures get -1/-1 until end of turn for each basic land type among lands you control. - DynamicValue dv = new SignInversionDynamicValue(new DomainValue()); Effect effect = new BoostAllEffect(dv, dv, Duration.EndOfTurn); effect.setText("Domain — All creatures get -1/-1 until end of turn for each basic land type among lands you control."); this.getSpellAbility().addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/p/PlanarGuide.java b/Mage.Sets/src/mage/cards/p/PlanarGuide.java index f41d3116427..c366fbe99c7 100644 --- a/Mage.Sets/src/mage/cards/p/PlanarGuide.java +++ b/Mage.Sets/src/mage/cards/p/PlanarGuide.java @@ -67,11 +67,11 @@ class PlanarGuideExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Player controller = game.getPlayer(source.getControllerId()); if (sourceObject != null && controller != null) { Set toExile = new HashSet<>(); - toExile.addAll(game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)); + toExile.addAll(game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)); controller.moveCardsToExile(toExile, source, game, true, source.getSourceId(), sourceObject.getIdName()); ExileZone exile = game.getExile().getExileZone(source.getSourceId()); if (exile != null && !exile.isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/p/PlanarIncision.java b/Mage.Sets/src/mage/cards/p/PlanarIncision.java new file mode 100644 index 00000000000..8dc6ceab064 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PlanarIncision.java @@ -0,0 +1,84 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.cards.p; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.counters.Counters; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.util.CardUtil; + +/** + * @author jeffwadsworth + */ +public final class PlanarIncision extends CardImpl { + + public PlanarIncision(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); + + // Exile target artifact or creature, then return it to the battlefield under its owner’s control with a +1/+1 counter on it. + this.getSpellAbility().addEffect(new PlanarIncisionEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE)); + } + + private PlanarIncision(final PlanarIncision card) { + super(card); + } + + @Override + public PlanarIncision copy() { + return new PlanarIncision(this); + } +} + +class PlanarIncisionEffect extends OneShotEffect { + + PlanarIncisionEffect() { + super(Outcome.Benefit); + staticText = "Exile target artifact or creature, then return it to the battlefield under its owner's control with a +1/+1 counter on it"; + } + + private PlanarIncisionEffect(final PlanarIncisionEffect effect) { + super(effect); + } + + @Override + public PlanarIncisionEffect copy() { + return new PlanarIncisionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + Player controller = game.getPlayer(source.getControllerId()); + if (permanent != null + && controller != null) { + UUID exileId = CardUtil.getExileZoneId("planarIncisionExile" + source.toString(), game); + if (controller.moveCardsToExile(permanent, source, game, true, exileId, "")) { + Card exiledCard = game.getExile().getExileZone(exileId).get(permanent.getId(), game); + if (exiledCard != null) { + Counters countersToAdd = new Counters(); + countersToAdd.addCounter(CounterType.P1P1.createInstance()); + game.setEnterWithCounters(exiledCard.getId(), countersToAdd); + return controller.moveCards(exiledCard, Zone.BATTLEFIELD, source, game, false, false, true, null); + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PlanarOverlay.java b/Mage.Sets/src/mage/cards/p/PlanarOverlay.java index 9a397e94038..2174db94ccc 100644 --- a/Mage.Sets/src/mage/cards/p/PlanarOverlay.java +++ b/Mage.Sets/src/mage/cards/p/PlanarOverlay.java @@ -67,7 +67,7 @@ class PlanarOverlayEffect extends OneShotEffect { filter.add(landName.getPredicate()); filter.add(TargetController.YOU.getControllerPredicate()); Target target = new TargetLandPermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(outcome, target, source, game); lands.add(game.getPermanent(target.getFirstTarget())); } diff --git a/Mage.Sets/src/mage/cards/p/PlaneboundAccomplice.java b/Mage.Sets/src/mage/cards/p/PlaneboundAccomplice.java index f8509ccd998..4d59ae3cda9 100644 --- a/Mage.Sets/src/mage/cards/p/PlaneboundAccomplice.java +++ b/Mage.Sets/src/mage/cards/p/PlaneboundAccomplice.java @@ -81,7 +81,7 @@ class PlaneboundAccompliceEffect extends OneShotEffect { return true; } TargetCardInHand target = new TargetCardInHand(filter); - if (!controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + if (!controller.choose(Outcome.PutCreatureInPlay, target, source, game)) { return true; } Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/p/PlanewideCelebration.java b/Mage.Sets/src/mage/cards/p/PlanewideCelebration.java index bc782470193..e7868f0f28c 100644 --- a/Mage.Sets/src/mage/cards/p/PlanewideCelebration.java +++ b/Mage.Sets/src/mage/cards/p/PlanewideCelebration.java @@ -3,7 +3,7 @@ package mage.cards.p; import mage.abilities.Mode; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GainLifeEffect; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.effects.common.counter.ProliferateEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -34,7 +34,7 @@ public final class PlanewideCelebration extends CardImpl { this.getSpellAbility().addEffect(new CreateTokenEffect(new PlanewideCelebrationToken())); // • Return target permanent card from your graveyard to your hand. - Mode mode = new Mode(new ReturnToHandTargetEffect()); + Mode mode = new Mode(new ReturnFromGraveyardToHandTargetEffect()); mode.addTarget(new TargetCardInYourGraveyard(filter)); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/p/PlasmaJockey.java b/Mage.Sets/src/mage/cards/p/PlasmaJockey.java new file mode 100644 index 00000000000..2b60e54c2b9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PlasmaJockey.java @@ -0,0 +1,47 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.combat.CantBlockTargetEffect; +import mage.abilities.keyword.BlitzAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PlasmaJockey extends CardImpl { + + public PlasmaJockey(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.VIASHINO); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Whenever Plasma Jockey attacks, target creature an opponent controls can't block this turn. + Ability ability = new AttacksTriggeredAbility(new CantBlockTargetEffect(Duration.EndOfTurn)); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + + // Blitz {2}{R} + this.addAbility(new BlitzAbility(this, "{2}{R}")); + } + + private PlasmaJockey(final PlasmaJockey card) { + super(card); + } + + @Override + public PlasmaJockey copy() { + return new PlasmaJockey(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PlatedSliver.java b/Mage.Sets/src/mage/cards/p/PlatedSliver.java index 9e888a8f2a3..6511c894db6 100644 --- a/Mage.Sets/src/mage/cards/p/PlatedSliver.java +++ b/Mage.Sets/src/mage/cards/p/PlatedSliver.java @@ -27,7 +27,7 @@ public final class PlatedSliver extends CardImpl { this.toughness = new MageInt(1); // All Sliver creatures get +0/+1. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(0, 1, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, false))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(0, 1, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS, false))); } private PlatedSliver(final PlatedSliver card) { diff --git a/Mage.Sets/src/mage/cards/p/PledgeOfLoyalty.java b/Mage.Sets/src/mage/cards/p/PledgeOfLoyalty.java index c0bfd6bd50b..c74c0ac7371 100644 --- a/Mage.Sets/src/mage/cards/p/PledgeOfLoyalty.java +++ b/Mage.Sets/src/mage/cards/p/PledgeOfLoyalty.java @@ -1,56 +1,54 @@ package mage.cards.p; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - import mage.MageObject; import mage.ObjectColor; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.abilities.keyword.ProtectionAbility; -import mage.constants.*; -import mage.filter.Filter; -import mage.filter.FilterCard; -import mage.filter.FilterObject; -import mage.filter.predicate.Predicate; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.ColorPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.common.TargetCreaturePermanent; -import mage.abilities.Ability; import mage.abilities.effects.common.AttachEffect; -import mage.target.TargetPermanent; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.ProtectionAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; /** - * * @author noahg */ public final class PledgeOfLoyalty extends CardImpl { + private static final FilterCard filter = new FilterCard("the colors of permanents you control"); + + static { + filter.add(PledgeOfLoyaltyPredicate.instance); + } + public PledgeOfLoyalty(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); - + this.subtype.add(SubType.AURA); // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Enchanted creature has protection from the colors of permanents you control. This effect doesn't remove Pledge of Loyalty. - ProtectionAbility gainedAbility = new PledgeOfLoyaltyProtectionAbility(); - gainedAbility.setAuraIdNotToBeRemoved(this.getId()); - Effect effect = new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA); - effect.setText("Enchanted creature has protection from the colors of permanents you control. This effect doesn't remove {this}."); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( + new ProtectionAbility(filter), AttachmentType.AURA + ).setDoesntRemoveItself(true))); } private PledgeOfLoyalty(final PledgeOfLoyalty card) { @@ -61,73 +59,21 @@ public final class PledgeOfLoyalty extends CardImpl { public PledgeOfLoyalty copy() { return new PledgeOfLoyalty(this); } +} - class PledgeOfLoyaltyProtectionAbility extends ProtectionAbility { +enum PledgeOfLoyaltyPredicate implements ObjectSourcePlayerPredicate { + instance; - public PledgeOfLoyaltyProtectionAbility() { - super(new FilterCard()); - } - - public PledgeOfLoyaltyProtectionAbility(final PledgeOfLoyaltyProtectionAbility ability) { - super(ability); - } - - @Override - public PledgeOfLoyaltyProtectionAbility copy() { - return new PledgeOfLoyaltyProtectionAbility(this); - } - - - @Override - public boolean canTarget(MageObject source, Game game) { - ObjectColor color = new ObjectColor(); - for (Permanent permanent: game.getBattlefield().getAllActivePermanents(controllerId)) { - ObjectColor permanentColor = permanent.getColor(game); - if (permanentColor.isColorless()) { - continue; - } - if (permanentColor.isBlack()) { - color.setBlack(true); - } - if (permanentColor.isBlue()) { - color.setBlue(true); - } - if (permanentColor.isGreen()) { - color.setGreen(true); - } - if (permanentColor.isRed()) { - color.setRed(true); - } - if (permanentColor.isWhite()) { - color.setWhite(true); - } - } - - List> colorPredicates = new ArrayList<>(); - if (color.isBlack()) { - colorPredicates.add(new ColorPredicate(ObjectColor.BLACK)); - } - if (color.isBlue()) { - colorPredicates.add(new ColorPredicate(ObjectColor.BLUE)); - } - if (color.isGreen()) { - colorPredicates.add(new ColorPredicate(ObjectColor.GREEN)); - } - if (color.isRed()) { - colorPredicates.add(new ColorPredicate(ObjectColor.RED)); - } - if (color.isWhite()) { - colorPredicates.add(new ColorPredicate(ObjectColor.WHITE)); - } - Filter protectionFilter = new FilterObject("the colors of permanents you control"); - protectionFilter.add(Predicates.or(colorPredicates)); - this.filter = protectionFilter; - return super.canTarget(source, game); - } - - @Override - public String getRule() { - return "{this} has protection from the colors of permanents you control."; - } + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + ObjectColor color = input.getObject().getColor(game); + return color.hasColor() + && game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_PERMANENT, + input.getPlayerId(), input.getSource(), game + ).stream() + .anyMatch(permanent -> permanent.getColor(game).shares(color)); } } diff --git a/Mage.Sets/src/mage/cards/p/PlungeIntoDarkness.java b/Mage.Sets/src/mage/cards/p/PlungeIntoDarkness.java index bf6ead3e34f..95fc93e7ae4 100644 --- a/Mage.Sets/src/mage/cards/p/PlungeIntoDarkness.java +++ b/Mage.Sets/src/mage/cards/p/PlungeIntoDarkness.java @@ -40,8 +40,7 @@ public final class PlungeIntoDarkness extends CardImpl { // Sacrifice any number of creatures, then you gain 3 life for each sacrificed creature; this.getSpellAbility().addEffect(new PlungeIntoDarknessLifeEffect()); // or pay X life, then look at the top X cards of your library, put one of those cards into your hand, and exile the rest. - Mode mode = new Mode(); - mode.addEffect(new PlungeIntoDarknessSearchEffect()); + Mode mode = new Mode(new PlungeIntoDarknessSearchEffect()); this.getSpellAbility().getModes().addMode(mode); // Entwine {B} diff --git a/Mage.Sets/src/mage/cards/p/PolymorphistsJest.java b/Mage.Sets/src/mage/cards/p/PolymorphistsJest.java index 1ad549483b8..721d81b047a 100644 --- a/Mage.Sets/src/mage/cards/p/PolymorphistsJest.java +++ b/Mage.Sets/src/mage/cards/p/PolymorphistsJest.java @@ -62,7 +62,7 @@ class PolymorphistsJestEffect extends ContinuousEffectImpl { game.getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - getTargetPointer().getFirst(game, source), source.getSourceId(), game + getTargetPointer().getFirst(game, source), source, game ).stream() .map(permanent -> new MageObjectReference(permanent, game)) .forEach(affectedObjectList::add); diff --git a/Mage.Sets/src/mage/cards/p/PolymorphousRush.java b/Mage.Sets/src/mage/cards/p/PolymorphousRush.java index 60233d3f703..1097da357b2 100644 --- a/Mage.Sets/src/mage/cards/p/PolymorphousRush.java +++ b/Mage.Sets/src/mage/cards/p/PolymorphousRush.java @@ -69,7 +69,7 @@ class PolymorphousRushCopyEffect extends OneShotEffect { Target target = new TargetCreaturePermanent(new FilterCreaturePermanent("")); target.setNotTarget(true); target.setTargetName("a creature on the battlefield (creature to copy)"); - if (target.canChoose(source.getId(), controller.getId(), game) && controller.chooseTarget(outcome, target, source, game)) { + if (target.canChoose(controller.getId(), source, game) && controller.chooseTarget(outcome, target, source, game)) { Permanent copyFromCreature = game.getPermanent(target.getFirstTarget()); if (copyFromCreature != null) { for (UUID copyToId : getTargetPointer().getTargets(game, source)) { diff --git a/Mage.Sets/src/mage/cards/p/Ponder.java b/Mage.Sets/src/mage/cards/p/Ponder.java index 67f7965df86..7191766552c 100644 --- a/Mage.Sets/src/mage/cards/p/Ponder.java +++ b/Mage.Sets/src/mage/cards/p/Ponder.java @@ -1,9 +1,9 @@ - package mage.cards.p; import java.util.UUID; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LookLibraryControllerEffect; +import mage.abilities.effects.common.ShuffleLibrarySourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -16,9 +16,10 @@ public final class Ponder extends CardImpl { public Ponder(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{U}"); - - // Look at the top three cards of your library, then put them back in any order. You may shuffle your library. - this.getSpellAbility().addEffect(new LookLibraryControllerEffect(3, true, true)); + // Look at the top three cards of your library, then put them back in any order. + this.getSpellAbility().addEffect(new LookLibraryControllerEffect(3)); + // You may shuffle. + this.getSpellAbility().addEffect(new ShuffleLibrarySourceEffect(true)); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } @@ -31,4 +32,4 @@ public final class Ponder extends CardImpl { public Ponder copy() { return new Ponder(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/p/PonderingMage.java b/Mage.Sets/src/mage/cards/p/PonderingMage.java index b9e38f3eb74..b8fe061f66d 100644 --- a/Mage.Sets/src/mage/cards/p/PonderingMage.java +++ b/Mage.Sets/src/mage/cards/p/PonderingMage.java @@ -5,6 +5,7 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LookLibraryControllerEffect; +import mage.abilities.effects.common.ShuffleLibrarySourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -26,9 +27,8 @@ public final class PonderingMage extends CardImpl { this.toughness = new MageInt(4); // When Pondering Mage enters the battlefield, look at the top three cards of your library, then put them back in any order. You may shuffle your library. Draw a card. - Ability ability = new EntersBattlefieldTriggeredAbility( - new LookLibraryControllerEffect(3, true, true) - ); + Ability ability = new EntersBattlefieldTriggeredAbility(new LookLibraryControllerEffect(3)); + ability.addEffect(new ShuffleLibrarySourceEffect(true)); ability.addEffect(new DrawCardSourceControllerEffect(1)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/PonybackBrigade.java b/Mage.Sets/src/mage/cards/p/PonybackBrigade.java index 5fa30bc973d..c67129f4d5f 100644 --- a/Mage.Sets/src/mage/cards/p/PonybackBrigade.java +++ b/Mage.Sets/src/mage/cards/p/PonybackBrigade.java @@ -14,7 +14,6 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.game.permanent.token.GoblinToken; import mage.game.permanent.token.Token; @@ -37,7 +36,7 @@ public final class PonybackBrigade extends CardImpl { this.addAbility(new PonybackBrigadeAbility(new GoblinToken())); // Morph {2}{R}{W}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{R}{W}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{R}{W}{B}"))); } private PonybackBrigade(final PonybackBrigade card) { diff --git a/Mage.Sets/src/mage/cards/p/PoppetFactory.java b/Mage.Sets/src/mage/cards/p/PoppetFactory.java index 0dd45685704..862f5e6ec0c 100644 --- a/Mage.Sets/src/mage/cards/p/PoppetFactory.java +++ b/Mage.Sets/src/mage/cards/p/PoppetFactory.java @@ -76,7 +76,7 @@ class PoppetFactoryEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { for (Permanent permanent : game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game )) { switch (layer) { case AbilityAddingRemovingEffects_6: diff --git a/Mage.Sets/src/mage/cards/p/Porcuparrot.java b/Mage.Sets/src/mage/cards/p/Porcuparrot.java index 1f8bf3b988c..a6a5fed909b 100644 --- a/Mage.Sets/src/mage/cards/p/Porcuparrot.java +++ b/Mage.Sets/src/mage/cards/p/Porcuparrot.java @@ -32,9 +32,12 @@ public final class Porcuparrot extends CardImpl { this.addAbility(new MutateAbility(this, "{2}{R}")); // {T}: This creature deals X damage to any target, where X is the number of times this creature has mutated. - Ability ability = new SimpleActivatedAbility(new DamageTargetEffect( - SourceMutatedCount.instance, "this creature" - ), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility( + new DamageTargetEffect(SourceMutatedCount.instance) + .setText("this creature deals X damage to any target, " + + "where X is the number of times this creature has mutated"), + new TapSourceCost() + ); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/PorphyryNodes.java b/Mage.Sets/src/mage/cards/p/PorphyryNodes.java index 6ed42490729..a6b24365ca4 100644 --- a/Mage.Sets/src/mage/cards/p/PorphyryNodes.java +++ b/Mage.Sets/src/mage/cards/p/PorphyryNodes.java @@ -93,8 +93,8 @@ class PorphyryNodesEffect extends OneShotEffect { filter.add(new PowerPredicate(ComparisonType.EQUAL_TO, leastPower)); Target target = new TargetPermanent(filter); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { - if (controller.choose(outcome, target, source.getSourceId(), game)) { + if (target.canChoose(source.getControllerId(), source, game)) { + if (controller.choose(outcome, target, source, game)) { permanentToDestroy = game.getPermanent(target.getFirstTarget()); } } @@ -127,7 +127,7 @@ class PorphyryNodesStateTriggeredAbility extends StateTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - return game.getBattlefield().count(PorphyryNodes.filter, this.getSourceId(), this.getControllerId(), game) == 0; + return game.getBattlefield().count(PorphyryNodes.filter, this.getControllerId(), this, game) == 0; } @Override diff --git a/Mage.Sets/src/mage/cards/p/PortOfKarfell.java b/Mage.Sets/src/mage/cards/p/PortOfKarfell.java index e9861125187..b838903cd1f 100644 --- a/Mage.Sets/src/mage/cards/p/PortOfKarfell.java +++ b/Mage.Sets/src/mage/cards/p/PortOfKarfell.java @@ -78,10 +78,10 @@ class PortOfKarfellEffect extends OneShotEffect { player.millCards(4, source, game); TargetCard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (!target.canChoose(source.getControllerId(), source, game)) { return true; } - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card != null) { player.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); diff --git a/Mage.Sets/src/mage/cards/p/PortalMage.java b/Mage.Sets/src/mage/cards/p/PortalMage.java index 1dc20e2c301..2ba54f086a7 100644 --- a/Mage.Sets/src/mage/cards/p/PortalMage.java +++ b/Mage.Sets/src/mage/cards/p/PortalMage.java @@ -109,7 +109,6 @@ class PortalMageEffect extends OneShotEffect { } // Select the new defender TargetDefender target = new TargetDefender(defenders, null); - target.setNotTarget(true); // player or planswalker hexproof does not prevent attacking a player if (controller.chooseTarget(Outcome.Damage, target, source, game)) { if (!combatGroupTarget.getDefenderId().equals(target.getFirstTarget())) { if (combatGroupTarget.changeDefenderPostDeclaration(target.getFirstTarget(), game)) { diff --git a/Mage.Sets/src/mage/cards/p/PossessedSkaab.java b/Mage.Sets/src/mage/cards/p/PossessedSkaab.java index e87fca4d0fa..025c0e63253 100644 --- a/Mage.Sets/src/mage/cards/p/PossessedSkaab.java +++ b/Mage.Sets/src/mage/cards/p/PossessedSkaab.java @@ -1,32 +1,24 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; 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.constants.*; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.events.ZoneChangeEvent; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class PossessedSkaab extends CardImpl { @@ -37,22 +29,23 @@ public final class PossessedSkaab extends CardImpl { filter.add(Predicates.or( CardType.INSTANT.getPredicate(), CardType.SORCERY.getPredicate(), - CardType.CREATURE.getPredicate())); + CardType.CREATURE.getPredicate() + )); } public PossessedSkaab(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{B}"); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(3); this.toughness = new MageInt(2); // When Possessed Skaab enters the battlefield, return target instant, sorcery, or creature card from your graveyard to your hand. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false); + EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), false); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); // If Possessed Skaab would die, exile it instead. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PossessedSkaabDiesEffect())); + this.addAbility(new SimpleStaticAbility(new PossessedSkaabDiesEffect())); } private PossessedSkaab(final PossessedSkaab card) { @@ -100,5 +93,4 @@ class PossessedSkaabDiesEffect extends ReplacementEffectImpl { } return false; } - } diff --git a/Mage.Sets/src/mage/cards/p/PossibilityStorm.java b/Mage.Sets/src/mage/cards/p/PossibilityStorm.java index 10dafb8feac..87a3cdf4201 100644 --- a/Mage.Sets/src/mage/cards/p/PossibilityStorm.java +++ b/Mage.Sets/src/mage/cards/p/PossibilityStorm.java @@ -70,16 +70,15 @@ class PossibilityStormTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getZone() == Zone.HAND) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getTargetId())); - } - return true; - } + if (event.getZone() != Zone.HAND) { return false; } + + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell == null) { return false; } + + for (Effect effect : this.getEffects()) { + effect.setTargetPointer(new FixedTarget(event.getTargetId())); } - return false; + return true; } @Override @@ -107,43 +106,44 @@ class PossibilityStormEffect extends OneShotEffect { spell = ((Spell) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.STACK)); noLongerOnStack = true; } + if (spell == null) { return false; } + + Player spellController = game.getPlayer(spell.getControllerId()); + if (spellController == null) { return false; } + MageObject sourceObject = source.getSourceObject(game); - if (sourceObject != null && spell != null) { - Player spellController = game.getPlayer(spell.getControllerId()); - if (spellController != null) { - if (!noLongerOnStack) { - spellController.moveCardsToExile(spell, source, game, true, source.getSourceId(), sourceObject.getIdName()); - } - if (spellController.getLibrary().hasCards()) { - Library library = spellController.getLibrary(); - Card card; - do { - card = library.getFromTop(game); - if (card != null) { - spellController.moveCardsToExile(card, source, game, true, source.getSourceId(), sourceObject.getIdName()); - } - } while (library.hasCards() && card != null && !sharesType(card, spell.getCardType(game), game)); + if (sourceObject == null) { return false; } - if (card != null && sharesType(card, spell.getCardType(game), game) - && !card.isLand(game) - && card.getSpellAbility().canChooseTarget(game, spellController.getId())) { - if (spellController.chooseUse(Outcome.PlayForFree, "Cast " + card.getLogName() + " without paying cost?", source, game)) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - spellController.cast(spellController.chooseAbilityForCast(card, game, true), game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - } - } + if (!noLongerOnStack) { + spellController.moveCardsToExile(spell, source, game, true, source.getSourceId(), sourceObject.getIdName()); + } - ExileZone exile = game.getExile().getExileZone(source.getSourceId()); - if (exile != null) { - spellController.putCardsOnBottomOfLibrary(exile, game, source, false); - } + if (!spellController.getLibrary().hasCards()) { return true; } + Library library = spellController.getLibrary(); + Card card; + do { + card = library.getFromTop(game); + if (card != null) { + spellController.moveCardsToExile(card, source, game, true, source.getSourceId(), sourceObject.getIdName()); + } + } while (library.hasCards() && card != null && !sharesType(card, spell.getCardType(game), game)); - } - return true; + if (card != null && sharesType(card, spell.getCardType(game), game) + && !card.isLand(game) + && card.getSpellAbility().canChooseTarget(game, spellController.getId())) { + if (spellController.chooseUse(Outcome.PlayForFree, "Cast " + card.getLogName() + " without paying cost?", source, game)) { + game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); + spellController.cast(spellController.chooseAbilityForCast(card, game, true), game, true, new ApprovingObject(source, game)); + game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } } - return false; + + ExileZone exile = game.getExile().getExileZone(source.getSourceId()); + if (exile != null) { + spellController.putCardsOnBottomOfLibrary(exile, game, source, false); + } + + return true; } private boolean sharesType(Card card, List cardTypes, Game game) { diff --git a/Mage.Sets/src/mage/cards/p/PoulticeSliver.java b/Mage.Sets/src/mage/cards/p/PoulticeSliver.java index 4f3e3ef12ea..b1a3629dffc 100644 --- a/Mage.Sets/src/mage/cards/p/PoulticeSliver.java +++ b/Mage.Sets/src/mage/cards/p/PoulticeSliver.java @@ -35,11 +35,11 @@ public final class PoulticeSliver extends CardImpl { // All Slivers have "{2}, {tap}: Regenerate target Sliver." Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateTargetEffect(), new GenericManaCost(2)); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ALL_SLIVERS)); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(ability, - Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, + Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS, "All Slivers have \"{2}, {T}: Regenerate target Sliver.\""))); } diff --git a/Mage.Sets/src/mage/cards/p/PowderKeg.java b/Mage.Sets/src/mage/cards/p/PowderKeg.java index afc9a251195..e60027d165e 100644 --- a/Mage.Sets/src/mage/cards/p/PowderKeg.java +++ b/Mage.Sets/src/mage/cards/p/PowderKeg.java @@ -72,7 +72,7 @@ class PowderKegEffect extends OneShotEffect { FilterPermanent filter = new FilterPermanent(); filter.add(Predicates.or(CardType.ARTIFACT.getPredicate(), CardType.CREATURE.getPredicate())); filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, count)); - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { perm.destroy(source, game, false); } return true; diff --git a/Mage.Sets/src/mage/cards/p/PowerArmor.java b/Mage.Sets/src/mage/cards/p/PowerArmor.java index 691283bce24..7c236b76b45 100644 --- a/Mage.Sets/src/mage/cards/p/PowerArmor.java +++ b/Mage.Sets/src/mage/cards/p/PowerArmor.java @@ -28,7 +28,7 @@ public final class PowerArmor extends CardImpl { // Domain - {3}, {tap}: Target creature gets +1/+1 until end of turn for each basic land type among lands you control. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect( - new DomainValue(), new DomainValue(), Duration.EndOfTurn), new TapSourceCost()); + DomainValue.REGULAR, DomainValue.REGULAR, Duration.EndOfTurn), new TapSourceCost()); ability.addCost(new ManaCostsImpl("{3}")); ability.addTarget(new TargetCreaturePermanent()); ability.setAbilityWord(AbilityWord.DOMAIN); diff --git a/Mage.Sets/src/mage/cards/p/PowerConduit.java b/Mage.Sets/src/mage/cards/p/PowerConduit.java index 7839ec05905..9b9d1fb6529 100644 --- a/Mage.Sets/src/mage/cards/p/PowerConduit.java +++ b/Mage.Sets/src/mage/cards/p/PowerConduit.java @@ -30,8 +30,7 @@ public final class PowerConduit extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.CHARGE.createInstance()), new TapSourceCost()); ability.addCost(new RemoveCounterCost(new TargetControlledPermanent())); ability.addTarget(new TargetArtifactPermanent()); - Mode mode = new Mode(); - mode.addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + Mode mode = new Mode(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); mode.addTarget(new TargetCreaturePermanent()); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/p/PowerDepot.java b/Mage.Sets/src/mage/cards/p/PowerDepot.java index 73b5ea4fe67..990f9b9be77 100644 --- a/Mage.Sets/src/mage/cards/p/PowerDepot.java +++ b/Mage.Sets/src/mage/cards/p/PowerDepot.java @@ -74,7 +74,7 @@ enum PowerDepotCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && object.isArtifact(game); } } diff --git a/Mage.Sets/src/mage/cards/p/PowerOfPersuasion.java b/Mage.Sets/src/mage/cards/p/PowerOfPersuasion.java index 3e112cb30f1..9f3c975acce 100644 --- a/Mage.Sets/src/mage/cards/p/PowerOfPersuasion.java +++ b/Mage.Sets/src/mage/cards/p/PowerOfPersuasion.java @@ -1,8 +1,6 @@ package mage.cards.p; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.effects.common.RollDieWithResultTableEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; @@ -10,9 +8,6 @@ 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.players.Player; import mage.target.common.TargetOpponentsCreaturePermanent; import java.util.UUID; @@ -36,7 +31,9 @@ public final class PowerOfPersuasion extends CardImpl { effect.addTableEntry(1, 9, new ReturnToHandTargetEffect().setText("return it to its owner's hand")); // 10-19 | Its owner puts it on the top of bottom of their library. - effect.addTableEntry(10, 19, new PowerOfPersuasionEffect()); + effect.addTableEntry(10, 19, new PutOnTopOrBottomLibraryTargetEffect( + "its owner puts it on the top of bottom of their library" + )); // 20 | Gain control of it until the end of your next turn. effect.addTableEntry(20, 20, new GainControlTargetEffect( @@ -53,33 +50,3 @@ public final class PowerOfPersuasion extends CardImpl { return new PowerOfPersuasion(this); } } - -class PowerOfPersuasionEffect extends OneShotEffect { - - PowerOfPersuasionEffect() { - super(Outcome.Benefit); - staticText = "its owner puts it on the top or bottom of their library"; - } - - private PowerOfPersuasionEffect(final PowerOfPersuasionEffect effect) { - super(effect); - } - - @Override - public PowerOfPersuasionEffect copy() { - return new PowerOfPersuasionEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget())); - if (player == null) { - return false; - } - if (player.chooseUse(Outcome.Detriment, "Put the targeted object on the top or bottom of your library?", - "", "Top", "Bottom", source, game)) { - return new PutOnLibraryTargetEffect(true).apply(game, source); - } - return new PutOnLibraryTargetEffect(false).apply(game, source); - } -} diff --git a/Mage.Sets/src/mage/cards/p/PowerSink.java b/Mage.Sets/src/mage/cards/p/PowerSink.java index 0a9b3271587..289ebd02190 100644 --- a/Mage.Sets/src/mage/cards/p/PowerSink.java +++ b/Mage.Sets/src/mage/cards/p/PowerSink.java @@ -66,7 +66,7 @@ class PowerSinkCounterUnlessPaysEffect extends OneShotEffect { if (spell != null) { Player player = game.getPlayer(spell.getControllerId()); Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (player != null && controller != null && sourceObject != null) { int amount = source.getManaCostsToPay().getX(); if (amount > 0) { diff --git a/Mage.Sets/src/mage/cards/p/PowerstoneMinefield.java b/Mage.Sets/src/mage/cards/p/PowerstoneMinefield.java index 6871fbed40c..e69f54accc4 100644 --- a/Mage.Sets/src/mage/cards/p/PowerstoneMinefield.java +++ b/Mage.Sets/src/mage/cards/p/PowerstoneMinefield.java @@ -12,7 +12,6 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; @@ -59,7 +58,7 @@ class PowerstoneMinefieldTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanent(event.getSourceId()); - if (filter.match(permanent, getSourceId(), getControllerId(), game)) { + if (filter.match(permanent, getControllerId(), this, game)) { for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(permanent, game)); } diff --git a/Mage.Sets/src/mage/cards/p/Pox.java b/Mage.Sets/src/mage/cards/p/Pox.java index 62e0023aba6..ad9a77092cd 100644 --- a/Mage.Sets/src/mage/cards/p/Pox.java +++ b/Mage.Sets/src/mage/cards/p/Pox.java @@ -86,7 +86,7 @@ class PoxEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null) { FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - int creaturesToSacrifice = (int) Math.ceil(game.getBattlefield().count(filter, source.getSourceId(), player.getId(), game) / 3.0); + int creaturesToSacrifice = (int) Math.ceil(game.getBattlefield().count(filter, player.getId(), source, game) / 3.0); if (creaturesToSacrifice > 0) { Target target = new TargetControlledCreaturePermanent(creaturesToSacrifice, creaturesToSacrifice, filter, true); target.chooseTarget(Outcome.Sacrifice, playerId, source, game); @@ -104,7 +104,7 @@ class PoxEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null) { FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); - int landsToSacrifice = (int) Math.ceil(game.getBattlefield().count(filter, source.getSourceId(), player.getId(), game) / 3.0); + int landsToSacrifice = (int) Math.ceil(game.getBattlefield().count(filter, player.getId(), source, game) / 3.0); if (landsToSacrifice > 0) { Target target = new TargetControlledPermanent(landsToSacrifice, landsToSacrifice, filter, true); target.chooseTarget(Outcome.Sacrifice, playerId, source, game); diff --git a/Mage.Sets/src/mage/cards/p/PrecursorGolem.java b/Mage.Sets/src/mage/cards/p/PrecursorGolem.java index 3193a0944c8..14055e2644d 100644 --- a/Mage.Sets/src/mage/cards/p/PrecursorGolem.java +++ b/Mage.Sets/src/mage/cards/p/PrecursorGolem.java @@ -144,7 +144,7 @@ class PrecursorGolemCopySpellEffect extends CopySpellForEachItCouldTargetEffect Permanent permanent = game.getPermanent((UUID) getValue("targetedGolem")); return game.getBattlefield() .getActivePermanents( - filter, player.getId(), source.getSourceId(), game + filter, player.getId(), source, game ).stream() .filter(Objects::nonNull) .filter(p -> !p.equals(permanent)) diff --git a/Mage.Sets/src/mage/cards/p/PredatorsGambit.java b/Mage.Sets/src/mage/cards/p/PredatorsGambit.java index af9c3c6deaa..c7116ad88eb 100644 --- a/Mage.Sets/src/mage/cards/p/PredatorsGambit.java +++ b/Mage.Sets/src/mage/cards/p/PredatorsGambit.java @@ -1,4 +1,3 @@ - package mage.cards.p; import java.util.UUID; @@ -6,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CreatureCountCondition; import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; @@ -23,7 +21,8 @@ import mage.target.common.TargetCreaturePermanent; */ public final class PredatorsGambit extends CardImpl { - private static final String rule = "Enchanted creature has intimidate as long as its controller controls no other creatures"; + private static final String rule = "Enchanted creature has intimidate as long as its controller controls no other creatures. " + + "(It can't be blocked except by artifact creatures and/or creatures that share a color with it.)"; public PredatorsGambit(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{B}"); @@ -38,12 +37,14 @@ public final class PredatorsGambit extends CardImpl { this.addAbility(ability); // Enchanted creature gets +2/+1. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, 1, Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(2, 1))); // Enchanted creature has intimidate as long as its controller controls no other creatures. - ContinuousEffect effect = new GainAbilityAttachedEffect(IntimidateAbility.getInstance(), AttachmentType.AURA); - ConditionalContinuousEffect intimidate = new ConditionalContinuousEffect(effect, new CreatureCountCondition(1, TargetController.YOU), rule); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, intimidate)); + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilityAttachedEffect(IntimidateAbility.getInstance(), AttachmentType.AURA), + new CreatureCountCondition(1, TargetController.YOU), + rule + ))); } diff --git a/Mage.Sets/src/mage/cards/p/PredatoryImpetus.java b/Mage.Sets/src/mage/cards/p/PredatoryImpetus.java index 76dcd0113f3..101fa288773 100644 --- a/Mage.Sets/src/mage/cards/p/PredatoryImpetus.java +++ b/Mage.Sets/src/mage/cards/p/PredatoryImpetus.java @@ -1,9 +1,10 @@ package mage.cards.p; import mage.abilities.Ability; -import mage.abilities.common.GoadAttachedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.combat.GoadAttachedEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; @@ -37,11 +38,10 @@ public final class PredatoryImpetus extends CardImpl { this.addAbility(ability); // Enchanted creature gets +3/+3, must be blocked if able, and is goaded. - this.addAbility(new GoadAttachedAbility( - new BoostEnchantedEffect(3, 3) - .setText("Enchanted creature gets +3/+3"), - new PredatoryImpetusEffect() - )); + ability = new SimpleStaticAbility(new BoostEnchantedEffect(3, 3)); + ability.addEffect(new PredatoryImpetusEffect()); + ability.addEffect(new GoadAttachedEffect().concatBy(",")); + this.addAbility(ability); } private PredatoryImpetus(final PredatoryImpetus card) { diff --git a/Mage.Sets/src/mage/cards/p/PredatorySliver.java b/Mage.Sets/src/mage/cards/p/PredatorySliver.java index 43a8747cfba..d642c6e97ff 100644 --- a/Mage.Sets/src/mage/cards/p/PredatorySliver.java +++ b/Mage.Sets/src/mage/cards/p/PredatorySliver.java @@ -28,7 +28,7 @@ public final class PredatorySliver extends CardImpl { // Sliver creatures you control get +1/+1. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new BoostControlledEffect(1, 1, Duration.WhileInGraveyard, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS))); + new BoostControlledEffect(1, 1, Duration.WhileInGraveyard, StaticFilters.FILTER_PERMANENT_SLIVERS))); } private PredatorySliver(final PredatorySliver card) { diff --git a/Mage.Sets/src/mage/cards/p/PreeminentCaptain.java b/Mage.Sets/src/mage/cards/p/PreeminentCaptain.java index 021dc61b36e..3431375138f 100644 --- a/Mage.Sets/src/mage/cards/p/PreeminentCaptain.java +++ b/Mage.Sets/src/mage/cards/p/PreeminentCaptain.java @@ -70,8 +70,8 @@ class PreeminentCaptainEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); TargetCardInHand target = new TargetCardInHand(filter); - if (controller != null && target.canChoose(source.getSourceId(), controller.getId(), game) - && target.choose(outcome, controller.getId(), source.getSourceId(), game)) { + if (controller != null && target.canChoose(controller.getId(), source, game) + && target.choose(outcome, controller.getId(), source.getSourceId(), source, game)) { if (!target.getTargets().isEmpty()) { UUID cardId = target.getFirstTarget(); Card card = controller.getHand().get(cardId, game); diff --git a/Mage.Sets/src/mage/cards/p/PreferredSelection.java b/Mage.Sets/src/mage/cards/p/PreferredSelection.java index 46bd3918406..f020d5f41ee 100644 --- a/Mage.Sets/src/mage/cards/p/PreferredSelection.java +++ b/Mage.Sets/src/mage/cards/p/PreferredSelection.java @@ -6,10 +6,10 @@ import mage.abilities.costs.CompositeCost; import mage.abilities.costs.Cost; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.Cards; @@ -17,8 +17,6 @@ import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.TargetController; -import mage.constants.Zone; -import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; @@ -52,7 +50,7 @@ class PreferredSelectionEffect extends OneShotEffect { PreferredSelectionEffect() { super(Outcome.Benefit); - staticText = "At the beginning of your upkeep, look at the top two cards of your library. " + + staticText = "look at the top two cards of your library. " + "You may sacrifice {this} and pay {2}{G}{G}. If you do, put one of those cards into your hand. " + "If you don't, put one of those cards on the bottom of your library."; } @@ -79,15 +77,9 @@ class PreferredSelectionEffect extends OneShotEffect { "sacrifice this permanent and pay {2}{G}{G}" ); return new DoIfCostPaid( - new LookLibraryAndPickControllerEffect( - StaticValue.get(2), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.HAND, true, false - ), - new LookLibraryAndPickControllerEffect( - StaticValue.get(2), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.HAND, true, false, - false, Zone.LIBRARY, false, true, false - ), cost + new LookLibraryAndPickControllerEffect(2, 1, PutCards.HAND, PutCards.TOP_ANY), + new LookLibraryAndPickControllerEffect(2, 1, PutCards.BOTTOM_ANY, PutCards.TOP_ANY), + cost ).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/p/PrematureBurial.java b/Mage.Sets/src/mage/cards/p/PrematureBurial.java index cdf917f8900..90b28af2dde 100644 --- a/Mage.Sets/src/mage/cards/p/PrematureBurial.java +++ b/Mage.Sets/src/mage/cards/p/PrematureBurial.java @@ -65,11 +65,11 @@ class ETBSinceYourLastTurnTarget extends TargetCreaturePermanent { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - MageObject targetSource = game.getObject(sourceId); + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + MageObject targetSource = game.getObject(source); ETBSinceYourLastTurnWatcher watcher = game.getState().getWatcher(ETBSinceYourLastTurnWatcher.class); if (targetSource != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { if (watcher != null && watcher.enteredSinceLastTurn(sourceControllerId, new MageObjectReference(permanent.getId(), game))) { return true; diff --git a/Mage.Sets/src/mage/cards/p/PressIntoService.java b/Mage.Sets/src/mage/cards/p/PressIntoService.java index 4ed731d89ba..68783fe3aab 100644 --- a/Mage.Sets/src/mage/cards/p/PressIntoService.java +++ b/Mage.Sets/src/mage/cards/p/PressIntoService.java @@ -28,18 +28,20 @@ public final class PressIntoService extends CardImpl { getSpellAbility().addEffect(new SupportEffect(this, 2, false)); // Gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn. - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - Effect effect = new GainControlTargetEffect(Duration.EndOfTurn); - effect.setTargetPointer(new SecondTargetPointer()); // First target is used by Support - this.getSpellAbility().addEffect(effect); - effect = new UntapTargetEffect(); - effect.setText("Untap that creature"); - effect.setTargetPointer(new SecondTargetPointer()); // First target is used by Support - this.getSpellAbility().addEffect(effect); - effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); - effect.setTargetPointer(new SecondTargetPointer()); // First target is used by Suppor - effect.setText("It gains haste until end of turn"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // First target is used by Support + + this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn) + .setText("Gain control of target creature until end of turn") + .setTargetPointer(new SecondTargetPointer()) + ); + this.getSpellAbility().addEffect(new UntapTargetEffect() + .setText("Untap that creature") + .setTargetPointer(new SecondTargetPointer()) + ); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn) + .setText("It gains haste until end of turn") + .setTargetPointer(new SecondTargetPointer()) + ); } private PressIntoService(final PressIntoService card) { diff --git a/Mage.Sets/src/mage/cards/p/PrideOfTheClouds.java b/Mage.Sets/src/mage/cards/p/PrideOfTheClouds.java index dcb00281a68..8adc07492d6 100644 --- a/Mage.Sets/src/mage/cards/p/PrideOfTheClouds.java +++ b/Mage.Sets/src/mage/cards/p/PrideOfTheClouds.java @@ -1,4 +1,3 @@ - package mage.cards.p; import java.util.UUID; @@ -16,11 +15,11 @@ 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.mageobject.AbilityPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.WhiteBlueBirdToken; + /** * * @author fireshoes @@ -33,6 +32,8 @@ public final class PrideOfTheClouds extends CardImpl { filter.add(AnotherPredicate.instance); filter.add(new AbilityPredicate(FlyingAbility.class)); } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); public PrideOfTheClouds(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{U}"); @@ -43,13 +44,12 @@ public final class PrideOfTheClouds extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // Pride of the Clouds gets +1/+1 for each other creature with flying on the battlefield. - DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceEffect(xValue, xValue, Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(new BoostSourceEffect(xValue, xValue, Duration.WhileOnBattlefield))); // Forecast - {2}{W}{U}, Reveal Pride of the Clouds from your hand: Create a 1/1 white and blue Bird creature token with flying. - this.addAbility(new ForecastAbility(new CreateTokenEffect(new BirdToken()), new ManaCostsImpl("{2}{W}{U}"))); + this.addAbility(new ForecastAbility(new CreateTokenEffect(new WhiteBlueBirdToken()), new ManaCostsImpl("{2}{W}{U}"))); } private PrideOfTheClouds(final PrideOfTheClouds card) { @@ -60,25 +60,4 @@ public final class PrideOfTheClouds extends CardImpl { public PrideOfTheClouds copy() { return new PrideOfTheClouds(this); } - - private static class BirdToken extends TokenImpl { - - public BirdToken() { - super("Bird", "1/1 white and blue Bird creature token with flying"); - cardType.add(CardType.CREATURE); - color.setWhite(true); - color.setBlue(true); - subtype.add(SubType.BIRD); - power = new MageInt(1); - toughness = new MageInt(1); - addAbility(FlyingAbility.getInstance()); - } - public BirdToken(final BirdToken token) { - super(token); - } - - public BirdToken copy() { - return new BirdToken(this); - } - } } diff --git a/Mage.Sets/src/mage/cards/p/PriestOfTheBlessedGraf.java b/Mage.Sets/src/mage/cards/p/PriestOfTheBlessedGraf.java index c7f0ff1ae68..e53b005ea4e 100644 --- a/Mage.Sets/src/mage/cards/p/PriestOfTheBlessedGraf.java +++ b/Mage.Sets/src/mage/cards/p/PriestOfTheBlessedGraf.java @@ -83,7 +83,7 @@ enum PriestOfTheBlessedGrafValue implements DynamicValue { .getActivePermanents( StaticFilters.FILTER_LAND, source.getControllerId(), - source.getSourceId(), game + source, game ).stream() .map(Controllable::getControllerId) .collect(Collectors.toMap(Function.identity(), u -> 1, Integer::sum)); diff --git a/Mage.Sets/src/mage/cards/p/PriestOfTheWakeningSun.java b/Mage.Sets/src/mage/cards/p/PriestOfTheWakeningSun.java index 23a784c96b5..de09b3299f6 100644 --- a/Mage.Sets/src/mage/cards/p/PriestOfTheWakeningSun.java +++ b/Mage.Sets/src/mage/cards/p/PriestOfTheWakeningSun.java @@ -92,10 +92,10 @@ class PriestOfTheWakeningSunEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { - if (controller.getHand().count(filter, source.getSourceId(), source.getControllerId(), game) > 0) { + if (controller.getHand().count(filter, source.getControllerId(), source, game) > 0) { if (controller.chooseUse(outcome, "Reveal a Dinosaur card?", source, game)) { TargetCardInHand target = new TargetCardInHand(0, 1, filter); if (controller.chooseTarget(outcome, target, source, game) && !target.getTargets().isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/p/PrimalBeyond.java b/Mage.Sets/src/mage/cards/p/PrimalBeyond.java index 6df864fd9f8..ceb104e0a1f 100644 --- a/Mage.Sets/src/mage/cards/p/PrimalBeyond.java +++ b/Mage.Sets/src/mage/cards/p/PrimalBeyond.java @@ -28,7 +28,7 @@ import mage.target.common.TargetCardInHand; */ public final class PrimalBeyond extends CardImpl { - private static final FilterCard filter = new FilterCard("a Elemental card from your hand"); + private static final FilterCard filter = new FilterCard("an Elemental card from your hand"); static { filter.add(SubType.ELEMENTAL.getPredicate()); @@ -38,7 +38,7 @@ public final class PrimalBeyond extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.LAND},""); // As Primal Beyond enters the battlefield, you may reveal an Elemental card from your hand. If you don't, Primal Beyond enters the battlefield tapped. - this.addAbility(new AsEntersBattlefieldAbility(new TapSourceUnlessPaysEffect(new RevealTargetFromHandCost(new TargetCardInHand(filter))), "you may reveal a Elemental card from your hand. If you don't, {this} enters the battlefield tapped")); + this.addAbility(new AsEntersBattlefieldAbility(new TapSourceUnlessPaysEffect(new RevealTargetFromHandCost(new TargetCardInHand(filter))), "you may reveal an Elemental card from your hand. If you don't, {this} enters the battlefield tapped")); // {tap}: Add {C}. this.addAbility(new ColorlessManaAbility()); // {tap}: Add one mana of any color. Spend this mana only to cast an Elemental spell or activate an ability of an Elemental. @@ -65,7 +65,7 @@ class PrimalBeyondManaBuilder extends ConditionalManaBuilder { @Override public String getRule() { - return "Spend this mana only to cast Elemental spells or activate abilities of Elementals"; + return "Spend this mana only to cast an Elemental spell or activate an ability of an Elemental"; } } @@ -73,7 +73,7 @@ class PrimalBeyondConditionalMana extends ConditionalMana { public PrimalBeyondConditionalMana(Mana mana) { super(mana); - this.staticText = "Spend this mana only to cast Elemental spells or activate abilities of Elementals"; + this.staticText = "Spend this mana only to cast an Elemental spell or activate an ability of an Elemental"; addCondition(new PrimalBeyondManaCondition()); } } @@ -82,7 +82,7 @@ class PrimalBeyondManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && object.hasSubtype(SubType.ELEMENTAL, game); } } diff --git a/Mage.Sets/src/mage/cards/p/PrimalCommand.java b/Mage.Sets/src/mage/cards/p/PrimalCommand.java index 31a6bdc661a..5a14a3c7377 100644 --- a/Mage.Sets/src/mage/cards/p/PrimalCommand.java +++ b/Mage.Sets/src/mage/cards/p/PrimalCommand.java @@ -45,19 +45,16 @@ public final class PrimalCommand extends CardImpl { this.getSpellAbility().addEffect(new GainLifeTargetEffect(7)); this.getSpellAbility().addTarget(new TargetPlayer()); // or put target noncreature permanent on top of its owner's library; - Mode mode = new Mode(); - mode.addEffect(new PutOnLibraryTargetEffect(true)); + Mode mode = new Mode(new PutOnLibraryTargetEffect(true)); Target target = new TargetPermanent(filterNonCreature); mode.addTarget(target); this.getSpellAbility().getModes().addMode(mode); // or target player shuffles their graveyard into their library; - mode = new Mode(); - mode.addEffect(new PrimalCommandShuffleGraveyardEffect()); + mode = new Mode(new PrimalCommandShuffleGraveyardEffect()); mode.addTarget(new TargetPlayer()); this.getSpellAbility().getModes().addMode(mode); // or search your library for a creature card, reveal it, put it into your hand, then shuffle your library. - mode = new Mode(); - mode.addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_CREATURE), true, true)); + mode = new Mode(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_CREATURE), true, true)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/p/PrimalEmpathy.java b/Mage.Sets/src/mage/cards/p/PrimalEmpathy.java index c4f3c0acbf8..ce5744e1519 100644 --- a/Mage.Sets/src/mage/cards/p/PrimalEmpathy.java +++ b/Mage.Sets/src/mage/cards/p/PrimalEmpathy.java @@ -87,7 +87,7 @@ class PrimalEmpathyEffect extends OneShotEffect { } Target target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (!player.choose(outcome, target, source.getSourceId(), game)) { + if (!player.choose(outcome, target, source, game)) { return false; } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/p/PrimalWellspring.java b/Mage.Sets/src/mage/cards/p/PrimalWellspring.java index ab26a7e5e15..5b081add0d0 100644 --- a/Mage.Sets/src/mage/cards/p/PrimalWellspring.java +++ b/Mage.Sets/src/mage/cards/p/PrimalWellspring.java @@ -78,7 +78,7 @@ class PyrimalWellspringTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (event.getData().equals(abilityOriginalId)) { Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null && filter.match(spell, getSourceId(), getControllerId(), game)) { + if (spell != null && filter.match(spell, getControllerId(), this, game)) { for (Effect effect : getEffects()) { effect.setTargetPointer(new FixedTarget(event.getTargetId())); } diff --git a/Mage.Sets/src/mage/cards/p/PrimalWhisperer.java b/Mage.Sets/src/mage/cards/p/PrimalWhisperer.java index 6d41b7ed3f4..72a7275e076 100644 --- a/Mage.Sets/src/mage/cards/p/PrimalWhisperer.java +++ b/Mage.Sets/src/mage/cards/p/PrimalWhisperer.java @@ -40,7 +40,7 @@ public final class PrimalWhisperer extends CardImpl { PermanentsOnBattlefieldCount amount = new PermanentsOnBattlefieldCount(filter, 2); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceEffect(amount, amount, Duration.WhileOnBattlefield))); // Morph {3}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{G}"))); } private PrimalWhisperer(final PrimalWhisperer card) { diff --git a/Mage.Sets/src/mage/cards/p/PrimevalProtector.java b/Mage.Sets/src/mage/cards/p/PrimevalProtector.java index 1249e131245..9d5bcd5044f 100644 --- a/Mage.Sets/src/mage/cards/p/PrimevalProtector.java +++ b/Mage.Sets/src/mage/cards/p/PrimevalProtector.java @@ -85,7 +85,7 @@ class PrimevalProtectorCostReductionEffect extends CostModificationEffectImpl { public boolean apply(Game game, Ability source, Ability abilityToModify) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - int reductionAmount = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int reductionAmount = game.getBattlefield().count(filter, source.getControllerId(), source, game); CardUtil.reduceCost(abilityToModify, reductionAmount); return true; } diff --git a/Mage.Sets/src/mage/cards/p/PrimordialMist.java b/Mage.Sets/src/mage/cards/p/PrimordialMist.java index aed0a8ee77e..7351d56fa39 100644 --- a/Mage.Sets/src/mage/cards/p/PrimordialMist.java +++ b/Mage.Sets/src/mage/cards/p/PrimordialMist.java @@ -83,14 +83,14 @@ class PrimordialMistCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return target.canChoose(source.getSourceId(), controllerId, game); + return target.canChoose(controllerId, source, game); } @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { - if (target.choose(Outcome.Exile, controllerId, source.getSourceId(), game)) { + if (target.choose(Outcome.Exile, controllerId, source.getSourceId(), source, game)) { Card card = game.getCard(source.getSourceId()); if (card != null) { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); diff --git a/Mage.Sets/src/mage/cards/p/PrismaticGeoscope.java b/Mage.Sets/src/mage/cards/p/PrismaticGeoscope.java index 9ac57bc9f93..eebdde8a129 100644 --- a/Mage.Sets/src/mage/cards/p/PrismaticGeoscope.java +++ b/Mage.Sets/src/mage/cards/p/PrismaticGeoscope.java @@ -28,7 +28,7 @@ public final class PrismaticGeoscope extends CardImpl { // Domain — {T}: Add X mana in any combination of colors, where X is the number of basic land types among lands you control. Ability ability = new DynamicManaAbility( - new Mana(0, 0, 0, 0, 0, 0, 1, 0), new DomainValue(), new TapSourceCost(), + new Mana(0, 0, 0, 0, 0, 0, 1, 0), DomainValue.REGULAR, new TapSourceCost(), "Add X mana in any combination of colors," + " where X is the number of basic land types among lands you control." ); diff --git a/Mage.Sets/src/mage/cards/p/PrismaticStrands.java b/Mage.Sets/src/mage/cards/p/PrismaticStrands.java index 803605e2a27..242af3e501d 100644 --- a/Mage.Sets/src/mage/cards/p/PrismaticStrands.java +++ b/Mage.Sets/src/mage/cards/p/PrismaticStrands.java @@ -76,7 +76,7 @@ class PrismaticStrandsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { ChoiceColor choice = new ChoiceColor(); controller.choose(Outcome.PreventDamage, choice, game); diff --git a/Mage.Sets/src/mage/cards/p/Prizefight.java b/Mage.Sets/src/mage/cards/p/Prizefight.java new file mode 100644 index 00000000000..381f2dea9df --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/Prizefight.java @@ -0,0 +1,40 @@ +package mage.cards.p; + +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.FightTargetsEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.TreasureToken; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Prizefight extends CardImpl { + + public Prizefight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + // Target creature you control fights target creature you don't control. + this.getSpellAbility().addEffect(new FightTargetsEffect()); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + + // Create a Treasure token. + this.getSpellAbility().addEffect(new CreateTokenEffect(new TreasureToken()).concatBy("
")); + } + + private Prizefight(final Prizefight card) { + super(card); + } + + @Override + public Prizefight copy() { + return new Prizefight(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/Probe.java b/Mage.Sets/src/mage/cards/p/Probe.java index b7c63cd7288..a21c1aa04c3 100644 --- a/Mage.Sets/src/mage/cards/p/Probe.java +++ b/Mage.Sets/src/mage/cards/p/Probe.java @@ -32,7 +32,7 @@ public final class Probe extends CardImpl { this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new DiscardTargetEffect(2), KickedCondition.instance, - "

If this spell was kicked, target player discards two cards")); + "If this spell was kicked, target player discards two cards")); this.getSpellAbility().setTargetAdjuster(ProbeAdjuster.instance); } diff --git a/Mage.Sets/src/mage/cards/p/ProfaneCommand.java b/Mage.Sets/src/mage/cards/p/ProfaneCommand.java index c574c926348..83cff5d98c7 100644 --- a/Mage.Sets/src/mage/cards/p/ProfaneCommand.java +++ b/Mage.Sets/src/mage/cards/p/ProfaneCommand.java @@ -46,23 +46,20 @@ public final class ProfaneCommand extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayer()); // * Return target creature card with converted mana cost X or less from your graveyard to the battlefield. - Mode mode = new Mode(); - mode.addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); + Mode mode = new Mode(new ReturnFromGraveyardToBattlefieldTargetEffect()); mode.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card with mana value X or less from your graveyard"))); this.getSpellAbility().addMode(mode); // * Target creature gets -X/-X until end of turn. DynamicValue minusValue = new SignInversionDynamicValue(xValue); - mode = new Mode(); - mode.addEffect(new BoostTargetEffect(minusValue, minusValue, Duration.EndOfTurn)); + mode = new Mode(new BoostTargetEffect(minusValue, minusValue, Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // * Up to X target creatures gain fear until end of turn. - mode = new Mode(); Effect effect = new GainAbilityTargetEffect(FearAbility.getInstance(), Duration.EndOfTurn); effect.setText("Up to X target creatures gain fear until end of turn"); - mode.addEffect(effect); + mode = new Mode(effect); mode.addTarget(new TargetCreaturePermanent(0, 1)); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/p/ProfanerOfTheDead.java b/Mage.Sets/src/mage/cards/p/ProfanerOfTheDead.java index 050443cac41..198f63905ca 100644 --- a/Mage.Sets/src/mage/cards/p/ProfanerOfTheDead.java +++ b/Mage.Sets/src/mage/cards/p/ProfanerOfTheDead.java @@ -68,7 +68,7 @@ class ProfanerOfTheDeadReturnEffect extends OneShotEffect { filter.add(TargetController.OPPONENT.getControllerPredicate()); filter.add(new ToughnessPredicate(ComparisonType.FEWER_THAN, exploitedCreature.getToughness().getValue())); Cards cardsToHand = new CardsImpl(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { cardsToHand.add(permanent); } controller.moveCards(cardsToHand, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/p/ProfessionalFaceBreaker.java b/Mage.Sets/src/mage/cards/p/ProfessionalFaceBreaker.java new file mode 100644 index 00000000000..355b38514bc --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ProfessionalFaceBreaker.java @@ -0,0 +1,55 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.common.DealCombatDamageControlledTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEndOfTurnEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ProfessionalFaceBreaker extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledPermanent(SubType.TREASURE, "a Treasure"); + + public ProfessionalFaceBreaker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Menace + this.addAbility(new MenaceAbility(false)); + + // Whenever one or more creatures you control deal combat damage to a player, create a Treasure token. + this.addAbility(new DealCombatDamageControlledTriggeredAbility(new CreateTokenEffect(new TreasureToken()))); + + // Sacrifice a Treasure: Exile the top card of your library. You may play that card this turn. + this.addAbility(new SimpleActivatedAbility( + new ExileTopXMayPlayUntilEndOfTurnEffect(1, false), new SacrificeTargetCost(filter) + )); + } + + private ProfessionalFaceBreaker(final ProfessionalFaceBreaker card) { + super(card); + } + + @Override + public ProfessionalFaceBreaker copy() { + return new ProfessionalFaceBreaker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/ProfessorOnyx.java b/Mage.Sets/src/mage/cards/p/ProfessorOnyx.java index 090d468a5ef..b5f4a36bd55 100644 --- a/Mage.Sets/src/mage/cards/p/ProfessorOnyx.java +++ b/Mage.Sets/src/mage/cards/p/ProfessorOnyx.java @@ -5,10 +5,13 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.MagecraftAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.*; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.common.SacrificeOpponentsEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -45,7 +48,7 @@ public final class ProfessorOnyx extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.LILIANA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Magecraft — Whenever you cast or copy an instant or sorcery spell, each opponent loses 2 life and you gain 2 life. Ability ability = new MagecraftAbility(new LoseLifeOpponentsEffect(2), false); @@ -54,10 +57,7 @@ public final class ProfessorOnyx extends CardImpl { // +1: You lose 1 life. Look at the top three cards of your library. Put one of them into your hand and the rest into your graveyard. ability = new LoyaltyAbility(new LoseLifeSourceControllerEffect(1), 1); - ability.addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(3), false, StaticValue.get(1), StaticFilters.FILTER_CARD, - Zone.GRAVEYARD, false, false, false, Zone.HAND, false - ).setText("Look at the top three cards of your library. Put one of them into your hand and the rest into your graveyard")); + ability.addEffect(new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.GRAVEYARD)); this.addAbility(ability); // −3: Each opponent sacrifices a creature with the greatest power among creatures that player controls. @@ -127,7 +127,7 @@ class ProfessorOnyxEffect extends OneShotEffect { TargetDiscard target = new TargetDiscard( 0, 1, StaticFilters.FILTER_CARD, playerId ); - player.choose(Outcome.Discard, target, source.getSourceId(), game); + player.choose(Outcome.Discard, target, source, game); playerMap.put(playerId, game.getCard(target.getFirstTarget())); } for (UUID playerId : game.getOpponents(source.getControllerId())) { diff --git a/Mage.Sets/src/mage/cards/p/ProfitLoss.java b/Mage.Sets/src/mage/cards/p/ProfitLoss.java index af7aeb4544c..099516005f7 100644 --- a/Mage.Sets/src/mage/cards/p/ProfitLoss.java +++ b/Mage.Sets/src/mage/cards/p/ProfitLoss.java @@ -1,4 +1,3 @@ - package mage.cards.p; import java.util.UUID; @@ -9,28 +8,21 @@ import mage.cards.SplitCard; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SpellAbilityType; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; public final class ProfitLoss extends SplitCard { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public ProfitLoss(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}", "{2}{B}", SpellAbilityType.SPLIT_FUSED); // Profit // Creatures you control get +1/+1 until end of turn. - getLeftHalfCard().getSpellAbility().addEffect(new BoostControlledEffect(1, 1, Duration.EndOfTurn, new FilterCreaturePermanent())); + getLeftHalfCard().getSpellAbility().addEffect(new BoostControlledEffect(1, 1, Duration.EndOfTurn)); // Loss // Creatures your opponents control get -1/-1 until end of turn. - getRightHalfCard().getSpellAbility().addEffect(new BoostAllEffect(-1, -1, Duration.EndOfTurn, filter, false)); - + getRightHalfCard().getSpellAbility().addEffect( + new BoostAllEffect(-1, -1, Duration.EndOfTurn, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, false)); } private ProfitLoss(final ProfitLoss card) { diff --git a/Mage.Sets/src/mage/cards/p/PromiseOfLoyalty.java b/Mage.Sets/src/mage/cards/p/PromiseOfLoyalty.java index 1a0847bb96e..3a03bf6bae5 100644 --- a/Mage.Sets/src/mage/cards/p/PromiseOfLoyalty.java +++ b/Mage.Sets/src/mage/cards/p/PromiseOfLoyalty.java @@ -67,13 +67,13 @@ class PromiseOfLoyaltyEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player == null || game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getSourceId(), playerId, game + playerId, source, game ) < 1) { continue; } TargetPermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent == null) { continue; diff --git a/Mage.Sets/src/mage/cards/p/PromiseOfPower.java b/Mage.Sets/src/mage/cards/p/PromiseOfPower.java index c8109933f5b..25a4f67796d 100644 --- a/Mage.Sets/src/mage/cards/p/PromiseOfPower.java +++ b/Mage.Sets/src/mage/cards/p/PromiseOfPower.java @@ -39,8 +39,7 @@ public final class PromiseOfPower extends CardImpl { this.getSpellAbility().addEffect(effect); // - Create an X/X black Demon creature token with flying, where X is the number of cards in your hand. - Mode mode = new Mode(); - mode.addEffect(new PromiseOfPowerEffect()); + Mode mode = new Mode(new PromiseOfPowerEffect()); this.getSpellAbility().getModes().addMode(mode); // Entwine {4} diff --git a/Mage.Sets/src/mage/cards/p/Prophecy.java b/Mage.Sets/src/mage/cards/p/Prophecy.java index 26d3f8daa76..282250b8454 100644 --- a/Mage.Sets/src/mage/cards/p/Prophecy.java +++ b/Mage.Sets/src/mage/cards/p/Prophecy.java @@ -66,7 +66,7 @@ class ProphecyEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player targetPlayer = game.getPlayer(source.getFirstTarget()); Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject == null || targetPlayer == null || controller == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/p/PropheticBolt.java b/Mage.Sets/src/mage/cards/p/PropheticBolt.java index d8661e219a7..d52add9501e 100644 --- a/Mage.Sets/src/mage/cards/p/PropheticBolt.java +++ b/Mage.Sets/src/mage/cards/p/PropheticBolt.java @@ -1,15 +1,12 @@ - package mage.cards.p; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.FilterCard; import mage.target.common.TargetAnyTarget; /** @@ -25,7 +22,7 @@ public final class PropheticBolt extends CardImpl { // Prophetic Bolt deals 4 damage to any target. Look at the top four cards of your library. Put one of those cards into your hand and the rest on the bottom of your library in any order. this.getSpellAbility().addEffect(new DamageTargetEffect(4)); this.getSpellAbility().addTarget(new TargetAnyTarget()); - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(4), false, StaticValue.get(1), new FilterCard(), Zone.LIBRARY, false, false)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(4, 1, PutCards.HAND, PutCards.BOTTOM_ANY)); } private PropheticBolt(final PropheticBolt card) { diff --git a/Mage.Sets/src/mage/cards/p/PropheticTitan.java b/Mage.Sets/src/mage/cards/p/PropheticTitan.java index 648bf296302..eda7d02bfba 100644 --- a/Mage.Sets/src/mage/cards/p/PropheticTitan.java +++ b/Mage.Sets/src/mage/cards/p/PropheticTitan.java @@ -4,16 +4,15 @@ import mage.MageInt; import mage.abilities.Mode; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.hint.common.CardTypesInGraveyardHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.target.common.TargetAnyTarget; @@ -54,16 +53,13 @@ class PropheticTitanTriggeredAbility extends EntersBattlefieldTriggeredAbility { public PropheticTitanTriggeredAbility() { super(new DamageTargetEffect(4), false); this.addMode(new Mode(new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.LIBRARY, false, false - ).setBackInRandomOrder(true).setText("look at the top four cards of your library. " + - "Put one of them into your hand and the rest on the bottom of your library in a random order"))); + 4, 1, PutCards.HAND, PutCards.BOTTOM_RANDOM))); this.getModes().setChooseText( "choose one. If there are four or more card types among cards in your graveyard, choose both instead." ); this.addTarget(new TargetAnyTarget()); this.addHint(CardTypesInGraveyardHint.YOU); - this.withFlavorWord("Delirium"); + this.setAbilityWord(AbilityWord.DELIRIUM); } private PropheticTitanTriggeredAbility(final PropheticTitanTriggeredAbility ability) { @@ -85,4 +81,4 @@ class PropheticTitanTriggeredAbility extends EntersBattlefieldTriggeredAbility { this.getModes().setMaxModes(modes); return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/p/ProsperousPartnership.java b/Mage.Sets/src/mage/cards/p/ProsperousPartnership.java new file mode 100644 index 00000000000..38789287798 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ProsperousPartnership.java @@ -0,0 +1,47 @@ +package mage.cards.p; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.CitizenGreenWhiteToken; +import mage.game.permanent.token.TreasureToken; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ProsperousPartnership extends CardImpl { + + public ProsperousPartnership(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{W}"); + + // When Prosperous Partnership enters the battlefield, create two 1/1 green and white Citizen creature tokens. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new CreateTokenEffect(new CitizenGreenWhiteToken(), 2) + )); + + // Tap three untapped creatures you control: Create a Treasure token. + this.addAbility(new SimpleActivatedAbility( + new CreateTokenEffect(new TreasureToken()), + new TapTargetCost(new TargetControlledPermanent( + 3, StaticFilters.FILTER_CONTROLLED_UNTAPPED_CREATURES + )) + )); + } + + private ProsperousPartnership(final ProsperousPartnership card) { + super(card); + } + + @Override + public ProsperousPartnership copy() { + return new ProsperousPartnership(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/ProtectionRacket.java b/Mage.Sets/src/mage/cards/p/ProtectionRacket.java new file mode 100644 index 00000000000..a63b49b83d2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ProtectionRacket.java @@ -0,0 +1,88 @@ +package mage.cards.p; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ProtectionRacket extends CardImpl { + + public ProtectionRacket(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); + + // At the beginning of your upkeep, repeat the following process for each opponent in turn order. Reveal the top card of your library. That player pay pay life equal to that card's mana value. If they do, exile that card. Otherwise, put it into your hand. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new ProtectionRacketEffect(), TargetController.YOU, false + )); + } + + private ProtectionRacket(final ProtectionRacket card) { + super(card); + } + + @Override + public ProtectionRacket copy() { + return new ProtectionRacket(this); + } +} + +class ProtectionRacketEffect extends OneShotEffect { + + ProtectionRacketEffect() { + super(Outcome.Benefit); + staticText = "repeat the following process for each opponent in turn order. " + + "Reveal the top card of your library. That player may pay life equal to that card's mana value. " + + "If they do, exile that card. Otherwise, put it into your hand"; + } + + private ProtectionRacketEffect(final ProtectionRacketEffect effect) { + super(effect); + } + + @Override + public ProtectionRacketEffect copy() { + return new ProtectionRacketEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + for (UUID playerId : game.getOpponents(source.getControllerId())) { + Player player = game.getPlayer(playerId); + Card card = controller.getLibrary().getFromTop(game); + if (player == null || card == null) { + continue; + } + controller.revealCards(source, new CardsImpl(card), game); + int mv = card.getManaValue(); + Cost cost = new PayLifeCost(mv); + if (cost.canPay(source, source, playerId, game) && player.chooseUse( + Outcome.Detriment, "Pay " + mv + " life to exile " + card.getName() + '?', source, game + )) { + cost.pay(source, game, source, playerId, true); + controller.moveCards(card, Zone.EXILED, source, game); + } + controller.moveCards(card, Zone.HAND, source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/p/ProtectiveBubble.java b/Mage.Sets/src/mage/cards/p/ProtectiveBubble.java index b1354ce80fc..9e590f3b0e6 100644 --- a/Mage.Sets/src/mage/cards/p/ProtectiveBubble.java +++ b/Mage.Sets/src/mage/cards/p/ProtectiveBubble.java @@ -1,7 +1,6 @@ - package mage.cards.p; -import java.util.UUID; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.combat.CantBeBlockedAttachedEffect; @@ -12,31 +11,34 @@ 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.Zone; +import mage.constants.SubType; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class ProtectiveBubble extends CardImpl { public ProtectiveBubble(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}"); this.subtype.add(SubType.AURA); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // Enchanted creature can't be blocked and has shroud. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeBlockedAttachedEffect(AttachmentType.AURA))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ShroudAbility.getInstance(), AttachmentType.AURA))); + Ability ability = new SimpleStaticAbility(new CantBeBlockedAttachedEffect(AttachmentType.AURA)); + ability.addEffect(new GainAbilityAttachedEffect( + ShroudAbility.getInstance(), AttachmentType.AURA + ).setText("and has shroud")); + this.addAbility(ability); } private ProtectiveBubble(final ProtectiveBubble card) { diff --git a/Mage.Sets/src/mage/cards/p/ProtectiveSphere.java b/Mage.Sets/src/mage/cards/p/ProtectiveSphere.java index 568ba369b55..a74c315252d 100644 --- a/Mage.Sets/src/mage/cards/p/ProtectiveSphere.java +++ b/Mage.Sets/src/mage/cards/p/ProtectiveSphere.java @@ -88,7 +88,7 @@ class ProtectiveSphereEffect extends PreventionEffectImpl { CardUtil.addToolTipMarkTags("Last mana used for protective ability: " + source.getManaCostsToPay().getUsedManaToPay()), game); } - this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); super.init(source, game); } diff --git a/Mage.Sets/src/mage/cards/p/ProteusMachine.java b/Mage.Sets/src/mage/cards/p/ProteusMachine.java index a38591273fb..4e8cb1312ff 100644 --- a/Mage.Sets/src/mage/cards/p/ProteusMachine.java +++ b/Mage.Sets/src/mage/cards/p/ProteusMachine.java @@ -26,7 +26,7 @@ public final class ProteusMachine extends CardImpl { this.toughness = new MageInt(2); // Morph {0} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{0}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{0}"))); // When Proteus Machine is turned face up, it becomes the creature type of your choice. (This effect lasts indefinitely.) this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new BecomesChosenCreatureTypeSourceEffect(false, Duration.Custom))); diff --git a/Mage.Sets/src/mage/cards/p/ProtomatterPowder.java b/Mage.Sets/src/mage/cards/p/ProtomatterPowder.java index a226b39c18e..6b68dc4a4ef 100644 --- a/Mage.Sets/src/mage/cards/p/ProtomatterPowder.java +++ b/Mage.Sets/src/mage/cards/p/ProtomatterPowder.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; @@ -12,24 +10,25 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Plopman */ public final class ProtomatterPowder extends CardImpl { public ProtomatterPowder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{U}"); // {4}{W}, {tap}, Sacrifice Protomatter Powder: Return target artifact card from your graveyard to the battlefield. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnFromGraveyardToBattlefieldTargetEffect(), new ManaCostsImpl("{4}{W}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/PrototypePortal.java b/Mage.Sets/src/mage/cards/p/PrototypePortal.java index 7e505fff634..858ab8e3e50 100644 --- a/Mage.Sets/src/mage/cards/p/PrototypePortal.java +++ b/Mage.Sets/src/mage/cards/p/PrototypePortal.java @@ -14,6 +14,7 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -38,7 +39,7 @@ public final class PrototypePortal extends CardImpl { // Imprint - When Prototype Portal enters the battlefield, you may exile an artifact card from your hand. this.addAbility(new EntersBattlefieldTriggeredAbility( new PrototypePortalEffect(), true) - .withFlavorWord("Imprint") + .setAbilityWord(AbilityWord.IMPRINT) ); // {X}, {tap}: Create a token that's a copy of the exiled card. X is the converted mana cost of that card. @@ -96,7 +97,7 @@ class PrototypePortalEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { if (!controller.getHand().isEmpty()) { TargetCard target = new TargetCard(Zone.HAND, StaticFilters.FILTER_CARD_ARTIFACT); diff --git a/Mage.Sets/src/mage/cards/p/ProwlingGeistcatcher.java b/Mage.Sets/src/mage/cards/p/ProwlingGeistcatcher.java index 43359ed16d8..ca32e5d05a5 100644 --- a/Mage.Sets/src/mage/cards/p/ProwlingGeistcatcher.java +++ b/Mage.Sets/src/mage/cards/p/ProwlingGeistcatcher.java @@ -14,6 +14,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.StaticFilters; +import mage.game.ExileZone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentToken; @@ -110,11 +111,8 @@ class ProwlingGeistcatcherReturnEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - return player.moveCards(game.getExile().getExileZone( - CardUtil.getExileZoneId(game, source) - ), Zone.BATTLEFIELD, source, game); + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + return player != null && exileZone != null && !exileZone.isEmpty() + && player.moveCards(exileZone, Zone.BATTLEFIELD, source, game); } } diff --git a/Mage.Sets/src/mage/cards/p/PryingQuestions.java b/Mage.Sets/src/mage/cards/p/PryingQuestions.java index 7648643d4e1..8bb3fd0ba88 100644 --- a/Mage.Sets/src/mage/cards/p/PryingQuestions.java +++ b/Mage.Sets/src/mage/cards/p/PryingQuestions.java @@ -64,7 +64,7 @@ class PryingQuestionsEffect extends OneShotEffect { TargetCardInHand target = new TargetCardInHand(); target.setNotTarget(true); target.setTargetName("a card from your hand to put on top of your library"); - targetOpponent.choose(Outcome.Detriment, target, source.getSourceId(), game); + targetOpponent.choose(Outcome.Detriment, target, source, game); Card card = targetOpponent.getHand().get(target.getFirstTarget(), game); if (card != null) { targetOpponent.moveCardToLibraryWithInfo(card, source, game, Zone.HAND, true, false); diff --git a/Mage.Sets/src/mage/cards/p/PsionicSnoop.java b/Mage.Sets/src/mage/cards/p/PsionicSnoop.java new file mode 100644 index 00000000000..370976500e0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PsionicSnoop.java @@ -0,0 +1,42 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PsionicSnoop extends CardImpl { + + public PsionicSnoop(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // When Psionic Snoop enters the battlefield, it connives. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ConniveSourceEffect())); + } + + private PsionicSnoop(final PsionicSnoop card) { + super(card); + } + + @Override + public PsionicSnoop copy() { + return new PsionicSnoop(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PsychicBattle.java b/Mage.Sets/src/mage/cards/p/PsychicBattle.java index 5f16ba8501d..f7b4116d71c 100644 --- a/Mage.Sets/src/mage/cards/p/PsychicBattle.java +++ b/Mage.Sets/src/mage/cards/p/PsychicBattle.java @@ -101,7 +101,7 @@ class PsychicBattleEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null) { Map manacostMap = new HashMap<>(); for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { diff --git a/Mage.Sets/src/mage/cards/p/PsychicImpetus.java b/Mage.Sets/src/mage/cards/p/PsychicImpetus.java index bbbedc9098c..0c477f1680e 100644 --- a/Mage.Sets/src/mage/cards/p/PsychicImpetus.java +++ b/Mage.Sets/src/mage/cards/p/PsychicImpetus.java @@ -2,8 +2,9 @@ package mage.cards.p; import mage.abilities.Ability; import mage.abilities.common.AttacksAttachedTriggeredAbility; -import mage.abilities.common.GoadAttachedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.combat.GoadAttachedEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.effects.keyword.ScryEffect; import mage.abilities.keyword.EnchantAbility; @@ -36,7 +37,9 @@ public final class PsychicImpetus extends CardImpl { this.addAbility(ability); // Enchanted creature gets +2/+2 and is goaded. - this.addAbility(new GoadAttachedAbility(new BoostEnchantedEffect(2, 2))); + ability = new SimpleStaticAbility(new BoostEnchantedEffect(2, 2)); + ability.addEffect(new GoadAttachedEffect()); + this.addAbility(ability); // Whenever enchanted creature attacks, you scry 2. this.addAbility(new AttacksAttachedTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/p/PsychicIntrusion.java b/Mage.Sets/src/mage/cards/p/PsychicIntrusion.java index c1715b61647..8fdab756c3e 100644 --- a/Mage.Sets/src/mage/cards/p/PsychicIntrusion.java +++ b/Mage.Sets/src/mage/cards/p/PsychicIntrusion.java @@ -68,7 +68,7 @@ class PsychicIntrusionExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player opponent = game.getPlayer(targetPointer.getFirst(game, source)); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (opponent != null && sourceObject != null) { opponent.revealCards(sourceObject.getName(), opponent.getHand(), game); Player controller = game.getPlayer(source.getControllerId()); diff --git a/Mage.Sets/src/mage/cards/p/PsychicPickpocket.java b/Mage.Sets/src/mage/cards/p/PsychicPickpocket.java new file mode 100644 index 00000000000..7f04184474c --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PsychicPickpocket.java @@ -0,0 +1,43 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PsychicPickpocket extends CardImpl { + + public PsychicPickpocket(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.CEPHALID); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // When Psychic Pickpocket enters the battlefield, it connives. When it connives this way, return up to one target nonland permanent to its owner's hand. + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new ReturnToHandTargetEffect(), false); + ability.addTarget(new TargetNonlandPermanent(0, 1)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new ConniveSourceEffect("it", ability))); + } + + private PsychicPickpocket(final PsychicPickpocket card) { + super(card); + } + + @Override + public PsychicPickpocket copy() { + return new PsychicPickpocket(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PsychoticEpisode.java b/Mage.Sets/src/mage/cards/p/PsychoticEpisode.java index 539173ccac2..d9998b81a06 100644 --- a/Mage.Sets/src/mage/cards/p/PsychoticEpisode.java +++ b/Mage.Sets/src/mage/cards/p/PsychoticEpisode.java @@ -34,7 +34,7 @@ public final class PsychoticEpisode extends CardImpl { this.getSpellAbility().addEffect(new PsychoticEpisodeEffect()); this.getSpellAbility().addTarget(new TargetPlayer()); // Madness {1}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{1}{B}"))); } private PsychoticEpisode(final PsychoticEpisode card) { diff --git a/Mage.Sets/src/mage/cards/p/PsychoticHaze.java b/Mage.Sets/src/mage/cards/p/PsychoticHaze.java index cfc3c70a426..e222257364b 100644 --- a/Mage.Sets/src/mage/cards/p/PsychoticHaze.java +++ b/Mage.Sets/src/mage/cards/p/PsychoticHaze.java @@ -23,7 +23,7 @@ public final class PsychoticHaze extends CardImpl { this.getSpellAbility().addEffect(new DamageEverythingEffect(1)); // Madness {1}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{1}{B}"))); } private PsychoticHaze(final PsychoticHaze card) { diff --git a/Mage.Sets/src/mage/cards/p/PublicEnemy.java b/Mage.Sets/src/mage/cards/p/PublicEnemy.java new file mode 100644 index 00000000000..ae9bbf15c89 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PublicEnemy.java @@ -0,0 +1,99 @@ +package mage.cards.p; + +import mage.abilities.Ability; +import mage.abilities.common.DiesAttachedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.RequirementEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.EnchantAbility; +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.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PublicEnemy extends CardImpl { + + public PublicEnemy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // All creatures attack enchanted creature's controller each combat if able. + this.addAbility(new SimpleStaticAbility(new PublicEnemyEffect())); + + // When enchanted creature dies, draw a card. + this.addAbility(new DiesAttachedTriggeredAbility( + new DrawCardSourceControllerEffect(1), "enchanted creature" + )); + } + + private PublicEnemy(final PublicEnemy card) { + super(card); + } + + @Override + public PublicEnemy copy() { + return new PublicEnemy(this); + } +} + +class PublicEnemyEffect extends RequirementEffect { + + PublicEnemyEffect() { + super(Duration.WhileOnBattlefield); + staticText = "all creatures attack enchanted creature's controller each combat if able"; + } + + private PublicEnemyEffect(final PublicEnemyEffect effect) { + super(effect); + } + + @Override + public PublicEnemyEffect copy() { + return new PublicEnemyEffect(this); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return true; + } + + @Override + public UUID mustAttackDefender(Ability source, Game game) { + return Optional.of(source.getSourcePermanentIfItStillExists(game)) + .filter(Objects::nonNull) + .map(Permanent::getAttachedTo) + .map(game::getControllerId) + .orElse(null); + } + + @Override + public boolean mustAttack(Game game) { + return true; + } + + @Override + public boolean mustBlock(Game game) { + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PucasMischief.java b/Mage.Sets/src/mage/cards/p/PucasMischief.java index 9c3c739ccc9..bec4dc4d74d 100644 --- a/Mage.Sets/src/mage/cards/p/PucasMischief.java +++ b/Mage.Sets/src/mage/cards/p/PucasMischief.java @@ -63,11 +63,11 @@ class TargetControlledPermanentWithCMCGreaterOrLessThanOpponentPermanent extends } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); if(targetSource != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { possibleTargets.add(permanent.getId()); } @@ -112,12 +112,12 @@ class PucasMischiefSecondTarget extends TargetPermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); if (firstTarget != null) { - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); if (targetSource != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { if (firstTarget.getManaValue() >= permanent.getManaValue()) { possibleTargets.add(permanent.getId()); diff --git a/Mage.Sets/src/mage/cards/p/PugnaciousPugilist.java b/Mage.Sets/src/mage/cards/p/PugnaciousPugilist.java new file mode 100644 index 00000000000..bbf99910a15 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PugnaciousPugilist.java @@ -0,0 +1,45 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.BlitzAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.DevilToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PugnaciousPugilist extends CardImpl { + + public PugnaciousPugilist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever Pugnacious Pugilist attacks, create a tapped and attacking 1/1 red Devil creature token with "When this creature dies, it deals 1 damage to any target." + this.addAbility(new AttacksTriggeredAbility(new CreateTokenEffect( + new DevilToken(), 1, true, true + ))); + + // Blitz {3}{R} + this.addAbility(new BlitzAbility(this, "{3}{R}")); + } + + private PugnaciousPugilist(final PugnaciousPugilist card) { + super(card); + } + + @Override + public PugnaciousPugilist copy() { + return new PugnaciousPugilist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PunctureBolt.java b/Mage.Sets/src/mage/cards/p/PunctureBolt.java index 7a1faf54ab1..da2625f8058 100644 --- a/Mage.Sets/src/mage/cards/p/PunctureBolt.java +++ b/Mage.Sets/src/mage/cards/p/PunctureBolt.java @@ -19,10 +19,9 @@ public final class PunctureBolt extends CardImpl { public PunctureBolt(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}"); - // Puncture Bolt deals 1 damage to target creature. Put a -1/-1 counter on that creature. this.getSpellAbility().addEffect(new DamageTargetEffect(1)); - this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.M1M1.createInstance())); + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.M1M1.createInstance()).setText("put a -1/-1 counter on that creature")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/p/PunishingFire.java b/Mage.Sets/src/mage/cards/p/PunishingFire.java index c1b023c93e6..6244ded3109 100644 --- a/Mage.Sets/src/mage/cards/p/PunishingFire.java +++ b/Mage.Sets/src/mage/cards/p/PunishingFire.java @@ -1,34 +1,32 @@ - package mage.cards.p; -import java.util.UUID; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DoIfCostPaid; -import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author North */ public final class PunishingFire extends CardImpl { public PunishingFire(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); // Punishing Fire deals 2 damage to any target. this.getSpellAbility().addEffect(new DamageTargetEffect(2)); this.getSpellAbility().addTarget(new TargetAnyTarget()); + // Whenever an opponent gains life, you may pay {R}. If you do, return Punishing Fire from your graveyard to your hand. this.addAbility(new PunishingFireTriggeredAbility()); } @@ -46,7 +44,7 @@ public final class PunishingFire extends CardImpl { class PunishingFireTriggeredAbility extends TriggeredAbilityImpl { public PunishingFireTriggeredAbility() { - super(Zone.GRAVEYARD, new DoIfCostPaid(new ReturnToHandSourceEffect(), new ManaCostsImpl("{R}"))); + super(Zone.GRAVEYARD, new DoIfCostPaid(new ReturnSourceFromGraveyardToHandEffect(), new ManaCostsImpl<>("{R}"))); } public PunishingFireTriggeredAbility(final PunishingFireTriggeredAbility ability) { @@ -70,6 +68,6 @@ class PunishingFireTriggeredAbility extends TriggeredAbilityImpl { @Override public String getTriggerPhrase() { - return "Whenever an opponent gains life, " ; + return "Whenever an opponent gains life, "; } } diff --git a/Mage.Sets/src/mage/cards/p/PureReflection.java b/Mage.Sets/src/mage/cards/p/PureReflection.java index 280e3bcdd20..91f0a7b923d 100644 --- a/Mage.Sets/src/mage/cards/p/PureReflection.java +++ b/Mage.Sets/src/mage/cards/p/PureReflection.java @@ -68,7 +68,7 @@ public final class PureReflection extends CardImpl { // destroy all Reflections FilterPermanent filter = new FilterPermanent("Reflections"); filter.add(SubType.REFLECTION.getPredicate()); - game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game).forEach((permanent) -> { + game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game).forEach((permanent) -> { permanent.destroy(source, game,false); }); game.getState().processAction(game); diff --git a/Mage.Sets/src/mage/cards/p/PurgingScythe.java b/Mage.Sets/src/mage/cards/p/PurgingScythe.java index 84c3744262a..47f697e0c00 100644 --- a/Mage.Sets/src/mage/cards/p/PurgingScythe.java +++ b/Mage.Sets/src/mage/cards/p/PurgingScythe.java @@ -85,8 +85,8 @@ class PurgingScytheEffect extends OneShotEffect { filter.add(new ToughnessPredicate(ComparisonType.EQUAL_TO, leastToughness)); Target target = new TargetPermanent(filter); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { - if (controller.choose(outcome, target, source.getSourceId(), game)) { + if (target.canChoose(source.getControllerId(), source, game)) { + if (controller.choose(outcome, target, source, game)) { permanentToDamage = game.getPermanent(target.getFirstTarget()); } } diff --git a/Mage.Sets/src/mage/cards/p/PurphorosBronzeBlooded.java b/Mage.Sets/src/mage/cards/p/PurphorosBronzeBlooded.java index 00e7cf2696b..396936b60fb 100644 --- a/Mage.Sets/src/mage/cards/p/PurphorosBronzeBlooded.java +++ b/Mage.Sets/src/mage/cards/p/PurphorosBronzeBlooded.java @@ -107,7 +107,7 @@ class PurphurosBronzeBloodedEffect extends OneShotEffect { return true; } TargetCardInHand target = new TargetCardInHand(filter); - if (!controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + if (!controller.choose(Outcome.PutCreatureInPlay, target, source, game)) { return true; } Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/p/Putrefaction.java b/Mage.Sets/src/mage/cards/p/Putrefaction.java index 3b46d4d2d30..7a89783453b 100644 --- a/Mage.Sets/src/mage/cards/p/Putrefaction.java +++ b/Mage.Sets/src/mage/cards/p/Putrefaction.java @@ -58,7 +58,7 @@ class PutrefactionTriggeredAbility extends SpellCastAllTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.SPELL_CAST) { Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null && filterGreenOrWhiteSpell.match(spell, getSourceId(), getControllerId(), game)) { + if (spell != null && filterGreenOrWhiteSpell.match(spell, getControllerId(), this, game)) { this.getEffects().get(0).setTargetPointer(new FixedTarget(event.getPlayerId())); return true; } diff --git a/Mage.Sets/src/mage/cards/p/PutridRaptor.java b/Mage.Sets/src/mage/cards/p/PutridRaptor.java index effdc56764f..bac4f725919 100644 --- a/Mage.Sets/src/mage/cards/p/PutridRaptor.java +++ b/Mage.Sets/src/mage/cards/p/PutridRaptor.java @@ -32,7 +32,7 @@ public final class PutridRaptor extends CardImpl { this.toughness = new MageInt(4); // Morph-Discard a Zombie card. - this.addAbility(new MorphAbility(this, new DiscardCardCost(filter))); + this.addAbility(new MorphAbility(new DiscardCardCost(filter))); } private PutridRaptor(final PutridRaptor card) { diff --git a/Mage.Sets/src/mage/cards/p/PutridWarrior.java b/Mage.Sets/src/mage/cards/p/PutridWarrior.java index ea4589e7f07..2a83d5b1d81 100644 --- a/Mage.Sets/src/mage/cards/p/PutridWarrior.java +++ b/Mage.Sets/src/mage/cards/p/PutridWarrior.java @@ -37,8 +37,7 @@ public final class PutridWarrior extends CardImpl { // Whenever Putrid Warrior deals damage, choose one - Each player loses 1 life; or each player gains 1 life. Ability ability = new PutridWarriorDealsDamageTriggeredAbility(new LoseLifeAllPlayersEffect(1)); - Mode mode = new Mode(); - mode.addEffect(new PutridWarriorGainLifeEffect()); + Mode mode = new Mode(new PutridWarriorGainLifeEffect()); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/Pyramids.java b/Mage.Sets/src/mage/cards/p/Pyramids.java index 297ab08af36..f470fda641d 100644 --- a/Mage.Sets/src/mage/cards/p/Pyramids.java +++ b/Mage.Sets/src/mage/cards/p/Pyramids.java @@ -43,8 +43,7 @@ public final class Pyramids extends CardImpl { effect.setText("Destroy target Aura attached to a land"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{2}")); //or the next time target land would be destroyed this turn, remove all damage marked on it instead. - Mode mode = new Mode(); //back in the day this was not technically "damage", hopefully this modern description will work nowadays - mode.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn)); + Mode mode = new Mode(new PreventDamageToTargetEffect(Duration.EndOfTurn)); //back in the day this was not technically "damage", hopefully this modern description will work nowadays mode.addTarget(new TargetLandPermanent()); ability.addMode(mode); diff --git a/Mage.Sets/src/mage/cards/p/PyreSledgeArsonist.java b/Mage.Sets/src/mage/cards/p/PyreSledgeArsonist.java new file mode 100644 index 00000000000..9e3f844e322 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PyreSledgeArsonist.java @@ -0,0 +1,116 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.common.TargetAnyTarget; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PyreSledgeArsonist extends CardImpl { + + private static final Hint hint = new ValueHint( + "Permanents you've sacrificed this turn", PyreSledgeArsonistValue.instance + ); + + public PyreSledgeArsonist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.VIASHINO); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {1}, {T}: Pyre-Sledge Arsonist deals X damage to any target, where X is the number of permanents you sacrificed this turn. + Ability ability = new SimpleActivatedAbility( + new DamageTargetEffect(PyreSledgeArsonistValue.instance), new GenericManaCost(1) + ); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability.addHint(hint)); + } + + private PyreSledgeArsonist(final PyreSledgeArsonist card) { + super(card); + } + + @Override + public PyreSledgeArsonist copy() { + return new PyreSledgeArsonist(this); + } +} + +enum PyreSledgeArsonistValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return PyreSledgeArsonistWatcher.getAmount(sourceAbility.getControllerId(), game); + } + + @Override + public PyreSledgeArsonistValue copy() { + return this; + } + + @Override + public String getMessage() { + return "the number of permanents you've sacrificed this turn"; + } + + @Override + public String toString() { + return "X"; + } +} + +class PyreSledgeArsonistWatcher extends Watcher { + + private final Map playerMap = new HashMap<>(); + + PyreSledgeArsonistWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.SACRIFICED_PERMANENT) { + playerMap.compute(event.getPlayerId(), CardUtil::setOrIncrementValue); + } + } + + @Override + public void reset() { + super.reset(); + playerMap.clear(); + } + + static int getAmount(UUID playerId, Game game) { + return game + .getState() + .getWatcher(PyreSledgeArsonistWatcher.class) + .playerMap + .getOrDefault(playerId, 0); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PyrewildShaman.java b/Mage.Sets/src/mage/cards/p/PyrewildShaman.java index 2cca7bf0ae7..f6b9d15b274 100644 --- a/Mage.Sets/src/mage/cards/p/PyrewildShaman.java +++ b/Mage.Sets/src/mage/cards/p/PyrewildShaman.java @@ -3,7 +3,7 @@ package mage.cards.p; import java.util.UUID; import mage.MageInt; -import mage.abilities.common.ControlledCreaturesDealCombatDamagePlayerTriggeredAbility; +import mage.abilities.common.DealCombatDamageControlledTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.ReturnToHandSourceEffect; @@ -30,7 +30,7 @@ public final class PyrewildShaman extends CardImpl { this.addAbility(new BloodrushAbility("{1}{R}", new BoostTargetEffect(3, 1, Duration.EndOfTurn))); // Whenever one or more creatures you control deal combat damage to a player, if Pyrewild Shaman is in your graveyard, you may pay {3}. If you do, return Pyrewild Shaman to your hand. - this.addAbility(new ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Zone.GRAVEYARD, + this.addAbility(new DealCombatDamageControlledTriggeredAbility(Zone.GRAVEYARD, new DoIfCostPaid(new ReturnToHandSourceEffect(), new ManaCostsImpl("{3}")) .setText("if {this} is in your graveyard, you may pay {3}. If you do, return {this} to your hand"))); diff --git a/Mage.Sets/src/mage/cards/p/Pyroblast.java b/Mage.Sets/src/mage/cards/p/Pyroblast.java index b75b40910fb..1218d9c746e 100644 --- a/Mage.Sets/src/mage/cards/p/Pyroblast.java +++ b/Mage.Sets/src/mage/cards/p/Pyroblast.java @@ -27,8 +27,7 @@ public final class Pyroblast extends CardImpl { this.getSpellAbility().addEffect(new PyroblastCounterTargetEffect()); this.getSpellAbility().addTarget(new TargetSpell()); - Mode mode = new Mode(); - mode.addEffect(new PyroblastDestroyTargetEffect()); + Mode mode = new Mode(new PyroblastDestroyTargetEffect()); mode.addTarget(new TargetPermanent()); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/p/Pyrokinesis.java b/Mage.Sets/src/mage/cards/p/Pyrokinesis.java index 179950b2854..b86e2277b50 100644 --- a/Mage.Sets/src/mage/cards/p/Pyrokinesis.java +++ b/Mage.Sets/src/mage/cards/p/Pyrokinesis.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.costs.AlternativeCostSourceAbility; import mage.abilities.costs.common.ExileFromHandCost; @@ -10,28 +8,30 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterOwnedCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCreaturePermanentAmount; +import java.util.UUID; + /** - * * @author Plopman */ public final class Pyrokinesis extends CardImpl { - public Pyrokinesis(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{4}{R}{R}"); + private static final FilterOwnedCard filter + = new FilterOwnedCard("a red card from your hand"); + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + } + + public Pyrokinesis(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}{R}"); // You may exile a red card from your hand rather than pay Pyrokinesis's mana cost. - FilterOwnedCard filter = new FilterOwnedCard("a red card from your hand"); - filter.add(new ColorPredicate(ObjectColor.RED)); - filter.add(Predicates.not(new CardIdPredicate(this.getId()))); // the exile cost can never be paid with the card itself this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter)))); - + // Pyrokinesis deals 4 damage divided as you choose among any number of target creatures. this.getSpellAbility().addEffect(new DamageMultiEffect(4)); this.getSpellAbility().addTarget(new TargetCreaturePermanentAmount(4)); diff --git a/Mage.Sets/src/mage/cards/p/PyromancersGoggles.java b/Mage.Sets/src/mage/cards/p/PyromancersGoggles.java index e0d275217f4..9b9ef58deea 100644 --- a/Mage.Sets/src/mage/cards/p/PyromancersGoggles.java +++ b/Mage.Sets/src/mage/cards/p/PyromancersGoggles.java @@ -17,7 +17,6 @@ import mage.filter.common.FilterInstantOrSorcerySpell; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.stack.Spell; import mage.target.targetpointer.FixedTarget; @@ -86,7 +85,7 @@ class PyromancersGogglesTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (event.getData().equals(abilityOriginalId)) { Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null && filter.match(spell, getSourceId(), getControllerId(), game)) { + if (spell != null && filter.match(spell, getControllerId(), this, game)) { for (Effect effect : getEffects()) { effect.setTargetPointer(new FixedTarget(event.getTargetId())); } diff --git a/Mage.Sets/src/mage/cards/p/Pyromatics.java b/Mage.Sets/src/mage/cards/p/Pyromatics.java index 28e4ae95972..ae25b1f27d3 100644 --- a/Mage.Sets/src/mage/cards/p/Pyromatics.java +++ b/Mage.Sets/src/mage/cards/p/Pyromatics.java @@ -20,7 +20,7 @@ public final class Pyromatics extends CardImpl { // Replicate {1}{R} - this.addAbility(new ReplicateAbility(this, "{1}{R}")); + this.addAbility(new ReplicateAbility("{1}{R}")); // Pyromatics deals 1 damage to any target. this.getSpellAbility().addEffect(new DamageTargetEffect(1)); this.getSpellAbility().addTarget(new TargetAnyTarget()); diff --git a/Mage.Sets/src/mage/cards/q/QarsiDeceiver.java b/Mage.Sets/src/mage/cards/q/QarsiDeceiver.java index 796af6814b0..086c12f658e 100644 --- a/Mage.Sets/src/mage/cards/q/QarsiDeceiver.java +++ b/Mage.Sets/src/mage/cards/q/QarsiDeceiver.java @@ -71,7 +71,7 @@ class QarsiDeceiverManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object instanceof Spell) { if (((Spell) object).isFaceDown(game)) { return true; diff --git a/Mage.Sets/src/mage/cards/q/QasaliAmbusher.java b/Mage.Sets/src/mage/cards/q/QasaliAmbusher.java index 8e523c0312c..a285efbab12 100644 --- a/Mage.Sets/src/mage/cards/q/QasaliAmbusher.java +++ b/Mage.Sets/src/mage/cards/q/QasaliAmbusher.java @@ -1,6 +1,5 @@ package mage.cards.q; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.CompoundCondition; @@ -13,27 +12,28 @@ import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashSourceEffe import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; import mage.watchers.common.PlayerAttackedStepWatcher; +import java.util.UUID; + /** - * * @author Plopman */ public final class QasaliAmbusher extends CardImpl { - private static final FilterControlledPermanent filterForest = new FilterControlledPermanent(); - private static final FilterControlledPermanent filterPlains = new FilterControlledPermanent(); + private static final FilterControlledPermanent filterForest = new FilterControlledPermanent(SubType.FOREST); + private static final FilterControlledPermanent filterPlains = new FilterControlledPermanent(SubType.PLAINS); - static { - filterForest.add(SubType.FOREST.getPredicate()); - filterPlains.add(SubType.PLAINS.getPredicate()); - } - - private static final Condition condition = - new CompoundCondition("If a creature is attacking you and you control a Forest and a Plains", - AttackedThisStepCondition.instance, new PermanentsOnTheBattlefieldCondition(filterForest), new PermanentsOnTheBattlefieldCondition(filterPlains)); + private static final Condition condition = new CompoundCondition( + "If a creature is attacking you and you control a Forest and a Plains", + AttackedThisStepCondition.instance, + new PermanentsOnTheBattlefieldCondition(filterForest), + new PermanentsOnTheBattlefieldCondition(filterPlains) + ); public QasaliAmbusher(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}"); @@ -48,11 +48,14 @@ public final class QasaliAmbusher extends CardImpl { // If a creature is attacking you and you control a Forest and a Plains, // you may cast Qasali Ambusher without paying its mana cost and as though it had flash. - Ability ability = new AlternativeCostSourceAbility(null, condition); - ability.addEffect(new ConditionalAsThoughEffect(new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame), condition) - .setText("you may cast {this} without paying its mana cost and as though it had flash")); - ability.addWatcher(new PlayerAttackedStepWatcher()); - this.addAbility(ability); + Ability ability = new AlternativeCostSourceAbility( + null, condition, "if a creature is attacking you and you control a Forest and a Plains, " + + "you may cast {this} without paying its mana cost and as though it had flash." + ); + ability.addEffect(new ConditionalAsThoughEffect( + new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame), condition + )); + this.addAbility(ability, new PlayerAttackedStepWatcher()); } private QasaliAmbusher(final QasaliAmbusher card) { @@ -63,4 +66,4 @@ public final class QasaliAmbusher extends CardImpl { public QasaliAmbusher copy() { return new QasaliAmbusher(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/q/Quakebringer.java b/Mage.Sets/src/mage/cards/q/Quakebringer.java index 820fcea1702..59a94214a43 100644 --- a/Mage.Sets/src/mage/cards/q/Quakebringer.java +++ b/Mage.Sets/src/mage/cards/q/Quakebringer.java @@ -75,7 +75,7 @@ class QuakebringerTriggeredAbility extends TriggeredAbilityImpl { return game.isActivePlayer(getControllerId()); case GRAVEYARD: return game.isActivePlayer(game.getOwnerId(getSourceId())) - && game.getBattlefield().count(filter, getSourceId(), getControllerId(), game) > 0; + && game.getBattlefield().count(filter, getControllerId(), this, game) > 0; } return false; } diff --git a/Mage.Sets/src/mage/cards/q/QuandrixApprentice.java b/Mage.Sets/src/mage/cards/q/QuandrixApprentice.java index 8c4e470d11b..93d6e53ad55 100644 --- a/Mage.Sets/src/mage/cards/q/QuandrixApprentice.java +++ b/Mage.Sets/src/mage/cards/q/QuandrixApprentice.java @@ -2,13 +2,12 @@ package mage.cards.q; import mage.MageInt; import mage.abilities.common.MagecraftAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import java.util.UUID; @@ -28,9 +27,7 @@ public final class QuandrixApprentice extends CardImpl { // Magecraft — Whenever you cast or copy an instant or sorcery spell, look at the top three cards of your library. You may reveal a land card from among them and put that card into your hand. Put the rest on the bottom of your library in any order. this.addAbility(new MagecraftAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(3), false, StaticValue.get(1), StaticFilters.FILTER_CARD_LAND_A, - Zone.LIBRARY, false, true, false, Zone.HAND, true - ))); + 3, 1, StaticFilters.FILTER_CARD_LAND_A, PutCards.HAND, PutCards.BOTTOM_ANY))); } private QuandrixApprentice(final QuandrixApprentice card) { diff --git a/Mage.Sets/src/mage/cards/q/QuestForTheGemblades.java b/Mage.Sets/src/mage/cards/q/QuestForTheGemblades.java index af8c4671382..17f588f0306 100644 --- a/Mage.Sets/src/mage/cards/q/QuestForTheGemblades.java +++ b/Mage.Sets/src/mage/cards/q/QuestForTheGemblades.java @@ -28,7 +28,7 @@ public final class QuestForTheGemblades extends CardImpl { // Whenever a creature you control deals combat damage to a creature, you may put a quest counter on Quest for the Gemblades. this.addAbility(new DealsDamageToACreatureAllTriggeredAbility( - new AddCountersSourceEffect(CounterType.QUEST.createInstance()), false, + new AddCountersSourceEffect(CounterType.QUEST.createInstance()), true, StaticFilters.FILTER_CONTROLLED_A_CREATURE, SetTargetPointer.PERMANENT, true )); diff --git a/Mage.Sets/src/mage/cards/q/QuestForTheHolyRelic.java b/Mage.Sets/src/mage/cards/q/QuestForTheHolyRelic.java index 7b4ec91c3b2..c010b787e1a 100644 --- a/Mage.Sets/src/mage/cards/q/QuestForTheHolyRelic.java +++ b/Mage.Sets/src/mage/cards/q/QuestForTheHolyRelic.java @@ -93,7 +93,7 @@ class QuestForTheHolyRelicEffect extends OneShotEffect { if (card != null && controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { Permanent equipment = game.getPermanent(card.getId()); Target targetCreature = new TargetControlledCreaturePermanent(); - if (equipment != null && controller.choose(Outcome.BoostCreature, targetCreature, source.getSourceId(), game)) { + if (equipment != null && controller.choose(Outcome.BoostCreature, targetCreature, source, game)) { Permanent permanent = game.getPermanent(targetCreature.getFirstTarget()); permanent.addAttachment(equipment.getId(), source, game); } diff --git a/Mage.Sets/src/mage/cards/q/QuezaAugurOfAgonies.java b/Mage.Sets/src/mage/cards/q/QuezaAugurOfAgonies.java new file mode 100644 index 00000000000..2be0501f245 --- /dev/null +++ b/Mage.Sets/src/mage/cards/q/QuezaAugurOfAgonies.java @@ -0,0 +1,46 @@ +package mage.cards.q; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DrawCardControllerTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class QuezaAugurOfAgonies extends CardImpl { + + public QuezaAugurOfAgonies(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.CEPHALID); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Whenever you draw a card, target opponent loses 1 life and you gain 1 life. + Ability ability = new DrawCardControllerTriggeredAbility(new LoseLifeTargetEffect(1), false); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + private QuezaAugurOfAgonies(final QuezaAugurOfAgonies card) { + super(card); + } + + @Override + public QuezaAugurOfAgonies copy() { + return new QuezaAugurOfAgonies(this); + } +} diff --git a/Mage.Sets/src/mage/cards/q/QuickDrawDagger.java b/Mage.Sets/src/mage/cards/q/QuickDrawDagger.java new file mode 100644 index 00000000000..eb530edab8e --- /dev/null +++ b/Mage.Sets/src/mage/cards/q/QuickDrawDagger.java @@ -0,0 +1,61 @@ +package mage.cards.q; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlashAbility; +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.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class QuickDrawDagger extends CardImpl { + + public QuickDrawDagger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // When Quick-Draw Dagger enters the battlefield, attach it to target creature you control. That creature gains first strike until end of turn. + Ability ability = new EntersBattlefieldTriggeredAbility(new AttachEffect( + Outcome.BoostCreature, "attach it to target creature you control" + ), false); + ability.addEffect(new GainAbilityTargetEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn, + "That creature gains first strike until end of turn" + )); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + + // Equipped creature gets +1/+1. + this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 1))); + + // Equip {1} + this.addAbility(new EquipAbility(1)); + } + + private QuickDrawDagger(final QuickDrawDagger card) { + super(card); + } + + @Override + public QuickDrawDagger copy() { + return new QuickDrawDagger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/q/QuickSliver.java b/Mage.Sets/src/mage/cards/q/QuickSliver.java index 120575ed317..97ac74de838 100644 --- a/Mage.Sets/src/mage/cards/q/QuickSliver.java +++ b/Mage.Sets/src/mage/cards/q/QuickSliver.java @@ -20,7 +20,7 @@ import mage.filter.common.FilterCreatureCard; */ public final class QuickSliver extends CardImpl { - private static final FilterCreatureCard filter = new FilterCreatureCard("Sliver cards"); + private static final FilterCreatureCard filter = new FilterCreatureCard("Sliver spells"); static { filter.add(SubType.SLIVER.getPredicate()); } diff --git a/Mage.Sets/src/mage/cards/q/QuicksilverDragon.java b/Mage.Sets/src/mage/cards/q/QuicksilverDragon.java index 358c2274fe9..6a48f146f6b 100644 --- a/Mage.Sets/src/mage/cards/q/QuicksilverDragon.java +++ b/Mage.Sets/src/mage/cards/q/QuicksilverDragon.java @@ -43,7 +43,7 @@ public final class QuicksilverDragon extends CardImpl { this.addAbility(ability); // Morph {4}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{4}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl<>("{4}{U}"))); } private QuicksilverDragon(final QuicksilverDragon card) { diff --git a/Mage.Sets/src/mage/cards/q/QuicksilverFountain.java b/Mage.Sets/src/mage/cards/q/QuicksilverFountain.java index cfd1f6faa2e..ded892c4d58 100644 --- a/Mage.Sets/src/mage/cards/q/QuicksilverFountain.java +++ b/Mage.Sets/src/mage/cards/q/QuicksilverFountain.java @@ -96,7 +96,7 @@ class QuicksilverFountainEffect extends OneShotEffect { Permanent landChosen = game.getPermanent(source.getFirstTarget()); landChosen.addCounters(CounterType.FLOOD.createInstance(), player.getId(), source, game); ContinuousEffect becomesBasicLandTargetEffect - = new BecomesBasicLandTargetEffect(Duration.Custom, false, SubType.ISLAND); + = new BecomesBasicLandTargetEffect(Duration.Custom, SubType.ISLAND); ConditionalContinuousEffect effect = new ConditionalContinuousEffect(becomesBasicLandTargetEffect, new LandHasFloodCounterCondition(), staticText); diff --git a/Mage.Sets/src/mage/cards/q/QuicksmithSpy.java b/Mage.Sets/src/mage/cards/q/QuicksmithSpy.java index daa5a2ac99a..bab34952d38 100644 --- a/Mage.Sets/src/mage/cards/q/QuicksmithSpy.java +++ b/Mage.Sets/src/mage/cards/q/QuicksmithSpy.java @@ -5,7 +5,7 @@ import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -14,7 +14,6 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.TargetPermanent; -import mage.target.common.TargetAnyTarget; import java.util.UUID; @@ -32,9 +31,9 @@ public final class QuicksmithSpy extends CardImpl { this.toughness = new MageInt(3); // When Quicksmith Spy enters the battlefield, target artifact you control gains "{T}: Draw a card" for as long as you control Quicksmith Spy. - Ability artifactAbility = new SimpleActivatedAbility(new DamageTargetEffect(2), new TapSourceCost()); - artifactAbility.addTarget(new TargetAnyTarget()); - Ability ability = new EntersBattlefieldTriggeredAbility(new GainAbilityTargetEffect(artifactAbility, Duration.WhileControlled).setText("target artifact you control gains \"{T}: Draw a card\" for as long as you control {this}")); + Ability ability = new EntersBattlefieldTriggeredAbility(new GainAbilityTargetEffect( + new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new TapSourceCost()), Duration.WhileControlled + ).setText("target artifact you control gains \"{T}: Draw a card\" for as long as you control {this}")); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/q/QuietDisrepair.java b/Mage.Sets/src/mage/cards/q/QuietDisrepair.java index 99be8e39e65..55dddf5eadc 100644 --- a/Mage.Sets/src/mage/cards/q/QuietDisrepair.java +++ b/Mage.Sets/src/mage/cards/q/QuietDisrepair.java @@ -39,8 +39,7 @@ public final class QuietDisrepair extends CardImpl { // At the beginning of your upkeep, choose one - Destroy enchanted permanent; or you gain 2 life. ability = new BeginningOfUpkeepTriggeredAbility(new DestroyAttachedToEffect("enchanted permanent"), TargetController.YOU, false); - Mode mode = new Mode(); - mode.addEffect(new GainLifeEffect(2)); + Mode mode = new Mode(new GainLifeEffect(2)); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/q/QuietusSpike.java b/Mage.Sets/src/mage/cards/q/QuietusSpike.java index 5cf54ae778d..ba3ce8bf873 100644 --- a/Mage.Sets/src/mage/cards/q/QuietusSpike.java +++ b/Mage.Sets/src/mage/cards/q/QuietusSpike.java @@ -31,7 +31,7 @@ public final class QuietusSpike extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(DeathtouchAbility.getInstance(), AttachmentType.EQUIPMENT))); // Whenever equipped creature deals combat damage to a player, that player loses half their life, rounded up. - this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility(new LoseHalfLifeTargetEffect(), "equipped", false, true)); + this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility(new LoseHalfLifeTargetEffect(), "equipped creature", false, true)); // Equip {3} this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(3), false)); diff --git a/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java b/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java index 70117e0de71..29e17f02005 100644 --- a/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java +++ b/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java @@ -9,22 +9,18 @@ import mage.abilities.costs.Cost; import mage.abilities.costs.common.RemoveVariableCountersSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; 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.ComparisonType; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import mage.target.targetadjustment.TargetAdjuster; @@ -33,6 +29,8 @@ import mage.target.targetadjustment.TargetAdjuster; */ public final class QuillmaneBaku extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with mana value X or less"); + public QuillmaneBaku(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); this.subtype.add(SubType.SPIRIT); @@ -40,14 +38,14 @@ public final class QuillmaneBaku extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(3); - // Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Skullmane Baku. + // Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Quillmane Baku. this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true)); - // {1}, Tap, Remove X ki counters from Quillmane Baku: Return target creature with converted mana cost X or less to its owner's hand. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new QuillmaneBakuReturnEffect(), new GenericManaCost(1)); + // {1}, {T}, Remove X ki counters from Quillmane Baku: Return target creature with mana value X or less to its owner's hand. + Ability ability = new SimpleActivatedAbility(new ReturnToHandTargetEffect(), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); - ability.addCost(new RemoveVariableCountersSourceCost(CounterType.KI.createInstance(1))); - ability.addTarget(new TargetCreaturePermanent()); + ability.addCost(new RemoveVariableCountersSourceCost(CounterType.KI.createInstance())); + ability.addTarget(new TargetCreaturePermanent(filter)); ability.setTargetAdjuster(QuillmaneBakuAdjuster.instance); this.addAbility(ability); } @@ -67,46 +65,15 @@ enum QuillmaneBakuAdjuster implements TargetAdjuster { @Override public void adjustTargets(Ability ability, Game game) { - int maxConvManaCost = 0; + int xValue = 0; for (Cost cost : ability.getCosts()) { if (cost instanceof RemoveVariableCountersSourceCost) { - maxConvManaCost = ((RemoveVariableCountersSourceCost) cost).getAmount(); + xValue = ((RemoveVariableCountersSourceCost) cost).getAmount(); } } ability.getTargets().clear(); - FilterCreaturePermanent newFilter = new FilterCreaturePermanent("creature with mana value " + maxConvManaCost + " or less"); - newFilter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, maxConvManaCost + 1)); - TargetCreaturePermanent target = new TargetCreaturePermanent(newFilter); - ability.getTargets().add(target); - } -} - -class QuillmaneBakuReturnEffect extends OneShotEffect { - - public QuillmaneBakuReturnEffect() { - super(Outcome.ReturnToHand); - this.staticText = "Return target creature with mana value X or less to its owner's hand"; - } - - public QuillmaneBakuReturnEffect(final QuillmaneBakuReturnEffect effect) { - super(effect); - } - - @Override - public QuillmaneBakuReturnEffect copy() { - return new QuillmaneBakuReturnEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); - if (permanent != null) { - controller.moveCards(permanent, Zone.HAND, source, game); - } - return true; + FilterCreaturePermanent newFilter = new FilterCreaturePermanent("creature with mana value " + xValue + " or less"); + newFilter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, xValue + 1)); + ability.addTarget(new TargetCreaturePermanent(newFilter)); } } diff --git a/Mage.Sets/src/mage/cards/r/RabbleRousing.java b/Mage.Sets/src/mage/cards/r/RabbleRousing.java new file mode 100644 index 00000000000..1c84b86d3b8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RabbleRousing.java @@ -0,0 +1,78 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.HideawayPlayEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; +import mage.abilities.keyword.HideawayAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.token.CitizenGreenWhiteToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RabbleRousing extends CardImpl { + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + StaticFilters.FILTER_PERMANENT_CREATURE, ComparisonType.MORE_THAN, 9 + ); + + public RabbleRousing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{W}"); + + // Hideaway 5 + this.addAbility(new HideawayAbility(5)); + + // Whenever you attack with one or more creatures, create that many 1/1 green and white Citizen creature tokens. Then if you control ten or more creatures, you may play the exiled card without paying its mana cost. + Ability ability = new AttacksWithCreaturesTriggeredAbility( + new CreateTokenEffect(new CitizenGreenWhiteToken(), RabbleRousingValue.instance) + .setText("create that many 1/1 green and white Citizen creature tokens"), 1 + ).setTriggerPhrase("Whenever you attack with one or more creatures, "); + ability.addEffect(new ConditionalOneShotEffect( + new HideawayPlayEffect(), condition, "Then if you control ten or more creatures, " + + "you may play the exiled card without paying its mana cost" + )); + this.addAbility(ability.addHint(CreaturesYouControlHint.instance)); + } + + private RabbleRousing(final RabbleRousing card) { + super(card); + } + + @Override + public RabbleRousing copy() { + return new RabbleRousing(this); + } +} + +enum RabbleRousingValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return (Integer) effect.getValue("attackers"); + } + + @Override + public RabbleRousingValue copy() { + return this; + } + + @Override + public String getMessage() { + return ""; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/RacersRing.java b/Mage.Sets/src/mage/cards/r/RacersRing.java new file mode 100644 index 00000000000..3b7616a2afd --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RacersRing.java @@ -0,0 +1,50 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; +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.DrawCardSourceControllerEffect; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RacersRing extends CardImpl { + + public RacersRing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Racers' Ring enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {R} or {G}. + this.addAbility(new RedManaAbility()); + this.addAbility(new GreenManaAbility()); + + // {2}{R}{G}, {T}, Sacrifice Racers' Ring: Draw a card. + Ability ability = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{2}{R}{G}") + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private RacersRing(final RacersRing card) { + super(card); + } + + @Override + public RacersRing copy() { + return new RacersRing(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RadiantEpicure.java b/Mage.Sets/src/mage/cards/r/RadiantEpicure.java index 57476794588..d4b76ca0c60 100644 --- a/Mage.Sets/src/mage/cards/r/RadiantEpicure.java +++ b/Mage.Sets/src/mage/cards/r/RadiantEpicure.java @@ -8,10 +8,7 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamagePlayersEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.TargetController; +import mage.constants.*; import mage.game.Game; import mage.players.Player; import mage.watchers.common.ManaSpentToCastWatcher; @@ -34,7 +31,7 @@ public final class RadiantEpicure extends CardImpl { // Converge — When Radiant Epicure enters the battlefield, each opponent loses X life and you gain X life, where X is the number of colors of mana spent to cast this spell. this.addAbility(new EntersBattlefieldTriggeredAbility( new RadiantEpicureEffect(), false) - .withFlavorWord("Converge") + .setAbilityWord(AbilityWord.CONVERGE) ); } diff --git a/Mage.Sets/src/mage/cards/r/RadiantGrace.java b/Mage.Sets/src/mage/cards/r/RadiantGrace.java index 0ab4e8ac2d9..ec94edc67b2 100644 --- a/Mage.Sets/src/mage/cards/r/RadiantGrace.java +++ b/Mage.Sets/src/mage/cards/r/RadiantGrace.java @@ -96,8 +96,7 @@ class RadiantGraceEffect extends OneShotEffect { } game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); - UUID secondFaceId = game.getCard(source.getSourceId()).getSecondCardFace().getId(); - game.getState().setValue("attachTo:" + secondFaceId, player.getId()); + game.getState().setValue("attachTo:" + source.getSourceId(), player.getId()); if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { player.addAttachment(card.getId(), source, game); } diff --git a/Mage.Sets/src/mage/cards/r/RadiantPerformer.java b/Mage.Sets/src/mage/cards/r/RadiantPerformer.java index 8ec84b230d2..0a14e6dc75c 100644 --- a/Mage.Sets/src/mage/cards/r/RadiantPerformer.java +++ b/Mage.Sets/src/mage/cards/r/RadiantPerformer.java @@ -131,7 +131,7 @@ class RadiantPerformerEffect extends CopySpellForEachItCouldTargetEffect { .orElse(null); game.getBattlefield() .getActivePermanents( - StaticFilters.FILTER_PERMANENT, player.getId(), source.getSourceId(), game + StaticFilters.FILTER_PERMANENT, player.getId(), source, game ).stream() .filter(Objects::nonNull) .filter(p -> !p.equals(game.getPermanent(targeted))) diff --git a/Mage.Sets/src/mage/cards/r/Radiate.java b/Mage.Sets/src/mage/cards/r/Radiate.java index 5e8eeabc69e..3898c50a951 100644 --- a/Mage.Sets/src/mage/cards/r/Radiate.java +++ b/Mage.Sets/src/mage/cards/r/Radiate.java @@ -134,7 +134,7 @@ class RadiateEffect extends CopySpellForEachItCouldTargetEffect { .orElse(null); game.getBattlefield() .getActivePermanents( - StaticFilters.FILTER_PERMANENT, player.getId(), source.getSourceId(), game + StaticFilters.FILTER_PERMANENT, player.getId(), source, game ).stream() .filter(Objects::nonNull) .filter(p -> !p.equals(game.getPermanent(targeted))) diff --git a/Mage.Sets/src/mage/cards/r/RaffineSchemingSeer.java b/Mage.Sets/src/mage/cards/r/RaffineSchemingSeer.java new file mode 100644 index 00000000000..2133863a684 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RaffineSchemingSeer.java @@ -0,0 +1,97 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.AttackingCreatureCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.WardAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetAttackingCreature; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RaffineSchemingSeer extends CardImpl { + + private static final Hint hint = new ValueHint( + "Attacking creatures", new AttackingCreatureCount("attacking creatures") + ); + + public RaffineSchemingSeer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SPHINX); + this.subtype.add(SubType.DEMON); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Ward {1} + this.addAbility(new WardAbility(new ManaCostsImpl<>("{1}"))); + + // Whenever you attack, target creature connives X, where X is the number of attacking creatures. + Ability ability = new AttacksWithCreaturesTriggeredAbility(new RaffineSchemingSeerEffect(), 1); + ability.addTarget(new TargetAttackingCreature()); + this.addAbility(ability.addHint(hint)); + } + + private RaffineSchemingSeer(final RaffineSchemingSeer card) { + super(card); + } + + @Override + public RaffineSchemingSeer copy() { + return new RaffineSchemingSeer(this); + } +} + +class RaffineSchemingSeerEffect extends OneShotEffect { + + RaffineSchemingSeerEffect() { + super(Outcome.Benefit); + staticText = "target attacking creature connives X, where X is the number of attacking creatures. " + + "(Draw X cards, then discard X cards. Put a +1/+1 counter on that creature " + + "for each nonland card discarded this way.)"; + } + + private RaffineSchemingSeerEffect(final RaffineSchemingSeerEffect effect) { + super(effect); + } + + @Override + public RaffineSchemingSeerEffect copy() { + return new RaffineSchemingSeerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + return false; + } + int amount = game.getBattlefield().count( + StaticFilters.FILTER_ATTACKING_CREATURES, + source.getControllerId(), source, game + ); + return ConniveSourceEffect.connive(permanent, amount, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RaffinesGuidance.java b/Mage.Sets/src/mage/cards/r/RaffinesGuidance.java new file mode 100644 index 00000000000..df67ecd5b26 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RaffinesGuidance.java @@ -0,0 +1,93 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.Costs; +import mage.abilities.costs.CostsImpl; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author Hiddevb + */ +public final class RaffinesGuidance extends CardImpl { + + public RaffinesGuidance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{W}"); + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature gets +1/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 1, Duration.WhileOnBattlefield))); + + // You may cast Raffine’s Guidance from your graveyard by paying {2}{W} instead of its mana cost. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new RafinnesGuidancePlayEffect())); + } + + private RaffinesGuidance(final RaffinesGuidance card) { + super(card); + } + + @Override + public RaffinesGuidance copy() { + return new RaffinesGuidance(this); + } +} + +class RafinnesGuidancePlayEffect extends AsThoughEffectImpl { + + public RafinnesGuidancePlayEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfGame, Outcome.Benefit); + staticText = "You may cast {this} from your graveyard by paying {2}{W} rather than paying its mana cost."; + } + + public RafinnesGuidancePlayEffect(final RafinnesGuidancePlayEffect effect) { + super(effect); + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + if (sourceId.equals(source.getSourceId()) && source.isControlledBy(affectedControllerId)) { + if (game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) { + Player player = game.getPlayer(affectedControllerId); + if (player != null) { + Costs costs = new CostsImpl<>(); + player.setCastSourceIdWithAlternateMana(sourceId, new ManaCostsImpl<>("{2}{W}"), costs); + return true; + } + } + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public RafinnesGuidancePlayEffect copy() { + return new RafinnesGuidancePlayEffect(this); + } + + +} diff --git a/Mage.Sets/src/mage/cards/r/RaffinesInformant.java b/Mage.Sets/src/mage/cards/r/RaffinesInformant.java new file mode 100644 index 00000000000..0ea5554eacb --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RaffinesInformant.java @@ -0,0 +1,38 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RaffinesInformant extends CardImpl { + + public RaffinesInformant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // When Raffine's Informant enters the battlefield, it connives. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ConniveSourceEffect())); + } + + private RaffinesInformant(final RaffinesInformant card) { + super(card); + } + + @Override + public RaffinesInformant copy() { + return new RaffinesInformant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RaffinesSilencer.java b/Mage.Sets/src/mage/cards/r/RaffinesSilencer.java new file mode 100644 index 00000000000..94c3bbccbb6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RaffinesSilencer.java @@ -0,0 +1,83 @@ +package mage.cards.r; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +/** + * + * @author weirddan455 + */ +public final class RaffinesSilencer extends CardImpl { + + public RaffinesSilencer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When Raffine's Silencer enters the battlefield, it connives. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ConniveSourceEffect())); + + // When Raffine's Silencer dies, target creature an opponent controls gets -X/-X until end of turn, where X is Raffine's Silencer's power. + Ability ability = new DiesSourceTriggeredAbility( + new BoostTargetEffect(RaffinesSilencerValue.instance, RaffinesSilencerValue.instance, Duration.EndOfTurn, true), + false + ); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private RaffinesSilencer(final RaffinesSilencer card) { + super(card); + } + + @Override + public RaffinesSilencer copy() { + return new RaffinesSilencer(this); + } +} + +enum RaffinesSilencerValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Object died = effect.getValue("permanentLeftBattlefield"); + if (died instanceof Permanent) { + return -((Permanent) died).getPower().getValue(); + } + return 0; + } + + @Override + public RaffinesSilencerValue copy() { + return this; + } + + @Override + public String toString() { + return "-X"; + } + + @Override + public String getMessage() { + return "{this}'s power"; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RaffinesTower.java b/Mage.Sets/src/mage/cards/r/RaffinesTower.java new file mode 100644 index 00000000000..6951af8efe6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RaffinesTower.java @@ -0,0 +1,48 @@ +package mage.cards.r; + +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.keyword.CyclingAbility; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RaffinesTower extends CardImpl { + + public RaffinesTower(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + this.subtype.add(SubType.PLAINS); + this.subtype.add(SubType.ISLAND); + this.subtype.add(SubType.SWAMP); + + // ({T}: Add {W}, {U}, or {B}.) + this.addAbility(new WhiteManaAbility()); + this.addAbility(new BlueManaAbility()); + this.addAbility(new BlackManaAbility()); + + // Raffine's Tower enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // Cycling {3} + this.addAbility(new CyclingAbility(new GenericManaCost(3))); + } + + private RaffinesTower(final RaffinesTower card) { + super(card); + } + + @Override + public RaffinesTower copy() { + return new RaffinesTower(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RafiqOfTheMany.java b/Mage.Sets/src/mage/cards/r/RafiqOfTheMany.java index 3a123322796..1e01d8a5c6d 100644 --- a/Mage.Sets/src/mage/cards/r/RafiqOfTheMany.java +++ b/Mage.Sets/src/mage/cards/r/RafiqOfTheMany.java @@ -34,7 +34,7 @@ public final class RafiqOfTheMany extends CardImpl { // Whenever a creature you control attacks alone, it gains double strike until end of turn. this.addAbility(new AttacksAloneControlledTriggeredAbility(new GainAbilityTargetEffect( DoubleStrikeAbility.getInstance(), Duration.EndOfTurn - ).setText("it gains double strike until end of turn"))); + ).setText("it gains double strike until end of turn"), true, false)); } private RafiqOfTheMany(final RafiqOfTheMany card) { diff --git a/Mage.Sets/src/mage/cards/r/RagavanNimblePilferer.java b/Mage.Sets/src/mage/cards/r/RagavanNimblePilferer.java index 8d5751714fb..87cca377d89 100644 --- a/Mage.Sets/src/mage/cards/r/RagavanNimblePilferer.java +++ b/Mage.Sets/src/mage/cards/r/RagavanNimblePilferer.java @@ -39,7 +39,7 @@ public final class RagavanNimblePilferer extends CardImpl { this.addAbility(ability); // Dash {1}{R} - this.addAbility(new DashAbility(this, "{1}{R}")); + this.addAbility(new DashAbility("{1}{R}")); } private RagavanNimblePilferer(final RagavanNimblePilferer card) { diff --git a/Mage.Sets/src/mage/cards/r/RageExtractor.java b/Mage.Sets/src/mage/cards/r/RageExtractor.java index 9c4d203be7d..ef77b41705b 100644 --- a/Mage.Sets/src/mage/cards/r/RageExtractor.java +++ b/Mage.Sets/src/mage/cards/r/RageExtractor.java @@ -1,31 +1,44 @@ - package mage.cards.r; -import java.util.UUID; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.costs.mana.ManaCost; -import mage.abilities.costs.mana.PhyrexianManaCost; -import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.filter.predicate.Predicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.stack.Spell; +import mage.game.stack.StackObject; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** * @author Loki */ public final class RageExtractor extends CardImpl { + private static final FilterSpell filter = new FilterSpell("a spell with {P} in its mana cost"); + + static { + filter.add(RageExtractorPredicate.instance); + } + public RageExtractor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}{R/P}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}{R/P}"); - - this.addAbility(new RageExtractorTriggeredAbility()); + Ability ability = new SpellCastControllerTriggeredAbility( + new DamageTargetEffect(RageExtractorValue.instance) + .setText("{this} deals damage equal to that spell's mana value to any target"), + filter, false + ); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); } private RageExtractor(final RageExtractor card) { @@ -38,44 +51,31 @@ public final class RageExtractor extends CardImpl { } } -class RageExtractorTriggeredAbility extends TriggeredAbilityImpl { - RageExtractorTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(0)); - this.addTarget(new TargetAnyTarget()); - } - - RageExtractorTriggeredAbility(final RageExtractorTriggeredAbility ability) { - super(ability); - } +enum RageExtractorPredicate implements Predicate { + instance; @Override - public RageExtractorTriggeredAbility copy() { - return new RageExtractorTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SPELL_CAST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getPlayerId().equals(this.controllerId)) { - Spell spell = (Spell) game.getStack().getStackObject(event.getTargetId()); - if (spell != null) { - for (ManaCost cost : spell.getCard().getManaCost()) { - if (cost instanceof PhyrexianManaCost) { - ((DamageTargetEffect)getEffects().get(0)).setAmount(StaticValue.get(spell.getManaValue())); - return true; - } - } - } - } - return false; - } - - @Override - public String getRule() { - return "Whenever you cast a spell with {P} in its mana cost, {this} deals damage equal to that spell's mana value to any target."; + public boolean apply(StackObject input, Game game) { + return ((Spell) input).getCard().getManaCost().stream().anyMatch(ManaCost::isPhyrexian); + } +} + +enum RageExtractorValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Spell spell = (Spell) effect.getValue("spellCast"); + return spell != null ? spell.getManaValue() : 0; + } + + @Override + public RageExtractorValue copy() { + return this; + } + + @Override + public String getMessage() { + return ""; } } diff --git a/Mage.Sets/src/mage/cards/r/RageReflection.java b/Mage.Sets/src/mage/cards/r/RageReflection.java index 67084a10142..f0879bbd541 100644 --- a/Mage.Sets/src/mage/cards/r/RageReflection.java +++ b/Mage.Sets/src/mage/cards/r/RageReflection.java @@ -23,7 +23,7 @@ public final class RageReflection extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{R}{R}"); // Creatures you control have double strike. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE, false))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES, false))); } private RageReflection(final RageReflection card) { diff --git a/Mage.Sets/src/mage/cards/r/RaggedVeins.java b/Mage.Sets/src/mage/cards/r/RaggedVeins.java index f77066b7a4d..8af532872e7 100644 --- a/Mage.Sets/src/mage/cards/r/RaggedVeins.java +++ b/Mage.Sets/src/mage/cards/r/RaggedVeins.java @@ -1,13 +1,10 @@ - - package mage.cards.r; import java.util.UUID; import mage.abilities.common.DealtDamageAttachedTriggeredAbility; -import mage.abilities.dynamicvalue.common.NumericSetToEffectValues; -import mage.abilities.effects.Effect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.effects.common.LoseLifeControllerAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.FlashAbility; import mage.cards.CardImpl; @@ -15,8 +12,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Outcome; -import mage.constants.SetTargetPointer; -import mage.constants.Zone; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -30,7 +25,6 @@ public final class RaggedVeins extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{B}"); this.subtype.add(SubType.AURA); - // Flash this.addAbility(FlashAbility.getInstance()); @@ -41,9 +35,10 @@ public final class RaggedVeins extends CardImpl { this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Whenever enchanted creature is dealt damage, its controller loses that much life. - Effect effect = new LoseLifeTargetEffect(new NumericSetToEffectValues("that much", "damage")); - effect.setText("its controller loses that much life"); - this.addAbility(new DealtDamageAttachedTriggeredAbility(Zone.BATTLEFIELD, effect, false, SetTargetPointer.PLAYER)); + this.addAbility(new DealtDamageAttachedTriggeredAbility( + new LoseLifeControllerAttachedEffect(SavedDamageValue.MUCH), + false + )); } private RaggedVeins(final RaggedVeins card) { diff --git a/Mage.Sets/src/mage/cards/r/RagingRiver.java b/Mage.Sets/src/mage/cards/r/RagingRiver.java index a712afc0885..157501fc9b1 100644 --- a/Mage.Sets/src/mage/cards/r/RagingRiver.java +++ b/Mage.Sets/src/mage/cards/r/RagingRiver.java @@ -86,13 +86,13 @@ class RagingRiverEffect extends OneShotEffect { FilterControlledCreaturePermanent filterBlockers = new FilterControlledCreaturePermanent("creatures without flying you control to assign to the \"left\" pile (creatures not chosen will be assigned to the \"right\" pile)"); filterBlockers.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filterBlockers, true); - if (target.canChoose(source.getSourceId(), defenderId, game)) { + if (target.canChoose(defenderId, source, game)) { if (defender.chooseTarget(Outcome.Neutral, target, source, game)) { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), defenderId, game)) { if (target.getTargets().contains(permanent.getId())) { left.add(permanent); leftLog.add(permanent); - } else if (filterBlockers.match(permanent, source.getSourceId(), defenderId, game)) { + } else if (filterBlockers.match(permanent, defenderId, source, game)) { right.add(permanent); rightLog.add(permanent); } diff --git a/Mage.Sets/src/mage/cards/r/RagsRiches.java b/Mage.Sets/src/mage/cards/r/RagsRiches.java index 25443012c5e..3306ee4bc3c 100644 --- a/Mage.Sets/src/mage/cards/r/RagsRiches.java +++ b/Mage.Sets/src/mage/cards/r/RagsRiches.java @@ -76,7 +76,7 @@ class RichesEffect extends OneShotEffect { if (opponent != null) { TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (opponent.choose(Outcome.Detriment, target, source.getSourceId(), game)) { + if (opponent.choose(Outcome.Detriment, target, source, game)) { creaturesToSteal.add(target.getTargets().get(0)); } } diff --git a/Mage.Sets/src/mage/cards/r/RaidersWake.java b/Mage.Sets/src/mage/cards/r/RaidersWake.java index 7c667a08f2b..f4da9d6ef89 100644 --- a/Mage.Sets/src/mage/cards/r/RaidersWake.java +++ b/Mage.Sets/src/mage/cards/r/RaidersWake.java @@ -33,7 +33,7 @@ public final class RaidersWake extends CardImpl { // Raid — At the beginning of your end step, if you attacked this turn, target opponent discards a card. Ability ability = new ConditionalInterveningIfTriggeredAbility( new BeginningOfEndStepTriggeredAbility(new DiscardTargetEffect(1), TargetController.YOU, false), RaidCondition.instance, - "Raid — At the beginning of your end step, if you attacked this turn, target opponent discards a card."); + "At the beginning of your end step, if you attacked this turn, target opponent discards a card."); ability.addTarget(new TargetOpponent()); ability.setAbilityWord(AbilityWord.RAID); ability.addHint(RaidHint.instance); diff --git a/Mage.Sets/src/mage/cards/r/RaidingParty.java b/Mage.Sets/src/mage/cards/r/RaidingParty.java index 60b23191a5e..2c6991e1049 100644 --- a/Mage.Sets/src/mage/cards/r/RaidingParty.java +++ b/Mage.Sets/src/mage/cards/r/RaidingParty.java @@ -101,7 +101,7 @@ class RaidingPartyEffect extends OneShotEffect { 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)) { + if (player.choose(Outcome.Benefit, untappedCreatureTarget, source, game)) { tappedCount = untappedCreatureTarget.getTargets().size(); for (UUID creatureId : untappedCreatureTarget.getTargets()) { Permanent creature = game.getPermanentOrLKIBattlefield(creatureId); @@ -112,7 +112,7 @@ class RaidingPartyEffect extends OneShotEffect { } if (tappedCount > 0) { Target plainsToSaveTarget = new TargetPermanent(0, tappedCount * 2, filter2, true); - if (player.choose(Outcome.Benefit, plainsToSaveTarget, source.getSourceId(), game)) { + if (player.choose(Outcome.Benefit, plainsToSaveTarget, source, game)) { for (UUID plainsId : plainsToSaveTarget.getTargets()) { plainsToSave.add(plainsId); Permanent plains = game.getPermanent(plainsId); @@ -124,7 +124,7 @@ class RaidingPartyEffect extends OneShotEffect { } } } - for (Permanent plains : game.getBattlefield().getActivePermanents(filter2, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent plains : game.getBattlefield().getActivePermanents(filter2, source.getControllerId(), source, game)) { if (!plainsToSave.contains(plains.getId())) { plains.destroy(source, game, false); } diff --git a/Mage.Sets/src/mage/cards/r/RainOfRust.java b/Mage.Sets/src/mage/cards/r/RainOfRust.java index 458093c852e..7d5aebdd7d4 100644 --- a/Mage.Sets/src/mage/cards/r/RainOfRust.java +++ b/Mage.Sets/src/mage/cards/r/RainOfRust.java @@ -25,8 +25,7 @@ public final class RainOfRust extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetArtifactPermanent()); //or destroy target land. - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetLandPermanent()); this.getSpellAbility().getModes().addMode(mode); // Entwine {3}{R} diff --git a/Mage.Sets/src/mage/cards/r/RainOfThorns.java b/Mage.Sets/src/mage/cards/r/RainOfThorns.java index e712c2b9cd1..72c93ce4e9f 100644 --- a/Mage.Sets/src/mage/cards/r/RainOfThorns.java +++ b/Mage.Sets/src/mage/cards/r/RainOfThorns.java @@ -26,13 +26,11 @@ public final class RainOfThorns extends CardImpl { this.getSpellAbility().getModes().setMaxModes(1); this.getSpellAbility().getModes().setMaxModes(3); - Mode mode1 = new Mode(); - mode1.addEffect(new DestroyTargetEffect()); + Mode mode1 = new Mode(new DestroyTargetEffect()); mode1.addTarget(new TargetEnchantmentPermanent().withChooseHint("destroy")); this.getSpellAbility().addMode(mode1); - Mode mode2 = new Mode(); - mode2.addEffect(new DestroyTargetEffect()); + Mode mode2 = new Mode(new DestroyTargetEffect()); mode2.addTarget(new TargetLandPermanent().withChooseHint("destroy")); this.getSpellAbility().addMode(mode2); } diff --git a/Mage.Sets/src/mage/cards/r/RaiseDead.java b/Mage.Sets/src/mage/cards/r/RaiseDead.java index 7b74a60b707..fbac0c100ca 100644 --- a/Mage.Sets/src/mage/cards/r/RaiseDead.java +++ b/Mage.Sets/src/mage/cards/r/RaiseDead.java @@ -1,16 +1,15 @@ - package mage.cards.r; -import java.util.UUID; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Plopman */ public final class RaiseDead extends CardImpl { @@ -20,7 +19,7 @@ public final class RaiseDead extends CardImpl { // 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()); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); } private RaiseDead(final RaiseDead card) { diff --git a/Mage.Sets/src/mage/cards/r/RaiseTheDraugr.java b/Mage.Sets/src/mage/cards/r/RaiseTheDraugr.java index 8e6c1295a83..f53cdc145ba 100644 --- a/Mage.Sets/src/mage/cards/r/RaiseTheDraugr.java +++ b/Mage.Sets/src/mage/cards/r/RaiseTheDraugr.java @@ -74,8 +74,8 @@ class RaiseTheDraugrTarget extends TargetCardInYourGraveyard { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - MageObject targetSource = game.getObject(sourceId); + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + MageObject targetSource = game.getObject(source); Player player = game.getPlayer(sourceControllerId); if (player == null) { return false; @@ -84,7 +84,7 @@ class RaiseTheDraugrTarget extends TargetCardInYourGraveyard { return false; } List cards = player.getGraveyard().getCards( - filter, sourceId, sourceControllerId, game + filter, sourceControllerId, source, game ).stream().collect(Collectors.toList()); if (cards.size() < 2) { return false; diff --git a/Mage.Sets/src/mage/cards/r/RakdosCharm.java b/Mage.Sets/src/mage/cards/r/RakdosCharm.java index d3ef4189804..5f8d0203455 100644 --- a/Mage.Sets/src/mage/cards/r/RakdosCharm.java +++ b/Mage.Sets/src/mage/cards/r/RakdosCharm.java @@ -31,14 +31,12 @@ public final class RakdosCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayer()); // or destroy target artifact; - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetArtifactPermanent()); this.getSpellAbility().addMode(mode); // or each creature deals 1 damage to its controller. - mode = new Mode(); - mode.addEffect(new RakdosCharmDamageEffect()); + mode = new Mode(new RakdosCharmDamageEffect()); this.getSpellAbility().addMode(mode); } @@ -68,7 +66,7 @@ public final class RakdosCharm extends CardImpl { FilterPermanent filter = new FilterPermanent(); filter.add(CardType.CREATURE.getPredicate()); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { Player controller = game.getPlayer(permanent.getControllerId()); if (controller != null) { controller.damage(1, permanent.getId(), source, game); diff --git a/Mage.Sets/src/mage/cards/r/RakdosPitDragon.java b/Mage.Sets/src/mage/cards/r/RakdosPitDragon.java index 79f9f607fd1..77bde17ecc3 100644 --- a/Mage.Sets/src/mage/cards/r/RakdosPitDragon.java +++ b/Mage.Sets/src/mage/cards/r/RakdosPitDragon.java @@ -1,8 +1,5 @@ - - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -15,39 +12,42 @@ import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author Loki */ public final class RakdosPitDragon extends CardImpl { - public RakdosPitDragon (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}{R}"); + public RakdosPitDragon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); this.subtype.add(SubType.DRAGON); this.power = new MageInt(3); this.toughness = new MageInt(3); + // {R}{R}: Rakdos Pit Dragon gains flying until end of turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), - new ManaCostsImpl("{R}{R}"))); + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl<>("{R}{R}"))); + // {R}: Rakdos Pit Dragon gets +1/+0 until end of turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new BoostSourceEffect(1, 0, Duration.EndOfTurn), - new ManaCostsImpl("{R}"))); + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl<>("{R}") + )); // Hellbent — Rakdos Pit Dragon has double strike as long as you have no cards in hand. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( new GainAbilitySourceEffect(DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield), - HellbentCondition.instance, - "Hellbent - Rakdos Pit Dragon has double strike as long as you have no cards in hand"))); + HellbentCondition.instance, "{this} has double strike as long as you have no cards in hand" + )).setAbilityWord(AbilityWord.HELLBENT)); } - public RakdosPitDragon (final RakdosPitDragon card) { + public RakdosPitDragon(final RakdosPitDragon card) { super(card); } @@ -55,5 +55,4 @@ public final class RakdosPitDragon extends CardImpl { public RakdosPitDragon copy() { return new RakdosPitDragon(this); } - } diff --git a/Mage.Sets/src/mage/cards/r/RakdosRiteknife.java b/Mage.Sets/src/mage/cards/r/RakdosRiteknife.java index d52e50bea72..5658b06f5d4 100644 --- a/Mage.Sets/src/mage/cards/r/RakdosRiteknife.java +++ b/Mage.Sets/src/mage/cards/r/RakdosRiteknife.java @@ -1,7 +1,5 @@ package mage.cards.r; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -9,50 +7,51 @@ import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CountersSourceCount; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.SacrificeEffect; -import mage.abilities.effects.common.continuous.BoostEquippedEffect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.EquipAbility; -import mage.constants.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPlayer; import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; /** - * - * @author noahg + * @author TheElk801 */ public final class RakdosRiteknife extends CardImpl { + private static final DynamicValue xValue = new CountersSourceCount(CounterType.BLOOD); + public RakdosRiteknife(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); - + this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +1/+0 for each blood counter on Rakdos Riteknife and has "{T}, Sacrifice a creature: Put a blood counter on Rakdos Riteknife." - SimpleStaticAbility staticAbility = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(new CountersSourceCount(CounterType.BLOOD), StaticValue.get(0)).setText("Equipped creature gets +1/+0 for each blood counter on {this}")); - SimpleActivatedAbility grantedAbility = new SimpleActivatedAbility(new RakdosRiteKnifeEffect(this.getId()), new TapSourceCost()); - grantedAbility.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); - staticAbility.addEffect(new GainAbilityAttachedEffect(grantedAbility, AttachmentType.EQUIPMENT).setText("and has \"{T}, Sacrifice a creature: Put a blood counter on {this}.\"")); - this.addAbility(staticAbility); + this.addAbility(new SimpleStaticAbility(new RakdosRiteknifeEffect())); // {B}{R}, Sacrifice Rakdos Riteknife: Target player sacrifices a permanent for each blood counter on Rakdos Riteknife. - SimpleActivatedAbility activatedAbility = new SimpleActivatedAbility( - new SacrificeEffect(StaticFilters.FILTER_PERMANENT, new CountersSourceCount(CounterType.BLOOD), "Target player") - .setText("target player sacrifices a permanent for each blood counter on {this}"), new ManaCostsImpl("{R}{B}")); - activatedAbility.addCost(new SacrificeSourceCost()); - activatedAbility.addTarget(new TargetPlayer()); - this.addAbility(activatedAbility); + Ability ability = new SimpleActivatedAbility( + new SacrificeEffect(StaticFilters.FILTER_PERMANENT, xValue, "Target player") + .setText("target player sacrifices a permanent for each blood counter on {this}"), + new ManaCostsImpl<>("{R}{B}") + ); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); // Equip {2} this.addAbility(new EquipAbility(2, false)); @@ -68,34 +67,69 @@ public final class RakdosRiteknife extends CardImpl { } } -class RakdosRiteKnifeEffect extends OneShotEffect { +class RakdosRiteknifeEffect extends ContinuousEffectImpl { - private UUID effectGivingEquipmentId; - - public RakdosRiteKnifeEffect(UUID effectGivingEquipmentId) { - super(Outcome.Benefit); - this.effectGivingEquipmentId = effectGivingEquipmentId; - staticText = "Put a blood counter on Rakdos Riteknife"; + RakdosRiteknifeEffect() { + super(Duration.WhileOnBattlefield, Outcome.AddAbility); + staticText = "equipped creature gets +1/+0 for each blood counter on {this} " + + "and has \"{T}, Sacrifice a creature: Put a blood counter on {this}.\""; } - public RakdosRiteKnifeEffect(final RakdosRiteKnifeEffect effect) { + private RakdosRiteknifeEffect(final RakdosRiteknifeEffect effect) { super(effect); - this.effectGivingEquipmentId = effect.effectGivingEquipmentId; } @Override public boolean apply(Game game, Ability source) { - Permanent equipment = game.getPermanent(this.effectGivingEquipmentId); - if (equipment != null) { - equipment.addCounters(CounterType.BLOOD.createInstance(), source.getControllerId(), source, game); - } - return true; + return false; } @Override - public RakdosRiteKnifeEffect copy() { - return new RakdosRiteKnifeEffect(this); + public RakdosRiteknifeEffect copy() { + return new RakdosRiteknifeEffect(this); } + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + return false; + } + Permanent creature = game.getPermanent(permanent.getAttachedTo()); + if (creature == null) { + return false; + } + switch (layer) { + case AbilityAddingRemovingEffects_6: + creature.addAbility(makeAbility(permanent, game), source.getSourceId(), game); + return true; + case PTChangingEffects_7: + if (sublayer != SubLayer.ModifyPT_7c) { + return false; + } + int count = permanent.getCounters(game).getCount(CounterType.BLOOD); + if (count > 0) { + creature.addPower(count); + return true; + } + } + return false; + } -} \ No newline at end of file + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.AbilityAddingRemovingEffects_6 + || layer == Layer.PTChangingEffects_7; + } + + private static Ability makeAbility(Permanent permanent, Game game) { + Ability ability = new SimpleActivatedAbility( + new AddCountersTargetEffect(CounterType.BLOOD.createInstance()) + .setText("put a blood counter on " + permanent.getName()) + .setTargetPointer(new FixedTarget(permanent, game)), + new TapSourceCost() + ); + ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); + return ability; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RakishRevelers.java b/Mage.Sets/src/mage/cards/r/RakishRevelers.java new file mode 100644 index 00000000000..5c44f64529b --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RakishRevelers.java @@ -0,0 +1,44 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.GiveManaAbilityAndCastSourceAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.CitizenGreenWhiteToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RakishRevelers extends CardImpl { + + public RakishRevelers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}{W}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.DRUID); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(5); + this.toughness = new MageInt(3); + + // When Rakish Revelers enters the battlefield, create a 1/1 green and white Citizen creature token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new CitizenGreenWhiteToken()))); + + // {2}, Exile Rakish Revelers from your hand: Target land gains "{T}: Add {R}, {G}, or {W}" until Rakish Revelers is cast from exile. You may cast Rakish Revelers for as long as it remains exiled. + this.addAbility(new GiveManaAbilityAndCastSourceAbility("RGW")); + } + + private RakishRevelers(final RakishRevelers card) { + super(card); + } + + @Override + public RakishRevelers copy() { + return new RakishRevelers(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RakkaMar.java b/Mage.Sets/src/mage/cards/r/RakkaMar.java index 22e48170c3b..194d8527230 100644 --- a/Mage.Sets/src/mage/cards/r/RakkaMar.java +++ b/Mage.Sets/src/mage/cards/r/RakkaMar.java @@ -1,20 +1,19 @@ - package mage.cards.r; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.ColoredManaCost; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; -import mage.game.permanent.token.RakkaMarElementalToken; +import mage.game.permanent.token.ElementalTokenWithHaste; import java.util.UUID; @@ -34,9 +33,8 @@ public final class RakkaMar extends CardImpl { this.addAbility(HasteAbility.getInstance()); Ability ability = new SimpleActivatedAbility( - Zone.BATTLEFIELD, - new CreateTokenEffect(new RakkaMarElementalToken()), - new ManaCostsImpl("{R}") + new CreateTokenEffect(new ElementalTokenWithHaste()), + new ColoredManaCost(ColoredManaSymbol.R) ); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/r/RalCallerOfStorms.java b/Mage.Sets/src/mage/cards/r/RalCallerOfStorms.java index a0759f424a2..efa91873583 100644 --- a/Mage.Sets/src/mage/cards/r/RalCallerOfStorms.java +++ b/Mage.Sets/src/mage/cards/r/RalCallerOfStorms.java @@ -3,7 +3,6 @@ package mage.cards.r; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.DamageMultiEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -28,7 +27,7 @@ public final class RalCallerOfStorms extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.RAL); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Draw a card. this.addAbility(new LoyaltyAbility( diff --git a/Mage.Sets/src/mage/cards/r/RalIzzetViceroy.java b/Mage.Sets/src/mage/cards/r/RalIzzetViceroy.java index afd6b54e811..ce751defc3c 100644 --- a/Mage.Sets/src/mage/cards/r/RalIzzetViceroy.java +++ b/Mage.Sets/src/mage/cards/r/RalIzzetViceroy.java @@ -2,12 +2,11 @@ package mage.cards.r; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.InstantSorceryExileGraveyardCount; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; import mage.cards.CardImpl; @@ -15,8 +14,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import mage.game.command.emblems.RalIzzetViceroyEmblem; import mage.target.common.TargetCreaturePermanent; @@ -36,15 +33,10 @@ public final class RalIzzetViceroy extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.RAL); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Look at the top two cards of your library. Put one of them into your hand and the other into your graveyard. - this.addAbility(new LoyaltyAbility( - new LookLibraryAndPickControllerEffect( - StaticValue.get(2), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.GRAVEYARD, false, false - ), 1 - )); + this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect(2, 1, PutCards.HAND, PutCards.GRAVEYARD), 1)); // -3: Ral, Izzet Viceroy deals damage to target creature equal to the total number of instant and sorcery cards you own in exile and in your graveyard. Ability ability = new LoyaltyAbility(new DamageTargetEffect( diff --git a/Mage.Sets/src/mage/cards/r/RalStormConduit.java b/Mage.Sets/src/mage/cards/r/RalStormConduit.java index 2585a926a2d..caa6a54e3db 100644 --- a/Mage.Sets/src/mage/cards/r/RalStormConduit.java +++ b/Mage.Sets/src/mage/cards/r/RalStormConduit.java @@ -3,7 +3,6 @@ package mage.cards.r; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CopyTargetSpellEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; @@ -30,7 +29,7 @@ public final class RalStormConduit extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.RAL); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // Whenever you cast or copy an instant or sorcery spell, Ral, Storm Conduit deals 1 damage to target opponent or planeswalker. this.addAbility(new RalStormConduitTriggeredAbility()); diff --git a/Mage.Sets/src/mage/cards/r/RalZarek.java b/Mage.Sets/src/mage/cards/r/RalZarek.java index edfebbc8438..bbc6520f49c 100644 --- a/Mage.Sets/src/mage/cards/r/RalZarek.java +++ b/Mage.Sets/src/mage/cards/r/RalZarek.java @@ -4,7 +4,6 @@ package mage.cards.r; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; @@ -42,7 +41,7 @@ public final class RalZarek extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.RAL); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Tap target permanent, then untap another target permanent. LoyaltyAbility ability1 = new LoyaltyAbility(new TapTargetEffect(), 1); diff --git a/Mage.Sets/src/mage/cards/r/RallyTheRighteous.java b/Mage.Sets/src/mage/cards/r/RallyTheRighteous.java index b023e3dad84..21bf66e984b 100644 --- a/Mage.Sets/src/mage/cards/r/RallyTheRighteous.java +++ b/Mage.Sets/src/mage/cards/r/RallyTheRighteous.java @@ -65,7 +65,7 @@ class RallyTheRighteousUntapEffect extends OneShotEffect { if (target != null) { ObjectColor color = target.getColor(game); target.untap(game); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { if (permanent.getColor(game).shares(color) && !permanent.getId().equals(target.getId())) { permanent.untap(game); } @@ -94,7 +94,7 @@ class RallyTheRighteousBoostEffect extends ContinuousEffectImpl { if (target != null) { affectedObjectList.add(new MageObjectReference(target, game)); ObjectColor color = target.getColor(game); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { if (!permanent.getId().equals(target.getId()) && permanent.getColor(game).shares(color)) { affectedObjectList.add(new MageObjectReference(permanent, game)); } diff --git a/Mage.Sets/src/mage/cards/r/RalsOutburst.java b/Mage.Sets/src/mage/cards/r/RalsOutburst.java index 43c5dffb7c0..af16157c2b5 100644 --- a/Mage.Sets/src/mage/cards/r/RalsOutburst.java +++ b/Mage.Sets/src/mage/cards/r/RalsOutburst.java @@ -1,13 +1,11 @@ package mage.cards.r; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import mage.target.common.TargetAnyTarget; import java.util.UUID; @@ -23,10 +21,7 @@ public final class RalsOutburst extends CardImpl { // Ral's Outburst deals 3 damage to any target. Look at the top two cards of your library. Put one of them into your hand and the other into your graveyard. this.getSpellAbility().addEffect(new DamageTargetEffect(3)); this.getSpellAbility().addTarget(new TargetAnyTarget()); - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(2), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.GRAVEYARD, false, false - )); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(2, 1, PutCards.HAND, PutCards.GRAVEYARD)); } private RalsOutburst(final RalsOutburst card) { diff --git a/Mage.Sets/src/mage/cards/r/RampageOfTheClans.java b/Mage.Sets/src/mage/cards/r/RampageOfTheClans.java index a05dfd1a88f..e778f768168 100644 --- a/Mage.Sets/src/mage/cards/r/RampageOfTheClans.java +++ b/Mage.Sets/src/mage/cards/r/RampageOfTheClans.java @@ -61,7 +61,7 @@ class RampageOfTheClansEffect extends OneShotEffect { Map playersWithPermanents = new HashMap<>(); for (Permanent p : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game )) { UUID controllerId = p.getControllerId(); if (p.destroy(source, game, false)) { diff --git a/Mage.Sets/src/mage/cards/r/RampageOfTheValkyries.java b/Mage.Sets/src/mage/cards/r/RampageOfTheValkyries.java index cdd2845b220..bd5f0d149ab 100644 --- a/Mage.Sets/src/mage/cards/r/RampageOfTheValkyries.java +++ b/Mage.Sets/src/mage/cards/r/RampageOfTheValkyries.java @@ -77,10 +77,10 @@ class RampageOfTheValkyriesEffect extends OneShotEffect { } TargetPermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), playerId, game)) { + if (!target.canChoose(playerId, source, game)) { continue; } - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); perms.add(target.getFirstTarget()); } for (UUID permID : perms) { diff --git a/Mage.Sets/src/mage/cards/r/RampagingFerocidon.java b/Mage.Sets/src/mage/cards/r/RampagingFerocidon.java index 643d0b355bb..aa4d29bc318 100644 --- a/Mage.Sets/src/mage/cards/r/RampagingFerocidon.java +++ b/Mage.Sets/src/mage/cards/r/RampagingFerocidon.java @@ -88,7 +88,7 @@ class RampagingFerocidonEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); Player player = game.getPlayer(event.getPlayerId()); if (mageObject != null && player != null) { return player.getLogName() + " can't get " + event.getAmount() + " life (" + mageObject.getIdName() + ")."; diff --git a/Mage.Sets/src/mage/cards/r/RampantRejuvenator.java b/Mage.Sets/src/mage/cards/r/RampantRejuvenator.java new file mode 100644 index 00000000000..5d1aba22a98 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RampantRejuvenator.java @@ -0,0 +1,99 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.MageItem; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RampantRejuvenator extends CardImpl { + + public RampantRejuvenator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.PLANT); + this.subtype.add(SubType.HYDRA); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Rampant Rejuvenator enters the battlefield with two +1/+1 counters on it. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect( + CounterType.P1P1.createInstance(2) + ), "with two +1/+1 counters on it")); + + // When Rampant Rejuvenator dies, search your library for up to X basic land cards, where X is Rampant Rejuvenator's power, put them onto the battlefield, then shuffle. + this.addAbility(new DiesSourceTriggeredAbility(new RampantRejuvenatorEffect())); + } + + private RampantRejuvenator(final RampantRejuvenator card) { + super(card); + } + + @Override + public RampantRejuvenator copy() { + return new RampantRejuvenator(this); + } +} + +class RampantRejuvenatorEffect extends OneShotEffect { + + RampantRejuvenatorEffect() { + super(Outcome.Benefit); + staticText = "search your library for up to X basic land cards, " + + "where X is {this}'s power, put them onto the battlefield, then shuffle"; + } + + private RampantRejuvenatorEffect(final RampantRejuvenatorEffect effect) { + super(effect); + } + + @Override + public RampantRejuvenatorEffect copy() { + return new RampantRejuvenatorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = source.getSourcePermanentOrLKI(game); + if (player == null || permanent == null) { + return false; + } + TargetCardInLibrary target = new TargetCardInLibrary( + 0, permanent.getPower().getValue(), + StaticFilters.FILTER_CARD_BASIC_LANDS + ); + player.searchLibrary(target, source, game); + Cards cards = new CardsImpl(); + player.getLibrary() + .getCards(game) + .stream() + .map(MageItem::getId) + .filter(target.getTargets()::contains) + .forEach(cards::add); + player.moveCards(cards, Zone.BATTLEFIELD, source, game); + player.shuffleLibrary(source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RamunapHydra.java b/Mage.Sets/src/mage/cards/r/RamunapHydra.java index dc8c1e92d0d..8b770815a3e 100644 --- a/Mage.Sets/src/mage/cards/r/RamunapHydra.java +++ b/Mage.Sets/src/mage/cards/r/RamunapHydra.java @@ -6,6 +6,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; +import mage.abilities.condition.common.DesertControlledOrGraveyardCondition; import mage.abilities.effects.WhileConditionContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceWhileControlsEffect; import mage.abilities.keyword.ReachAbility; @@ -52,7 +53,7 @@ public final class RamunapHydra extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceWhileControlsEffect(new FilterPermanent(SubType.DESERT, "Desert"), 1, 1))); // Ramunap Hydra gets +1/+1 as long as there is a Desert card in your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new RamunapHydraBoostEffect(1, 1))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new RamunapHydraBoostEffect(1, 1)).addHint(DesertControlledOrGraveyardCondition.getHint())); } private RamunapHydra(final RamunapHydra card) { diff --git a/Mage.Sets/src/mage/cards/r/RangeTrooper.java b/Mage.Sets/src/mage/cards/r/RangeTrooper.java index 059cb4a3469..2aa6a6e11f2 100644 --- a/Mage.Sets/src/mage/cards/r/RangeTrooper.java +++ b/Mage.Sets/src/mage/cards/r/RangeTrooper.java @@ -71,7 +71,7 @@ class RangeTrooperEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (permanent != null && sourceObject != null) { if (permanent.moveToExile(source.getSourceId(), sourceObject.getIdName(), source, game)) { Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false); diff --git a/Mage.Sets/src/mage/cards/r/RangerCaptainOfEos.java b/Mage.Sets/src/mage/cards/r/RangerCaptainOfEos.java index 8d6122791c0..5e17f7dec7c 100644 --- a/Mage.Sets/src/mage/cards/r/RangerCaptainOfEos.java +++ b/Mage.Sets/src/mage/cards/r/RangerCaptainOfEos.java @@ -85,7 +85,7 @@ class RangerCaptainOfEosEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast noncreature spells this turn (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/r/RansackTheLab.java b/Mage.Sets/src/mage/cards/r/RansackTheLab.java index 7242bd300a1..047fe23ddb9 100644 --- a/Mage.Sets/src/mage/cards/r/RansackTheLab.java +++ b/Mage.Sets/src/mage/cards/r/RansackTheLab.java @@ -1,12 +1,10 @@ package mage.cards.r; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import java.util.UUID; @@ -19,8 +17,7 @@ public final class RansackTheLab extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); // Look at the top three cards of your library. Put one of them into your hand and the rest into your graveyard. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(3), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.GRAVEYARD, false, false, false, Zone.HAND, false)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.GRAVEYARD)); } private RansackTheLab(final RansackTheLab card) { diff --git a/Mage.Sets/src/mage/cards/r/RattleclawMystic.java b/Mage.Sets/src/mage/cards/r/RattleclawMystic.java index 4a6c47398df..2a8fc3c49bc 100644 --- a/Mage.Sets/src/mage/cards/r/RattleclawMystic.java +++ b/Mage.Sets/src/mage/cards/r/RattleclawMystic.java @@ -36,7 +36,7 @@ public final class RattleclawMystic extends CardImpl { this.addAbility(new RedManaAbility()); // Morph {2} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}"))); // When Rattleclaw Mystic is turned face up, add {G}{U}{R}. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new AddManaToManaPoolSourceControllerEffect(new Mana(0, 1, 0, 1,1, 0,0, 0)))); diff --git a/Mage.Sets/src/mage/cards/r/RaugrinTriome.java b/Mage.Sets/src/mage/cards/r/RaugrinTriome.java index 8953e63b1a8..975242485bb 100644 --- a/Mage.Sets/src/mage/cards/r/RaugrinTriome.java +++ b/Mage.Sets/src/mage/cards/r/RaugrinTriome.java @@ -1,7 +1,7 @@ package mage.cards.r; import mage.abilities.common.EntersBattlefieldTappedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.keyword.CyclingAbility; import mage.abilities.mana.BlueManaAbility; import mage.abilities.mana.RedManaAbility; @@ -34,7 +34,7 @@ public final class RaugrinTriome extends CardImpl { this.addAbility(new EntersBattlefieldTappedAbility()); // Cycling {3} - this.addAbility(new CyclingAbility(new ManaCostsImpl("{3}"))); + this.addAbility(new CyclingAbility(new GenericManaCost(3))); } private RaugrinTriome(final RaugrinTriome card) { diff --git a/Mage.Sets/src/mage/cards/r/RavagerOfTheFells.java b/Mage.Sets/src/mage/cards/r/RavagerOfTheFells.java index 75d0f2abc71..e01bb4e0b06 100644 --- a/Mage.Sets/src/mage/cards/r/RavagerOfTheFells.java +++ b/Mage.Sets/src/mage/cards/r/RavagerOfTheFells.java @@ -119,16 +119,16 @@ class RavagerOfTheFellsTarget extends TargetPermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set availablePossibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set availablePossibleTargets = super.possibleTargets(sourceControllerId, source, game); Set possibleTargets = new HashSet<>(); - MageObject object = game.getObject(sourceId); + MageObject object = game.getObject(source); for (StackObject item : game.getState().getStack()) { - if (item.getId().equals(sourceId)) { + if (item.getId().equals(source.getSourceId())) { object = item; } - if (item.getSourceId().equals(sourceId)) { + if (item.getSourceId().equals(source.getSourceId())) { object = item; } } diff --git a/Mage.Sets/src/mage/cards/r/RavenFamiliar.java b/Mage.Sets/src/mage/cards/r/RavenFamiliar.java index 33c9c17c898..87b38a3bd4f 100644 --- a/Mage.Sets/src/mage/cards/r/RavenFamiliar.java +++ b/Mage.Sets/src/mage/cards/r/RavenFamiliar.java @@ -1,18 +1,16 @@ - package mage.cards.r; import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.EchoAbility; import mage.abilities.keyword.FlyingAbility; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.StaticFilters; /** * @@ -31,10 +29,10 @@ public final class RavenFamiliar extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Echo {2}{U} this.addAbility(new EchoAbility("{2}{U}")); - // When Raven Familiar enters the battlefield, look at the top three cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order. + // When Raven Familiar enters the battlefield, look at the top three cards of your library. + // Put one of them into your hand and the rest on the bottom of your library in any order. this.addAbility(new EntersBattlefieldTriggeredAbility( - new LookLibraryAndPickControllerEffect(StaticValue.get(3), false, StaticValue.get(1), StaticFilters.FILTER_CARD, Zone.LIBRARY, false, false), - false)); + new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.BOTTOM_ANY))); } private RavenFamiliar(final RavenFamiliar card) { diff --git a/Mage.Sets/src/mage/cards/r/RavenGuildInitiate.java b/Mage.Sets/src/mage/cards/r/RavenGuildInitiate.java index 9825c9f5475..c098c694c7b 100644 --- a/Mage.Sets/src/mage/cards/r/RavenGuildInitiate.java +++ b/Mage.Sets/src/mage/cards/r/RavenGuildInitiate.java @@ -33,7 +33,7 @@ public final class RavenGuildInitiate extends CardImpl { this.toughness = new MageInt(4); // Morph-Return a Bird you control to its owner's hand. - this.addAbility(new MorphAbility(this, new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(filter)))); + this.addAbility(new MorphAbility(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(filter)))); } diff --git a/Mage.Sets/src/mage/cards/r/RavenGuildMaster.java b/Mage.Sets/src/mage/cards/r/RavenGuildMaster.java index db5856c1179..25d2eae10ef 100644 --- a/Mage.Sets/src/mage/cards/r/RavenGuildMaster.java +++ b/Mage.Sets/src/mage/cards/r/RavenGuildMaster.java @@ -30,7 +30,7 @@ public final class RavenGuildMaster extends CardImpl { this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new ExileCardsFromTopOfLibraryTargetEffect(10, "that player"), false, true)); // Morph {2}{U}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{U}{U}"))); } private RavenGuildMaster(final RavenGuildMaster card) { diff --git a/Mage.Sets/src/mage/cards/r/Ravenform.java b/Mage.Sets/src/mage/cards/r/Ravenform.java index 9c7679f7b1d..58db871b3a3 100644 --- a/Mage.Sets/src/mage/cards/r/Ravenform.java +++ b/Mage.Sets/src/mage/cards/r/Ravenform.java @@ -11,7 +11,7 @@ import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.permanent.token.OwlToken; +import mage.game.permanent.token.BlueBirdToken; import mage.players.Player; import mage.target.TargetPermanent; @@ -68,7 +68,7 @@ class RavenformEffect extends OneShotEffect { } Player player = game.getPlayer(permanent.getControllerId()); player.moveCards(permanent, Zone.EXILED, source, game); - new OwlToken().putOntoBattlefield(1, game, source, player.getId()); + new BlueBirdToken().putOntoBattlefield(1, game, source, player.getId()); return true; } } diff --git a/Mage.Sets/src/mage/cards/r/RavenousRotbelly.java b/Mage.Sets/src/mage/cards/r/RavenousRotbelly.java index 0c90d344ad4..81ca082e72d 100644 --- a/Mage.Sets/src/mage/cards/r/RavenousRotbelly.java +++ b/Mage.Sets/src/mage/cards/r/RavenousRotbelly.java @@ -75,7 +75,7 @@ class RavenousRotbellyEffect extends OneShotEffect { return false; } TargetPermanent target = new TargetPermanent(0, 3, filter, true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); int amount = 0; for (UUID permanentId : target.getTargets()) { Permanent permanent = game.getPermanent(permanentId); diff --git a/Mage.Sets/src/mage/cards/r/RavingOniSlave.java b/Mage.Sets/src/mage/cards/r/RavingOniSlave.java index 99d500be093..645c329801e 100644 --- a/Mage.Sets/src/mage/cards/r/RavingOniSlave.java +++ b/Mage.Sets/src/mage/cards/r/RavingOniSlave.java @@ -63,7 +63,7 @@ class RavingOniSlaveEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (game.getBattlefield().count(new FilterCreaturePermanent(SubType.DEMON, "Demon"), source.getSourceId(), source.getControllerId(), game) < 1) { + if (game.getBattlefield().count(new FilterCreaturePermanent(SubType.DEMON, "Demon"), source.getControllerId(), source, game) < 1) { controller.loseLife(3, game, source, false); } return true; diff --git a/Mage.Sets/src/mage/cards/r/RaziasPurification.java b/Mage.Sets/src/mage/cards/r/RaziasPurification.java index 09c27708bed..45cfedbbcd8 100644 --- a/Mage.Sets/src/mage/cards/r/RaziasPurification.java +++ b/Mage.Sets/src/mage/cards/r/RaziasPurification.java @@ -61,9 +61,9 @@ class RaziasPurificationEffect extends OneShotEffect { Target target1 = new TargetControlledPermanent(1, 1, new FilterControlledPermanent(), true); - if (player != null && target1.canChoose(source.getSourceId(), player.getId(), game)) { + if (player != null && target1.canChoose(player.getId(), source, game)) { int chosenPermanents = 0; - while (player.canRespond() && !target1.isChosen() && target1.canChoose(source.getSourceId(), player.getId(), game) && chosenPermanents < 3) { + while (player.canRespond() && !target1.isChosen() && target1.canChoose(player.getId(), source, game) && chosenPermanents < 3) { player.chooseTarget(Outcome.Benefit, target1, source, game); for (UUID targetId : target1.getTargets()) { Permanent p = game.getPermanent(targetId); diff --git a/Mage.Sets/src/mage/cards/r/RazorBoomerang.java b/Mage.Sets/src/mage/cards/r/RazorBoomerang.java index c72a379c471..d47d5571926 100644 --- a/Mage.Sets/src/mage/cards/r/RazorBoomerang.java +++ b/Mage.Sets/src/mage/cards/r/RazorBoomerang.java @@ -34,8 +34,8 @@ public final class RazorBoomerang extends CardImpl { // Equipped creature has "{tap}, Unattach Razor Boomerang: Razor Boomerang deals 1 damage to any target. Return Razor Boomerang to its owner's hand." this.addAbility(new SimpleStaticAbility(new GainAbilityWithAttachmentEffect( - "equipped creature has \"{tap}, Unattach {this}: " + - "{this} deals 1 damage to any target. Return {this} to its owner's hand.\"", + "equipped creature has \"{T}, Unattach {this}: " + + "It deals 1 damage to any target. Return {this} to its owner's hand.\"", new RazorBoomerangEffect(), new TargetAnyTarget(), new UnattachCost(), new TapSourceCost() ))); diff --git a/Mage.Sets/src/mage/cards/r/RazorHippogriff.java b/Mage.Sets/src/mage/cards/r/RazorHippogriff.java index b067eb6b062..77fdcab6cef 100644 --- a/Mage.Sets/src/mage/cards/r/RazorHippogriff.java +++ b/Mage.Sets/src/mage/cards/r/RazorHippogriff.java @@ -1,6 +1,5 @@ package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -11,21 +10,20 @@ 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.filter.common.FilterArtifactCard; +import mage.constants.SubType; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author nantuko */ public final class RazorHippogriff extends CardImpl { - private static final FilterArtifactCard filter = new FilterArtifactCard("artifact card from your graveyard"); - public RazorHippogriff(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); this.subtype.add(SubType.HIPPOGRIFF); @@ -36,7 +34,7 @@ public final class RazorHippogriff extends CardImpl { this.addAbility(FlyingAbility.getInstance()); Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); - ability.addTarget(new TargetCardInYourGraveyard(filter)); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); ability.addEffect(new RazorHippogriffGainLifeEffect()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/r/ReadyToRumble.java b/Mage.Sets/src/mage/cards/r/ReadyToRumble.java new file mode 100644 index 00000000000..dcf01046bc9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/ReadyToRumble.java @@ -0,0 +1,39 @@ +package mage.cards.r; + +import mage.abilities.Mode; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetArtifactPermanent; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ReadyToRumble extends CardImpl { + + public ReadyToRumble(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}"); + + // Choose one — + // • Ready to Rumble deals 5 damage to target creature or planeswalker. + this.getSpellAbility().addEffect(new DamageTargetEffect(5)); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + + // • Destroy target artifact. + this.getSpellAbility().addMode(new Mode(new DestroyTargetEffect()).addTarget(new TargetArtifactPermanent())); + } + + private ReadyToRumble(final ReadyToRumble card) { + super(card); + } + + @Override + public ReadyToRumble copy() { + return new ReadyToRumble(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RealityHeist.java b/Mage.Sets/src/mage/cards/r/RealityHeist.java index 5df4ca20370..395f1864f63 100644 --- a/Mage.Sets/src/mage/cards/r/RealityHeist.java +++ b/Mage.Sets/src/mage/cards/r/RealityHeist.java @@ -2,8 +2,8 @@ package mage.cards.r; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.ArtifactYouControlCount; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect; import mage.abilities.hint.common.ArtifactYouControlHint; import mage.cards.CardImpl; @@ -28,16 +28,8 @@ public final class RealityHeist extends CardImpl { ).addHint(ArtifactYouControlHint.instance)); // Look at the top seven cards of your library. You may reveal up to two artifact cards from among them and put them into your hand. Put the rest on the bottom of your library in a random order. - this.getSpellAbility().addEffect( - new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), - StaticFilters.FILTER_CARD_ARTIFACT, Zone.LIBRARY, false, true, - false, Zone.HAND, true, false, false - ).setBackInRandomOrder(true) - .setText("look at the top seven cards of your library. You may reveal up to " + - "two artifact cards from among them and put them into your hand. " + - "Put the rest on the bottom of your library in a random order") - ); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + 7, 2, StaticFilters.FILTER_CARD_ARTIFACTS, PutCards.HAND, PutCards.BOTTOM_RANDOM)); } private RealityHeist(final RealityHeist card) { diff --git a/Mage.Sets/src/mage/cards/r/RealitySpasm.java b/Mage.Sets/src/mage/cards/r/RealitySpasm.java index 74a2fc6cb99..7826915199f 100644 --- a/Mage.Sets/src/mage/cards/r/RealitySpasm.java +++ b/Mage.Sets/src/mage/cards/r/RealitySpasm.java @@ -1,35 +1,31 @@ - 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.TapTargetEffect; +import mage.abilities.effects.common.UntapTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.filter.FilterPermanent; -import mage.game.Game; -import mage.game.permanent.Permanent; import mage.target.TargetPermanent; +import mage.target.targetadjustment.XTargetsAdjuster; /** * - * @author jeffwadsworth + * @author awjackson */ public final class RealitySpasm extends CardImpl { public RealitySpasm(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{U}{U}"); - // Choose one - Tap X target permanents; or untap X target permanents. - this.getSpellAbility().addEffect(new RealitySpasmTapEffect()); - Mode mode = new Mode(); - mode.addEffect(new RealitySpasmUntapEffect()); + this.getSpellAbility().addEffect(new TapTargetEffect("tap X target permanents")); + this.getSpellAbility().addTarget(new TargetPermanent()); + Mode mode = new Mode(new UntapTargetEffect("untap X target permanents")); + mode.addTarget(new TargetPermanent()); this.getSpellAbility().addMode(mode); + this.getSpellAbility().setTargetAdjuster(XTargetsAdjuster.instance); } private RealitySpasm(final RealitySpasm card) { @@ -41,83 +37,3 @@ public final class RealitySpasm extends CardImpl { return new RealitySpasm(this); } } - -class RealitySpasmTapEffect extends OneShotEffect { - - private static final FilterPermanent filter = new FilterPermanent("permanent"); - - public RealitySpasmTapEffect() { - super(Outcome.Tap); - staticText = "Tap X target permanents"; - } - - public RealitySpasmTapEffect(final RealitySpasmTapEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - int numberToTap = source.getManaCostsToPay().getX(); - numberToTap = Math.min(game.getBattlefield().getAllActivePermanents().size(), numberToTap); - TargetPermanent target = new TargetPermanent(numberToTap, filter); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) && target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), game)) { - if (!target.getTargets().isEmpty()) { - List targets = target.getTargets(); - for (UUID targetId : targets) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null) { - permanent.tap(source, game); - } - } - } - return true; - } - return false; - } - - @Override - public RealitySpasmTapEffect copy() { - return new RealitySpasmTapEffect(this); - } - -} - -class RealitySpasmUntapEffect extends OneShotEffect { - - private static final FilterPermanent filter = new FilterPermanent("permanent"); - - public RealitySpasmUntapEffect() { - super(Outcome.Untap); - staticText = "Untap X target permanents"; - } - - public RealitySpasmUntapEffect(final RealitySpasmUntapEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - int numberToTap = source.getManaCostsToPay().getX(); - numberToTap = Math.min(game.getBattlefield().getAllActivePermanents().size(), numberToTap); - TargetPermanent target = new TargetPermanent(numberToTap, filter); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) && target.choose(Outcome.Untap, source.getControllerId(), source.getSourceId(), game)) { - if (!target.getTargets().isEmpty()) { - List targets = target.getTargets(); - for (UUID targetId : targets) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null) { - permanent.untap(game); - } - } - } - return true; - } - return false; - } - - @Override - public RealitySpasmUntapEffect copy() { - return new RealitySpasmUntapEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/r/RealityStrobe.java b/Mage.Sets/src/mage/cards/r/RealityStrobe.java index 2e4ae802a41..9190b70a70c 100644 --- a/Mage.Sets/src/mage/cards/r/RealityStrobe.java +++ b/Mage.Sets/src/mage/cards/r/RealityStrobe.java @@ -31,7 +31,7 @@ public final class RealityStrobe extends CardImpl { this.getSpellAbility().addEffect(new ExileSpellEffect()); // with three time counters on it. Effect effect = new AddCountersSourceEffect(CounterType.TIME.createInstance(), StaticValue.get(3), false, true); - effect.setText("with 3 time counters on it"); + effect.setText("with three time counters on it"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetPermanent()); diff --git a/Mage.Sets/src/mage/cards/r/RealmRazer.java b/Mage.Sets/src/mage/cards/r/RealmRazer.java index eb94b29230c..9b887201a75 100644 --- a/Mage.Sets/src/mage/cards/r/RealmRazer.java +++ b/Mage.Sets/src/mage/cards/r/RealmRazer.java @@ -67,7 +67,7 @@ class ExileAllEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - List permanents = game.getBattlefield().getActivePermanents(new FilterLandPermanent(), source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(new FilterLandPermanent(), source.getControllerId(), source, game); for (Permanent permanent : permanents) { permanent.moveToExile(source.getSourceId(), "Realm Razer", source, game); } diff --git a/Mage.Sets/src/mage/cards/r/RealmsUncharted.java b/Mage.Sets/src/mage/cards/r/RealmsUncharted.java index 0a1699fa1af..472cd5f8c77 100644 --- a/Mage.Sets/src/mage/cards/r/RealmsUncharted.java +++ b/Mage.Sets/src/mage/cards/r/RealmsUncharted.java @@ -1,9 +1,11 @@ package mage.cards.r; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -11,12 +13,11 @@ import mage.filter.FilterCard; import mage.filter.common.FilterLandCard; import mage.game.Game; import mage.players.Player; -import mage.target.Target; import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCardWithDifferentNameInLibrary; import mage.target.common.TargetOpponent; -import java.util.Set; import java.util.UUID; /** @@ -43,9 +44,14 @@ public final class RealmsUncharted extends CardImpl { class RealmsUnchartedEffect extends OneShotEffect { + private static final FilterCard filter = new FilterLandCard("land cards with different names"); + private static final FilterCard filter2 = new FilterCard("cards to put in graveyard"); + public RealmsUnchartedEffect() { super(Outcome.DrawCard); - this.staticText = "Search your library for four land cards with different names and reveal them. An opponent chooses two of those cards. Put the chosen cards into your graveyard and the rest into your hand. Then shuffle"; + this.staticText = "Search your library for up to four land cards with different names and reveal them. " + + "An opponent chooses two of those cards. Put the chosen cards into your graveyard " + + "and the rest into your hand. Then shuffle"; } public RealmsUnchartedEffect(final RealmsUnchartedEffect effect) { @@ -59,81 +65,36 @@ class RealmsUnchartedEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller == null || sourceObject == null) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { return false; } - - RealmsUnchartedTarget target = new RealmsUnchartedTarget(); - if (controller.searchLibrary(target, source, game)) { - if (!target.getTargets().isEmpty()) { - Cards cards = new CardsImpl(); - for (UUID cardId : target.getTargets()) { - Card card = controller.getLibrary().getCard(cardId, game); - if (card != null) { - cards.add(card); - } - } - controller.revealCards(sourceObject.getName(), cards, game); - - CardsImpl cardsToKeep = new CardsImpl(); - if (cards.size() > 2) { - cardsToKeep.addAll(cards); - - Player opponent; - Set opponents = game.getOpponents(controller.getId()); - if (opponents.size() == 1) { - opponent = game.getPlayer(opponents.iterator().next()); - } else { - Target targetOpponent = new TargetOpponent(true); - controller.chooseTarget(Outcome.Detriment, targetOpponent, source, game); - opponent = game.getPlayer(targetOpponent.getFirstTarget()); - } - TargetCard targetDiscard = new TargetCard(2, Zone.LIBRARY, new FilterCard("cards to put in graveyard")); - if (opponent != null && opponent.choose(Outcome.Discard, cards, targetDiscard, game)) { - cardsToKeep.removeAll(targetDiscard.getTargets()); - cards.removeAll(cardsToKeep); - } - } - controller.moveCards(cards, Zone.GRAVEYARD, source, game); - controller.moveCards(cardsToKeep, Zone.HAND, source, game); - } - controller.shuffleLibrary(source, game); - return true; + TargetCardInLibrary target = new TargetCardWithDifferentNameInLibrary(0, 4, filter); + player.searchLibrary(target, source, game); + Cards cards = new CardsImpl(target.getTargets()); + cards.retainZone(Zone.LIBRARY, game); + if (cards.isEmpty()) { + player.shuffleLibrary(source, game); } - controller.shuffleLibrary(source, game); - return false; - } -} - -class RealmsUnchartedTarget extends TargetCardInLibrary { - - public RealmsUnchartedTarget() { - super(0, 4, new FilterLandCard("land cards with different names")); - } - - public RealmsUnchartedTarget(final RealmsUnchartedTarget target) { - super(target); - } - - @Override - public RealmsUnchartedTarget copy() { - return new RealmsUnchartedTarget(this); - } - - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Cards cards, Game game) { - Card card = cards.get(id, game); - if (card != null) { - for (UUID targetId : this.getTargets()) { - Card iCard = game.getCard(targetId); - if (iCard != null && iCard.getName().equals(card.getName())) { - return false; - } - } - return filter.match(card, playerId, game); - } - return false; + player.revealCards(source, cards, game); + + if (cards.size() > 2) { + TargetOpponent targetOpponent = new TargetOpponent(); + targetOpponent.setNotTarget(true); + player.choose(outcome, target, source, game); + Player opponent = game.getPlayer(targetOpponent.getFirstTarget()); + Cards cardsToKeep = new CardsImpl(); + cardsToKeep.addAll(cards); + TargetCard targetDiscard = new TargetCard(2, Zone.LIBRARY, filter2); + if (opponent.choose(Outcome.Discard, cards, targetDiscard, game)) { + cardsToKeep.removeIf(targetDiscard.getTargets()::contains); + cards.removeAll(cardsToKeep); + } + player.moveCards(cardsToKeep, Zone.HAND, source, game); + } + + player.moveCards(cards, Zone.GRAVEYARD, source, game); + player.shuffleLibrary(source, game); + return true; } } diff --git a/Mage.Sets/src/mage/cards/r/Realmwright.java b/Mage.Sets/src/mage/cards/r/Realmwright.java index 96b76907af1..2c3441e00f8 100644 --- a/Mage.Sets/src/mage/cards/r/Realmwright.java +++ b/Mage.Sets/src/mage/cards/r/Realmwright.java @@ -113,7 +113,7 @@ class RealmwrightEffect extends ContinuousEffectImpl { } for (Permanent land : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game )) { if (land == null || land.hasSubtype(choice, game)) { continue; diff --git a/Mage.Sets/src/mage/cards/r/Reap.java b/Mage.Sets/src/mage/cards/r/Reap.java index 5930d317b96..e5097a1c31a 100644 --- a/Mage.Sets/src/mage/cards/r/Reap.java +++ b/Mage.Sets/src/mage/cards/r/Reap.java @@ -29,7 +29,7 @@ public final class Reap extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); // Return up to X target cards from your graveyard to your hand, where X is the number of black permanents target opponent controls as you cast Reap. - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect().setText("Return up to X target cards from your graveyard to your hand, where X is the number of black permanents target opponent controls as you cast Reap.")); + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect().setText("Return up to X target cards from your graveyard to your hand, where X is the number of black permanents target opponent controls as you cast this spell")); this.getSpellAbility().addTarget(new TargetOpponent()); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 0)); this.getSpellAbility().setTargetAdjuster(ReapAdjuster.instance); diff --git a/Mage.Sets/src/mage/cards/r/ReapAndSow.java b/Mage.Sets/src/mage/cards/r/ReapAndSow.java index 64ac405284f..8751100efeb 100644 --- a/Mage.Sets/src/mage/cards/r/ReapAndSow.java +++ b/Mage.Sets/src/mage/cards/r/ReapAndSow.java @@ -30,8 +30,7 @@ public final class ReapAndSow extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetLandPermanent()); //or search your library for a land card, put that card onto the battlefield, then shuffle your library. - Mode mode = new Mode(); - mode.addEffect(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(new FilterLandCard()))); + Mode mode = new Mode(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(new FilterLandCard()))); this.getSpellAbility().getModes().addMode(mode); // Entwine {1}{G} diff --git a/Mage.Sets/src/mage/cards/r/ReapIntellect.java b/Mage.Sets/src/mage/cards/r/ReapIntellect.java index 0d5fde0fd59..2c964c81201 100644 --- a/Mage.Sets/src/mage/cards/r/ReapIntellect.java +++ b/Mage.Sets/src/mage/cards/r/ReapIntellect.java @@ -74,7 +74,7 @@ class ReapIntellectEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player targetPlayer = game.getPlayer(source.getFirstTarget()); Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (targetPlayer != null && sourceObject != null && controller != null) { // reveal hand of target player diff --git a/Mage.Sets/src/mage/cards/r/RebbecArchitectOfAscension.java b/Mage.Sets/src/mage/cards/r/RebbecArchitectOfAscension.java index e5f023a7ba0..f1bfbf404e9 100644 --- a/Mage.Sets/src/mage/cards/r/RebbecArchitectOfAscension.java +++ b/Mage.Sets/src/mage/cards/r/RebbecArchitectOfAscension.java @@ -70,7 +70,7 @@ enum RebbecArchitectOfAscensionPredicate implements ObjectSourcePlayerPredicate< return game.getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, - game.getControllerId(input.getSourceId()), input.getSourceId(), game + game.getControllerId(input.getSourceId()), input.getSource(), game ).stream() .filter(Objects::nonNull) .mapToInt(MageObject::getManaValue) diff --git a/Mage.Sets/src/mage/cards/r/Rebound.java b/Mage.Sets/src/mage/cards/r/Rebound.java index eae18ec190e..adf5cbd7db1 100644 --- a/Mage.Sets/src/mage/cards/r/Rebound.java +++ b/Mage.Sets/src/mage/cards/r/Rebound.java @@ -66,7 +66,7 @@ class ReboundEffect extends OneShotEffect { && controller != null) { spell.getSpellAbility().getTargets().clear(); TargetPlayer targetPlayer = new TargetPlayer(); - if (controller.choose(Outcome.Neutral, targetPlayer, source.getSourceId(), game)) { + if (controller.choose(Outcome.Neutral, targetPlayer, source, game)) { spell.getSpellAbility().addTarget(targetPlayer); game.informPlayers("The target of the spell was changed to " + targetPlayer.getTargetedName(game)); return true; diff --git a/Mage.Sets/src/mage/cards/r/Recall.java b/Mage.Sets/src/mage/cards/r/Recall.java index 974f8ba0285..6289e4028ac 100644 --- a/Mage.Sets/src/mage/cards/r/Recall.java +++ b/Mage.Sets/src/mage/cards/r/Recall.java @@ -68,7 +68,7 @@ class RecallEffect extends OneShotEffect { // then return a card from your graveyard to your hand for each card discarded this way TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(cardsDiscarded.size(), new FilterCard()); target.setNotTarget(true); - target.choose(Outcome.ReturnToHand, controller.getId(), source.getSourceId(), game); + target.choose(Outcome.ReturnToHand, controller.getId(), source.getSourceId(), source, game); controller.moveCards(new CardsImpl(target.getTargets()), Zone.HAND, source, game); } diff --git a/Mage.Sets/src/mage/cards/r/Reciprocate.java b/Mage.Sets/src/mage/cards/r/Reciprocate.java index 1ec811f1158..2f5426def95 100644 --- a/Mage.Sets/src/mage/cards/r/Reciprocate.java +++ b/Mage.Sets/src/mage/cards/r/Reciprocate.java @@ -61,8 +61,8 @@ class ReciprocateTarget extends TargetPermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set availablePossibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set availablePossibleTargets = super.possibleTargets(sourceControllerId, source, game); Set possibleTargets = new HashSet<>(); PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, sourceControllerId); for (UUID targetId : availablePossibleTargets) { @@ -75,16 +75,16 @@ class ReciprocateTarget extends TargetPermanent { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { int remainingTargets = this.minNumberOfTargets - targets.size(); if (remainingTargets == 0) { return true; } int count = 0; - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); if(targetSource != null) { PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, sourceControllerId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && watcher != null && watcher.hasSourceDoneDamage(permanent.getId(), game)) { count++; diff --git a/Mage.Sets/src/mage/cards/r/RecklessCrew.java b/Mage.Sets/src/mage/cards/r/RecklessCrew.java index ef9c09b7619..3b46270613c 100644 --- a/Mage.Sets/src/mage/cards/r/RecklessCrew.java +++ b/Mage.Sets/src/mage/cards/r/RecklessCrew.java @@ -64,10 +64,10 @@ class RecklessCrewEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int equipCount = game.getBattlefield().count( - filter1, source.getSourceId(), source.getControllerId(), game + filter1, source.getControllerId(), source, game ); int vehicleCount = game.getBattlefield().count( - filter2, source.getSourceId(), source.getControllerId(), game + filter2, source.getControllerId(), source, game ); if (equipCount + vehicleCount < 1) { return false; @@ -88,7 +88,7 @@ class RecklessCrewEffect extends OneShotEffect { } TargetPermanent target = new TargetPermanent(0, 1, filter1, true); target.withChooseHint("(to attach to " + permanent.getIdName() + ")"); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); permanent.addAttachment(target.getFirstTarget(), source, game); } return true; diff --git a/Mage.Sets/src/mage/cards/r/RecklessImp.java b/Mage.Sets/src/mage/cards/r/RecklessImp.java index 3b8c9f72ac8..58f9657eb58 100644 --- a/Mage.Sets/src/mage/cards/r/RecklessImp.java +++ b/Mage.Sets/src/mage/cards/r/RecklessImp.java @@ -30,7 +30,7 @@ public final class RecklessImp extends CardImpl { this.addAbility(new CantBlockAbility()); // Dash {1}{B} - this.addAbility(new DashAbility(this, "{1}{B}")); + this.addAbility(new DashAbility("{1}{B}")); } private RecklessImp(final RecklessImp card) { diff --git a/Mage.Sets/src/mage/cards/r/RecklessWurm.java b/Mage.Sets/src/mage/cards/r/RecklessWurm.java index e37e946404d..6c9452912a0 100644 --- a/Mage.Sets/src/mage/cards/r/RecklessWurm.java +++ b/Mage.Sets/src/mage/cards/r/RecklessWurm.java @@ -28,7 +28,7 @@ public final class RecklessWurm extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Madness {2}{R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{2}{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{2}{R}"))); } private RecklessWurm(final RecklessWurm card) { diff --git a/Mage.Sets/src/mage/cards/r/ReckonerShakedown.java b/Mage.Sets/src/mage/cards/r/ReckonerShakedown.java new file mode 100644 index 00000000000..fb198136f67 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/ReckonerShakedown.java @@ -0,0 +1,103 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ReckonerShakedown extends CardImpl { + + public ReckonerShakedown(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); + + // Target opponent reveals their hand. You may choose a nonland card from it. If you do, that player discards that card. If you don't, put two +1/+1 counters on a creature or Vehicle you control. + this.getSpellAbility().addEffect(new ReckonerShakedownEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + private ReckonerShakedown(final ReckonerShakedown card) { + super(card); + } + + @Override + public ReckonerShakedown copy() { + return new ReckonerShakedown(this); + } +} + +class ReckonerShakedownEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterControlledPermanent("creature or Vehicle you control"); + + static { + filter.add(Predicates.or( + CardType.CREATURE.getPredicate(), + SubType.VEHICLE.getPredicate() + )); + } + + ReckonerShakedownEffect() { + super(Outcome.Benefit); + staticText = "target opponent reveals their hand. You may choose a nonland card from it. " + + "If you do, that player discards that card. If you don't, " + + "put two +1/+1 counters on a creature or Vehicle you control"; + } + + private ReckonerShakedownEffect(final ReckonerShakedownEffect effect) { + super(effect); + } + + @Override + public ReckonerShakedownEffect copy() { + return new ReckonerShakedownEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(source.getFirstTarget()); + if (controller == null || player == null) { + return false; + } + player.revealCards(source, player.getHand(), game); + TargetCard target = new TargetCardInHand(0, 1, StaticFilters.FILTER_CARD_A_NON_LAND); + controller.choose(Outcome.Discard, player.getHand(), target, game); + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + player.discard(card, false, source, game); + return true; + } + if (!game.getBattlefield().contains(filter, source, game, 1)) { + return true; + } + TargetPermanent targetPermanent = new TargetPermanent(filter); + targetPermanent.setNotTarget(true); + player.choose(Outcome.BoostCreature, targetPermanent, source, game); + Permanent permanent = game.getPermanent(targetPermanent.getFirstTarget()); + if (permanent != null) { + permanent.addCounters(CounterType.P1P1.createInstance(2), source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/r/ReckonersBargain.java b/Mage.Sets/src/mage/cards/r/ReckonersBargain.java new file mode 100644 index 00000000000..64a64c39a06 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/ReckonersBargain.java @@ -0,0 +1,84 @@ +package mage.cards.r; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.target.common.TargetControlledPermanent; +import mage.util.CardUtil; + +import java.util.Collection; +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ReckonersBargain extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledPermanent("an artifact or creature"); + + static { + filter.add(Predicates.or( + CardType.ARTIFACT.getPredicate(), + CardType.CREATURE.getPredicate() + )); + } + + public ReckonersBargain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); + + // As an additional cost to cast this spell, sacrifice an artifact or creature. + this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); + + // You gain life equal to the sacrificed permanent's mana value. Draw two cards. + this.getSpellAbility().addEffect(new GainLifeEffect( + ReckonersBargainValue.instance, "you gain life " + + "equal to the sacrificed permanent's mana value" + )); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); + } + + private ReckonersBargain(final ReckonersBargain card) { + super(card); + } + + @Override + public ReckonersBargain copy() { + return new ReckonersBargain(this); + } +} + +enum ReckonersBargainValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return CardUtil.castStream(sourceAbility.getCosts().stream(), SacrificeTargetCost.class) + .map(SacrificeTargetCost::getPermanents) + .flatMap(Collection::stream) + .filter(Objects::nonNull) + .mapToInt(MageObject::getManaValue) + .sum(); + } + + @Override + public ReckonersBargainValue copy() { + return this; + } + + @Override + public String getMessage() { + return ""; + } +} diff --git a/Mage.Sets/src/mage/cards/r/Recollect.java b/Mage.Sets/src/mage/cards/r/Recollect.java index 99bf88cf441..570a23d2378 100644 --- a/Mage.Sets/src/mage/cards/r/Recollect.java +++ b/Mage.Sets/src/mage/cards/r/Recollect.java @@ -1,15 +1,14 @@ - package mage.cards.r; -import java.util.UUID; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Loki */ public final class Recollect extends CardImpl { @@ -18,7 +17,7 @@ public final class Recollect extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); // Return target card from your graveyard to your hand. - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard()); } diff --git a/Mage.Sets/src/mage/cards/r/Reconstruction.java b/Mage.Sets/src/mage/cards/r/Reconstruction.java index 6ad87127f6d..6c7be571150 100644 --- a/Mage.Sets/src/mage/cards/r/Reconstruction.java +++ b/Mage.Sets/src/mage/cards/r/Reconstruction.java @@ -1,26 +1,25 @@ - package mage.cards.r; -import java.util.UUID; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class Reconstruction extends CardImpl { public Reconstruction(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}"); // Return target artifact card from your graveyard to your hand. - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); } private Reconstruction(final Reconstruction card) { diff --git a/Mage.Sets/src/mage/cards/r/Recover.java b/Mage.Sets/src/mage/cards/r/Recover.java index 7fa8cb49758..515a0d26fdd 100644 --- a/Mage.Sets/src/mage/cards/r/Recover.java +++ b/Mage.Sets/src/mage/cards/r/Recover.java @@ -1,17 +1,16 @@ - package mage.cards.r; -import java.util.UUID; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author dustinconrad */ public final class Recover extends CardImpl { @@ -21,9 +20,9 @@ public final class Recover extends CardImpl { // 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()); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private Recover(final Recover card) { diff --git a/Mage.Sets/src/mage/cards/r/Recuperate.java b/Mage.Sets/src/mage/cards/r/Recuperate.java index 89f67fe2e85..dd7cfeae795 100644 --- a/Mage.Sets/src/mage/cards/r/Recuperate.java +++ b/Mage.Sets/src/mage/cards/r/Recuperate.java @@ -24,8 +24,7 @@ public final class Recuperate extends CardImpl { // Choose one - You gain 6 life; this.getSpellAbility().addEffect(new GainLifeEffect(6)); // or prevent the next 6 damage that would be dealt to target creature this turn. - Mode mode = new Mode(); - mode.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, 6)); + Mode mode = new Mode(new PreventDamageToTargetEffect(Duration.EndOfTurn, 6)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/r/RedElementalBlast.java b/Mage.Sets/src/mage/cards/r/RedElementalBlast.java index 7c5d466dba0..0f0c804fe49 100644 --- a/Mage.Sets/src/mage/cards/r/RedElementalBlast.java +++ b/Mage.Sets/src/mage/cards/r/RedElementalBlast.java @@ -36,8 +36,7 @@ public final class RedElementalBlast extends CardImpl { this.getSpellAbility().addEffect(new CounterTargetEffect()); this.getSpellAbility().addTarget(new TargetSpell(filterSpell)); - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetPermanent(filterPermanent)); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/r/RedWard.java b/Mage.Sets/src/mage/cards/r/RedWard.java index d41d9e49bd8..7e789ea4185 100644 --- a/Mage.Sets/src/mage/cards/r/RedWard.java +++ b/Mage.Sets/src/mage/cards/r/RedWard.java @@ -1,10 +1,7 @@ - package mage.cards.r; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; @@ -13,28 +10,20 @@ 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.Zone; -import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.ColorPredicate; +import mage.constants.SubType; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LoneFox */ public final class RedWard extends CardImpl { - private static final FilterCard filter = new FilterCard("red"); - - static { - filter.add(new ColorPredicate(ObjectColor.RED)); - } - public RedWard(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -42,12 +31,10 @@ public final class RedWard extends CardImpl { this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Protect)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); - // Enchanted creature has protection from red. This effect doesn't remove Red Ward. - ProtectionAbility gainedAbility = new ProtectionAbility(filter); - gainedAbility.setAuraIdNotToBeRemoved(this.getId()); - Effect effect = new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA); - effect.setText("Enchanted creature has protection from red. This effect doesn't remove {this}."); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + + this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( + ProtectionAbility.from(ObjectColor.RED), AttachmentType.AURA + ).setDoesntRemoveItself(true))); } private RedWard(final RedWard card) { diff --git a/Mage.Sets/src/mage/cards/r/ReflectionOfKikiJiki.java b/Mage.Sets/src/mage/cards/r/ReflectionOfKikiJiki.java new file mode 100644 index 00000000000..2a4dd547193 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/ReflectionOfKikiJiki.java @@ -0,0 +1,91 @@ +package mage.cards.r; + +import mage.MageInt; +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.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.Game; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ReflectionOfKikiJiki extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("another nonlegendary creature you control"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); + } + + public ReflectionOfKikiJiki(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + this.color.setRed(true); + this.nightCard = true; + + // {1}, {T}: Create a token that's a copy of another target nonlegendary creature you control, except it has haste. Sacrifice it at the beginning of the next end step. + Ability ability = new SimpleActivatedAbility(new ReflectionOfKikiJikiEffect(), new GenericManaCost(1)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private ReflectionOfKikiJiki(final ReflectionOfKikiJiki card) { + super(card); + } + + @Override + public ReflectionOfKikiJiki copy() { + return new ReflectionOfKikiJiki(this); + } +} + +class ReflectionOfKikiJikiEffect extends OneShotEffect { + + ReflectionOfKikiJikiEffect() { + super(Outcome.Benefit); + staticText = "create a token that's a copy of another target nonlegendary creature you control, " + + "except it has haste. Sacrifice it at the beginning of the next end step"; + } + + private ReflectionOfKikiJikiEffect(final ReflectionOfKikiJikiEffect effect) { + super(effect); + } + + @Override + public ReflectionOfKikiJikiEffect copy() { + return new ReflectionOfKikiJikiEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(null, null, true); + effect.setTargetPointer(new FixedTarget(source.getFirstTarget(), game)); + effect.apply(game, source); + effect.sacrificeTokensCreatedAtNextEndStep(game, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RefractionTrap.java b/Mage.Sets/src/mage/cards/r/RefractionTrap.java index c7d8f930938..f0af5d69b50 100644 --- a/Mage.Sets/src/mage/cards/r/RefractionTrap.java +++ b/Mage.Sets/src/mage/cards/r/RefractionTrap.java @@ -106,7 +106,7 @@ class RefractionTrapPreventDamageEffect extends PreventionEffectImpl { @Override public void init(Ability source, Game game) { - this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); super.init(source, game); } diff --git a/Mage.Sets/src/mage/cards/r/Refurbish.java b/Mage.Sets/src/mage/cards/r/Refurbish.java index e4c90a7d8b9..7ab8d062ab8 100644 --- a/Mage.Sets/src/mage/cards/r/Refurbish.java +++ b/Mage.Sets/src/mage/cards/r/Refurbish.java @@ -1,25 +1,24 @@ - package mage.cards.r; -import java.util.UUID; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class Refurbish extends CardImpl { public Refurbish(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{W}"); // Return target artifact card from your graveyard to the battlefield. - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); } diff --git a/Mage.Sets/src/mage/cards/r/RefuseToYield.java b/Mage.Sets/src/mage/cards/r/RefuseToYield.java new file mode 100644 index 00000000000..fa2c62c1468 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RefuseToYield.java @@ -0,0 +1,34 @@ +package mage.cards.r; + +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RefuseToYield extends CardImpl { + + public RefuseToYield(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + // Target creature gets +2/+7 until end of turn. Untap it. + this.getSpellAbility().addEffect(new BoostTargetEffect(2, 7)); + this.getSpellAbility().addEffect(new UntapTargetEffect("Untap it")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private RefuseToYield(final RefuseToYield card) { + super(card); + } + + @Override + public RefuseToYield copy() { + return new RefuseToYield(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RegalLeosaur.java b/Mage.Sets/src/mage/cards/r/RegalLeosaur.java index da3993b7e8b..24ef8eba65e 100644 --- a/Mage.Sets/src/mage/cards/r/RegalLeosaur.java +++ b/Mage.Sets/src/mage/cards/r/RegalLeosaur.java @@ -30,7 +30,7 @@ public final class RegalLeosaur extends CardImpl { // Whenever this creature mutates, other creatures you control get +2/+1 until end of turn. this.addAbility(new MutatesSourceTriggeredAbility( - new BoostControlledEffect(2, 1, Duration.EndOfTurn, false) + new BoostControlledEffect(2, 1, Duration.EndOfTurn, true) )); } diff --git a/Mage.Sets/src/mage/cards/r/RegnasSanction.java b/Mage.Sets/src/mage/cards/r/RegnasSanction.java index 7717297b92a..91d66e9afce 100644 --- a/Mage.Sets/src/mage/cards/r/RegnasSanction.java +++ b/Mage.Sets/src/mage/cards/r/RegnasSanction.java @@ -83,7 +83,7 @@ class RegnasSanctionEffect extends OneShotEffect { TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); if (game.getBattlefield().contains(filter, source, game, 1) - && player.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + && player.choose(Outcome.Benefit, target, source, game)) { filterToTap.add(Predicates.not(new PermanentIdPredicate(target.getFirstTarget()))); } } @@ -94,7 +94,7 @@ class RegnasSanctionEffect extends OneShotEffect { .map(Predicates::not) .forEach(filterToTap::add); for (Permanent permanent : game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game + StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game )) { if (choice.getFriends().stream().map(MageItem::getId).anyMatch(permanent::isControlledBy)) { permanent.addCounters(CounterType.P1P1.createInstance(), source, game); diff --git a/Mage.Sets/src/mage/cards/r/ReidaneGodOfTheWorthy.java b/Mage.Sets/src/mage/cards/r/ReidaneGodOfTheWorthy.java index 5395bb93631..bf21dbc3f19 100644 --- a/Mage.Sets/src/mage/cards/r/ReidaneGodOfTheWorthy.java +++ b/Mage.Sets/src/mage/cards/r/ReidaneGodOfTheWorthy.java @@ -182,6 +182,9 @@ class ValkmiraProtectorsShieldTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { + if (event.getTargetId().equals(getSourceId())) { + return false; + } StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); if (stackObject == null || !game.getOpponents(getControllerId()).contains(stackObject.getControllerId())) { return false; @@ -200,7 +203,7 @@ class ValkmiraProtectorsShieldTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever you or a permanent you control becomes the target of a spell or ability " + + return "Whenever you or another permanent you control becomes the target of a spell or ability " + "an opponent controls, counter that spell or ability unless its controller pays {1}."; } } diff --git a/Mage.Sets/src/mage/cards/r/ReignOfChaos.java b/Mage.Sets/src/mage/cards/r/ReignOfChaos.java index ef4db6b60e6..eb57bd91e4e 100644 --- a/Mage.Sets/src/mage/cards/r/ReignOfChaos.java +++ b/Mage.Sets/src/mage/cards/r/ReignOfChaos.java @@ -39,8 +39,7 @@ public final class ReignOfChaos extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect(false, true)); this.getSpellAbility().addTarget(new TargetPermanent(filter1)); this.getSpellAbility().addTarget(new TargetPermanent(filter2)); - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect(false, true)); + Mode mode = new Mode(new DestroyTargetEffect(false, true)); mode.addTarget(new TargetPermanent(filter3)); mode.addTarget(new TargetPermanent(filter4)); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/r/ReignOfTerror.java b/Mage.Sets/src/mage/cards/r/ReignOfTerror.java index 71499a45ea4..620f7a8a33c 100644 --- a/Mage.Sets/src/mage/cards/r/ReignOfTerror.java +++ b/Mage.Sets/src/mage/cards/r/ReignOfTerror.java @@ -73,7 +73,7 @@ class ReignOfTerrorEffect extends OneShotEffect { "", "Green", "White", source, game ) ? greenFilter : whiteFilter; int died = game.getBattlefield() - .getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game) + .getActivePermanents(filter, source.getControllerId(), source, game) .stream() .mapToInt(permanent -> permanent.destroy(source, game, true) ? 1 : 0) .sum(); diff --git a/Mage.Sets/src/mage/cards/r/ReignOfThePit.java b/Mage.Sets/src/mage/cards/r/ReignOfThePit.java index 15d500f4990..15936203a88 100644 --- a/Mage.Sets/src/mage/cards/r/ReignOfThePit.java +++ b/Mage.Sets/src/mage/cards/r/ReignOfThePit.java @@ -68,9 +68,9 @@ class ReignOfThePitEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null) { TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(1, 1, new FilterControlledCreaturePermanent(), true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { while (!target.isChosen() && player.canRespond()) { - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + player.choose(Outcome.Sacrifice, target, source, game); } perms.addAll(target.getTargets()); } diff --git a/Mage.Sets/src/mage/cards/r/Reincarnation.java b/Mage.Sets/src/mage/cards/r/Reincarnation.java index 81250560bda..baf5e354ec4 100644 --- a/Mage.Sets/src/mage/cards/r/Reincarnation.java +++ b/Mage.Sets/src/mage/cards/r/Reincarnation.java @@ -143,7 +143,7 @@ class ReincarnationDelayedEffect extends OneShotEffect { filter.add(new OwnerIdPredicate(player.getId())); Target targetCreature = new TargetCardInGraveyard(filter); targetCreature.setNotTarget(true); - if (targetCreature.canChoose(source.getSourceId(), controller.getId(), game) + if (targetCreature.canChoose(controller.getId(), source, game) && controller.chooseTarget(outcome, targetCreature, source, game)) { Card card = game.getCard(targetCreature.getFirstTarget()); if (card != null && game.getState().getZone(card.getId()) == Zone.GRAVEYARD) { diff --git a/Mage.Sets/src/mage/cards/r/ReinsOfPower.java b/Mage.Sets/src/mage/cards/r/ReinsOfPower.java index 7f1ab2982ca..848d6df633d 100644 --- a/Mage.Sets/src/mage/cards/r/ReinsOfPower.java +++ b/Mage.Sets/src/mage/cards/r/ReinsOfPower.java @@ -76,12 +76,12 @@ class ReinsOfPowerEffect extends OneShotEffect { // You and that opponent each gain control of all creatures the other controls until end of turn. Set yourCreatures = new HashSet<>(); Set opponentCreatures = new HashSet<>(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), source.getControllerId(), source, game)) { yourCreatures.add(permanent.getId()); } FilterCreaturePermanent filterOpponent = new FilterCreaturePermanent(); filterOpponent.add(new ControllerIdPredicate(opponentId)); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filterOpponent, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filterOpponent, source.getControllerId(), source, game)) { opponentCreatures.add(permanent.getId()); } for (UUID creatureId : yourCreatures) { diff --git a/Mage.Sets/src/mage/cards/r/ReinsOfTheVinesteed.java b/Mage.Sets/src/mage/cards/r/ReinsOfTheVinesteed.java index f97d8b80521..a3ab0474701 100644 --- a/Mage.Sets/src/mage/cards/r/ReinsOfTheVinesteed.java +++ b/Mage.Sets/src/mage/cards/r/ReinsOfTheVinesteed.java @@ -85,7 +85,7 @@ class ReinsOfTheVinesteedEffect extends OneShotEffect { TargetPermanent target = new TargetPermanent(FILTER); target.setNotTarget(true); if (controller != null - && controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { + && controller.choose(Outcome.PutCardInPlay, target, source, game)) { Permanent targetPermanent = game.getPermanent(target.getFirstTarget()); if (!targetPermanent.cantBeAttachedBy(aura, source, game, false)) { game.getState().setValue("attachTo:" + aura.getId(), targetPermanent); diff --git a/Mage.Sets/src/mage/cards/r/Reinterpret.java b/Mage.Sets/src/mage/cards/r/Reinterpret.java index c48522aab3f..7fdfc9de9f3 100644 --- a/Mage.Sets/src/mage/cards/r/Reinterpret.java +++ b/Mage.Sets/src/mage/cards/r/Reinterpret.java @@ -2,14 +2,18 @@ package mage.cards.r; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.Outcome; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.game.stack.Spell; +import mage.players.Player; import mage.target.TargetSpell; +import mage.util.CardUtil; import java.util.UUID; @@ -56,12 +60,17 @@ class ReinterpretEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Spell spell = game.getSpell(source.getFirstTarget()); - if (spell == null) { + Player controller = game.getPlayer(source.getControllerId()); + if (spell == null || controller == null) { return false; } int manaValue = spell.getManaValue(); - game.getStack().counter(spell.getId(), source, game); - new CastWithoutPayingManaCostEffect(manaValue).apply(game, source); + game.getStack().counter(spell.getId(), source, game);; + FilterCard filter = new FilterCard(); + filter.add(new ManaValuePredicate( + ComparisonType.FEWER_THAN, manaValue + 1 + )); + CardUtil.castSpellWithAttributesForFree(controller, source, game, controller.getHand(), filter); return true; } } diff --git a/Mage.Sets/src/mage/cards/r/RekindledFlame.java b/Mage.Sets/src/mage/cards/r/RekindledFlame.java index 641012684eb..3cae4599540 100644 --- a/Mage.Sets/src/mage/cards/r/RekindledFlame.java +++ b/Mage.Sets/src/mage/cards/r/RekindledFlame.java @@ -1,12 +1,12 @@ package mage.cards.r; -import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.common.OpponentHasNoCardsInHandCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -21,6 +21,10 @@ import java.util.UUID; */ public final class RekindledFlame extends CardImpl { + private static final Hint hint = new ConditionHint( + OpponentHasNoCardsInHandCondition.instance, "Opponent has no cards in hand" + ); + public RekindledFlame(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}{R}"); @@ -29,14 +33,13 @@ public final class RekindledFlame extends CardImpl { this.getSpellAbility().addTarget(new TargetAnyTarget()); // At the beginning of your upkeep, if an opponent has no cards in hand, you may return Rekindled Flame from your graveyard to your hand. - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new BeginningOfUpkeepTriggeredAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), TargetController.YOU, true), - OpponentHasNoCardsInHandCondition.instance, - "If an opponent has no cards in hand, you may return Rekindled Flame from your graveyard to your hand."); - ability.addHint(new ConditionHint(OpponentHasNoCardsInHandCondition.instance, "Opponent has no cards in hand")); - ability.setRuleVisible(true); - this.addAbility(ability); - + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new BeginningOfUpkeepTriggeredAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), + TargetController.YOU, true + ), OpponentHasNoCardsInHandCondition.instance, "At the beginning of your upkeep, " + + "if an opponent has no cards in hand, you may return {this} from your graveyard to your hand." + ).addHint(hint)); } private RekindledFlame(final RekindledFlame card) { @@ -47,4 +50,4 @@ public final class RekindledFlame extends CardImpl { public RekindledFlame copy() { return new RekindledFlame(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/r/ReleaseToMemory.java b/Mage.Sets/src/mage/cards/r/ReleaseToMemory.java new file mode 100644 index 00000000000..c323affd7a2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/ReleaseToMemory.java @@ -0,0 +1,71 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.token.SpiritToken; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ReleaseToMemory extends CardImpl { + + public ReleaseToMemory(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{W}"); + + // Exile target opponent's graveyard. For each creature card exiled this way, create a 1/1 colorless Spirit creature token. + this.getSpellAbility().addEffect(new ReleaseToMemoryEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + private ReleaseToMemory(final ReleaseToMemory card) { + super(card); + } + + @Override + public ReleaseToMemory copy() { + return new ReleaseToMemory(this); + } +} + +class ReleaseToMemoryEffect extends OneShotEffect { + + ReleaseToMemoryEffect() { + super(Outcome.Benefit); + staticText = "exile target opponent's graveyard. For each creature " + + "card exiled this way, create a 1/1 colorless Spirit creature token"; + } + + private ReleaseToMemoryEffect(final ReleaseToMemoryEffect effect) { + super(effect); + } + + @Override + public ReleaseToMemoryEffect copy() { + return new ReleaseToMemoryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getFirstTarget()); + if (player == null) { + return false; + } + int creatures = player.getGraveyard().count(StaticFilters.FILTER_CARD_CREATURE, game); + player.moveCards(player.getGraveyard(), Zone.EXILED, source, game); + if (creatures > 0) { + new SpiritToken().putOntoBattlefield(creatures, game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RelentlessDead.java b/Mage.Sets/src/mage/cards/r/RelentlessDead.java index f0c19dddf28..4a562026809 100644 --- a/Mage.Sets/src/mage/cards/r/RelentlessDead.java +++ b/Mage.Sets/src/mage/cards/r/RelentlessDead.java @@ -13,7 +13,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.players.Player; @@ -79,7 +79,7 @@ class RelentlessDeadEffect extends OneShotEffect { FilterCard filter = new FilterCard("Another target Zombie card with mana value {" + payCount + "}"); filter.add(SubType.ZOMBIE.getPredicate()); filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, payCount)); - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(filter); if (controller.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/r/RelentlessPursuit.java b/Mage.Sets/src/mage/cards/r/RelentlessPursuit.java index b67f29782e0..1d156693a96 100644 --- a/Mage.Sets/src/mage/cards/r/RelentlessPursuit.java +++ b/Mage.Sets/src/mage/cards/r/RelentlessPursuit.java @@ -65,7 +65,7 @@ class RelentlessPursuitEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/r/RelentlessRats.java b/Mage.Sets/src/mage/cards/r/RelentlessRats.java index 475ccb9b5ea..79a1c9c8343 100644 --- a/Mage.Sets/src/mage/cards/r/RelentlessRats.java +++ b/Mage.Sets/src/mage/cards/r/RelentlessRats.java @@ -69,7 +69,7 @@ public final class RelentlessRats extends CardImpl { @Override public boolean apply(Game game, Ability source) { - int count = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) - 1; + int count = game.getBattlefield().count(filter, source.getControllerId(), source, game) - 1; if (count > 0) { Permanent target = game.getPermanent(source.getSourceId()); if (target != null) { diff --git a/Mage.Sets/src/mage/cards/r/RelicBind.java b/Mage.Sets/src/mage/cards/r/RelicBind.java index c2de0e588c3..c3e5d39a6f0 100644 --- a/Mage.Sets/src/mage/cards/r/RelicBind.java +++ b/Mage.Sets/src/mage/cards/r/RelicBind.java @@ -48,8 +48,7 @@ public final class RelicBind extends CardImpl { Ability ability2 = new BecomesTappedAttachedTriggeredAbility(new DamageTargetEffect(1), "enchanted artifact"); ability2.addTarget(new TargetPlayerOrPlaneswalker()); // — Target player gains 1 life. - Mode mode = new Mode(); - mode.addEffect(new GainLifeTargetEffect(1)); + Mode mode = new Mode(new GainLifeTargetEffect(1)); mode.addTarget(new TargetPlayer()); ability2.addMode(mode); diff --git a/Mage.Sets/src/mage/cards/r/RememberTheFallen.java b/Mage.Sets/src/mage/cards/r/RememberTheFallen.java index 41d91b74cf5..f6ae54d0968 100644 --- a/Mage.Sets/src/mage/cards/r/RememberTheFallen.java +++ b/Mage.Sets/src/mage/cards/r/RememberTheFallen.java @@ -1,12 +1,11 @@ package mage.cards.r; import mage.abilities.Mode; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; -import mage.filter.common.FilterArtifactCard; import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; @@ -16,8 +15,6 @@ import java.util.UUID; */ public final class RememberTheFallen extends CardImpl { - 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}"); @@ -26,13 +23,12 @@ public final class RememberTheFallen extends CardImpl { this.getSpellAbility().getModes().setMaxModes(2); // • Return target creature card from your graveyard to your hand. - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD).withChooseHint("return to hand")); // • Return target artifact card from your graveyard to your hand. - Mode mode = new Mode(); - mode.addEffect(new ReturnToHandTargetEffect()); - mode.addTarget(new TargetCardInYourGraveyard(filterArtifact).withChooseHint("return to hand")); + Mode mode = new Mode(new ReturnFromGraveyardToHandTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD).withChooseHint("return to hand")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/r/RemnantOfTheRisingStar.java b/Mage.Sets/src/mage/cards/r/RemnantOfTheRisingStar.java new file mode 100644 index 00000000000..306cc7f262e --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RemnantOfTheRisingStar.java @@ -0,0 +1,134 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.costs.mana.ManaCosts; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.ModifiedPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RemnantOfTheRisingStar extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(ModifiedPredicate.instance); + } + + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 4); + private static final Hint hint + = new ValueHint("Modified creatures you control", new PermanentsOnBattlefieldCount(filter)); + + public RemnantOfTheRisingStar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); + + this.subtype.add(SubType.DRAGON); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + this.color.setGreen(true); + this.nightCard = true; + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever another creature enters the battlefield under your control, you may pay {X}. When you do, put X +1/+1 counters on that creature. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + new RemnantOfTheRisingStarEffect(), StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE + )); + + // As long as you control five or more modified creatures, Remnant of the Rising Star gets +5/+5 and has trample. + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(5, 5, Duration.WhileOnBattlefield), + condition, "as long as you control five or more modified creatures, {this} gets +5/+5" + )); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(TrampleAbility.getInstance()), condition, "and has trample" + )); + this.addAbility(ability.addHint(hint)); + } + + private RemnantOfTheRisingStar(final RemnantOfTheRisingStar card) { + super(card); + } + + @Override + public RemnantOfTheRisingStar copy() { + return new RemnantOfTheRisingStar(this); + } +} + +class RemnantOfTheRisingStarEffect extends OneShotEffect { + + RemnantOfTheRisingStarEffect() { + super(Outcome.Benefit); + staticText = "you may pay {X}. When you do, put X +1/+1 counters on that creature"; + } + + private RemnantOfTheRisingStarEffect(final RemnantOfTheRisingStarEffect effect) { + super(effect); + } + + @Override + public RemnantOfTheRisingStarEffect copy() { + return new RemnantOfTheRisingStarEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + ManaCosts cost = new ManaCostsImpl<>("{X}"); + if (player == null || !player.chooseUse( + Outcome.BoostCreature, "Pay " + cost.getText() + "?", source, game + )) { + return false; + } + int xValue = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + cost.add(new GenericManaCost(xValue)); + if (!cost.pay(source, game, source, source.getControllerId(), false, null)) { + return false; + } + Permanent permanent = (Permanent) getValue("permanentEnteringBattlefield"); + if (permanent == null) { + return false; + } + game.fireReflexiveTriggeredAbility(new ReflexiveTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance(xValue)) + .setTargetPointer(new FixedTarget(permanent, game)), false + ), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RemorselessPunishment.java b/Mage.Sets/src/mage/cards/r/RemorselessPunishment.java index 97cf6ccebc4..2a4405214c6 100644 --- a/Mage.Sets/src/mage/cards/r/RemorselessPunishment.java +++ b/Mage.Sets/src/mage/cards/r/RemorselessPunishment.java @@ -79,10 +79,10 @@ class RemorselessPunishmentEffect extends OneShotEffect { return; } } - if (game.getBattlefield().containsControlled(filter, source.getSourceId(), opponent.getId(), game, 1)) { + if (game.getBattlefield().containsControlled(filter, source.getSourceId(), opponent.getId(), source, game, 1)) { if (opponent.chooseUse(outcome, "Choose your " + iteration + " punishment.", null, "Sacrifice a creature or planeswalker", "Lose 5 life", source, game)) { TargetPermanent target = new TargetPermanent(1, 1, filter, true); - if (target.choose(Outcome.Sacrifice, opponent.getId(), source.getId(), game)) { + if (target.choose(Outcome.Sacrifice, opponent.getId(), source.getId(), source, game)) { for (UUID targetId : target.getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/r/RenderSilent.java b/Mage.Sets/src/mage/cards/r/RenderSilent.java index f868ee002a6..d2f18055614 100644 --- a/Mage.Sets/src/mage/cards/r/RenderSilent.java +++ b/Mage.Sets/src/mage/cards/r/RenderSilent.java @@ -107,7 +107,7 @@ class RenderSilentEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast spells this turn (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/r/RenegadeRallier.java b/Mage.Sets/src/mage/cards/r/RenegadeRallier.java index f3a0bfc3595..8b99f7d8665 100644 --- a/Mage.Sets/src/mage/cards/r/RenegadeRallier.java +++ b/Mage.Sets/src/mage/cards/r/RenegadeRallier.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -12,15 +10,16 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; +import mage.constants.SubType; import mage.filter.common.FilterPermanentCard; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.target.common.TargetCardInYourGraveyard; import mage.watchers.common.RevoltWatcher; +import java.util.UUID; + /** - * * @author fireshoes */ public final class RenegadeRallier extends CardImpl { @@ -41,14 +40,13 @@ public final class RenegadeRallier extends CardImpl { // Revolt — When Renegade Rallier enters the battlefield, if a permanent you controlled left the battlefield this turn, // return target permanent card with converted mana cost 2 or less from your graveyard to your battlefield. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( - new ReturnFromGraveyardToBattlefieldTargetEffect(), false), RevoltCondition.instance, - "Revolt — When {this} enters the battlefield, if a permanent you controlled left" - + " the battlefield this turn, return target permanent card with mana value 2 or less from your graveyard to the battlefield."); - ability.setAbilityWord(AbilityWord.REVOLT); + Ability ability = new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), false), + RevoltCondition.instance, "When {this} enters the battlefield, if a permanent you controlled " + + "left the battlefield this turn, return target permanent card with mana value 2 or less from your graveyard to the battlefield." + ).setAbilityWord(AbilityWord.REVOLT); ability.addTarget(new TargetCardInYourGraveyard(filter)); - ability.addWatcher(new RevoltWatcher()); - this.addAbility(ability); + this.addAbility(ability, new RevoltWatcher()); } private RenegadeRallier(final RenegadeRallier card) { diff --git a/Mage.Sets/src/mage/cards/r/RenegadeTactics.java b/Mage.Sets/src/mage/cards/r/RenegadeTactics.java index e8fbb8dd6d3..c9d30484b0a 100644 --- a/Mage.Sets/src/mage/cards/r/RenegadeTactics.java +++ b/Mage.Sets/src/mage/cards/r/RenegadeTactics.java @@ -23,7 +23,7 @@ public final class RenegadeTactics extends CardImpl { this.getSpellAbility().addEffect(new CantBlockTargetEffect(Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private RenegadeTactics(final RenegadeTactics card) { diff --git a/Mage.Sets/src/mage/cards/r/RenownedWeaponsmith.java b/Mage.Sets/src/mage/cards/r/RenownedWeaponsmith.java index cba2d148b1c..15d9b60bcba 100644 --- a/Mage.Sets/src/mage/cards/r/RenownedWeaponsmith.java +++ b/Mage.Sets/src/mage/cards/r/RenownedWeaponsmith.java @@ -42,7 +42,7 @@ public final class RenownedWeaponsmith extends CardImpl { this.addAbility(new ConditionalColorlessManaAbility(new TapSourceCost(), 2, new RenownedWeaponsmithManaBuilder())); // {U}, {T}: Search your library for a card named Heart-Piercer Bow or Vial of Dragonfire, reveal it, put it into your hand, then shuffle your library. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RenownedWeaponsmithEffect(), new ManaCostsImpl("{U")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RenownedWeaponsmithEffect(), new ManaCostsImpl("{U}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); @@ -83,7 +83,7 @@ class RenownedWeaponsmithCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return (object != null && object.isArtifact(game)); } @@ -110,7 +110,7 @@ class RenownedWeaponsmithEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && controller != null) { TargetCardInLibrary target = new TargetCardInLibrary(filter); if (controller.searchLibrary(target, source, game)) { diff --git a/Mage.Sets/src/mage/cards/r/RepelIntruders.java b/Mage.Sets/src/mage/cards/r/RepelIntruders.java index 14ddd8b7dfc..a3956709f5f 100644 --- a/Mage.Sets/src/mage/cards/r/RepelIntruders.java +++ b/Mage.Sets/src/mage/cards/r/RepelIntruders.java @@ -32,7 +32,7 @@ public final class RepelIntruders extends CardImpl { new ManaWasSpentCondition(ColoredManaSymbol.W), "Create two 1/1 white Kithkin Soldier creature tokens if {W} was spent to cast this spell")); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new CounterTargetEffect(), - new ManaWasSpentCondition(ColoredManaSymbol.U), " Counter up to one target creature spell if {U} was spent to cast this spell")); + new ManaWasSpentCondition(ColoredManaSymbol.U), "Counter up to one target creature spell if {U} was spent to cast this spell")); this.getSpellAbility().addTarget(target); this.getSpellAbility().addEffect(new InfoEffect("(Do both if {W}{U} was spent.)")); diff --git a/Mage.Sets/src/mage/cards/r/RepelTheDarkness.java b/Mage.Sets/src/mage/cards/r/RepelTheDarkness.java index e64dc813215..8a0716ac12b 100644 --- a/Mage.Sets/src/mage/cards/r/RepelTheDarkness.java +++ b/Mage.Sets/src/mage/cards/r/RepelTheDarkness.java @@ -20,7 +20,7 @@ public final class RepelTheDarkness extends CardImpl { this.getSpellAbility().addEffect(new TapTargetEffect()); - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); } diff --git a/Mage.Sets/src/mage/cards/r/Replenish.java b/Mage.Sets/src/mage/cards/r/Replenish.java index 3c0376be3be..59de2d17685 100644 --- a/Mage.Sets/src/mage/cards/r/Replenish.java +++ b/Mage.Sets/src/mage/cards/r/Replenish.java @@ -56,8 +56,8 @@ class ReplenishEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - return controller.moveCards(controller.getGraveyard().getCards(new FilterEnchantmentCard(), source.getSourceId(), - source.getControllerId(), game), Zone.BATTLEFIELD, source, game); + return controller.moveCards(controller.getGraveyard().getCards(new FilterEnchantmentCard(), + source.getControllerId(), source, game), Zone.BATTLEFIELD, source, game); } return false; } diff --git a/Mage.Sets/src/mage/cards/r/RescuerSphinx.java b/Mage.Sets/src/mage/cards/r/RescuerSphinx.java index caa6c5b79c9..a3a46dc9703 100644 --- a/Mage.Sets/src/mage/cards/r/RescuerSphinx.java +++ b/Mage.Sets/src/mage/cards/r/RescuerSphinx.java @@ -87,7 +87,7 @@ class RescuerSphinxEffect extends OneShotEffect { return false; } Target target = new TargetPermanent(0, 1, filter, true); - if (!player.choose(outcome, target, source.getSourceId(), game)) { + if (!player.choose(outcome, target, source, game)) { return false; } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/r/ResearchThief.java b/Mage.Sets/src/mage/cards/r/ResearchThief.java new file mode 100644 index 00000000000..b9d96c11c7f --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/ResearchThief.java @@ -0,0 +1,60 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterArtifactCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ResearchThief extends CardImpl { + + private static final FilterPermanent filter + = new FilterArtifactCreaturePermanent("an artifact creature you control"); + + static { + filter.add(TargetController.YOU.getControllerPredicate()); + } + + public ResearchThief(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.MOONFOLK); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever an artifact creature you control deals combat damage to a player, draw a card. + this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility( + new DrawCardSourceControllerEffect(1), + filter, false, SetTargetPointer.NONE, true + )); + } + + private ResearchThief(final ResearchThief card) { + super(card); + } + + @Override + public ResearchThief copy() { + return new ResearchThief(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/ReservoirKraken.java b/Mage.Sets/src/mage/cards/r/ReservoirKraken.java new file mode 100644 index 00000000000..f5d64e50531 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/ReservoirKraken.java @@ -0,0 +1,111 @@ +package mage.cards.r; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.condition.common.SourceTappedCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.keyword.WardAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.FishToken; +import mage.players.Player; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author weirddan455 + */ +public final class ReservoirKraken extends CardImpl { + + public ReservoirKraken(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + + this.subtype.add(SubType.KRAKEN); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Ward {2} + this.addAbility(new WardAbility(new ManaCostsImpl<>("{2}"))); + + // At the beginning of each combat, if Reservoir Kraken is untapped, any opponent may tap an untapped creature they control. If they do, tap Reservoir Kraken and create a 1/1 blue Fish creature token with "This creature can't be blocked." + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new BeginningOfCombatTriggeredAbility(new ReservoirKrakenEffect(), TargetController.ANY, false), + SourceTappedCondition.UNTAPPED, + "At the beginning of each combat, if {this} is untapped, any opponent may tap an untapped creature they control. If they do, tap {this} and create a 1/1 blue Fish creature token with \"This creature can't be blocked.\"" + )); + } + + private ReservoirKraken(final ReservoirKraken card) { + super(card); + } + + @Override + public ReservoirKraken copy() { + return new ReservoirKraken(this); + } +} + +class ReservoirKrakenEffect extends OneShotEffect { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); + + static { + filter.add(TappedPredicate.UNTAPPED); + } + + public ReservoirKrakenEffect() { + super(Outcome.Tap); + this.staticText = "any opponent may tap an untapped creature they control. If they do, tap {this} and create a 1/1 blue Fish creature token with \"This creature can't be blocked.\""; + } + + private ReservoirKrakenEffect(final ReservoirKrakenEffect effect) { + super(effect); + } + + @Override + public ReservoirKrakenEffect copy() { + return new ReservoirKrakenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + boolean opponentTapped = false; + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(1, 1, filter, true); + if (target.canChoose(opponentId, source, game) && opponent.chooseUse(Outcome.AIDontUseIt, "Tap an untapped creature you control?", source, game)) { + opponent.chooseTarget(Outcome.Tap, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null && permanent.tap(source, game)) { + opponentTapped = true; + } + } + } + } + if (opponentTapped) { + Permanent kraken = source.getSourcePermanentIfItStillExists(game); + if (kraken != null) { + kraken.tap(source, game); + } + new FishToken().putOntoBattlefield(1, game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/r/ResoluteStrike.java b/Mage.Sets/src/mage/cards/r/ResoluteStrike.java index df88ff51118..bbe8a6612c3 100644 --- a/Mage.Sets/src/mage/cards/r/ResoluteStrike.java +++ b/Mage.Sets/src/mage/cards/r/ResoluteStrike.java @@ -69,12 +69,12 @@ class ResoluteStrikeEffect extends OneShotEffect { if (player == null || permanent == null || !permanent.hasSubtype(SubType.WARRIOR, game) - || game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) == 0 + || game.getBattlefield().count(filter, source.getControllerId(), source, game) == 0 || !player.chooseUse(outcome, "Attach an equipment you control?", source, game)) { return false; } TargetPermanent targetPermanent = new TargetPermanent(0, 1, filter, true); - player.choose(outcome, targetPermanent, source.getSourceId(), game); + player.choose(outcome, targetPermanent, source, game); return permanent.addAttachment(targetPermanent.getFirstTarget(), source, game); } } diff --git a/Mage.Sets/src/mage/cards/r/ResourcefulReturn.java b/Mage.Sets/src/mage/cards/r/ResourcefulReturn.java index 8bf98ff0a0f..2b9e985c4c5 100644 --- a/Mage.Sets/src/mage/cards/r/ResourcefulReturn.java +++ b/Mage.Sets/src/mage/cards/r/ResourcefulReturn.java @@ -5,6 +5,7 @@ import java.util.UUID; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -23,7 +24,7 @@ public final class ResourcefulReturn extends CardImpl { // Return target creature card from your graveyard to your hand. If you control an artifact, draw a card. this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new DrawCardSourceControllerEffect(1), new PermanentsOnTheBattlefieldCondition(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT), "If you control an artifact, draw a card")); diff --git a/Mage.Sets/src/mage/cards/r/ResplendentMarshal.java b/Mage.Sets/src/mage/cards/r/ResplendentMarshal.java index 29b5272f92c..d7d8188f893 100644 --- a/Mage.Sets/src/mage/cards/r/ResplendentMarshal.java +++ b/Mage.Sets/src/mage/cards/r/ResplendentMarshal.java @@ -89,11 +89,11 @@ class ResplendentMarshalEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Card exiledCard = game.getCard(targetPointer.getFirst(game, source)); if (controller != null && sourceObject != null && exiledCard != null) { for (Permanent permanent : game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, source.getControllerId(), source, game)) { if (permanent.shareCreatureTypes(game, exiledCard)) { permanent.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game); if (!game.isSimulation()) { diff --git a/Mage.Sets/src/mage/cards/r/RestForTheWeary.java b/Mage.Sets/src/mage/cards/r/RestForTheWeary.java index 29833b941c2..0831b7caa70 100644 --- a/Mage.Sets/src/mage/cards/r/RestForTheWeary.java +++ b/Mage.Sets/src/mage/cards/r/RestForTheWeary.java @@ -1,29 +1,34 @@ - package mage.cards.r; -import java.util.UUID; import mage.abilities.condition.common.LandfallCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.GainLifeTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.target.TargetPlayer; import mage.watchers.common.LandfallWatcher; +import java.util.UUID; + /** - * * @author Loki */ public final class RestForTheWeary extends CardImpl { public RestForTheWeary(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); // Target player gains 4 life. // Landfall - If you had a land enter the battlefield under your control this turn, that player gains 8 life instead. this.getSpellAbility().addWatcher(new LandfallWatcher()); - this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new GainLifeTargetEffect(8), new GainLifeTargetEffect(4), LandfallCondition.instance, "Target player gains 4 life.
Landfall - If you had a land enter the battlefield under your control this turn, that player gains 8 life instead")); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new GainLifeTargetEffect(8), new GainLifeTargetEffect(4), + LandfallCondition.instance, "Target player gains 4 life.
" + + AbilityWord.LANDFALL.formatWord() + "If you had a land enter the battlefield " + + "under your control this turn, that player gains 8 life instead" + )); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Sets/src/mage/cards/r/RestorationSpecialist.java b/Mage.Sets/src/mage/cards/r/RestorationSpecialist.java index b7169c83b9a..82f1de4cbb2 100644 --- a/Mage.Sets/src/mage/cards/r/RestorationSpecialist.java +++ b/Mage.Sets/src/mage/cards/r/RestorationSpecialist.java @@ -1,7 +1,6 @@ package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -14,12 +13,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.filter.common.FilterEnchantmentCard; import mage.target.common.TargetCardInGraveyard; +import java.util.UUID; + /** - * * @author Styxo */ public final class RestorationSpecialist extends CardImpl { @@ -36,7 +36,7 @@ public final class RestorationSpecialist extends CardImpl { Effect effect = new ReturnToHandTargetEffect(true); effect.setText("Return up to one target artifact card and up to one target enchantment card from your graveyard to your hand"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{W}")); - ability.addTarget(new TargetCardInGraveyard(0, 1, new FilterArtifactCard("artifact card from your graveyard"))); + ability.addTarget(new TargetCardInGraveyard(0, 1, StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); ability.addTarget(new TargetCardInGraveyard(0, 1, new FilterEnchantmentCard("enchantment card from your graveyard"))); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/r/Retether.java b/Mage.Sets/src/mage/cards/r/Retether.java index 032b1a9ed6c..bdd936f6871 100644 --- a/Mage.Sets/src/mage/cards/r/Retether.java +++ b/Mage.Sets/src/mage/cards/r/Retether.java @@ -74,7 +74,7 @@ class RetetherEffect extends OneShotEffect { if (controller != null) { Map auraMap = new HashMap<>(); auraCardsInGraveyard: - for (Card aura : controller.getGraveyard().getCards(filterAura, source.getSourceId(), source.getControllerId(), game)) { + for (Card aura : controller.getGraveyard().getCards(filterAura, source.getControllerId(), source, game)) { if (aura != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent("creature to enchant (" + aura.getLogName() + ')'); filter.add(new CanBeEnchantedByPredicate(aura)); @@ -100,9 +100,9 @@ class RetetherEffect extends OneShotEffect { if (target != null) { target.getFilter().add(CardType.CREATURE.getPredicate()); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { + if (target.canChoose(controller.getId(), source, game)) { target.setTargetName("creature to enchant (" + aura.getLogName() + ')'); - if (controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCardInPlay, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null && !permanent.cantBeAttachedBy(aura, source, game, true)) { auraMap.put(aura, permanent); diff --git a/Mage.Sets/src/mage/cards/r/RetracedImage.java b/Mage.Sets/src/mage/cards/r/RetracedImage.java index 44a715d73a9..d6450056fdb 100644 --- a/Mage.Sets/src/mage/cards/r/RetracedImage.java +++ b/Mage.Sets/src/mage/cards/r/RetracedImage.java @@ -61,8 +61,8 @@ class RetracedImageEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { TargetCardInHand target = new TargetCardInHand(); - if (target.canChoose(source.getSourceId(), controller.getId(), game) - && controller.choose(outcome, target, source.getSourceId(), game)) { + if (target.canChoose(controller.getId(), source, game) + && controller.choose(outcome, target, source, game)) { Card chosenCard = game.getCard(target.getFirstTarget()); if (chosenCard != null) { Cards cards = new CardsImpl(); diff --git a/Mage.Sets/src/mage/cards/r/RetreatToCoralhelm.java b/Mage.Sets/src/mage/cards/r/RetreatToCoralhelm.java index a2e60f9e9d2..2d4009dfb7f 100644 --- a/Mage.Sets/src/mage/cards/r/RetreatToCoralhelm.java +++ b/Mage.Sets/src/mage/cards/r/RetreatToCoralhelm.java @@ -23,8 +23,7 @@ public final class RetreatToCoralhelm extends CardImpl { // Landfall- Whenever a land enters the battlefield under your control, choose one - You may tap or untap target creature; or Scry 1. LandfallAbility ability = new LandfallAbility(new MayTapOrUntapTargetEffect(), false); ability.addTarget(new TargetCreaturePermanent()); - Mode mode = new Mode(); - mode.addEffect(new ScryEffect(1)); + Mode mode = new Mode(new ScryEffect(1)); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RetreatToEmeria.java b/Mage.Sets/src/mage/cards/r/RetreatToEmeria.java index c9ebf7b9e13..c436a9fda4e 100644 --- a/Mage.Sets/src/mage/cards/r/RetreatToEmeria.java +++ b/Mage.Sets/src/mage/cards/r/RetreatToEmeria.java @@ -23,8 +23,7 @@ public final class RetreatToEmeria extends CardImpl { // Landfall — Whenever a land enters the battlefield under you control, choose one - Create a 1/1 white Kor Ally creature token; or Creatures you control get +1/+1 until end of turn. LandfallAbility ability = new LandfallAbility(new CreateTokenEffect(new KorAllyToken()), false); - Mode mode = new Mode(); - mode.addEffect(new BoostControlledEffect(1, 1, Duration.EndOfTurn)); + Mode mode = new Mode(new BoostControlledEffect(1, 1, Duration.EndOfTurn)); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RetreatToHagra.java b/Mage.Sets/src/mage/cards/r/RetreatToHagra.java index 86f40f2d08c..f93977fbc5f 100644 --- a/Mage.Sets/src/mage/cards/r/RetreatToHagra.java +++ b/Mage.Sets/src/mage/cards/r/RetreatToHagra.java @@ -34,8 +34,7 @@ public final class RetreatToHagra extends CardImpl { ability.addTarget(new TargetCreaturePermanent()); // or Each opponent loses 1 life and you gain 1 life. - Mode mode = new Mode(); - mode.addEffect(new LoseLifeOpponentsEffect(1)); + Mode mode = new Mode(new LoseLifeOpponentsEffect(1)); Effect gainLife = new GainLifeEffect(1); gainLife.setText("and you gain 1 life"); mode.addEffect(gainLife); diff --git a/Mage.Sets/src/mage/cards/r/RetreatToKazandu.java b/Mage.Sets/src/mage/cards/r/RetreatToKazandu.java index 3a3dafae57d..3f863bb4349 100644 --- a/Mage.Sets/src/mage/cards/r/RetreatToKazandu.java +++ b/Mage.Sets/src/mage/cards/r/RetreatToKazandu.java @@ -24,8 +24,7 @@ public final class RetreatToKazandu extends CardImpl { // Landfall-Whenever a land enters the battlefield under your control, choose one - Put a +1/+1 counter on target creature; or You gain 2 life. LandfallAbility ability = new LandfallAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false); ability.addTarget(new TargetCreaturePermanent()); - Mode mode = new Mode(); - mode.addEffect(new GainLifeEffect(2)); + Mode mode = new Mode(new GainLifeEffect(2)); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RetreatToValakut.java b/Mage.Sets/src/mage/cards/r/RetreatToValakut.java index 184525cd90b..b555c17f021 100644 --- a/Mage.Sets/src/mage/cards/r/RetreatToValakut.java +++ b/Mage.Sets/src/mage/cards/r/RetreatToValakut.java @@ -26,8 +26,7 @@ public final class RetreatToValakut extends CardImpl { ability.addTarget(new TargetCreaturePermanent()); // or Target creature can't block this turn. - Mode mode = new Mode(); - mode.addEffect(new CantBlockTargetEffect(Duration.EndOfTurn)); + Mode mode = new Mode(new CantBlockTargetEffect(Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/r/ReturnFromExtinction.java b/Mage.Sets/src/mage/cards/r/ReturnFromExtinction.java index 0714310fd31..7c77ece8f41 100644 --- a/Mage.Sets/src/mage/cards/r/ReturnFromExtinction.java +++ b/Mage.Sets/src/mage/cards/r/ReturnFromExtinction.java @@ -74,8 +74,8 @@ class ReturnFromExtinctionTarget extends TargetCardInYourGraveyard { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - MageObject targetSource = game.getObject(sourceId); + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + MageObject targetSource = game.getObject(source); Player player = game.getPlayer(sourceControllerId); if (player == null) { return false; @@ -84,7 +84,7 @@ class ReturnFromExtinctionTarget extends TargetCardInYourGraveyard { return false; } List cards = player.getGraveyard().getCards( - filter, sourceId, sourceControllerId, game + filter, sourceControllerId, source, game ).stream().collect(Collectors.toList()); if (cards.size() < 2) { return false; diff --git a/Mage.Sets/src/mage/cards/r/ReturnOfTheNightstalkers.java b/Mage.Sets/src/mage/cards/r/ReturnOfTheNightstalkers.java index 20724d3355b..0927aa9552a 100644 --- a/Mage.Sets/src/mage/cards/r/ReturnOfTheNightstalkers.java +++ b/Mage.Sets/src/mage/cards/r/ReturnOfTheNightstalkers.java @@ -68,7 +68,7 @@ class ReturnOfTheNightstalkersEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { controller.moveCards(controller.getGraveyard().getCards(filter1, game), Zone.BATTLEFIELD, source, game); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter2, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter2, source.getControllerId(), source, game)) { permanent.destroy(source, game, false); } return true; diff --git a/Mage.Sets/src/mage/cards/r/ReturnToBattle.java b/Mage.Sets/src/mage/cards/r/ReturnToBattle.java index bb1f5fb8b6f..0542676a8ea 100644 --- a/Mage.Sets/src/mage/cards/r/ReturnToBattle.java +++ b/Mage.Sets/src/mage/cards/r/ReturnToBattle.java @@ -1,16 +1,15 @@ - package mage.cards.r; -import java.util.UUID; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author LoneFox */ public final class ReturnToBattle extends CardImpl { @@ -19,7 +18,7 @@ public final class ReturnToBattle extends CardImpl { 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().addEffect(new ReturnFromGraveyardToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } diff --git a/Mage.Sets/src/mage/cards/r/RevealingWind.java b/Mage.Sets/src/mage/cards/r/RevealingWind.java index a8be10d36c3..ba45e8388f3 100644 --- a/Mage.Sets/src/mage/cards/r/RevealingWind.java +++ b/Mage.Sets/src/mage/cards/r/RevealingWind.java @@ -73,7 +73,7 @@ class RevealingWindEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { - while (game.getBattlefield().count(filter, source.getOriginalId(), source.getControllerId(), game) > 0 && + while (game.getBattlefield().count(filter, source.getControllerId(), source, game) > 0 && controller.chooseUse(outcome, "Look at a face-down attacking creature?", source, game)) { if (!controller.canRespond()) { return false; diff --git a/Mage.Sets/src/mage/cards/r/RevelRuiner.java b/Mage.Sets/src/mage/cards/r/RevelRuiner.java new file mode 100644 index 00000000000..8e1e2109b80 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RevelRuiner.java @@ -0,0 +1,42 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RevelRuiner extends CardImpl { + + public RevelRuiner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.CEPHALID); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Menace + this.addAbility(new MenaceAbility()); + + // When Revel Ruiner enters the battlefield, it connives. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ConniveSourceEffect())); + } + + private RevelRuiner(final RevelRuiner card) { + super(card); + } + + @Override + public RevelRuiner copy() { + return new RevelRuiner(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RevelationOfPower.java b/Mage.Sets/src/mage/cards/r/RevelationOfPower.java new file mode 100644 index 00000000000..6c8a400291e --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RevelationOfPower.java @@ -0,0 +1,75 @@ +package mage.cards.r; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.Counter; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author weirddan455 + */ +public final class RevelationOfPower extends CardImpl { + + public RevelationOfPower(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + // Target creature gets +2/+2 until end of turn. If it has a counter on it, it also gains flying and lifelink until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2)); + this.getSpellAbility().addEffect(new RevelationOfPowerEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private RevelationOfPower(final RevelationOfPower card) { + super(card); + } + + @Override + public RevelationOfPower copy() { + return new RevelationOfPower(this); + } +} + +class RevelationOfPowerEffect extends OneShotEffect { + + public RevelationOfPowerEffect() { + super(Outcome.BoostCreature); + this.staticText = "If it has a counter on it, it also gains flying and lifelink until end of turn"; + } + + private RevelationOfPowerEffect(final RevelationOfPowerEffect effect) { + super(effect); + } + + @Override + public RevelationOfPowerEffect copy() { + return new RevelationOfPowerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent targetCreature = game.getPermanent(source.getFirstTarget()); + if (targetCreature != null) { + for (Counter counter : targetCreature.getCounters(game).values()) { + if (counter.getCount() > 0) { + game.addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance()), source); + game.addEffect(new GainAbilityTargetEffect(LifelinkAbility.getInstance()), source); + return true; + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RevelsongHorn.java b/Mage.Sets/src/mage/cards/r/RevelsongHorn.java index 4850edd4586..f93ecca0dd0 100644 --- a/Mage.Sets/src/mage/cards/r/RevelsongHorn.java +++ b/Mage.Sets/src/mage/cards/r/RevelsongHorn.java @@ -1,35 +1,43 @@ - package mage.cards.r; -import java.util.UUID; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapTargetCost; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Zone; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class RevelsongHorn extends CardImpl { + private static final FilterControlledPermanent filter + = new FilterControlledCreaturePermanent("an untapped creature you control"); + + static { + filter.add(TappedPredicate.UNTAPPED); + } + public RevelsongHorn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // {1}, {tap}, Tap an untapped creature you control: Target creature gets +1/+1 until end of turn. - SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new BoostTargetEffect(1, 1, Duration.EndOfTurn), - new ManaCostsImpl("{1}")); + SimpleActivatedAbility ability = new SimpleActivatedAbility( + new BoostTargetEffect(1, 1, Duration.EndOfTurn), new GenericManaCost(1) + ); ability.addCost(new TapSourceCost()); - ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent())); + ability.addCost(new TapTargetCost(new TargetControlledPermanent(filter))); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RevengeOfTheDrowned.java b/Mage.Sets/src/mage/cards/r/RevengeOfTheDrowned.java index 0187a86e455..c33b254f0a3 100644 --- a/Mage.Sets/src/mage/cards/r/RevengeOfTheDrowned.java +++ b/Mage.Sets/src/mage/cards/r/RevengeOfTheDrowned.java @@ -1,16 +1,11 @@ package mage.cards.r; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.game.Game; import mage.game.permanent.token.ZombieDecayedToken; -import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -24,7 +19,9 @@ public final class RevengeOfTheDrowned extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}"); // Target creature's owner puts it on the top or bottom of their library. You create a 2/2 black Zombie creature token with decayed. - this.getSpellAbility().addEffect(new RevengeOfTheDrownedEffect()); + this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect( + "target creature's owner puts it on the top or bottom of their library" + )); this.getSpellAbility().addEffect(new CreateTokenEffect(new ZombieDecayedToken()).concatBy("You")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } @@ -38,33 +35,3 @@ public final class RevengeOfTheDrowned extends CardImpl { return new RevengeOfTheDrowned(this); } } - -class RevengeOfTheDrownedEffect extends OneShotEffect { - - RevengeOfTheDrownedEffect() { - super(Outcome.Benefit); - staticText = "target creature's owner puts it on the top or bottom of their library."; - } - - private RevengeOfTheDrownedEffect(final RevengeOfTheDrownedEffect effect) { - super(effect); - } - - @Override - public RevengeOfTheDrownedEffect copy() { - return new RevengeOfTheDrownedEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget())); - if (player == null) { - return false; - } - if (player.chooseUse(Outcome.Detriment, "Put the targeted object on the top or bottom of your library?", - "", "Top", "Bottom", source, game)) { - return new PutOnLibraryTargetEffect(true).apply(game, source); - } - return new PutOnLibraryTargetEffect(false).apply(game, source); - } -} diff --git a/Mage.Sets/src/mage/cards/r/ReverentMantra.java b/Mage.Sets/src/mage/cards/r/ReverentMantra.java index d04cef231f5..4b2911d55dc 100644 --- a/Mage.Sets/src/mage/cards/r/ReverentMantra.java +++ b/Mage.Sets/src/mage/cards/r/ReverentMantra.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.costs.AlternativeCostSourceAbility; import mage.abilities.costs.common.ExileFromHandCost; @@ -10,31 +8,35 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterOwnedCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetCardInHand; +import java.util.UUID; + /** - * * @author ciaccona007 */ public final class ReverentMantra extends CardImpl { + private static final FilterOwnedCard filter + = new FilterOwnedCard("a white card from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + } + public ReverentMantra(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{W}"); // You may exile a white card from your hand rather than pay Reverent Mantra's mana cost. - FilterOwnedCard filter = new FilterOwnedCard("a white card from your hand"); - filter.add(new ColorPredicate(ObjectColor.WHITE)); - filter.add(Predicates.not(new CardIdPredicate(this.getId()))); - this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter)))); // Choose a color. All creatures gain protection from the chosen color until end of turn. - this.getSpellAbility().addEffect(new GainProtectionFromColorAllEffect(Duration.EndOfTurn, new FilterCreaturePermanent())); + this.getSpellAbility().addEffect(new GainProtectionFromColorAllEffect( + Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE + )); } private ReverentMantra(final ReverentMantra card) { diff --git a/Mage.Sets/src/mage/cards/r/ReverseDamage.java b/Mage.Sets/src/mage/cards/r/ReverseDamage.java index a42cb61cb1c..ab33be4df54 100644 --- a/Mage.Sets/src/mage/cards/r/ReverseDamage.java +++ b/Mage.Sets/src/mage/cards/r/ReverseDamage.java @@ -66,7 +66,7 @@ class ReverseDamageEffect extends PreventionEffectImpl { @Override public void init(Ability source, Game game) { - this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/r/RevivalExperiment.java b/Mage.Sets/src/mage/cards/r/RevivalExperiment.java index 86c35f7b9ca..6d40642a533 100644 --- a/Mage.Sets/src/mage/cards/r/RevivalExperiment.java +++ b/Mage.Sets/src/mage/cards/r/RevivalExperiment.java @@ -64,7 +64,7 @@ class RevivalExperimentEffect extends OneShotEffect { return false; } RevivalExperimentTarget target = new RevivalExperimentTarget(); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Cards cards = new CardsImpl(target.getTargets()); player.moveCards(cards, Zone.BATTLEFIELD, source, game); int toBattlefield = cards @@ -118,8 +118,8 @@ class RevivalExperimentTarget extends TargetCardInYourGraveyard { @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set possibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, null, game)); return possibleTargets; } diff --git a/Mage.Sets/src/mage/cards/r/Revive.java b/Mage.Sets/src/mage/cards/r/Revive.java index ca688b5b711..8da6a39d65c 100644 --- a/Mage.Sets/src/mage/cards/r/Revive.java +++ b/Mage.Sets/src/mage/cards/r/Revive.java @@ -1,9 +1,7 @@ - package mage.cards.r; -import java.util.UUID; import mage.ObjectColor; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -11,8 +9,9 @@ import mage.filter.FilterCard; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author North */ public final class Revive extends CardImpl { @@ -24,11 +23,10 @@ public final class Revive extends CardImpl { } public Revive(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{G}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); // Return target green card from your graveyard to your hand. - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); } diff --git a/Mage.Sets/src/mage/cards/r/Revivify.java b/Mage.Sets/src/mage/cards/r/Revivify.java index 7fbf9505243..f96dd2e74bb 100644 --- a/Mage.Sets/src/mage/cards/r/Revivify.java +++ b/Mage.Sets/src/mage/cards/r/Revivify.java @@ -93,7 +93,7 @@ class RevivifyEffect extends OneShotEffect { return false; } return player.moveCards(player.getGraveyard().getCards( - Revivify.filter, source.getSourceId(), source.getControllerId(), game + Revivify.filter, source.getControllerId(), source, game ), toHand ? Zone.HAND : Zone.BATTLEFIELD, source, game); } } diff --git a/Mage.Sets/src/mage/cards/r/RevivingMelody.java b/Mage.Sets/src/mage/cards/r/RevivingMelody.java index 5bd803499a4..1dc672d54f4 100644 --- a/Mage.Sets/src/mage/cards/r/RevivingMelody.java +++ b/Mage.Sets/src/mage/cards/r/RevivingMelody.java @@ -33,8 +33,7 @@ public final class RevivingMelody extends CardImpl { this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD).withChooseHint("return to hand")); // and/or return target enchantment card from your graveyard to your hand. - Mode mode = new Mode(); - mode.addEffect(new ReturnFromGraveyardToHandTargetEffect()); + Mode mode = new Mode(new ReturnFromGraveyardToHandTargetEffect()); mode.addTarget(new TargetCardInYourGraveyard(filterCard).withChooseHint("return to hand")); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/r/RevivingVapors.java b/Mage.Sets/src/mage/cards/r/RevivingVapors.java index 8acd1dcc264..991d8a7393d 100644 --- a/Mage.Sets/src/mage/cards/r/RevivingVapors.java +++ b/Mage.Sets/src/mage/cards/r/RevivingVapors.java @@ -50,7 +50,7 @@ class RevivingVaporsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/r/RevokePrivileges.java b/Mage.Sets/src/mage/cards/r/RevokePrivileges.java index baf51e77fd8..b92a7095d47 100644 --- a/Mage.Sets/src/mage/cards/r/RevokePrivileges.java +++ b/Mage.Sets/src/mage/cards/r/RevokePrivileges.java @@ -79,7 +79,7 @@ class RevokePrivilegeCantCrewEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "The creature enchanted by " + mageObject.getIdName() + " can't crew vehicles."; } diff --git a/Mage.Sets/src/mage/cards/r/Revolutionist.java b/Mage.Sets/src/mage/cards/r/Revolutionist.java index 9fb5d4e2a0d..33c8d83dd80 100644 --- a/Mage.Sets/src/mage/cards/r/Revolutionist.java +++ b/Mage.Sets/src/mage/cards/r/Revolutionist.java @@ -34,7 +34,7 @@ public final class Revolutionist extends CardImpl { this.addAbility(ability); // Madness {3}{R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{3}{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{3}{R}"))); } private Revolutionist(final Revolutionist card) { diff --git a/Mage.Sets/src/mage/cards/r/RhonasTheIndomitable.java b/Mage.Sets/src/mage/cards/r/RhonasTheIndomitable.java index a815713ed79..de02aa6eab3 100644 --- a/Mage.Sets/src/mage/cards/r/RhonasTheIndomitable.java +++ b/Mage.Sets/src/mage/cards/r/RhonasTheIndomitable.java @@ -109,7 +109,7 @@ class RhonasTheIndomitableRestrictionEffect extends RestrictionEffect { if (permanent.getId().equals(source.getSourceId())) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - int permanentsOnBattlefield = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int permanentsOnBattlefield = game.getBattlefield().count(filter, source.getControllerId(), source, game); return permanentsOnBattlefield < 1; // is this correct? } return true; diff --git a/Mage.Sets/src/mage/cards/r/RhoxPummeler.java b/Mage.Sets/src/mage/cards/r/RhoxPummeler.java new file mode 100644 index 00000000000..b143a41ecb0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RhoxPummeler.java @@ -0,0 +1,57 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RhoxPummeler extends CardImpl { + + private static final Condition condition = new SourceHasCounterCondition(CounterType.SHIELD); + + public RhoxPummeler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}"); + + this.subtype.add(SubType.RHINO); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(6); + this.toughness = new MageInt(3); + + // Rhox Pummeler enters the battlefield with a shield counter on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.SHIELD.createInstance(1)), + "with a shield counter on it. (If it would be dealt damage " + + "or destroyed, remove a shield counter from it instead.)" + )); + + // As long as Rhox Pummeler has a shield counter on it, it has trample. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(TrampleAbility.getInstance()), condition, + "{this} has trample as long as it has a shield counter on it" + ))); + } + + private RhoxPummeler(final RhoxPummeler card) { + super(card); + } + + @Override + public RhoxPummeler copy() { + return new RhoxPummeler(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RhysTheRedeemed.java b/Mage.Sets/src/mage/cards/r/RhysTheRedeemed.java index e69082506b1..8fc6510a2fc 100644 --- a/Mage.Sets/src/mage/cards/r/RhysTheRedeemed.java +++ b/Mage.Sets/src/mage/cards/r/RhysTheRedeemed.java @@ -1,4 +1,3 @@ - package mage.cards.r; import java.util.UUID; @@ -22,7 +21,7 @@ import mage.filter.FilterPermanent; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.permanent.token.RhysTheRedeemedToken; +import mage.game.permanent.token.GreenWhiteElfWarriorToken; import mage.players.Player; import mage.target.targetpointer.FixedTarget; @@ -42,7 +41,7 @@ public final class RhysTheRedeemed extends CardImpl { this.toughness = new MageInt(1); // {2}{GW}, {tap}: Create a 1/1 green and white Elf Warrior creature token. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new RhysTheRedeemedToken()), new ManaCostsImpl("{2}{G/W}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new GreenWhiteElfWarriorToken()), new ManaCostsImpl("{2}{G/W}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/r/RhysticScrying.java b/Mage.Sets/src/mage/cards/r/RhysticScrying.java index 79416b8666b..81db3e71340 100644 --- a/Mage.Sets/src/mage/cards/r/RhysticScrying.java +++ b/Mage.Sets/src/mage/cards/r/RhysticScrying.java @@ -52,7 +52,7 @@ class RhysticScryingEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { boolean result = true; boolean doEffect = false; diff --git a/Mage.Sets/src/mage/cards/r/RhysticStudy.java b/Mage.Sets/src/mage/cards/r/RhysticStudy.java index 53cea2e790d..2a8db1310f4 100644 --- a/Mage.Sets/src/mage/cards/r/RhysticStudy.java +++ b/Mage.Sets/src/mage/cards/r/RhysticStudy.java @@ -27,7 +27,7 @@ public final class RhysticStudy extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); // Whenever an opponent casts a spell, you may draw a card unless that player pays {1}. - this.addAbility(new SpellCastOpponentTriggeredAbility(Zone.BATTLEFIELD, new RhysticStudyDrawEffect(), StaticFilters.FILTER_SPELL, false, SetTargetPointer.PLAYER)); + this.addAbility(new SpellCastOpponentTriggeredAbility(Zone.BATTLEFIELD, new RhysticStudyDrawEffect(), StaticFilters.FILTER_SPELL_A, false, SetTargetPointer.PLAYER)); } private RhysticStudy(final RhysticStudy card) { diff --git a/Mage.Sets/src/mage/cards/r/RickSteadfastLeader.java b/Mage.Sets/src/mage/cards/r/RickSteadfastLeader.java index f7ae7f7d533..c2c695c1ce7 100644 --- a/Mage.Sets/src/mage/cards/r/RickSteadfastLeader.java +++ b/Mage.Sets/src/mage/cards/r/RickSteadfastLeader.java @@ -160,7 +160,7 @@ class RickSteadfastLeaderGainEffect extends ContinuousEffectImpl { return false; } for (Permanent permanent : game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game )) { if (permanent == null) { continue; diff --git a/Mage.Sets/src/mage/cards/r/Ricochet.java b/Mage.Sets/src/mage/cards/r/Ricochet.java index 029f4e5d193..fb9eddf9e45 100644 --- a/Mage.Sets/src/mage/cards/r/Ricochet.java +++ b/Mage.Sets/src/mage/cards/r/Ricochet.java @@ -142,7 +142,7 @@ class RicochetEffect extends OneShotEffect { target.clearChosen(); target.addTarget(loserId, sourceAbility, game); } - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (oldTargetName != null && sourceObject != null) { game.informPlayers(sourceObject.getLogName() + ": Changed target of " + spell.getLogName() + " from " + oldTargetName + " to " + loser.getLogName()); } diff --git a/Mage.Sets/src/mage/cards/r/Riddlesmith.java b/Mage.Sets/src/mage/cards/r/Riddlesmith.java index 87f35b3b36e..e5eb409d956 100644 --- a/Mage.Sets/src/mage/cards/r/Riddlesmith.java +++ b/Mage.Sets/src/mage/cards/r/Riddlesmith.java @@ -1,8 +1,5 @@ - - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.common.DrawDiscardControllerEffect; @@ -10,15 +7,20 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterSpell; import mage.filter.common.FilterArtifactSpell; +import java.util.UUID; + /** - * * @author Loki, North */ public final class Riddlesmith extends CardImpl { - public Riddlesmith (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + + private static final FilterSpell filter = new FilterArtifactSpell("an artifact spell"); + + public Riddlesmith(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ARTIFICER); @@ -26,10 +28,12 @@ public final class Riddlesmith extends CardImpl { this.toughness = new MageInt(1); // Whenever you cast an artifact spell, you may draw a card. If you do, discard a card. - this.addAbility(new SpellCastControllerTriggeredAbility(new DrawDiscardControllerEffect(), new FilterArtifactSpell("an artifact spell"), true)); + this.addAbility(new SpellCastControllerTriggeredAbility( + new DrawDiscardControllerEffect(true), filter, false + )); } - public Riddlesmith (final Riddlesmith card) { + public Riddlesmith(final Riddlesmith card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/r/RiftElemental.java b/Mage.Sets/src/mage/cards/r/RiftElemental.java index 54d4307e2d6..cf460ebcf39 100644 --- a/Mage.Sets/src/mage/cards/r/RiftElemental.java +++ b/Mage.Sets/src/mage/cards/r/RiftElemental.java @@ -78,7 +78,7 @@ class RiftElementalCost extends CostImpl { Player controller = game.getPlayer(controllerId); if (controller != null) { Target target = new TargetPermanentOrSuspendedCard(filter, true); - if (target.choose(Outcome.Neutral, controllerId, source.getSourceId(), game)) { + if (target.choose(Outcome.Neutral, controllerId, source.getSourceId(), source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.removeCounters(CounterType.TIME.createInstance(), source, game); @@ -99,7 +99,7 @@ class RiftElementalCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { Target target = new TargetPermanentOrSuspendedCard(filter, true); - return target.canChoose(source.getSourceId(), controllerId, game); + return target.canChoose(controllerId, source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/r/RighteousConfluence.java b/Mage.Sets/src/mage/cards/r/RighteousConfluence.java index 0f2de271fb4..f3cceaa4c5c 100644 --- a/Mage.Sets/src/mage/cards/r/RighteousConfluence.java +++ b/Mage.Sets/src/mage/cards/r/RighteousConfluence.java @@ -30,14 +30,12 @@ public final class RighteousConfluence extends CardImpl { this.getSpellAbility().addEffect(new CreateTokenEffect(new KnightToken())); // - Exile target enchantment; - Mode mode = new Mode(); - mode.addEffect(new ExileTargetEffect()); + Mode mode = new Mode(new ExileTargetEffect()); mode.addTarget(new TargetEnchantmentPermanent()); this.getSpellAbility().getModes().addMode(mode); // You gain 5 life; - mode = new Mode(); - mode.addEffect(new GainLifeEffect(5)); + mode = new Mode(new GainLifeEffect(5)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/r/RigoStreetwiseMentor.java b/Mage.Sets/src/mage/cards/r/RigoStreetwiseMentor.java new file mode 100644 index 00000000000..21ba8c9c514 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RigoStreetwiseMentor.java @@ -0,0 +1,94 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +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.SuperType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.DefenderAttackedEvent; +import mage.game.events.GameEvent; + +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RigoStreetwiseMentor extends CardImpl { + + public RigoStreetwiseMentor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G/W}{W}{W/U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Rigo, Streetwise Mentor enters the battlefield with a shield counter on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.SHIELD.createInstance(1)), + "with a shield counter on it. (If it would be dealt damage " + + "or destroyed, remove a shield counter from it instead.)" + )); + + // Whenever you attack a player or planeswalker with one or more creatures with power 1 or less, draw a card. + this.addAbility(new RigoStreetwiseMentorTriggeredAbility()); + } + + private RigoStreetwiseMentor(final RigoStreetwiseMentor card) { + super(card); + } + + @Override + public RigoStreetwiseMentor copy() { + return new RigoStreetwiseMentor(this); + } +} + +class RigoStreetwiseMentorTriggeredAbility extends TriggeredAbilityImpl { + + RigoStreetwiseMentorTriggeredAbility() { + super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), false); + } + + private RigoStreetwiseMentorTriggeredAbility(final RigoStreetwiseMentorTriggeredAbility ability) { + super(ability); + } + + @Override + public RigoStreetwiseMentorTriggeredAbility copy() { + return new RigoStreetwiseMentorTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DEFENDER_ATTACKED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return isControlledBy(event.getPlayerId()) + && ((DefenderAttackedEvent) event) + .getAttackers(game) + .stream() + .filter(Objects::nonNull) + .map(MageObject::getPower) + .mapToInt(MageInt::getValue) + .anyMatch(x -> x <= 1); + } + + @Override + public String getRule() { + return "Whenever you attack a player or planeswalker with one or more creatures with power 1 or less, draw a card."; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RimefeatherOwl.java b/Mage.Sets/src/mage/cards/r/RimefeatherOwl.java index 1fccc2e57a6..0f795093590 100644 --- a/Mage.Sets/src/mage/cards/r/RimefeatherOwl.java +++ b/Mage.Sets/src/mage/cards/r/RimefeatherOwl.java @@ -102,7 +102,7 @@ class RimefeatherOwlEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanent.addSuperType(SuperType.SNOW); } diff --git a/Mage.Sets/src/mage/cards/r/RiptideBiologist.java b/Mage.Sets/src/mage/cards/r/RiptideBiologist.java index 827fe7c2bbd..515ac8e8f06 100644 --- a/Mage.Sets/src/mage/cards/r/RiptideBiologist.java +++ b/Mage.Sets/src/mage/cards/r/RiptideBiologist.java @@ -34,7 +34,7 @@ public final class RiptideBiologist extends CardImpl { // Protection from Beasts this.addAbility(new ProtectionAbility(filter)); // Morph {2}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{U}"))); } private RiptideBiologist(final RiptideBiologist card) { diff --git a/Mage.Sets/src/mage/cards/r/RiptideChronologist.java b/Mage.Sets/src/mage/cards/r/RiptideChronologist.java index 9500cf03bbe..e3d73ab0105 100644 --- a/Mage.Sets/src/mage/cards/r/RiptideChronologist.java +++ b/Mage.Sets/src/mage/cards/r/RiptideChronologist.java @@ -64,7 +64,7 @@ class RiptideChronologistEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (player != null && sourceObject != null) { Choice typeChoice = new ChoiceCreatureType(sourceObject); if (player.choose(outcome, typeChoice, game)) { diff --git a/Mage.Sets/src/mage/cards/r/RiptideEntrancer.java b/Mage.Sets/src/mage/cards/r/RiptideEntrancer.java index c6833b81154..674c026fb72 100644 --- a/Mage.Sets/src/mage/cards/r/RiptideEntrancer.java +++ b/Mage.Sets/src/mage/cards/r/RiptideEntrancer.java @@ -39,7 +39,7 @@ public final class RiptideEntrancer extends CardImpl { this.addAbility(new RiptideEntrancerTriggeredAbility()); // Morph {U}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{U}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{U}{U}"))); } private RiptideEntrancer(final RiptideEntrancer card) { diff --git a/Mage.Sets/src/mage/cards/r/RiptidePilferer.java b/Mage.Sets/src/mage/cards/r/RiptidePilferer.java index 70e692d1758..4fd1669cc6d 100644 --- a/Mage.Sets/src/mage/cards/r/RiptidePilferer.java +++ b/Mage.Sets/src/mage/cards/r/RiptidePilferer.java @@ -27,7 +27,7 @@ public final class RiptidePilferer extends CardImpl { // Whenever Riptide Pilferer deals combat damage to a player, that player discards a card. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DiscardTargetEffect(1), false, true)); // Morph {U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{U}"))); } private RiptidePilferer(final RiptidePilferer card) { diff --git a/Mage.Sets/src/mage/cards/r/RiptideReplicator.java b/Mage.Sets/src/mage/cards/r/RiptideReplicator.java index 6c65fbb081d..54f86efbcc9 100644 --- a/Mage.Sets/src/mage/cards/r/RiptideReplicator.java +++ b/Mage.Sets/src/mage/cards/r/RiptideReplicator.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; @@ -23,10 +21,10 @@ import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.token.RiptideReplicatorToken; -import mage.game.permanent.token.Token; + +import java.util.UUID; /** - * * @author HanClinto */ public final class RiptideReplicator extends CardImpl { @@ -80,11 +78,10 @@ class RiptideReplicatorEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { ObjectColor color = (ObjectColor) game.getState().getValue(source.getSourceId() + "_color"); SubType subType = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game); - if (subType == null) { + if (subType == null || color == null) { return false; } int x = (new CountersSourceCount(CounterType.CHARGE)).calculate(game, source, this); - Token token = new RiptideReplicatorToken(color, subType, x); - return token.putOntoBattlefield(1, game, source, source.getControllerId()); + return new RiptideReplicatorToken(color, subType, x).putOntoBattlefield(1, game, source, source.getControllerId()); } } diff --git a/Mage.Sets/src/mage/cards/r/RiptideSurvivor.java b/Mage.Sets/src/mage/cards/r/RiptideSurvivor.java index dd7a114bbf9..b7d8b365f74 100644 --- a/Mage.Sets/src/mage/cards/r/RiptideSurvivor.java +++ b/Mage.Sets/src/mage/cards/r/RiptideSurvivor.java @@ -30,7 +30,7 @@ public final class RiptideSurvivor extends CardImpl { this.toughness = new MageInt(1); // Morph {1}{U}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{U}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{U}{U}"))); // When Riptide Survivor is turned face up, discard two cards, then draw three cards. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new DiscardControllerEffect(2)); Effect effect = new DrawCardSourceControllerEffect(3); diff --git a/Mage.Sets/src/mage/cards/r/RiseAndShine.java b/Mage.Sets/src/mage/cards/r/RiseAndShine.java index a1606fa21e7..8b34210af9e 100644 --- a/Mage.Sets/src/mage/cards/r/RiseAndShine.java +++ b/Mage.Sets/src/mage/cards/r/RiseAndShine.java @@ -83,7 +83,7 @@ class RiseAndShineEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { List permanents = game.getBattlefield().getActivePermanents( - RiseAndShine.filter, source.getControllerId(), source.getSourceId(), game + RiseAndShine.filter, source.getControllerId(), source, game ); if (permanents.isEmpty()) { return false; diff --git a/Mage.Sets/src/mage/cards/r/RiseFall.java b/Mage.Sets/src/mage/cards/r/RiseFall.java index 9ee4135c3a8..0adf51a8418 100644 --- a/Mage.Sets/src/mage/cards/r/RiseFall.java +++ b/Mage.Sets/src/mage/cards/r/RiseFall.java @@ -107,7 +107,7 @@ class FallEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/r/RisenExecutioner.java b/Mage.Sets/src/mage/cards/r/RisenExecutioner.java index d18787d5d02..bb68af55bc5 100644 --- a/Mage.Sets/src/mage/cards/r/RisenExecutioner.java +++ b/Mage.Sets/src/mage/cards/r/RisenExecutioner.java @@ -15,7 +15,7 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; import mage.game.stack.Spell; import mage.players.Player; @@ -104,7 +104,7 @@ class RisenExecutionerCostIncreasingEffect extends CostModificationEffectImpl { protected static final FilterCreatureCard filter = new FilterCreatureCard(); static { - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); } RisenExecutionerCostIncreasingEffect() { @@ -120,7 +120,7 @@ class RisenExecutionerCostIncreasingEffect extends CostModificationEffectImpl { public boolean apply(Game game, Ability source, Ability abilityToModify) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - CardUtil.increaseCost(abilityToModify, controller.getGraveyard().count(filter, source.getSourceId(), source.getControllerId(), game)); + CardUtil.increaseCost(abilityToModify, controller.getGraveyard().count(filter, source.getControllerId(), source, game)); } return true; } diff --git a/Mage.Sets/src/mage/cards/r/RishkarPeemaRenegade.java b/Mage.Sets/src/mage/cards/r/RishkarPeemaRenegade.java index 963bb2ccd04..4666bc3d435 100644 --- a/Mage.Sets/src/mage/cards/r/RishkarPeemaRenegade.java +++ b/Mage.Sets/src/mage/cards/r/RishkarPeemaRenegade.java @@ -43,7 +43,7 @@ public final class RishkarPeemaRenegade extends CardImpl { // When Rishkar, Peema Renegade enters the battlefield, put a +1/+1 counter on each of up to two target creatures. Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); - effect.setText("Put a +1/+1 counter on each of up to two target creatures"); + effect.setText("put a +1/+1 counter on each of up to two target creatures"); Ability ability = new EntersBattlefieldTriggeredAbility(effect, false); ability.addTarget(new TargetCreaturePermanent(0, 2)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/r/RishkarsExpertise.java b/Mage.Sets/src/mage/cards/r/RishkarsExpertise.java index 1db510524f0..e2635e62af7 100644 --- a/Mage.Sets/src/mage/cards/r/RishkarsExpertise.java +++ b/Mage.Sets/src/mage/cards/r/RishkarsExpertise.java @@ -1,20 +1,29 @@ - package mage.cards.r; -import java.util.UUID; import mage.abilities.dynamicvalue.common.GreatestPowerAmongControlledCreaturesValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect; +import mage.abilities.effects.common.cost.CastFromHandForFreeEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; + +import java.util.UUID; /** * @author fireshoes */ public final class RishkarsExpertise extends CardImpl { + private static final FilterCard filter = new FilterCard("a spell with mana value 5 or less"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 6)); + } + public RishkarsExpertise(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}{G}"); @@ -24,7 +33,7 @@ public final class RishkarsExpertise extends CardImpl { this.getSpellAbility().addEffect(effect); // You may cast a card with converted mana cost 5 or less from your hand without paying its mana cost. - this.getSpellAbility().addEffect(new CastWithoutPayingManaCostEffect(5).concatBy("
")); + this.getSpellAbility().addEffect(new CastFromHandForFreeEffect(filter).concatBy("
")); } private RishkarsExpertise(final RishkarsExpertise card) { diff --git a/Mage.Sets/src/mage/cards/r/RiskyMove.java b/Mage.Sets/src/mage/cards/r/RiskyMove.java index c6769da6b51..3717d1a1950 100644 --- a/Mage.Sets/src/mage/cards/r/RiskyMove.java +++ b/Mage.Sets/src/mage/cards/r/RiskyMove.java @@ -152,16 +152,16 @@ class RiskyMoveFlipCoinEffect extends OneShotEffect { Target target1 = new TargetControlledCreaturePermanent(1, 1, new FilterControlledCreaturePermanent(), true); Target target2 = new TargetOpponent(true); - if (target1.canChoose(source.getSourceId(), controller.getId(), game)) { + if (target1.canChoose(controller.getId(), source, game)) { while (!target1.isChosen() - && target1.canChoose(source.getSourceId(), controller.getId(), game) + && target1.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target1, source, game); } } - if (target2.canChoose(source.getSourceId(), controller.getId(), game)) { + if (target2.canChoose(controller.getId(), source, game)) { while (!target2.isChosen() - && target2.canChoose(source.getSourceId(), controller.getId(), game) + && target2.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target2, source, game); } diff --git a/Mage.Sets/src/mage/cards/r/RiteOfHarmony.java b/Mage.Sets/src/mage/cards/r/RiteOfHarmony.java index d5e5db6d7c5..94a6543cfe1 100644 --- a/Mage.Sets/src/mage/cards/r/RiteOfHarmony.java +++ b/Mage.Sets/src/mage/cards/r/RiteOfHarmony.java @@ -9,7 +9,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.TimingRule; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.game.Game; @@ -72,7 +71,7 @@ class RiteOfHarmonyTriggeredAbility extends DelayedTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { UUID targetId = event.getTargetId(); Permanent permanent = game.getPermanent(targetId); - return filter.match(permanent, getSourceId(), getControllerId(), game); + return filter.match(permanent, getControllerId(), this, game); } @Override diff --git a/Mage.Sets/src/mage/cards/r/RiteOfPassage.java b/Mage.Sets/src/mage/cards/r/RiteOfPassage.java index e4b6f9b6c8a..01ac2560174 100644 --- a/Mage.Sets/src/mage/cards/r/RiteOfPassage.java +++ b/Mage.Sets/src/mage/cards/r/RiteOfPassage.java @@ -13,7 +13,6 @@ import mage.counters.CounterType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; @@ -69,7 +68,7 @@ class RiteOfPassageTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { UUID targetId = event.getTargetId(); Permanent permanent = game.getPermanent(targetId); - if (permanent != null && filter.match(permanent, getSourceId(), getControllerId(), game)) { + if (permanent != null && filter.match(permanent, getControllerId(), this, game)) { getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); return true; } diff --git a/Mage.Sets/src/mage/cards/r/RithTheAwakener.java b/Mage.Sets/src/mage/cards/r/RithTheAwakener.java index f514b727bc9..635069f0016 100644 --- a/Mage.Sets/src/mage/cards/r/RithTheAwakener.java +++ b/Mage.Sets/src/mage/cards/r/RithTheAwakener.java @@ -81,7 +81,7 @@ class RithTheAwakenerEffect extends OneShotEffect { game.informPlayers(controller.getLogName() + " chooses " + choice.getColor()); FilterPermanent filter = new FilterPermanent(); filter.add(new ColorPredicate(choice.getColor())); - int cardsWithColor = game.getBattlefield().count(filter, source.getSourceId(), controller.getId(), game); + int cardsWithColor = game.getBattlefield().count(filter, controller.getId(), source, game); if (cardsWithColor > 0) { new CreateTokenEffect(new SaprolingToken(), cardsWithColor).apply(game, source); } diff --git a/Mage.Sets/src/mage/cards/r/RithsCharm.java b/Mage.Sets/src/mage/cards/r/RithsCharm.java index 6f6c5670a26..fb2454ef123 100644 --- a/Mage.Sets/src/mage/cards/r/RithsCharm.java +++ b/Mage.Sets/src/mage/cards/r/RithsCharm.java @@ -26,13 +26,11 @@ public final class RithsCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetNonBasicLandPermanent()); // or create three 1/1 green Saproling creature tokens; - Mode mode = new Mode(); - mode.addEffect(new CreateTokenEffect(new SaprolingToken(), 3)); + Mode mode = new Mode(new CreateTokenEffect(new SaprolingToken(), 3)); this.getSpellAbility().addMode(mode); // or prevent all damage a source of your choice would deal this turn. - mode = new Mode(); - mode.addEffect(new PreventDamageBySourceEffect()); + mode = new Mode(new PreventDamageBySourceEffect()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/r/RitualOfRestoration.java b/Mage.Sets/src/mage/cards/r/RitualOfRestoration.java index ddf4a863eb4..bdcfa028243 100644 --- a/Mage.Sets/src/mage/cards/r/RitualOfRestoration.java +++ b/Mage.Sets/src/mage/cards/r/RitualOfRestoration.java @@ -1,26 +1,25 @@ - package mage.cards.r; -import java.util.UUID; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class RitualOfRestoration extends CardImpl { public RitualOfRestoration(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{W}"); // Return target artifact card from your graveyard to your hand. - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); } private RitualOfRestoration(final RitualOfRestoration card) { diff --git a/Mage.Sets/src/mage/cards/r/RiverKelpie.java b/Mage.Sets/src/mage/cards/r/RiverKelpie.java index e8d136a1dd7..84fce32de15 100644 --- a/Mage.Sets/src/mage/cards/r/RiverKelpie.java +++ b/Mage.Sets/src/mage/cards/r/RiverKelpie.java @@ -76,7 +76,7 @@ class RiverKelpieTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever {this} or another permanent is put onto the battlefield from a graveyard, draw a card."; + return "Whenever {this} or another permanent enters the battlefield from a graveyard, draw a card."; } } diff --git a/Mage.Sets/src/mage/cards/r/RiverfallMimic.java b/Mage.Sets/src/mage/cards/r/RiverfallMimic.java index 9d61c7ef789..3f4891678a1 100644 --- a/Mage.Sets/src/mage/cards/r/RiverfallMimic.java +++ b/Mage.Sets/src/mage/cards/r/RiverfallMimic.java @@ -32,7 +32,7 @@ public final class RiverfallMimic extends CardImpl { filter.add(new ColorPredicate(ObjectColor.RED)); } - private String rule = "Whenever you cast a spell that's both blue and red, {this} has base power and toughness 3/3 until end of turn and can't be blocked this turn."; + private static final String rule = "Whenever you cast a spell that's both blue and red, {this} has base power and toughness 3/3 until end of turn and can't be blocked this turn."; public RiverfallMimic(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U/R}"); diff --git a/Mage.Sets/src/mage/cards/r/RiversGrasp.java b/Mage.Sets/src/mage/cards/r/RiversGrasp.java index 95b3fb8426e..e5fd3a9c489 100644 --- a/Mage.Sets/src/mage/cards/r/RiversGrasp.java +++ b/Mage.Sets/src/mage/cards/r/RiversGrasp.java @@ -34,7 +34,7 @@ public final class RiversGrasp extends CardImpl { this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new DiscardCardYouChooseTargetEffect(StaticFilters.FILTER_CARD_NON_LAND, TargetController.ANY), new ManaWasSpentCondition(ColoredManaSymbol.B), - " If {B} was spent to cast this spell, target player reveals their hand, you choose a nonland card from it, then that player discards that card") + "If {B} was spent to cast this spell, target player reveals their hand, you choose a nonland card from it, then that player discards that card") .setTargetPointer(new SecondTargetPointer())); this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1)); diff --git a/Mage.Sets/src/mage/cards/r/RiversRebuke.java b/Mage.Sets/src/mage/cards/r/RiversRebuke.java index bbce02913d5..d221d30d464 100644 --- a/Mage.Sets/src/mage/cards/r/RiversRebuke.java +++ b/Mage.Sets/src/mage/cards/r/RiversRebuke.java @@ -59,7 +59,7 @@ class RiversRebukeReturnToHandEffect extends OneShotEffect { Cards cards = new CardsImpl(); game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_PERMANENT_NON_LAND, - source.getFirstTarget(), source.getSourceId(), game + source.getFirstTarget(), source, game ).stream().forEach(cards::add); return player.moveCards(cards, Zone.HAND, source, game); } diff --git a/Mage.Sets/src/mage/cards/r/RiveteersAscendancy.java b/Mage.Sets/src/mage/cards/r/RiveteersAscendancy.java new file mode 100644 index 00000000000..67eed77dc65 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RiveteersAscendancy.java @@ -0,0 +1,76 @@ +package mage.cards.r; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SacrificePermanentTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RiveteersAscendancy extends CardImpl { + + private static final FilterCard filter + = new FilterCreatureCard("creature card with lesser mana value from your graveyard"); + + static { + filter.add(RiveteersAscendancyPredicate.instance); + } + + public RiveteersAscendancy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}{R}{G}"); + + // Whenever you sacrifice a creature, you may return target creature card with lesser mana value from your graveyard to the battlefield tapped. Do this only once each turn. + Ability ability = new SacrificePermanentTriggeredAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect(true), + StaticFilters.FILTER_PERMANENT_A_CREATURE + ).setDoOnlyOnce(true); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); + } + + private RiveteersAscendancy(final RiveteersAscendancy card) { + super(card); + } + + @Override + public RiveteersAscendancy copy() { + return new RiveteersAscendancy(this); + } +} + +enum RiveteersAscendancyPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return input + .getObject() + .getManaValue() + < input + .getSource() + .getEffects() + .stream() + .map(effect -> effect.getValue("sacrificedPermanent")) + .filter(Objects::nonNull) + .map(Permanent.class::cast) + .mapToInt(MageObject::getManaValue) + .max() + .orElse(0); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RiveteersCharm.java b/Mage.Sets/src/mage/cards/r/RiveteersCharm.java new file mode 100644 index 00000000000..fbc15358378 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RiveteersCharm.java @@ -0,0 +1,58 @@ +package mage.cards.r; + +import mage.abilities.Mode; +import mage.abilities.effects.common.ExileGraveyardAllTargetPlayerEffect; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEndOfTurnEffect; +import mage.abilities.effects.common.SacrificeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.filter.predicate.permanent.MaxManaValueControlledPermanentPredicate; +import mage.target.TargetPlayer; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RiveteersCharm extends CardImpl { + + private static final FilterPermanent filter = new FilterCreatureOrPlaneswalkerPermanent( + "creature or planeswalker they control with the highest mana value " + + "among creatures and planeswalkers they control" + ); + + static { + filter.add(MaxManaValueControlledPermanentPredicate.instance); + } + + public RiveteersCharm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}{R}{G}"); + + // Choose one — + // • Target opponent sacrifices a creature or planeswalker they control with the highest mana value among creatures and planeswalkers they control. + this.getSpellAbility().addEffect(new SacrificeEffect(filter, 1, "target opponent")); + this.getSpellAbility().addTarget(new TargetOpponent()); + + // • Exile the top three cards of your library. Until your next end step, you may play those cards. + this.getSpellAbility().addMode(new Mode(new ExileTopXMayPlayUntilEndOfTurnEffect( + 3, false, Duration.UntilYourNextEndStep + ))); + + // • Exile target player's graveyard. + this.getSpellAbility().addMode(new Mode(new ExileGraveyardAllTargetPlayerEffect()).addTarget(new TargetPlayer())); + } + + private RiveteersCharm(final RiveteersCharm card) { + super(card); + } + + @Override + public RiveteersCharm copy() { + return new RiveteersCharm(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RiveteersDecoy.java b/Mage.Sets/src/mage/cards/r/RiveteersDecoy.java new file mode 100644 index 00000000000..5956f8d84dd --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RiveteersDecoy.java @@ -0,0 +1,43 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.combat.MustBeBlockedByAtLeastOneSourceEffect; +import mage.abilities.keyword.BlitzAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RiveteersDecoy extends CardImpl { + + public RiveteersDecoy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Riveteers Decoy must be blocked if able. + this.addAbility(new SimpleStaticAbility(new MustBeBlockedByAtLeastOneSourceEffect(Duration.WhileOnBattlefield))); + + // Blitz {3}{G} + this.addAbility(new BlitzAbility(this, "{3}{G}")); + } + + private RiveteersDecoy(final RiveteersDecoy card) { + super(card); + } + + @Override + public RiveteersDecoy copy() { + return new RiveteersDecoy(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RiveteersInitiate.java b/Mage.Sets/src/mage/cards/r/RiveteersInitiate.java new file mode 100644 index 00000000000..fdbcbfc793f --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RiveteersInitiate.java @@ -0,0 +1,43 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RiveteersInitiate extends CardImpl { + + public RiveteersInitiate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.VIASHINO); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {1}{B/G}: Riveteers Initiate gains deathtouch until end of turn. + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + DeathtouchAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl<>("{1}{B/G}"))); + } + + private RiveteersInitiate(final RiveteersInitiate card) { + super(card); + } + + @Override + public RiveteersInitiate copy() { + return new RiveteersInitiate(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RiveteersOverlook.java b/Mage.Sets/src/mage/cards/r/RiveteersOverlook.java new file mode 100644 index 00000000000..0342de20e66 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RiveteersOverlook.java @@ -0,0 +1,57 @@ +package mage.cards.r; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.effects.common.DoWhenCostPaid; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RiveteersOverlook extends CardImpl { + + private static final FilterCard filter = new FilterCard("a basic Swamp, Mountain, or Forest card"); + + static { + filter.add(SuperType.BASIC.getPredicate()); + filter.add(Predicates.or( + SubType.SWAMP.getPredicate(), + SubType.MOUNTAIN.getPredicate(), + SubType.FOREST.getPredicate() + )); + } + + public RiveteersOverlook(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // When Riveteers Overlook enters the battlefield, sacrifice it. When you do, search your library for a basic Swamp, Mountain, or Forest card, put it onto the battlefield tapped, then shuffle and you gain 1 life. + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new SearchLibraryPutInPlayEffect( + new TargetCardInLibrary(filter), true, true + ), false); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DoWhenCostPaid( + ability, new SacrificeSourceCost().setText("sacrifice it"), null, false + ))); + } + + private RiveteersOverlook(final RiveteersOverlook card) { + super(card); + } + + @Override + public RiveteersOverlook copy() { + return new RiveteersOverlook(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RiveteersRequisitioner.java b/Mage.Sets/src/mage/cards/r/RiveteersRequisitioner.java new file mode 100644 index 00000000000..984d5ee7686 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RiveteersRequisitioner.java @@ -0,0 +1,43 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.BlitzAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RiveteersRequisitioner extends CardImpl { + + public RiveteersRequisitioner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.VIASHINO); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // When Riveteers Requisitioner dies, create a Treasure token. + this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new TreasureToken()))); + + // Blitz {2}{R} + this.addAbility(new BlitzAbility(this, "{2}{R}")); + } + + private RiveteersRequisitioner(final RiveteersRequisitioner card) { + super(card); + } + + @Override + public RiveteersRequisitioner copy() { + return new RiveteersRequisitioner(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RoarOfJukai.java b/Mage.Sets/src/mage/cards/r/RoarOfJukai.java index e8ec849ce7a..cb80d2e199f 100644 --- a/Mage.Sets/src/mage/cards/r/RoarOfJukai.java +++ b/Mage.Sets/src/mage/cards/r/RoarOfJukai.java @@ -85,7 +85,7 @@ class RoarOfJukaiEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { if (new PermanentsOnTheBattlefieldCondition(filter).apply(game, source)) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filterBlocked, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filterBlocked, source.getControllerId(), source, game)) { ContinuousEffect effect = new BoostTargetEffect(2, 2, Duration.EndOfTurn); effect.setTargetPointer(new FixedTarget(permanent, game)); game.addEffect(effect, source); diff --git a/Mage.Sets/src/mage/cards/r/RoarOfTheCrowd.java b/Mage.Sets/src/mage/cards/r/RoarOfTheCrowd.java index b9973446f01..8f382fae4c4 100644 --- a/Mage.Sets/src/mage/cards/r/RoarOfTheCrowd.java +++ b/Mage.Sets/src/mage/cards/r/RoarOfTheCrowd.java @@ -62,7 +62,7 @@ class RoarOfTheCrowdEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - Choice typeChoice = new ChoiceCreatureType(game.getObject(source.getSourceId())); + Choice typeChoice = new ChoiceCreatureType(game.getObject(source)); if (!player.choose(Outcome.LoseLife, typeChoice, game)) { return false; } diff --git a/Mage.Sets/src/mage/cards/r/RoarOfTheKha.java b/Mage.Sets/src/mage/cards/r/RoarOfTheKha.java index 07958c713a5..f512408c691 100644 --- a/Mage.Sets/src/mage/cards/r/RoarOfTheKha.java +++ b/Mage.Sets/src/mage/cards/r/RoarOfTheKha.java @@ -27,8 +27,7 @@ public final class RoarOfTheKha extends CardImpl { this.getSpellAbility().addEffect(new BoostControlledEffect(1, 1, Duration.EndOfTurn)); // or untap all creatures you control. - Mode mode = new Mode(); - mode.addEffect(new UntapAllControllerEffect(new FilterControlledCreaturePermanent(), rule)); + Mode mode = new Mode(new UntapAllControllerEffect(new FilterControlledCreaturePermanent(), rule)); this.getSpellAbility().getModes().addMode(mode); // Entwine {1}{W} diff --git a/Mage.Sets/src/mage/cards/r/RobTheArchives.java b/Mage.Sets/src/mage/cards/r/RobTheArchives.java new file mode 100644 index 00000000000..ca4541f5b41 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RobTheArchives.java @@ -0,0 +1,34 @@ +package mage.cards.r; + +import mage.abilities.effects.common.ExileTopXMayPlayUntilEndOfTurnEffect; +import mage.abilities.keyword.CasualtyAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RobTheArchives extends CardImpl { + + public RobTheArchives(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); + + // Casualty 1 + this.addAbility(new CasualtyAbility(this, 1)); + + // Exile the top two cards of your library. You may play those cards this turn. + this.getSpellAbility().addEffect(new ExileTopXMayPlayUntilEndOfTurnEffect(2, false)); + } + + private RobTheArchives(final RobTheArchives card) { + super(card); + } + + @Override + public RobTheArchives copy() { + return new RobTheArchives(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java b/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java index 0f065a31274..4d8298f83d5 100644 --- a/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java +++ b/Mage.Sets/src/mage/cards/r/RobberOfTheRich.java @@ -17,9 +17,12 @@ import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; import mage.watchers.common.AttackedThisTurnWatcher; - import java.util.Objects; import java.util.UUID; +import mage.abilities.decorator.ConditionalAsThoughEffect; +import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; +import mage.abilities.effects.common.asthought.YouMaySpendManaAsAnyColorToCastTargetEffect; +import mage.target.targetpointer.FixedTarget; /** * @author TheElk801 @@ -49,7 +52,7 @@ public final class RobberOfTheRich extends CardImpl { "if defending player has more cards in hand than you, exile the top card of their library. " + "During any turn you attacked with a Rogue, you may cast that card and " + "you may spend mana as though it were mana of any color to cast that spell." - ).addHint(new ConditionHint(RobberOfTheRichAnyTurnAttackedCondition.instance)), new AttackedThisTurnWatcher()); + ).addHint(new ConditionHint(new RogueAttackedThisTurnCondition(null))), new AttackedThisTurnWatcher()); } private RobberOfTheRich(final RobberOfTheRich card) { @@ -69,24 +72,36 @@ enum RobberOfTheRichAttacksCondition implements Condition { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(game.getCombat().getDefendingPlayerId(source.getSourceId(), game)); - return controller != null && player != null && controller.getHand().size() < player.getHand().size(); + return controller != null + && player != null + && controller.getHand().size() < player.getHand().size(); } } -enum RobberOfTheRichAnyTurnAttackedCondition implements Condition { - instance; +class RogueAttackedThisTurnCondition implements Condition { + + private Ability ability; + + RogueAttackedThisTurnCondition(Ability source) { + this.ability = source; + } @Override public boolean apply(Game game, Ability source) { + // in case the Robber leaves the battlefield, the ability must be referenced for controller information + if (ability == null) { + ability = source; + } // your turn - if (!source.isControlledBy(game.getActivePlayerId())) { + if (!ability.isControlledBy(game.getActivePlayerId())) { return false; } // attacked with Rogue + // note that the MOR object doesn't work well with LKI call when checking for the subtype, thus we check the LKI permanent in the battlefield AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); - return watcher != null && watcher.getAttackedThisTurnCreatures() + return watcher != null && watcher.getAttackedThisTurnCreaturesPermanentLKI() .stream() - .map(mor -> mor.getPermanentOrLKIBattlefield(game)) + .map(permanent -> permanent) .filter(Objects::nonNull) .anyMatch(permanent -> permanent.hasSubtype(SubType.ROGUE, game)); } @@ -100,7 +115,7 @@ enum RobberOfTheRichAnyTurnAttackedCondition implements Condition { class RobberOfTheRichEffect extends OneShotEffect { RobberOfTheRichEffect() { - super(Outcome.PutCreatureInPlay); + super(Outcome.Benefit); } private RobberOfTheRichEffect(final RobberOfTheRichEffect effect) { @@ -116,7 +131,8 @@ class RobberOfTheRichEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Player damagedPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); - if (controller == null || damagedPlayer == null) { + if (controller == null + || damagedPlayer == null) { return false; } Card card = damagedPlayer.getLibrary().getFromTop(game); @@ -125,13 +141,26 @@ class RobberOfTheRichEffect extends OneShotEffect { } // move card to exile controller.moveCardsToExile(card, source, game, true, CardUtil.getExileZoneId(game, source), CardUtil.getSourceName(game, source)); - // Add effects only if the card has a spellAbility (e.g. not for lands). + // add the effects to the exiled card directly + // don't worry about land if (card.getSpellAbility() != null) { - // allow to cast the card - // and you may spend mana as though it were mana of any color to cast it - CardUtil.makeCardPlayable(game, source, card, Duration.Custom, true, null, RobberOfTheRichAnyTurnAttackedCondition.instance); + // the exiled card is independent and requires a new ability in case the Robber leaves the battlefield + // the exiled card can be cast throughout the entire game as long as the controller attacked with a rogue that turn + Ability copiedAbility = source.copy(); + copiedAbility.newId(); + copiedAbility.setSourceId(card.getId()); + copiedAbility.setControllerId(source.getControllerId()); + PlayFromNotOwnHandZoneTargetEffect playFromExile = new PlayFromNotOwnHandZoneTargetEffect(Zone.EXILED, Duration.EndOfGame); + YouMaySpendManaAsAnyColorToCastTargetEffect spendAnyMana = new YouMaySpendManaAsAnyColorToCastTargetEffect(Duration.EndOfGame); + ConditionalAsThoughEffect castOnlyIfARogueAttackedThisTurn = new ConditionalAsThoughEffect(playFromExile, new RogueAttackedThisTurnCondition(copiedAbility)); + playFromExile.setTargetPointer(new FixedTarget(card, game)); + spendAnyMana.setTargetPointer(new FixedTarget(card, game)); + castOnlyIfARogueAttackedThisTurn.setTargetPointer(new FixedTarget(card, game)); + game.addEffect(castOnlyIfARogueAttackedThisTurn, copiedAbility); + game.addEffect(spendAnyMana, copiedAbility); + return true; } - return true; + return false; } } diff --git a/Mage.Sets/src/mage/cards/r/RoccoCabarettiCaterer.java b/Mage.Sets/src/mage/cards/r/RoccoCabarettiCaterer.java new file mode 100644 index 00000000000..bf434a1ae0d --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RoccoCabarettiCaterer.java @@ -0,0 +1,78 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.CastFromEverywhereSourceCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RoccoCabarettiCaterer extends CardImpl { + + private static final FilterCard filter = new FilterCreatureCard("creature card with mana value X or less"); + + static { + filter.add(RoccoCabarettiCatererPredicate.instance); + } + + public RoccoCabarettiCaterer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{X}{R}{G}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // When Rocco, Cabaretti Caterer enters the battlefield, if you cast it, you may search your library for a creature card with mana value X or less, put it onto the battlefield, then shuffle. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility( + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter)), + true + ), + CastFromEverywhereSourceCondition.instance, + "When {this} enters the battlefield, " + + "if you cast it, you may search your library for a creature card with mana value X or less, " + + "put it onto the battlefield, then shuffle.") + ); + } + + private RoccoCabarettiCaterer(final RoccoCabarettiCaterer card) { + super(card); + } + + @Override + public RoccoCabarettiCaterer copy() { + return new RoccoCabarettiCaterer(this); + } +} + +enum RoccoCabarettiCatererPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + if (input.getSource() == null) { + return false; + } + return input.getObject().getManaValue() + <= ManacostVariableValue.ETB.calculate(game, input.getSource(), null); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RockcasterPlatoon.java b/Mage.Sets/src/mage/cards/r/RockcasterPlatoon.java index 6743048b2ae..69919e1f7e3 100644 --- a/Mage.Sets/src/mage/cards/r/RockcasterPlatoon.java +++ b/Mage.Sets/src/mage/cards/r/RockcasterPlatoon.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -13,23 +11,24 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import java.util.UUID; + /** - * * @author Plopman */ public final class RockcasterPlatoon extends CardImpl { - + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying"); + static { filter.add(new AbilityPredicate(FlyingAbility.class)); } public RockcasterPlatoon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}{W}"); this.subtype.add(SubType.RHINO); this.subtype.add(SubType.SOLDIER); @@ -37,8 +36,8 @@ public final class RockcasterPlatoon extends CardImpl { this.toughness = new MageInt(7); // {4}{G}: Rockcaster Platoon deals 2 damage to each creature with flying and each player. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageAllEffect(2, filter), new ManaCostsImpl("{4}{G}")); - ability.addEffect(new DamagePlayersEffect(2)); + Ability ability = new SimpleActivatedAbility(new DamageAllEffect(2, filter), new ManaCostsImpl<>("{4}{G}")); + ability.addEffect(new DamagePlayersEffect(2).setText("and each player")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RocketLauncher.java b/Mage.Sets/src/mage/cards/r/RocketLauncher.java index 22074458c82..3563189cab9 100644 --- a/Mage.Sets/src/mage/cards/r/RocketLauncher.java +++ b/Mage.Sets/src/mage/cards/r/RocketLauncher.java @@ -1,8 +1,5 @@ - package mage.cards.r; -import java.util.Objects; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.condition.Condition; @@ -14,30 +11,30 @@ import mage.abilities.effects.common.DestroySourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.WatcherScope; import mage.constants.Zone; import mage.game.Game; -import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; import mage.target.common.TargetAnyTarget; -import mage.watchers.Watcher; + +import java.util.UUID; /** - * - * @author MarcoMarin + * @author TheElk801 */ public final class RocketLauncher extends CardImpl { public RocketLauncher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); - Watcher watcher = new RocketLauncherWatcher(this.getId()); // {2}: Rocket Launcher deals 1 damage to any target. Destroy Rocket Launcher at the beginning of the next end step. Activate this ability only if you've controlled Rocket Launcher continuously since the beginning of your most recent turn. - Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new DamageTargetEffect(1), new GenericManaCost(2), ControlledTurnCondition.instance); + Ability ability = new ConditionalActivatedAbility( + Zone.BATTLEFIELD, new DamageTargetEffect(1), + new GenericManaCost(2), RocketLauncherCondition.instance); ability.addTarget(new TargetAnyTarget()); - ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new DestroySourceEffect(true)))); - - this.addAbility(ability, watcher); + ability.addEffect(new CreateDelayedTriggeredAbilityEffect( + new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new DestroySourceEffect(true)) + ).setText("destroy {this} at the beginning of the next end step")); + this.addAbility(ability); } private RocketLauncher(final RocketLauncher card) { @@ -50,56 +47,17 @@ public final class RocketLauncher extends CardImpl { } } -class RocketLauncherWatcher extends Watcher { - - private boolean changedControllerOR1stTurn; - private UUID cardId = null; - - public RocketLauncherWatcher(UUID cardId) { - super(WatcherScope.GAME); - this.changedControllerOR1stTurn = true; - this.cardId = cardId; - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.CLEANUP_STEP_POST) { - changedControllerOR1stTurn = false; - } - if (event.getType() == GameEvent.EventType.LOST_CONTROL && - Objects.equals(event.getTargetId(), cardId)) { - changedControllerOR1stTurn = true; - } - } - - - @Override - public void reset() { - super.reset(); - changedControllerOR1stTurn = true; //when is this reset called? may cause problems if in mid-life - } - - public boolean isChangedControllerOR1stTurn() { - return changedControllerOR1stTurn; - } -} - -enum ControlledTurnCondition implements Condition { - +enum RocketLauncherCondition implements Condition { instance; - @Override public boolean apply(Game game, Ability source) { - RocketLauncherWatcher watcher = game.getState().getWatcher(RocketLauncherWatcher.class); - - return watcher != null && !watcher.isChangedControllerOR1stTurn(); + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + return permanent != null && permanent.wasControlledFromStartOfControllerTurn(); } @Override public String toString() { - return "Permanent hasn't changed controller NOR entered this turn"; + return "you've controlled {this} continuously since the beginning of your most recent turn"; } - - -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/r/RockshardElemental.java b/Mage.Sets/src/mage/cards/r/RockshardElemental.java index e38782d19f4..4f9257586f0 100644 --- a/Mage.Sets/src/mage/cards/r/RockshardElemental.java +++ b/Mage.Sets/src/mage/cards/r/RockshardElemental.java @@ -26,7 +26,7 @@ public final class RockshardElemental extends CardImpl { // Double strike this.addAbility(DoubleStrikeAbility.getInstance()); // Morph {4}{R}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{R}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{R}{R}"))); } private RockshardElemental(final RockshardElemental card) { diff --git a/Mage.Sets/src/mage/cards/r/RodOfAbsorption.java b/Mage.Sets/src/mage/cards/r/RodOfAbsorption.java new file mode 100644 index 00000000000..4da3c94390f --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RodOfAbsorption.java @@ -0,0 +1,200 @@ +package mage.cards.r; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +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.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.*; +import mage.constants.CardType; +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.events.ZoneChangeEvent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RodOfAbsorption extends CardImpl { + + public RodOfAbsorption(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{U}"); + + // Whenever a player casts an instant or sorcery spell, exile it instead of putting it into a graveyard as it resolves. + this.addAbility(new RodOfAbsorptionTriggeredAbility()); + + // {X}, {T}, Sacrifice Rod of Absorption: You may cast any number of spells from among cards exiled with Rod of Absorption with total mana value X or less without paying their mana costs. + Ability ability = new SimpleActivatedAbility(new RodOfAbsorptionCastEffect(), new ManaCostsImpl<>("{X}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private RodOfAbsorption(final RodOfAbsorption card) { + super(card); + } + + @Override + public RodOfAbsorption copy() { + return new RodOfAbsorption(this); + } +} + +class RodOfAbsorptionTriggeredAbility extends TriggeredAbilityImpl { + + RodOfAbsorptionTriggeredAbility() { + super(Zone.BATTLEFIELD, null, false); + } + + private RodOfAbsorptionTriggeredAbility(final RodOfAbsorptionTriggeredAbility ability) { + super(ability); + } + + @Override + public RodOfAbsorptionTriggeredAbility copy() { + return new RodOfAbsorptionTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell == null || !spell.isInstantOrSorcery(game)) { + return false; + } + this.getEffects().clear(); + this.addEffect(new RodOfAbsorptionExileEffect(spell, game)); + return true; + } + + @Override + public String getRule() { + return "Whenever a player casts an instant or sorcery spell, " + + "exile it instead of putting it into a graveyard as it resolves."; + } +} + +class RodOfAbsorptionExileEffect extends ReplacementEffectImpl { + + private final MageObjectReference mor; + + RodOfAbsorptionExileEffect(Spell spell, Game game) { + super(Duration.WhileOnStack, Outcome.Benefit); + this.mor = new MageObjectReference(spell, game); + } + + private RodOfAbsorptionExileEffect(final RodOfAbsorptionExileEffect effect) { + super(effect); + this.mor = effect.mor; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Spell sourceSpell = game.getStack().getSpell(event.getTargetId()); + if (sourceSpell == null || sourceSpell.isCopy()) { + return false; + } + Player player = game.getPlayer(sourceSpell.getOwnerId()); + if (player == null) { + return false; + } + player.moveCardsToExile( + sourceSpell, source, game, false, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ZoneChangeEvent zEvent = ((ZoneChangeEvent) event); + if (zEvent.getFromZone() != Zone.STACK + || zEvent.getToZone() != Zone.GRAVEYARD + || event.getSourceId() == null + || !event.getSourceId().equals(event.getTargetId()) + || mor.getZoneChangeCounter() != game.getState().getZoneChangeCounter(event.getSourceId())) { + return false; + } + Spell spell = game.getStack().getSpell(mor.getSourceId()); + return spell != null && spell.isInstantOrSorcery(game); + } + + @Override + public RodOfAbsorptionExileEffect copy() { + return new RodOfAbsorptionExileEffect(this); + } +} + +class RodOfAbsorptionCastEffect extends OneShotEffect { + + RodOfAbsorptionCastEffect() { + super(Outcome.Benefit); + staticText = "you may cast any number of spells from among cards exiled with " + + "{this} with total mana value X or less without paying their mana costs"; + } + + private RodOfAbsorptionCastEffect(final RodOfAbsorptionCastEffect effect) { + super(effect); + } + + @Override + public RodOfAbsorptionCastEffect copy() { + return new RodOfAbsorptionCastEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Cards cards = new CardsImpl(game.getExile().getExileZone(CardUtil.getExileZoneId(game, source))); + if (player == null || cards.isEmpty()) { + return false; + } + CardUtil.castMultipleWithAttributeForFree( + player, source, game, cards, StaticFilters.FILTER_CARD, Integer.MAX_VALUE, + new RodOfAbsorptionTracker(source.getManaCostsToPay().getX()) + ); + return true; + } +} + +class RodOfAbsorptionTracker implements CardUtil.SpellCastTracker { + + private final int xValue; + private int totalManaValue = 0; + + RodOfAbsorptionTracker(int xValue) { + this.xValue = xValue; + } + + @Override + public boolean checkCard(Card card, Game game) { + return card.getManaValue() + totalManaValue <= xValue; + } + + @Override + public void addCard(Card card, Ability source, Game game) { + totalManaValue += card.getManaValue(); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RofellossGift.java b/Mage.Sets/src/mage/cards/r/RofellossGift.java index be7e66e7e2a..a475486a81f 100644 --- a/Mage.Sets/src/mage/cards/r/RofellossGift.java +++ b/Mage.Sets/src/mage/cards/r/RofellossGift.java @@ -84,7 +84,7 @@ class RofellossGiftEffect extends OneShotEffect { int enchantmentsToReturn = Math.min(player.getGraveyard().count(filter2, game), targetCardInHand.getTargets().size()); TargetCardInYourGraveyard targetCardInYourGraveyard = new TargetCardInYourGraveyard(enchantmentsToReturn, filter2); targetCardInYourGraveyard.setNotTarget(true); - if (!player.choose(outcome, targetCardInYourGraveyard, source.getSourceId(), game)) { + if (!player.choose(outcome, targetCardInYourGraveyard, source, game)) { return false; } cards = new CardsImpl(); diff --git a/Mage.Sets/src/mage/cards/r/RogueSkycaptain.java b/Mage.Sets/src/mage/cards/r/RogueSkycaptain.java index 5b52e1cc54b..fe0089d759b 100644 --- a/Mage.Sets/src/mage/cards/r/RogueSkycaptain.java +++ b/Mage.Sets/src/mage/cards/r/RogueSkycaptain.java @@ -88,7 +88,7 @@ class RogueSkycaptainEffect extends OneShotEffect { } else { Target target = new TargetOpponent(true); target.setNotTarget(true); - target.choose(Outcome.GainControl, source.getControllerId(), source.getSourceId(), game); + target.choose(Outcome.GainControl, source.getControllerId(), source.getSourceId(), source, game); opponent = game.getPlayer(target.getFirstTarget()); } if (opponent != null) { diff --git a/Mage.Sets/src/mage/cards/r/RoguesGallery.java b/Mage.Sets/src/mage/cards/r/RoguesGallery.java new file mode 100644 index 00000000000..42f94c29deb --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RoguesGallery.java @@ -0,0 +1,90 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.common.ColorAssignment; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorlessPredicate; +import mage.game.Game; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RoguesGallery extends CardImpl { + + public RoguesGallery(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); + + // For each color, return up to one target creature card of that color from your graveyard to your hand. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect() + .setText("for each color, return up to one target creature card " + + "of that color from your graveyard to your hand")); + this.getSpellAbility().addTarget(new RoguesGalleryTarget()); + } + + private RoguesGallery(final RoguesGallery card) { + super(card); + } + + @Override + public RoguesGallery copy() { + return new RoguesGallery(this); + } +} + +class RoguesGalleryTarget extends TargetCardInYourGraveyard { + + private static final ColorAssignment colorAssigner = new ColorAssignment("W", "U", "B", "R", "G"); + + private static final FilterCard filter = new FilterCreatureCard("a creature card of each color"); + + static { + filter.add(Predicates.not(ColorlessPredicate.instance)); + } + + RoguesGalleryTarget() { + super(0, Integer.MAX_VALUE, filter, true); + } + + private RoguesGalleryTarget(final RoguesGalleryTarget target) { + super(target); + } + + @Override + public RoguesGalleryTarget copy() { + return new RoguesGalleryTarget(this); + } + + @Override + public boolean canTarget(UUID playerId, UUID id, Ability ability, Game game) { + if (!super.canTarget(playerId, id, ability, game)) { + return false; + } + Card card = game.getCard(id); + if (card == null) { + return false; + } + if (this.getTargets().isEmpty()) { + return true; + } + Cards cards = new CardsImpl(this.getTargets()); + cards.add(card); + return colorAssigner.getRoleCount(cards, game) >= cards.size(); + } + + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); + possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, null, game)); + return possibleTargets; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RohgahhOfKherKeep.java b/Mage.Sets/src/mage/cards/r/RohgahhOfKherKeep.java index 0a55641ed1f..498c3a96e93 100644 --- a/Mage.Sets/src/mage/cards/r/RohgahhOfKherKeep.java +++ b/Mage.Sets/src/mage/cards/r/RohgahhOfKherKeep.java @@ -103,7 +103,7 @@ class RohgahhOfKherKeepEffect extends OneShotEffect { || !cost.pay(source, game, source, player.getId(), false)) { TargetOpponent target = new TargetOpponent(); Player opponent = null; - if (target.choose(Outcome.Detriment, player.getId(), source.getSourceId(), game)) { + if (target.choose(Outcome.Detriment, player.getId(), source.getSourceId(), source, game)) { opponent = game.getPlayer(target.getFirstTarget()); } new TapAllEffect(filter).apply(game, source); diff --git a/Mage.Sets/src/mage/cards/r/RoilingWaters.java b/Mage.Sets/src/mage/cards/r/RoilingWaters.java index 1cb143e0384..c1888a0a28d 100644 --- a/Mage.Sets/src/mage/cards/r/RoilingWaters.java +++ b/Mage.Sets/src/mage/cards/r/RoilingWaters.java @@ -1,4 +1,3 @@ - package mage.cards.r; import java.util.UUID; @@ -8,10 +7,8 @@ import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; import mage.target.TargetPlayer; -import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; import mage.target.targetpointer.SecondTargetPointer; /** @@ -20,18 +17,12 @@ import mage.target.targetpointer.SecondTargetPointer; */ public final class RoilingWaters extends CardImpl { - private static final FilterCreaturePermanent FILTER = new FilterCreaturePermanent("creatures your opponents control"); - - static { - FILTER.add(TargetController.OPPONENT.getControllerPredicate()); - } - public RoilingWaters(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{5}{U}{U}"); // Return up to two target creatures your opponents control to their owners' hands. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2, FILTER, false)); + this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent(0, 2)); // Target player draws two cards. Effect effect = new DrawCardTargetEffect(2); effect.setTargetPointer(new SecondTargetPointer()); diff --git a/Mage.Sets/src/mage/cards/r/RoilmagesTrick.java b/Mage.Sets/src/mage/cards/r/RoilmagesTrick.java index 06cd03fc00d..01592640720 100644 --- a/Mage.Sets/src/mage/cards/r/RoilmagesTrick.java +++ b/Mage.Sets/src/mage/cards/r/RoilmagesTrick.java @@ -1,7 +1,7 @@ - package mage.cards.r; import java.util.UUID; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.ColorsOfManaSpentToCastCount; import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; @@ -12,8 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; /** * @@ -21,23 +20,21 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class RoilmagesTrick extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } + private static final DynamicValue xValue = new SignInversionDynamicValue(ColorsOfManaSpentToCastCount.getInstance()); public RoilmagesTrick(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{U}"); - // Converge — Creatures your opponents control get -X/-0 until end of turn, where X is the number of colors of mana spent to cast Roilmage's Trick. + // Converge — Creatures your opponents control get -X/-0 until end of turn, + // where X is the number of colors of mana spent to cast this spell. this.getSpellAbility().setAbilityWord(AbilityWord.CONVERGE); this.getSpellAbility().addEffect(new BoostAllEffect( - new SignInversionDynamicValue(ColorsOfManaSpentToCastCount.getInstance()), StaticValue.get(-0), Duration.EndOfTurn, filter, false, - "Creatures your opponents control get -X/-0 until end of turn, where X is the number of colors of mana spent to cast this spell.
", true)); + xValue, StaticValue.get(0), Duration.EndOfTurn, + StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, false, null, true + )); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private RoilmagesTrick(final RoilmagesTrick card) { diff --git a/Mage.Sets/src/mage/cards/r/RoleReversal.java b/Mage.Sets/src/mage/cards/r/RoleReversal.java index 5e5c8843679..9e0042487ed 100644 --- a/Mage.Sets/src/mage/cards/r/RoleReversal.java +++ b/Mage.Sets/src/mage/cards/r/RoleReversal.java @@ -69,11 +69,11 @@ class TargetPermanentsThatShareCardType extends TargetPermanent { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { Set cardTypes = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); if (targetSource != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { for (CardType cardType : permanent.getCardType(game)) { if (cardTypes.contains(cardType)) { diff --git a/Mage.Sets/src/mage/cards/r/RonaDiscipleOfGix.java b/Mage.Sets/src/mage/cards/r/RonaDiscipleOfGix.java index 5ba2ecda517..b08e7f7de62 100644 --- a/Mage.Sets/src/mage/cards/r/RonaDiscipleOfGix.java +++ b/Mage.Sets/src/mage/cards/r/RonaDiscipleOfGix.java @@ -99,7 +99,7 @@ class RonaDiscipleOfGixPlayNonLandEffect extends AsThoughEffectImpl { public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { if (affectedControllerId.equals(source.getControllerId())) { Card card = game.getCard(objectId); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (card != null && !card.isLand(game) && sourceObject != null) { UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), sourceObject.getZoneChangeCounter(game)); if (exileId != null) { diff --git a/Mage.Sets/src/mage/cards/r/RoninCliffrider.java b/Mage.Sets/src/mage/cards/r/RoninCliffrider.java index 8e3b1a24416..fb6127fba91 100644 --- a/Mage.Sets/src/mage/cards/r/RoninCliffrider.java +++ b/Mage.Sets/src/mage/cards/r/RoninCliffrider.java @@ -69,7 +69,7 @@ class RoninCliffriderEffect extends OneShotEffect { if (defenderId != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent(); filter.add(new ControllerIdPredicate(defenderId)); - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); for (Permanent permanent : permanents) { permanent.damage(1, source.getSourceId(), source, game, false, true); } diff --git a/Mage.Sets/src/mage/cards/r/RoninWarclub.java b/Mage.Sets/src/mage/cards/r/RoninWarclub.java index 9abbde787c3..70ac5ef13f5 100644 --- a/Mage.Sets/src/mage/cards/r/RoninWarclub.java +++ b/Mage.Sets/src/mage/cards/r/RoninWarclub.java @@ -1,41 +1,34 @@ package mage.cards.r; -import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.keyword.EquipAbility; 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.game.Game; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.constants.*; +import mage.filter.StaticFilters; import java.util.UUID; /** - * @author LevelX2 + * @author awjackson */ public final class RoninWarclub extends CardImpl { public RoninWarclub(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); this.subtype.add(SubType.EQUIPMENT); + // Equipped creature gets +2/+1. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(2, 1))); + this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(2, 1))); // Whenever a creature enters the battlefield under your control, attach Ronin Warclub to that creature. - Ability ability = new RoninWarclubTriggeredAbility(); - ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, new AttachEffect(Outcome.BoostCreature, "attach {this} to that creature"), + StaticFilters.FILTER_PERMANENT_A_CREATURE, false, SetTargetPointer.PERMANENT, null)); // Equip {5} ({5}: Attach to target creature you control. Equip only as a sorcery.) this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(5))); @@ -49,84 +42,4 @@ public final class RoninWarclub extends CardImpl { public RoninWarclub copy() { return new RoninWarclub(this); } - - private class RoninWarclubTriggeredAbility extends TriggeredAbilityImpl { - - public RoninWarclubTriggeredAbility() { - super(Zone.BATTLEFIELD, new RoninWarclubAttachEffect(), false); - } - - public RoninWarclubTriggeredAbility(RoninWarclubTriggeredAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null - && permanent.isCreature(game) - && permanent.isControlledBy(this.controllerId)) { - - if (!this.getTargets().isEmpty()) { - // remove previous target - if (!this.getTargets().get(0).getTargets().isEmpty()) { - this.getTargets().clear(); - this.addTarget(new TargetCreaturePermanent()); - } - Target target = this.getTargets().get(0); - if (target instanceof TargetCreaturePermanent) { - target.add(event.getTargetId(), game); - } - } - return true; - } - return false; - } - - @Override - public RoninWarclubTriggeredAbility copy() { - return new RoninWarclubTriggeredAbility(this); - } - } - - private static class RoninWarclubAttachEffect extends OneShotEffect { - - public RoninWarclubAttachEffect() { - super(Outcome.BoostCreature); - this.staticText = "Whenever a creature enters the battlefield under your control, attach {this} to that creature"; - } - - public RoninWarclubAttachEffect(final RoninWarclubAttachEffect effect) { - super(effect); - } - - @Override - public RoninWarclubAttachEffect copy() { - return new RoninWarclubAttachEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - Permanent attachment = game.getPermanent(source.getSourceId()); - if (permanent != null && attachment != null) { - if (attachment.getAttachedTo() != null) { - Permanent oldTarget = game.getPermanent(attachment.getAttachedTo()); - if (oldTarget != null) { - oldTarget.removeAttachment(source.getSourceId(), source, game); - } - } - boolean result; - result = permanent.addAttachment(source.getSourceId(), source, game); - return result; - } - return false; - } - } - } diff --git a/Mage.Sets/src/mage/cards/r/RooftopNuisance.java b/Mage.Sets/src/mage/cards/r/RooftopNuisance.java new file mode 100644 index 00000000000..5279d5a34b8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RooftopNuisance.java @@ -0,0 +1,42 @@ +package mage.cards.r; + +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.keyword.CasualtyAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RooftopNuisance extends CardImpl { + + public RooftopNuisance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}"); + + // Casualty 1 + this.addAbility(new CasualtyAbility(this, 1)); + + // Tap target creature. It doesn't untap during its controller's next untap step. + this.getSpellAbility().addEffect(new TapTargetEffect()); + this.getSpellAbility().addEffect(new DontUntapInControllersNextUntapStepTargetEffect("it")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); + } + + private RooftopNuisance(final RooftopNuisance card) { + super(card); + } + + @Override + public RooftopNuisance copy() { + return new RooftopNuisance(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RoonOfTheHiddenRealm.java b/Mage.Sets/src/mage/cards/r/RoonOfTheHiddenRealm.java index f8625e03d39..6ad268ff282 100644 --- a/Mage.Sets/src/mage/cards/r/RoonOfTheHiddenRealm.java +++ b/Mage.Sets/src/mage/cards/r/RoonOfTheHiddenRealm.java @@ -86,7 +86,7 @@ class RoonOfTheHiddenRealmEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { if (getTargetPointer().getFirst(game, source) != null) { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); diff --git a/Mage.Sets/src/mage/cards/r/RootElemental.java b/Mage.Sets/src/mage/cards/r/RootElemental.java index 1d47710a437..fcc12c300aa 100644 --- a/Mage.Sets/src/mage/cards/r/RootElemental.java +++ b/Mage.Sets/src/mage/cards/r/RootElemental.java @@ -26,7 +26,7 @@ public final class RootElemental extends CardImpl { this.toughness = new MageInt(5); // Morph {5}{G}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{5}{G}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{5}{G}{G}"))); // When Root Elemental is turned face up, you may put a creature card from your hand onto the battlefield. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_CREATURE_A))); } diff --git a/Mage.Sets/src/mage/cards/r/RootsOfWisdom.java b/Mage.Sets/src/mage/cards/r/RootsOfWisdom.java index 45eb9ab37e6..4ed83007bb2 100644 --- a/Mage.Sets/src/mage/cards/r/RootsOfWisdom.java +++ b/Mage.Sets/src/mage/cards/r/RootsOfWisdom.java @@ -75,8 +75,8 @@ class RootsOfWisdomEffect extends OneShotEffect { player.millCards(3, source, game); TargetCard targetCard = new TargetCardInYourGraveyard(filter); targetCard.setNotTarget(true); - if (targetCard.canChoose(source.getSourceId(), source.getControllerId(), game) - && player.choose(outcome, targetCard, source.getSourceId(), game)) { + if (targetCard.canChoose(source.getControllerId(), source, game) + && player.choose(outcome, targetCard, source, game)) { Card card = player.getGraveyard().get(targetCard.getFirstTarget(), game); if (card != null && player.moveCards(card, Zone.HAND, source, game)) { return true; diff --git a/Mage.Sets/src/mage/cards/r/RootwaterDiver.java b/Mage.Sets/src/mage/cards/r/RootwaterDiver.java index f044f1f18bf..392b33d0edc 100644 --- a/Mage.Sets/src/mage/cards/r/RootwaterDiver.java +++ b/Mage.Sets/src/mage/cards/r/RootwaterDiver.java @@ -1,39 +1,36 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author TGower */ public final class RootwaterDiver extends CardImpl { public RootwaterDiver(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); this.subtype.add(SubType.MERFOLK); this.power = new MageInt(1); this.toughness = new MageInt(1); // {tap}, Sacrifice Rootwater Diver: Return target artifact card from your graveyard to your hand. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); - } private RootwaterDiver(final RootwaterDiver card) { diff --git a/Mage.Sets/src/mage/cards/r/RootwaterThief.java b/Mage.Sets/src/mage/cards/r/RootwaterThief.java index 824b4ed0be3..d337ff95e0d 100644 --- a/Mage.Sets/src/mage/cards/r/RootwaterThief.java +++ b/Mage.Sets/src/mage/cards/r/RootwaterThief.java @@ -1,46 +1,43 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.effects.common.search.SearchLibraryAndExileTargetEffect; import mage.abilities.keyword.FlyingAbility; -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.game.Game; -import mage.players.Player; -import mage.target.common.TargetCardInLibrary; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author LoneFox - */ public final class RootwaterThief extends CardImpl { public RootwaterThief(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.MERFOLK); this.subtype.add(SubType.ROGUE); this.power = new MageInt(1); this.toughness = new MageInt(2); // {U}: Rootwater Thief gains flying until end of turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{U}"))); + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl<>("{U}"))); + // Whenever Rootwater Thief deals combat damage to a player, you may pay {2}. If you do, search that player's library for a card and exile it, then the player shuffles their library. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new RootwaterThiefEffect(), false, true)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DoIfCostPaid( + new SearchLibraryAndExileTargetEffect(1, false), new GenericManaCost(2) + ), false, true)); } private RootwaterThief(final RootwaterThief card) { @@ -52,47 +49,3 @@ public final class RootwaterThief extends CardImpl { return new RootwaterThief(this); } } - -class RootwaterThiefEffect extends OneShotEffect { - - RootwaterThiefEffect() { - super(Outcome.Exile); - staticText = "you may pay {2}. If you do, search that player's library for a card and exile it, then the player shuffles."; - } - - RootwaterThiefEffect(final RootwaterThiefEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Player damagedPlayer = game.getPlayer(targetPointer.getFirst(game, source)); - if (controller == null || damagedPlayer == null) { - return false; - } - String message = "Pay {2} to exile a card from damaged player's library?"; - Cost cost = new ManaCostsImpl("{2}"); - if(controller.chooseUse(Outcome.Benefit, message, source, game) && cost.pay(source, game, source, controller.getId(), false, null)) - { - TargetCardInLibrary target = new TargetCardInLibrary(); - if (controller.searchLibrary(target, source, game, damagedPlayer.getId())) { - if (!target.getTargets().isEmpty()) { - Card card = damagedPlayer.getLibrary().remove(target.getFirstTarget(), game); - if (card != null) { - controller.moveCardToExileWithInfo(card, null, "", source, game, Zone.LIBRARY, true); - } - } - } - - damagedPlayer.shuffleLibrary(source, game); - return true; - } - return false; - } - - @Override - public RootwaterThiefEffect copy() { - return new RootwaterThiefEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/r/RoseRoomTreasurer.java b/Mage.Sets/src/mage/cards/r/RoseRoomTreasurer.java new file mode 100644 index 00000000000..473a16308c5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RoseRoomTreasurer.java @@ -0,0 +1,93 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AllianceAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.costs.mana.ManaCosts; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.token.TreasureToken; +import mage.players.Player; +import mage.target.common.TargetAnyTarget; +import mage.watchers.common.AbilityResolvedWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RoseRoomTreasurer extends CardImpl { + + public RoseRoomTreasurer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Alliance — Whenever another creature enters the battlefield under your control, create a Treasure token if this is the first or second time this ability has resolved this turn. Otherwise, you may pay {X}. When you do, Rose Room Treasurer deals X damage to any target. + this.addAbility(new AllianceAbility(new RoseRoomTreasurerEffect()), new AbilityResolvedWatcher()); + } + + private RoseRoomTreasurer(final RoseRoomTreasurer card) { + super(card); + } + + @Override + public RoseRoomTreasurer copy() { + return new RoseRoomTreasurer(this); + } +} + +class RoseRoomTreasurerEffect extends OneShotEffect { + + RoseRoomTreasurerEffect() { + super(Outcome.Benefit); + staticText = "create a Treasure token if this is the first or second time this ability has resolved this turn. " + + "Otherwise, you may pay {X}. When you do, {this} deals X damage to any target"; + } + + private RoseRoomTreasurerEffect(final RoseRoomTreasurerEffect effect) { + super(effect); + } + + @Override + public RoseRoomTreasurerEffect copy() { + return new RoseRoomTreasurerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (AbilityResolvedWatcher.getResolutionCount(game, source) <= 2) { + return new TreasureToken().putOntoBattlefield(1, game, source); + } + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + ManaCosts cost = new ManaCostsImpl<>("{X}"); + if (!player.chooseUse(Outcome.BoostCreature, "Pay {X}?", source, game)) { + return false; + } + int costX = player.announceXMana(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source); + cost.add(new GenericManaCost(costX)); + if (!cost.pay(source, game, source, source.getControllerId(), false)) { + return false; + } + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new DamageTargetEffect(costX), false); + ability.addTarget(new TargetAnyTarget()); + game.fireReflexiveTriggeredAbility(ability, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RowanFearlessSparkmage.java b/Mage.Sets/src/mage/cards/r/RowanFearlessSparkmage.java index aa673718ad2..1e73be6fd15 100644 --- a/Mage.Sets/src/mage/cards/r/RowanFearlessSparkmage.java +++ b/Mage.Sets/src/mage/cards/r/RowanFearlessSparkmage.java @@ -2,7 +2,6 @@ package mage.cards.r; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.UntapAllEffect; import mage.abilities.effects.common.combat.CantBlockTargetEffect; @@ -33,7 +32,7 @@ public final class RowanFearlessSparkmage extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ROWAN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Up to one target creature gets +3/+0 and gains first strike until end of turn. Ability ability = new LoyaltyAbility(new BoostTargetEffect( diff --git a/Mage.Sets/src/mage/cards/r/RowanKenrith.java b/Mage.Sets/src/mage/cards/r/RowanKenrith.java index 45ec313fe47..fa10de5ed81 100644 --- a/Mage.Sets/src/mage/cards/r/RowanKenrith.java +++ b/Mage.Sets/src/mage/cards/r/RowanKenrith.java @@ -3,7 +3,6 @@ package mage.cards.r; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RequirementEffect; @@ -33,7 +32,7 @@ public final class RowanKenrith extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ROWAN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +2: During target player's next turn, each creature that player controls attacks if able. LoyaltyAbility ability = new LoyaltyAbility(new RowanKenrithAttackEffect(), 2); diff --git a/Mage.Sets/src/mage/cards/r/RowanScholarOfSparks.java b/Mage.Sets/src/mage/cards/r/RowanScholarOfSparks.java index 8d8ff3c1cc8..31fbc9caa24 100644 --- a/Mage.Sets/src/mage/cards/r/RowanScholarOfSparks.java +++ b/Mage.Sets/src/mage/cards/r/RowanScholarOfSparks.java @@ -3,7 +3,6 @@ package mage.cards.r; import mage.MageItem; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalOneShotEffect; @@ -55,7 +54,7 @@ public final class RowanScholarOfSparks extends ModalDoubleFacesCard { // Rowan, Scholar of Sparks // Legendary Planeswalker - Rowan this.getLeftHalfCard().addSuperType(SuperType.LEGENDARY); - this.getLeftHalfCard().addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(2)); + this.getLeftHalfCard().setStartingLoyalty(2); // Instant and sorcery spells you cast cost {1} less to cast. this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1))); @@ -79,7 +78,7 @@ public final class RowanScholarOfSparks extends ModalDoubleFacesCard { // Will, Scholar of Frost // Legendary Planeswalker - Will this.getRightHalfCard().addSuperType(SuperType.LEGENDARY); - this.getRightHalfCard().addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.getRightHalfCard().setStartingLoyalty(4); // Instant and sorcery spells you cast cost {1} less to cast. this.getRightHalfCard().addAbility(new SimpleStaticAbility( diff --git a/Mage.Sets/src/mage/cards/r/RoyalDecree.java b/Mage.Sets/src/mage/cards/r/RoyalDecree.java index da303e1b434..d23feaf24bc 100644 --- a/Mage.Sets/src/mage/cards/r/RoyalDecree.java +++ b/Mage.Sets/src/mage/cards/r/RoyalDecree.java @@ -80,7 +80,7 @@ class RoyalDecreeAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); - if (permanent != null && filter.match(permanent, getSourceId(), getControllerId(), game)) { + if (permanent != null && filter.match(permanent, getControllerId(), this, game)) { Player player = game.getPlayer(permanent.getControllerId()); if (player != null) { for (Effect effect : this.getEffects()) { diff --git a/Mage.Sets/src/mage/cards/r/RoyalTrooper.java b/Mage.Sets/src/mage/cards/r/RoyalTrooper.java index 94180eb5cee..9fc2e3a4fb7 100644 --- a/Mage.Sets/src/mage/cards/r/RoyalTrooper.java +++ b/Mage.Sets/src/mage/cards/r/RoyalTrooper.java @@ -1,16 +1,14 @@ - package mage.cards.r; import java.util.UUID; import mage.MageInt; import mage.abilities.common.BlocksSourceTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; /** * @@ -26,9 +24,7 @@ public final class RoyalTrooper extends CardImpl { this.toughness = new MageInt(2); // Whenever Royal Trooper blocks, it gets +2/+2 until end of turn. - Effect effect = new BoostSourceEffect(2, 2, Duration.EndOfTurn); - effect.setText("it gets +2/+2 until end of turn"); - this.addAbility(new BlocksSourceTriggeredAbility(effect, false)); + this.addAbility(new BlocksSourceTriggeredAbility(new BoostSourceEffect(2, 2, Duration.EndOfTurn, "it"))); } private RoyalTrooper(final RoyalTrooper card) { diff --git a/Mage.Sets/src/mage/cards/r/RubblebeltMaaka.java b/Mage.Sets/src/mage/cards/r/RubblebeltMaaka.java index 1508fd3f519..5162436657a 100644 --- a/Mage.Sets/src/mage/cards/r/RubblebeltMaaka.java +++ b/Mage.Sets/src/mage/cards/r/RubblebeltMaaka.java @@ -4,6 +4,7 @@ package mage.cards.r; import java.util.UUID; import mage.MageInt; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.keyword.BloodrushAbility; import mage.cards.CardImpl; @@ -11,6 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.Outcome; /** * @@ -28,7 +30,9 @@ public final class RubblebeltMaaka extends CardImpl { this.toughness = new MageInt(3); // Bloodrush — {R}, Discard Rubblebelt Maaka: Target attacking creature gets +3/+3 until end of turn. - this.addAbility(new BloodrushAbility("{R}", new BoostTargetEffect(3,3, Duration.EndOfTurn))); + Effect boostEffect = new BoostTargetEffect(3,3, Duration.EndOfTurn); + boostEffect.setOutcome(Outcome.Benefit); + this.addAbility(new BloodrushAbility("{R}", boostEffect)); } diff --git a/Mage.Sets/src/mage/cards/r/RudeAwakening.java b/Mage.Sets/src/mage/cards/r/RudeAwakening.java index ed6c16700c8..4238ef149b9 100644 --- a/Mage.Sets/src/mage/cards/r/RudeAwakening.java +++ b/Mage.Sets/src/mage/cards/r/RudeAwakening.java @@ -28,8 +28,7 @@ public final class RudeAwakening extends CardImpl { // Untap all lands you control; this.getSpellAbility().addEffect(new UntapAllLandsControllerEffect()); // or until end of turn, lands you control become 2/2 creatures that are still lands. - Mode mode = new Mode(); - mode.addEffect(new BecomesCreatureAllEffect( + Mode mode = new Mode(new BecomesCreatureAllEffect( new CreatureToken(2, 2), "lands", new FilterControlledLandPermanent("lands you control"), Duration.EndOfTurn, false)); this.getSpellAbility().getModes().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/r/RuinCrab.java b/Mage.Sets/src/mage/cards/r/RuinCrab.java index e3ea22eec1b..b561a673a0a 100644 --- a/Mage.Sets/src/mage/cards/r/RuinCrab.java +++ b/Mage.Sets/src/mage/cards/r/RuinCrab.java @@ -17,7 +17,7 @@ import mage.constants.TargetController; public final class RuinCrab extends CardImpl { public RuinCrab(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "U"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); this.subtype.add(SubType.CRAB); this.power = new MageInt(0); diff --git a/Mage.Sets/src/mage/cards/r/RuinGhost.java b/Mage.Sets/src/mage/cards/r/RuinGhost.java index 095ea6b2f23..9fc803b4925 100644 --- a/Mage.Sets/src/mage/cards/r/RuinGhost.java +++ b/Mage.Sets/src/mage/cards/r/RuinGhost.java @@ -12,7 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.StaticFilters; import mage.target.TargetPermanent; import java.util.UUID; @@ -30,10 +30,10 @@ public final class RuinGhost extends CardImpl { this.toughness = new MageInt(1); // {W}, {T}: Exile target land you control, then return it to the battlefield under your control. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect(), new ManaCostsImpl("{W")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetForSourceEffect(), new ManaCostsImpl("{W}")); ability.addCost(new TapSourceCost()); - ability.addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect(false)); - ability.addTarget(new TargetPermanent(new FilterControlledLandPermanent())); + ability.addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect(false).concatBy(", then")); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RuinRaider.java b/Mage.Sets/src/mage/cards/r/RuinRaider.java index 7459f2518ba..26287cb13e7 100644 --- a/Mage.Sets/src/mage/cards/r/RuinRaider.java +++ b/Mage.Sets/src/mage/cards/r/RuinRaider.java @@ -32,7 +32,7 @@ public final class RuinRaider extends CardImpl { Ability ability = new ConditionalInterveningIfTriggeredAbility( new BeginningOfEndStepTriggeredAbility(new RuinRaiderEffect(), TargetController.YOU, false), RaidCondition.instance, - "Raid — At the beginning of your end step, if you attacked this turn, " + "At the beginning of your end step, if you attacked this turn, " + "reveal the top card of your library and put that card into your hand. " + "You lose life equal to the card's mana value."); ability.setAbilityWord(AbilityWord.RAID); diff --git a/Mage.Sets/src/mage/cards/r/Rumination.java b/Mage.Sets/src/mage/cards/r/Rumination.java index 786f06e174a..103c1ee52ca 100644 --- a/Mage.Sets/src/mage/cards/r/Rumination.java +++ b/Mage.Sets/src/mage/cards/r/Rumination.java @@ -65,7 +65,7 @@ public final class Rumination extends CardImpl { private boolean putOnLibrary(Player player, Ability source, Game game) { TargetCardInHand target = new TargetCardInHand(); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.ReturnToHand, target, source, game); Card card = player.getHand().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/r/RumorGatherer.java b/Mage.Sets/src/mage/cards/r/RumorGatherer.java new file mode 100644 index 00000000000..5cea8654fca --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RumorGatherer.java @@ -0,0 +1,57 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AllianceAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.Game; +import mage.watchers.common.AbilityResolvedWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RumorGatherer extends CardImpl { + + public RumorGatherer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Alliance — Whenever another creature enters the battlefield under your control, scry 1. If this is the second time this ability has resolved this turn, draw a card instead. + this.addAbility(new AllianceAbility(new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(1), new ScryEffect(1), + RumorGathererCondition.instance, "scry 1. If this is the second time " + + "this ability has resolved this turn, draw a card instead" + )), new AbilityResolvedWatcher()); + } + + private RumorGatherer(final RumorGatherer card) { + super(card); + } + + @Override + public RumorGatherer copy() { + return new RumorGatherer(this); + } +} + +enum RumorGathererCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return AbilityResolvedWatcher.getResolutionCount(game, source) == 2; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RunAshore.java b/Mage.Sets/src/mage/cards/r/RunAshore.java index 5b761dfcd04..15252e271f3 100644 --- a/Mage.Sets/src/mage/cards/r/RunAshore.java +++ b/Mage.Sets/src/mage/cards/r/RunAshore.java @@ -1,16 +1,11 @@ package mage.cards.r; -import mage.abilities.Ability; import mage.abilities.Mode; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetNonlandPermanent; import java.util.UUID; @@ -28,7 +23,7 @@ public final class RunAshore extends CardImpl { this.getSpellAbility().getModes().setMaxModes(2); // • The owner of target nonland permanent puts it on the top or bottom of their library. - this.getSpellAbility().addEffect(new RunAshoreEffect()); + this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect()); this.getSpellAbility().addTarget(new TargetNonlandPermanent()); // • Return target nonland permanent to its owner's hand. @@ -46,33 +41,3 @@ public final class RunAshore extends CardImpl { return new RunAshore(this); } } - -class RunAshoreEffect extends OneShotEffect { - - RunAshoreEffect() { - super(Outcome.Benefit); - staticText = "The owner of target nonland permanent puts it on the top or bottom of their library."; - } - - private RunAshoreEffect(final RunAshoreEffect effect) { - super(effect); - } - - @Override - public RunAshoreEffect copy() { - return new RunAshoreEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget())); - if (player == null) { - return false; - } - if (player.chooseUse(Outcome.Detriment, "Put the targeted object on the top or bottom of your library?", - "", "Top", "Bottom", source, game)) { - return new PutOnLibraryTargetEffect(true).apply(game, source); - } - return new PutOnLibraryTargetEffect(false).apply(game, source); - } -} diff --git a/Mage.Sets/src/mage/cards/r/RunOutOfTown.java b/Mage.Sets/src/mage/cards/r/RunOutOfTown.java new file mode 100644 index 00000000000..5f5942a0d08 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RunOutOfTown.java @@ -0,0 +1,32 @@ +package mage.cards.r; + +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * @author weirddan455 + */ +public final class RunOutOfTown extends CardImpl { + + public RunOutOfTown(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}"); + + // The owner of target nonland permanent puts it on the top or bottom of their library. + this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect()); + this.getSpellAbility().addTarget(new TargetNonlandPermanent()); + } + + private RunOutOfTown(final RunOutOfTown card) { + super(card); + } + + @Override + public RunOutOfTown copy() { + return new RunOutOfTown(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RunawayTrashBot.java b/Mage.Sets/src/mage/cards/r/RunawayTrashBot.java index e2c97a36de6..27c5338a43a 100644 --- a/Mage.Sets/src/mage/cards/r/RunawayTrashBot.java +++ b/Mage.Sets/src/mage/cards/r/RunawayTrashBot.java @@ -25,7 +25,7 @@ import java.util.UUID; public final class RunawayTrashBot extends CardImpl { private static final FilterCard filter - = new FilterArtifactOrEnchantmentCard("artifact and/or enchantment card in your graveyard"); + = new FilterArtifactOrEnchantmentCard("artifact and/or enchantment card"); private static final DynamicValue xValue = new CardsInControllerGraveyardCount(filter); private static final Hint hint = new ValueHint("Artifacts and enchantments in your graveyard", xValue); diff --git a/Mage.Sets/src/mage/cards/r/RuneOfProtectionArtifacts.java b/Mage.Sets/src/mage/cards/r/RuneOfProtectionArtifacts.java index 4ae22891d7f..2b5a4e4e644 100644 --- a/Mage.Sets/src/mage/cards/r/RuneOfProtectionArtifacts.java +++ b/Mage.Sets/src/mage/cards/r/RuneOfProtectionArtifacts.java @@ -31,7 +31,7 @@ public final class RuneOfProtectionArtifacts extends CardImpl { // {W}: The next time an artifact source of your choice would deal damage to you this turn, prevent that damage. Effect effect = new PreventNextDamageFromChosenSourceToYouEffect(Duration.EndOfTurn, filter); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("W"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{W}"))); // Cycling {2} ({2}, Discard this card: Draw a card.) this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); } diff --git a/Mage.Sets/src/mage/cards/r/RuneOfProtectionBlack.java b/Mage.Sets/src/mage/cards/r/RuneOfProtectionBlack.java index be10bc46f9c..21f625619a8 100644 --- a/Mage.Sets/src/mage/cards/r/RuneOfProtectionBlack.java +++ b/Mage.Sets/src/mage/cards/r/RuneOfProtectionBlack.java @@ -31,7 +31,7 @@ public final class RuneOfProtectionBlack extends CardImpl { // {W}: The next time a black source of your choice would deal damage to you this turn, prevent that damage. Effect effect = new PreventNextDamageFromChosenSourceToYouEffect(Duration.EndOfTurn, filter); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("W"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{W}"))); // Cycling {2} ({2}, Discard this card: Draw a card.) this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); } diff --git a/Mage.Sets/src/mage/cards/r/RuneOfProtectionBlue.java b/Mage.Sets/src/mage/cards/r/RuneOfProtectionBlue.java index 2b5b3e8d4c5..27aa0896ae8 100644 --- a/Mage.Sets/src/mage/cards/r/RuneOfProtectionBlue.java +++ b/Mage.Sets/src/mage/cards/r/RuneOfProtectionBlue.java @@ -31,7 +31,7 @@ public final class RuneOfProtectionBlue extends CardImpl { // {W}: The next time a blue source of your choice would deal damage to you this turn, prevent that damage. Effect effect = new PreventNextDamageFromChosenSourceToYouEffect(Duration.EndOfTurn, filter); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("W"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{W}"))); // Cycling {2} ({2}, Discard this card: Draw a card.) this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); } diff --git a/Mage.Sets/src/mage/cards/r/RuneOfProtectionGreen.java b/Mage.Sets/src/mage/cards/r/RuneOfProtectionGreen.java index 2e3b040804b..3b56672c40e 100644 --- a/Mage.Sets/src/mage/cards/r/RuneOfProtectionGreen.java +++ b/Mage.Sets/src/mage/cards/r/RuneOfProtectionGreen.java @@ -31,7 +31,7 @@ public final class RuneOfProtectionGreen extends CardImpl { // {W}: The next time a green source of your choice would deal damage to you this turn, prevent that damage. Effect effect = new PreventNextDamageFromChosenSourceToYouEffect(Duration.EndOfTurn, filter); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("W"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{W}"))); // Cycling {2} ({2}, Discard this card: Draw a card.) this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); } diff --git a/Mage.Sets/src/mage/cards/r/RuneOfProtectionLands.java b/Mage.Sets/src/mage/cards/r/RuneOfProtectionLands.java index b5be55c2301..62180f1edb0 100644 --- a/Mage.Sets/src/mage/cards/r/RuneOfProtectionLands.java +++ b/Mage.Sets/src/mage/cards/r/RuneOfProtectionLands.java @@ -31,7 +31,7 @@ public final class RuneOfProtectionLands extends CardImpl { // {W}: The next time a land source of your choice would deal damage to you this turn, prevent that damage. Effect effect = new PreventNextDamageFromChosenSourceToYouEffect(Duration.EndOfTurn, filter); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("W"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{W}"))); // Cycling {2} ({2}, Discard this card: Draw a card.) this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); } diff --git a/Mage.Sets/src/mage/cards/r/RuneOfProtectionRed.java b/Mage.Sets/src/mage/cards/r/RuneOfProtectionRed.java index 6edb2bdcb94..70ebdcce348 100644 --- a/Mage.Sets/src/mage/cards/r/RuneOfProtectionRed.java +++ b/Mage.Sets/src/mage/cards/r/RuneOfProtectionRed.java @@ -31,7 +31,7 @@ public final class RuneOfProtectionRed extends CardImpl { // {W}: The next time a red source of your choice would deal damage to you this turn, prevent that damage. Effect effect = new PreventNextDamageFromChosenSourceToYouEffect(Duration.EndOfTurn, filter); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("W"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{W}"))); // Cycling {2} ({2}, Discard this card: Draw a card.) this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); } diff --git a/Mage.Sets/src/mage/cards/r/RuneOfProtectionWhite.java b/Mage.Sets/src/mage/cards/r/RuneOfProtectionWhite.java index b2e4f6148ab..2b1fc47eb63 100644 --- a/Mage.Sets/src/mage/cards/r/RuneOfProtectionWhite.java +++ b/Mage.Sets/src/mage/cards/r/RuneOfProtectionWhite.java @@ -31,7 +31,7 @@ public final class RuneOfProtectionWhite extends CardImpl { // {W}: The next time a white source of your choice would deal damage to you this turn, prevent that damage. Effect effect = new PreventNextDamageFromChosenSourceToYouEffect(Duration.EndOfTurn, filter); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("W"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{W}"))); // Cycling {2} ({2}, Discard this card: Draw a card.) this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); } diff --git a/Mage.Sets/src/mage/cards/r/Rupture.java b/Mage.Sets/src/mage/cards/r/Rupture.java index bb53ef7bab1..ca0750b8188 100644 --- a/Mage.Sets/src/mage/cards/r/Rupture.java +++ b/Mage.Sets/src/mage/cards/r/Rupture.java @@ -65,8 +65,8 @@ class RuptureEffect extends OneShotEffect { if (player != null) { int power = 0; TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(1, 1, new FilterControlledCreaturePermanent("creature to sacrifice"), true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { - while (!target.isChosen() && target.canChoose(source.getSourceId(), player.getId(), game) && player.canRespond()) { + if (target.canChoose(player.getId(), source, game)) { + while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) { player.chooseTarget(Outcome.Sacrifice, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/r/RustElemental.java b/Mage.Sets/src/mage/cards/r/RustElemental.java index a68eb8e3cc6..0563bd7e951 100644 --- a/Mage.Sets/src/mage/cards/r/RustElemental.java +++ b/Mage.Sets/src/mage/cards/r/RustElemental.java @@ -78,8 +78,8 @@ class RustElementalEffect extends OneShotEffect { if (controller != null) { TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); // if they can pay the cost, then they must pay - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - controller.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + if (target.canChoose(controller.getId(), source, game)) { + controller.choose(Outcome.Sacrifice, target, source, game); Permanent artifactSacrifice = game.getPermanent(target.getFirstTarget()); if (artifactSacrifice != null) { // sacrifice the chosen artifact diff --git a/Mage.Sets/src/mage/cards/r/RuthlessInstincts.java b/Mage.Sets/src/mage/cards/r/RuthlessInstincts.java index b32641d80df..f71007635d8 100644 --- a/Mage.Sets/src/mage/cards/r/RuthlessInstincts.java +++ b/Mage.Sets/src/mage/cards/r/RuthlessInstincts.java @@ -51,10 +51,9 @@ public final class RuthlessInstincts extends CardImpl { Target target = new TargetCreaturePermanent(filter); this.getSpellAbility().addTarget(target); // * Target attacking creature gets +2/+2 and gains trample until end of turn. - Mode mode = new Mode(); effect = new BoostTargetEffect(2,2,Duration.EndOfTurn); effect.setText("Target attacking creature gets +2/+2"); - mode.addEffect(effect); + Mode mode = new Mode(effect); effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); effect.setText("and gains trample until end of turn"); mode.addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/r/RuthlessRipper.java b/Mage.Sets/src/mage/cards/r/RuthlessRipper.java index 01f4da08f5a..efd680cf517 100644 --- a/Mage.Sets/src/mage/cards/r/RuthlessRipper.java +++ b/Mage.Sets/src/mage/cards/r/RuthlessRipper.java @@ -43,7 +43,7 @@ public final class RuthlessRipper extends CardImpl { this.addAbility(DeathtouchAbility.getInstance()); // Morph - Reveal a black card in your hand. - this.addAbility(new MorphAbility(this, new RevealTargetFromHandCost(new TargetCardInHand(filter)))); + this.addAbility(new MorphAbility(new RevealTargetFromHandCost(new TargetCardInHand(filter)))); // When Ruthless Ripper is turned face up, target player loses 2 life. Effect effect = new LoseLifeTargetEffect(2); diff --git a/Mage.Sets/src/mage/cards/r/RuthlessTechnomancer.java b/Mage.Sets/src/mage/cards/r/RuthlessTechnomancer.java new file mode 100644 index 00000000000..eeb16e5731e --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RuthlessTechnomancer.java @@ -0,0 +1,124 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeXTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.TreasureToken; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RuthlessTechnomancer extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledArtifactPermanent("artifacts"); + + public RuthlessTechnomancer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // When Ruthless Technomancer enters the battlefield, you may sacrifice another creature you control. If you do, create a number of Treasure tokens equal to that creature's power. + this.addAbility(new EntersBattlefieldTriggeredAbility(new RuthlessTechnomancerEffect())); + + // {2}{B}, Sacrifice X artifacts: Return target creature card with power X or less from your graveyard to the battlefield. X can't be 0. + Ability ability = new SimpleActivatedAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect() + .setText("return target creature card with power X or less " + + "from your graveyard to the battlefield. X can't be 0"), + new ManaCostsImpl<>("{2}{B}") + ); + ability.addCost(new SacrificeXTargetCost(filter, false, 1)); + this.addAbility(ability.setTargetAdjuster(RuthlessTechnomancerAdjuster.instance)); + } + + private RuthlessTechnomancer(final RuthlessTechnomancer card) { + super(card); + } + + @Override + public RuthlessTechnomancer copy() { + return new RuthlessTechnomancer(this); + } +} + +enum RuthlessTechnomancerAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int xValue = GetXValue.instance.calculate(game, ability, null); + FilterCard filter = new FilterCreatureCard( + "creature card in your graveyard with power " + xValue + " or less" + ); + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, xValue + 1)); + ability.getTargets().clear(); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + } +} + +class RuthlessTechnomancerEffect extends OneShotEffect { + + RuthlessTechnomancerEffect() { + super(Outcome.Benefit); + staticText = "you may sacrifice another creature you control. If you do, " + + "create a number of Treasure tokens equal to that creature's power"; + } + + private RuthlessTechnomancerEffect(final RuthlessTechnomancerEffect effect) { + super(effect); + } + + @Override + public RuthlessTechnomancerEffect copy() { + return new RuthlessTechnomancerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null || !game.getBattlefield().contains( + StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, source, game, 1 + )) { + return false; + } + TargetPermanent target = new TargetPermanent( + 0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, true + ); + player.choose(outcome, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null || !permanent.sacrifice(source, game)) { + return false; + } + int power = permanent.getPower().getValue(); + return power < 1 || new TreasureToken().putOntoBattlefield(power, game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RyuWorldWarrior.java b/Mage.Sets/src/mage/cards/r/RyuWorldWarrior.java new file mode 100644 index 00000000000..6c282b8e823 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RyuWorldWarrior.java @@ -0,0 +1,105 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.UntapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.TrainingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RyuWorldWarrior extends CardImpl { + + public RyuWorldWarrior(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Training + this.addAbility(new TrainingAbility()); + + // Hadoken—{4}{R}, {Q}, Discard a card: Ryu, World Warrior deals damage equal to his power to any target. If excess damage was dealt to a creature this way, draw a card. + Ability ability = new SimpleActivatedAbility(new RyuWorldWarriorEffect(), new ManaCostsImpl<>("{4}{R}")); + ability.addCost(new UntapSourceCost()); + ability.addCost(new DiscardCardCost()); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability.withFlavorWord("Hadoken")); + } + + private RyuWorldWarrior(final RyuWorldWarrior card) { + super(card); + } + + @Override + public RyuWorldWarrior copy() { + return new RyuWorldWarrior(this); + } +} + +class RyuWorldWarriorEffect extends OneShotEffect { + + RyuWorldWarriorEffect() { + super(Outcome.Benefit); + staticText = "{this} deals damage equal to his power to any target. " + + "If excess damage was dealt to a creature this way, draw a card"; + } + + private RyuWorldWarriorEffect(final RyuWorldWarriorEffect effect) { + super(effect); + } + + @Override + public RyuWorldWarriorEffect copy() { + return new RyuWorldWarriorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = source.getSourcePermanentOrLKI(game); + if (sourcePermanent == null) { + return false; + } + int amount = sourcePermanent.getPower().getValue(); + if (amount < 1) { + return false; + } + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + return player != null && player.damage(amount, source, game) > 0; + } + if (!permanent.isCreature(game)) { + return permanent.damage(amount, source, game) > 0; + } + int lethal = permanent.getLethalDamage(source.getSourceId(), game); + permanent.damage(amount, source.getSourceId(), source, game); + if (lethal >= amount) { + return true; + } + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + player.drawCards(1, source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SaberAnts.java b/Mage.Sets/src/mage/cards/s/SaberAnts.java index aa3cfcca21c..df191a05cba 100644 --- a/Mage.Sets/src/mage/cards/s/SaberAnts.java +++ b/Mage.Sets/src/mage/cards/s/SaberAnts.java @@ -1,20 +1,15 @@ - package mage.cards.s; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealtDamageToSourceTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Outcome; -import mage.game.Game; import mage.game.permanent.token.InsectToken; -import mage.players.Player; /** * @@ -30,7 +25,8 @@ public final class SaberAnts extends CardImpl { this.toughness = new MageInt(3); // Whenever Saber Ants is dealt damage, you may create that many 1/1 green Insect creature tokens. - this.addAbility(new DealtDamageToSourceTriggeredAbility(new SaberAntsEffect(), true, false)); + this.addAbility(new DealtDamageToSourceTriggeredAbility( + new CreateTokenEffect(new InsectToken(), SavedDamageValue.MANY), true)); } private SaberAnts(final SaberAnts card) { @@ -42,30 +38,3 @@ public final class SaberAnts extends CardImpl { return new SaberAnts(this); } } - -class SaberAntsEffect extends OneShotEffect { - - public SaberAntsEffect() { - super(Outcome.Benefit); - this.staticText = "you may create that many 1/1 green Insect creature tokens"; - } - - public SaberAntsEffect(final SaberAntsEffect effect) { - super(effect); - } - - @Override - public SaberAntsEffect copy() { - return new SaberAntsEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - int damage = (Integer) this.getValue("damage"); - return new CreateTokenEffect(new InsectToken(), damage).apply(game, source); - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SabertoothAlleyCat.java b/Mage.Sets/src/mage/cards/s/SabertoothAlleyCat.java index 4d19a8f3f1f..020786b9e8c 100644 --- a/Mage.Sets/src/mage/cards/s/SabertoothAlleyCat.java +++ b/Mage.Sets/src/mage/cards/s/SabertoothAlleyCat.java @@ -1,4 +1,3 @@ - package mage.cards.s; import java.util.UUID; @@ -24,6 +23,12 @@ import mage.filter.predicate.mageobject.AbilityPredicate; */ public final class SabertoothAlleyCat extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures without defender"); + + static { + filter.add(Predicates.not(new AbilityPredicate(DefenderAbility.class))); + } + public SabertoothAlleyCat(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); @@ -31,18 +36,14 @@ public final class SabertoothAlleyCat extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(1); - // Sabertooth Alley Cat attacks each turn if able. + // Sabertooth Alley Cat attacks each combat if able. this.addAbility(new AttacksEachCombatStaticAbility()); // {1}{R}: Creatures without defender can't block Sabertooth Alley Cat this turn. this.addAbility(new SimpleActivatedAbility( - Zone.BATTLEFIELD, - new CantBeBlockedByCreaturesSourceEffect( - (FilterCreaturePermanent) new FilterCreaturePermanent().add(Predicates.not(new AbilityPredicate(DefenderAbility.class))), - Duration.EndOfTurn - ) - .setText("Creatures without defender can't block {this} this turn"), - new ManaCostsImpl<>("{1}{R}"))); + new CantBeBlockedByCreaturesSourceEffect(filter, Duration.EndOfTurn), + new ManaCostsImpl<>("{1}{R}") + )); } private SabertoothAlleyCat(final SabertoothAlleyCat card) { diff --git a/Mage.Sets/src/mage/cards/s/SacellumGodspeaker.java b/Mage.Sets/src/mage/cards/s/SacellumGodspeaker.java index 1861ec0c4bb..a21594de418 100644 --- a/Mage.Sets/src/mage/cards/s/SacellumGodspeaker.java +++ b/Mage.Sets/src/mage/cards/s/SacellumGodspeaker.java @@ -89,7 +89,7 @@ class SacellumGodspeakerEffect extends ManaEffect { public Mana produceMana(Game game, Ability source) { if (game != null) { TargetCardInHand target = new TargetCardInHand(0, Integer.MAX_VALUE, filter); - if (target.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), game)) { + if (target.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), source, game)) { return Mana.GreenMana(target.getTargets().size()); } } diff --git a/Mage.Sets/src/mage/cards/s/SadisticAugermage.java b/Mage.Sets/src/mage/cards/s/SadisticAugermage.java index fe3d7d4a7b1..0013753d87b 100644 --- a/Mage.Sets/src/mage/cards/s/SadisticAugermage.java +++ b/Mage.Sets/src/mage/cards/s/SadisticAugermage.java @@ -71,7 +71,7 @@ class WidespreadPanicEffect extends OneShotEffect { if (!player.getHand().isEmpty()) { TargetCardInHand target = new TargetCardInHand(); target.setTargetName("a card from your hand to put on top of your library"); - player.choose(Outcome.Detriment, target, source.getSourceId(), game); + player.choose(Outcome.Detriment, target, source, game); Card card = player.getHand().get(target.getFirstTarget(), game); if (card != null) { player.moveCardToLibraryWithInfo(card, source, game, Zone.HAND, true, false); diff --git a/Mage.Sets/src/mage/cards/s/SadisticSacrament.java b/Mage.Sets/src/mage/cards/s/SadisticSacrament.java index 7861c852283..f1f927c5308 100644 --- a/Mage.Sets/src/mage/cards/s/SadisticSacrament.java +++ b/Mage.Sets/src/mage/cards/s/SadisticSacrament.java @@ -1,34 +1,27 @@ - package mage.cards.s; -import java.util.List; -import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.condition.common.KickedCondition; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.search.SearchLibraryAndExileTargetEffect; import mage.abilities.keyword.KickerAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.filter.FilterCard; -import mage.game.Game; -import mage.players.Player; import mage.target.TargetPlayer; -import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; /** - * * @author North */ public final class SadisticSacrament extends CardImpl { - private static final String ruleText = "Search target player's library for up to three cards, exile them, then that player shuffles. If this spell was kicked, instead search that player's library for up to fifteen cards, exile them, then that player shuffles"; + private static final String ruleText = "Search target player's library for up to three cards, exile them, " + + "then that player shuffles. If this spell was kicked, instead search that player's library " + + "for up to fifteen cards, exile them, then that player shuffles"; public SadisticSacrament(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{B}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}{B}{B}"); this.color.setBlack(true); @@ -38,10 +31,10 @@ public final class SadisticSacrament extends CardImpl { // Search target player's library for up to three cards, exile them, then that player shuffles their library. // If Sadistic Sacrament was kicked, instead search that player's library for up to fifteen cards, exile them, then that player shuffles their library. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new SadisticSacramentEffect(15), - new SadisticSacramentEffect(3), - KickedCondition.instance, - ruleText)); + new SearchLibraryAndExileTargetEffect(15, true), + new SearchLibraryAndExileTargetEffect(3, true), + KickedCondition.instance, ruleText + )); this.getSpellAbility().addTarget(new TargetPlayer()); } @@ -54,45 +47,3 @@ public final class SadisticSacrament extends CardImpl { return new SadisticSacrament(this); } } - -class SadisticSacramentEffect extends OneShotEffect { - - private int amount; - - public SadisticSacramentEffect(int amount) { - super(Outcome.Exile); - this.amount = amount; - } - - public SadisticSacramentEffect(final SadisticSacramentEffect effect) { - super(effect); - this.amount = effect.amount; - } - - @Override - public SadisticSacramentEffect copy() { - return new SadisticSacramentEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player targetPlayer = game.getPlayer(source.getFirstTarget()); - Player player = game.getPlayer(source.getControllerId()); - if (player != null && targetPlayer != null) { - TargetCardInLibrary target = new TargetCardInLibrary(0, amount, new FilterCard("cards to exile")); - if (player.searchLibrary(target, source, game, targetPlayer.getId())) { - List targets = target.getTargets(); - for (UUID targetId : targets) { - Card card = targetPlayer.getLibrary().remove(targetId, game); - if (card != null) { - card.moveToExile(null, "", source, game); - } - } - } - targetPlayer.shuffleLibrary(source, game); - return true; - } - - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SadisticSkymarcher.java b/Mage.Sets/src/mage/cards/s/SadisticSkymarcher.java index 87a0009aa11..e0df9838cdf 100644 --- a/Mage.Sets/src/mage/cards/s/SadisticSkymarcher.java +++ b/Mage.Sets/src/mage/cards/s/SadisticSkymarcher.java @@ -37,9 +37,9 @@ public final class SadisticSkymarcher extends CardImpl { // As an additional cost to cast Sadistic Skymarcher, reveal a Vampire card from your hand or pay {1}. this.getSpellAbility().addCost(new OrCost( - new RevealTargetFromHandCost(new TargetCardInHand(filter)), - new GenericManaCost(1), - "reveal a Vampire card from your hand or pay {1}")); + "reveal a Vampire card from your hand or pay {1}", new RevealTargetFromHandCost(new TargetCardInHand(filter)), + new GenericManaCost(1) + )); // Flying this.addAbility(FlyingAbility.getInstance()); diff --git a/Mage.Sets/src/mage/cards/s/SaffiEriksdotter.java b/Mage.Sets/src/mage/cards/s/SaffiEriksdotter.java index 48b69f2c1c5..a0168a02bce 100644 --- a/Mage.Sets/src/mage/cards/s/SaffiEriksdotter.java +++ b/Mage.Sets/src/mage/cards/s/SaffiEriksdotter.java @@ -57,7 +57,7 @@ class SaffiEriksdotterEffect extends OneShotEffect { public SaffiEriksdotterEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "When target creature is put into your graveyard from the battlefield this turn, return that card to the battlefield"; + this.staticText = "When target creature is put into your graveyard this turn, return that card to the battlefield"; } public SaffiEriksdotterEffect(final SaffiEriksdotterEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/SageEyeAvengers.java b/Mage.Sets/src/mage/cards/s/SageEyeAvengers.java index 26ffede2027..60ca085df22 100644 --- a/Mage.Sets/src/mage/cards/s/SageEyeAvengers.java +++ b/Mage.Sets/src/mage/cards/s/SageEyeAvengers.java @@ -70,7 +70,7 @@ class SageEyeAvengersEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && controller != null) { Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); if (targetCreature != null && targetCreature.getPower().getValue() < sourceObject.getPower().getValue()) { diff --git a/Mage.Sets/src/mage/cards/s/SageEyeHarrier.java b/Mage.Sets/src/mage/cards/s/SageEyeHarrier.java index 96f7cf11307..5b2215efc6d 100644 --- a/Mage.Sets/src/mage/cards/s/SageEyeHarrier.java +++ b/Mage.Sets/src/mage/cards/s/SageEyeHarrier.java @@ -28,7 +28,7 @@ public final class SageEyeHarrier extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Morph {3}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{W}"))); } private SageEyeHarrier(final SageEyeHarrier card) { diff --git a/Mage.Sets/src/mage/cards/s/SaguArcher.java b/Mage.Sets/src/mage/cards/s/SaguArcher.java index 70b2e9bf31b..b706cb6015f 100644 --- a/Mage.Sets/src/mage/cards/s/SaguArcher.java +++ b/Mage.Sets/src/mage/cards/s/SaguArcher.java @@ -28,7 +28,7 @@ public final class SaguArcher extends CardImpl { // Reach this.addAbility(ReachAbility.getInstance()); // Morph {4}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{G}"))); } private SaguArcher(final SaguArcher card) { diff --git a/Mage.Sets/src/mage/cards/s/SaguMauler.java b/Mage.Sets/src/mage/cards/s/SaguMauler.java index bc16cb96696..79995068d70 100644 --- a/Mage.Sets/src/mage/cards/s/SaguMauler.java +++ b/Mage.Sets/src/mage/cards/s/SaguMauler.java @@ -30,7 +30,7 @@ public final class SaguMauler extends CardImpl { // Hexproof this.addAbility(HexproofAbility.getInstance()); // Morph {3}{G}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{G}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{G}{U}"))); } private SaguMauler(final SaguMauler card) { diff --git a/Mage.Sets/src/mage/cards/s/SaheeliRai.java b/Mage.Sets/src/mage/cards/s/SaheeliRai.java index 904f5891f45..b246830c3a7 100644 --- a/Mage.Sets/src/mage/cards/s/SaheeliRai.java +++ b/Mage.Sets/src/mage/cards/s/SaheeliRai.java @@ -3,7 +3,6 @@ package mage.cards.s; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -12,16 +11,15 @@ import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.abilities.effects.keyword.ScryEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; import mage.constants.*; +import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.common.FilterArtifactCard; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCardWithDifferentNameInLibrary; import mage.target.common.TargetControlledPermanent; import mage.target.targetpointer.FixedTarget; @@ -32,12 +30,14 @@ import java.util.UUID; */ public final class SaheeliRai extends CardImpl { + private static final FilterCard filter = new FilterArtifactCard("artifact cards with different names"); + public SaheeliRai(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{U}{R}"); this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SAHEELI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Scry 1. Saheeli Rai deals 1 damage to each opponent. Effect effect = new ScryEffect(1); @@ -52,7 +52,7 @@ public final class SaheeliRai extends CardImpl { this.addAbility(ability); // -7: Search your library for up to three artifact cards with different names, put them onto the battlefield, then shuffle your library. - this.addAbility(new LoyaltyAbility(new SearchLibraryPutInPlayEffect(new SaheeliRaiTarget()), -7)); + this.addAbility(new LoyaltyAbility(new SearchLibraryPutInPlayEffect(new TargetCardWithDifferentNameInLibrary(0, 3, filter)), -7)); } private SaheeliRai(final SaheeliRai card) { @@ -99,34 +99,3 @@ class SaheeliRaiCreateTokenEffect extends OneShotEffect { return false; } } - -class SaheeliRaiTarget extends TargetCardInLibrary { - - SaheeliRaiTarget() { - super(0, 3, new FilterArtifactCard("artifact cards with different names")); - } - - SaheeliRaiTarget(final SaheeliRaiTarget target) { - super(target); - } - - @Override - public SaheeliRaiTarget copy() { - return new SaheeliRaiTarget(this); - } - - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Cards cards, Game game) { - Card card = cards.get(id, game); - if (card != null) { - for (UUID targetId : this.getTargets()) { - Card iCard = game.getCard(targetId); - if (iCard != null && iCard.getName().equals(card.getName())) { - return false; - } - } - return filter.match(card, playerId, game); - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SaheeliSublimeArtificer.java b/Mage.Sets/src/mage/cards/s/SaheeliSublimeArtificer.java index 64e66980243..53dcfabab84 100644 --- a/Mage.Sets/src/mage/cards/s/SaheeliSublimeArtificer.java +++ b/Mage.Sets/src/mage/cards/s/SaheeliSublimeArtificer.java @@ -3,7 +3,6 @@ package mage.cards.s; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; @@ -50,7 +49,7 @@ public final class SaheeliSublimeArtificer extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SAHEELI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Whenever you cast a noncreature spell, create a 1/1 colorless Servo artifact creature token. this.addAbility(new SpellCastControllerTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/s/SaheeliTheGifted.java b/Mage.Sets/src/mage/cards/s/SaheeliTheGifted.java index 99cf88d9516..3ce79c4066a 100644 --- a/Mage.Sets/src/mage/cards/s/SaheeliTheGifted.java +++ b/Mage.Sets/src/mage/cards/s/SaheeliTheGifted.java @@ -5,7 +5,6 @@ import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.SpellAbility; import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.effects.common.CreateTokenEffect; @@ -37,7 +36,7 @@ public final class SaheeliTheGifted extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SAHEELI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Create a 1/1 colorless Servo artifact creature token. this.addAbility(new LoyaltyAbility( diff --git a/Mage.Sets/src/mage/cards/s/SaheelisArtistry.java b/Mage.Sets/src/mage/cards/s/SaheelisArtistry.java index 1edb601e2e3..0461e871108 100644 --- a/Mage.Sets/src/mage/cards/s/SaheelisArtistry.java +++ b/Mage.Sets/src/mage/cards/s/SaheelisArtistry.java @@ -27,11 +27,10 @@ public final class SaheelisArtistry extends CardImpl { this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetArtifactPermanent().withChooseHint("create copy of that")); // • Create a token that's a copy of target creature, except that it's an artifact in addition to its other types. - Mode mode1 = new Mode(); effect = new CreateTokenCopyTargetEffect(); effect.setBecomesArtifact(true); - effect.setText("Create a token that's a copy of target creature, except that it's an artifact in addition to its other types"); - mode1.addEffect(effect); + effect.setText("Create a token that's a copy of target creature, except it's an artifact in addition to its other types"); + Mode mode1 = new Mode(effect); mode1.addTarget(new TargetCreaturePermanent().withChooseHint("create copy of that, artifact type")); this.getSpellAbility().addMode(mode1); } diff --git a/Mage.Sets/src/mage/cards/s/SaibaTrespassers.java b/Mage.Sets/src/mage/cards/s/SaibaTrespassers.java index 1e0c08f8e1c..f62482413d9 100644 --- a/Mage.Sets/src/mage/cards/s/SaibaTrespassers.java +++ b/Mage.Sets/src/mage/cards/s/SaibaTrespassers.java @@ -28,12 +28,9 @@ public final class SaibaTrespassers extends CardImpl { this.toughness = new MageInt(5); // Channel — {3}{U}, Discard Saiba Trespassers: Tap up to two target creatures you don't control. Those creatures don't untap during their controller's next untap step. - Ability ability = new ChannelAbility( - "{3}{U}", new TapTargetEffect() - .setText("tap up to two target creatures you don't control") - ); + Ability ability = new ChannelAbility("{3}{U}", new TapTargetEffect()); ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("Those creatures")); - ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + ability.addTarget(new TargetPermanent(0, 2, StaticFilters.FILTER_CREATURES_YOU_DONT_CONTROL)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SaidDone.java b/Mage.Sets/src/mage/cards/s/SaidDone.java index 24cb3f31eb6..b32b25fe168 100644 --- a/Mage.Sets/src/mage/cards/s/SaidDone.java +++ b/Mage.Sets/src/mage/cards/s/SaidDone.java @@ -1,7 +1,7 @@ package mage.cards.s; import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.effects.common.TapTargetEffect; import mage.cards.CardSetInfo; import mage.cards.SplitCard; @@ -27,7 +27,7 @@ public final class SaidDone extends SplitCard { // Said // Return target instant or sorcery card from your graveyard to your hand. - this.getLeftHalfCard().getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getLeftHalfCard().getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); this.getLeftHalfCard().getSpellAbility().addTarget(new TargetCardInYourGraveyard( StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD )); diff --git a/Mage.Sets/src/mage/cards/s/SakashimasWill.java b/Mage.Sets/src/mage/cards/s/SakashimasWill.java index 5edb0fee416..30647a25d5f 100644 --- a/Mage.Sets/src/mage/cards/s/SakashimasWill.java +++ b/Mage.Sets/src/mage/cards/s/SakashimasWill.java @@ -78,10 +78,10 @@ class SakashimasWillStealEffect extends OneShotEffect { } TargetPermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), player.getId(), game)) { + if (!target.canChoose(player.getId(), source, game)) { return false; } - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); if (game.getPermanent(target.getFirstTarget()) == null) { return false; } @@ -116,17 +116,17 @@ class SakashimasWillCopyEffect extends OneShotEffect { } TargetPermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), player.getId(), game)) { + if (!target.canChoose(player.getId(), source, game)) { return false; } - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Permanent chosenCreature = game.getPermanent(target.getFirstTarget()); if (chosenCreature == null) { return false; } for (Permanent permanent : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - player.getId(), source.getSourceId(), game + player.getId(), source, game )) { if (permanent == null || permanent.getId().equals(chosenCreature.getId())) { continue; diff --git a/Mage.Sets/src/mage/cards/s/SaltRoadAmbushers.java b/Mage.Sets/src/mage/cards/s/SaltRoadAmbushers.java index 310828ec3fd..d766236ffed 100644 --- a/Mage.Sets/src/mage/cards/s/SaltRoadAmbushers.java +++ b/Mage.Sets/src/mage/cards/s/SaltRoadAmbushers.java @@ -32,7 +32,7 @@ public final class SaltRoadAmbushers extends CardImpl { this.addAbility(new SaltRoadAmbushersTriggeredAbility()); // Megamorph {3}{G}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{G}{G}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{G}{G}"), true)); } private SaltRoadAmbushers(final SaltRoadAmbushers card) { diff --git a/Mage.Sets/src/mage/cards/s/Saltskitter.java b/Mage.Sets/src/mage/cards/s/Saltskitter.java index 673cf8c5c84..eca33af6caa 100644 --- a/Mage.Sets/src/mage/cards/s/Saltskitter.java +++ b/Mage.Sets/src/mage/cards/s/Saltskitter.java @@ -32,7 +32,7 @@ public final class Saltskitter extends CardImpl { this.toughness = new MageInt(4); // Whenever another creature enters the battlefield, exile Saltskitter. Return Saltskitter to the battlefield under its owner's control at the beginning of the next end step. - this.addAbility(new EntersBattlefieldAllTriggeredAbility(new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true), filter)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(), filter)); } private Saltskitter(final Saltskitter card) { diff --git a/Mage.Sets/src/mage/cards/s/SalvageScout.java b/Mage.Sets/src/mage/cards/s/SalvageScout.java index a3b56b6eaf2..1ae3743b175 100644 --- a/Mage.Sets/src/mage/cards/s/SalvageScout.java +++ b/Mage.Sets/src/mage/cards/s/SalvageScout.java @@ -1,37 +1,35 @@ - - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** * @author nantuko */ public final class SalvageScout extends CardImpl { public SalvageScout(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.SCOUT); this.power = new MageInt(1); this.toughness = new MageInt(1); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{W}")); - ability.addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl<>("{W}")); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } @@ -44,5 +42,4 @@ public final class SalvageScout extends CardImpl { public SalvageScout copy() { return new SalvageScout(this); } - } diff --git a/Mage.Sets/src/mage/cards/s/SalvageScuttler.java b/Mage.Sets/src/mage/cards/s/SalvageScuttler.java index 4e2c6b0b1f5..02d336c2703 100644 --- a/Mage.Sets/src/mage/cards/s/SalvageScuttler.java +++ b/Mage.Sets/src/mage/cards/s/SalvageScuttler.java @@ -1,20 +1,17 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnToHandChosenControlledPermanentEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterControlledArtifactPermanent; -import mage.target.common.TargetControlledPermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author fireshoes */ public final class SalvageScuttler extends CardImpl { @@ -27,9 +24,9 @@ public final class SalvageScuttler extends CardImpl { this.toughness = new MageInt(4); // Whenever Salvage Scuttler attacks, return an artifact you control to its owner's hand. - Ability ability = new AttacksTriggeredAbility(new ReturnToHandTargetEffect(), false); - ability.addTarget(new TargetControlledPermanent(new FilterControlledArtifactPermanent("an artifact you control"))); - this.addAbility(ability); + this.addAbility(new AttacksTriggeredAbility( + new ReturnToHandChosenControlledPermanentEffect(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT) + )); } private SalvageScuttler(final SalvageScuttler card) { diff --git a/Mage.Sets/src/mage/cards/s/SalvageTitan.java b/Mage.Sets/src/mage/cards/s/SalvageTitan.java index ee2ecba633e..2c163626e44 100644 --- a/Mage.Sets/src/mage/cards/s/SalvageTitan.java +++ b/Mage.Sets/src/mage/cards/s/SalvageTitan.java @@ -13,7 +13,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledArtifactPermanent; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetControlledPermanent; @@ -32,10 +32,10 @@ public final class SalvageTitan extends CardImpl { this.toughness = new MageInt(4); // You may sacrifice three artifacts rather than pay Salvage Titan's mana cost. - this.addAbility(new AlternativeCostSourceAbility(new SacrificeTargetCost(new TargetControlledPermanent(3, 3, new FilterControlledArtifactPermanent("three artifacts"), true)))); + this.addAbility(new AlternativeCostSourceAbility(new SacrificeTargetCost(new TargetControlledPermanent(3, 3, new FilterControlledArtifactPermanent("artifacts"), true)))); // Exile three artifact cards from your graveyard: Return Salvage Titan from your graveyard to your hand. - this.addAbility(new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), new ExileFromGraveCost(new TargetCardInYourGraveyard(3, new FilterArtifactCard("artifact cards"))))); + this.addAbility(new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), new ExileFromGraveCost(new TargetCardInYourGraveyard(3, StaticFilters.FILTER_CARD_ARTIFACTS)))); } private SalvageTitan(final SalvageTitan card) { diff --git a/Mage.Sets/src/mage/cards/s/SalvagerOfSecrets.java b/Mage.Sets/src/mage/cards/s/SalvagerOfSecrets.java index ca28ea97a7e..ce714d45038 100644 --- a/Mage.Sets/src/mage/cards/s/SalvagerOfSecrets.java +++ b/Mage.Sets/src/mage/cards/s/SalvagerOfSecrets.java @@ -1,20 +1,19 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.constants.SubType; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.common.FilterInstantOrSorceryCard; -import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class SalvagerOfSecrets extends CardImpl { @@ -30,9 +29,8 @@ public final class SalvagerOfSecrets extends CardImpl { this.toughness = new MageInt(2); // When Salvager of Secrets enters the battlefield, return target instant or sorcery card from your graveyard to your hand. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false); - Target target = new TargetCardInYourGraveyard(filter); - ability.addTarget(target); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), false); + ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SamiteMinistration.java b/Mage.Sets/src/mage/cards/s/SamiteMinistration.java index ed40a7d9296..601776c7784 100644 --- a/Mage.Sets/src/mage/cards/s/SamiteMinistration.java +++ b/Mage.Sets/src/mage/cards/s/SamiteMinistration.java @@ -62,7 +62,7 @@ class SamiteMinistrationEffect extends PreventionEffectImpl { @Override public void init(Ability source, Game game) { - this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/s/SamitePilgrim.java b/Mage.Sets/src/mage/cards/s/SamitePilgrim.java index 7dc7467ba7c..d5c30cbce2d 100644 --- a/Mage.Sets/src/mage/cards/s/SamitePilgrim.java +++ b/Mage.Sets/src/mage/cards/s/SamitePilgrim.java @@ -65,7 +65,7 @@ class SamitePilgrimPreventDamageToTargetEffect extends PreventionEffectImpl { @Override public void init(Ability source, Game game) { super.init(source, game); - amountToPrevent = new DomainValue().calculate(game, source, this); + amountToPrevent = DomainValue.REGULAR.calculate(game, source, this); } @Override diff --git a/Mage.Sets/src/mage/cards/s/SamutTheTested.java b/Mage.Sets/src/mage/cards/s/SamutTheTested.java index 7ba6c6c79e1..bf1211792e9 100644 --- a/Mage.Sets/src/mage/cards/s/SamutTheTested.java +++ b/Mage.Sets/src/mage/cards/s/SamutTheTested.java @@ -3,7 +3,6 @@ package mage.cards.s; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageMultiEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; @@ -37,7 +36,7 @@ public final class SamutTheTested extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SAMUT); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Up to one target creature gains double strike until end of turn. Effect effect = new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn); diff --git a/Mage.Sets/src/mage/cards/s/SamutTyrantSmasher.java b/Mage.Sets/src/mage/cards/s/SamutTyrantSmasher.java index a26b5c343f3..901df609861 100644 --- a/Mage.Sets/src/mage/cards/s/SamutTyrantSmasher.java +++ b/Mage.Sets/src/mage/cards/s/SamutTyrantSmasher.java @@ -3,7 +3,6 @@ package mage.cards.s; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -29,7 +28,7 @@ public final class SamutTyrantSmasher extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SAMUT); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Creatures you control have haste. this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( diff --git a/Mage.Sets/src/mage/cards/s/SanctuaryWarden.java b/Mage.Sets/src/mage/cards/s/SanctuaryWarden.java new file mode 100644 index 00000000000..4f926b367c4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SanctuaryWarden.java @@ -0,0 +1,74 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.costs.common.RemoveCounterCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.game.permanent.token.CitizenGreenWhiteToken; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SanctuaryWarden extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledPermanent("a creature or planeswalker you control"); + + static { + filter.add(Predicates.or( + CardType.CREATURE.getPredicate(), + CardType.PLANESWALKER.getPredicate() + )); + } + + public SanctuaryWarden(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); + + this.subtype.add(SubType.ANGEL); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Sanctuary Warden enters the battlefield with two shield counters on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.SHIELD.createInstance(2)), + "with two shield counters on it. (If it would be dealt damage " + + "or destroyed, remove a shield counter from it instead.)" + )); + + // Whenever Sanctuary Warden enters the battlefield or attacks, you may remove a counter from a creature or planeswalker you control. If you do, draw a card and create a 1/1 green and white Citizen creature token. + this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility( + new DoIfCostPaid( + new DrawCardSourceControllerEffect(1), + new RemoveCounterCost(new TargetControlledPermanent(filter)) + ).addEffect(new CreateTokenEffect(new CitizenGreenWhiteToken()).concatBy("and")) + )); + } + + private SanctuaryWarden(final SanctuaryWarden card) { + super(card); + } + + @Override + public SanctuaryWarden copy() { + return new SanctuaryWarden(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SanctumGargoyle.java b/Mage.Sets/src/mage/cards/s/SanctumGargoyle.java index 2e1f5f3feb3..198294d89cc 100644 --- a/Mage.Sets/src/mage/cards/s/SanctumGargoyle.java +++ b/Mage.Sets/src/mage/cards/s/SanctumGargoyle.java @@ -1,28 +1,26 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; -import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author North */ public final class SanctumGargoyle extends CardImpl { public SanctumGargoyle(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{W}"); this.subtype.add(SubType.GARGOYLE); this.power = new MageInt(2); @@ -32,7 +30,7 @@ public final class SanctumGargoyle extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Sanctum Gargoyle enters the battlefield, you may return target artifact card from your graveyard to your hand. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), true); - ability.addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SanctumPrelate.java b/Mage.Sets/src/mage/cards/s/SanctumPrelate.java index b7e04f22e9f..633ea117ca3 100644 --- a/Mage.Sets/src/mage/cards/s/SanctumPrelate.java +++ b/Mage.Sets/src/mage/cards/s/SanctumPrelate.java @@ -1,8 +1,5 @@ - package mage.cards.s; -import java.util.UUID; - import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -19,6 +16,8 @@ import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.players.Player; +import java.util.UUID; + /** * @author maxlebedev */ @@ -52,7 +51,7 @@ class ChooseNumberEffect extends OneShotEffect { public ChooseNumberEffect() { super(Outcome.Detriment); - staticText = setText(); + staticText = "choose a number"; } public ChooseNumberEffect(final ChooseNumberEffect effect) { @@ -67,7 +66,7 @@ class ChooseNumberEffect extends OneShotEffect { game.getState().setValue(source.getSourceId().toString(), numberChoice); Permanent permanent = game.getPermanentEntering(source.getSourceId()); - if(permanent != null) { + if (permanent != null) { permanent.addInfo("chosen players", "Chosen Number: " + numberChoice + "", game); game.informPlayers(permanent.getLogName() + ", chosen number: " + numberChoice); @@ -80,10 +79,6 @@ class ChooseNumberEffect extends OneShotEffect { public ChooseNumberEffect copy() { return new ChooseNumberEffect(this); } - - private String setText() { - return "Choose a number. Noncreature spells with mana value equal to the chosen number can't be cast"; - } } class SanctumPrelateReplacementEffect extends ContinuousRuleModifyingEffectImpl { @@ -111,7 +106,7 @@ class SanctumPrelateReplacementEffect extends ContinuousRuleModifyingEffectImpl @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast a noncreature card with that mana value (" + mageObject.getIdName() + " in play)."; } diff --git a/Mage.Sets/src/mage/cards/s/SandStrangler.java b/Mage.Sets/src/mage/cards/s/SandStrangler.java index 8eaffb957a5..a120a9649f8 100644 --- a/Mage.Sets/src/mage/cards/s/SandStrangler.java +++ b/Mage.Sets/src/mage/cards/s/SandStrangler.java @@ -1,37 +1,24 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.condition.OrCondition; -import mage.abilities.condition.common.CardsInControllerGraveyardCondition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.condition.common.DesertControlledOrGraveyardCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.FilterCard; -import mage.filter.common.FilterControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author spjspj */ public final class SandStrangler extends CardImpl { - private static final FilterControlledPermanent filterDesertPermanent = new FilterControlledPermanent("Desert"); - private static final FilterCard filterDesertCard = new FilterCard("Desert card"); - - static { - filterDesertPermanent.add(SubType.DESERT.getPredicate()); - filterDesertCard.add(SubType.DESERT.getPredicate()); - } - public SandStrangler(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); @@ -42,13 +29,11 @@ public final class SandStrangler extends CardImpl { // When Sand Strangler enters the battlefield, if you control a Desert or there is a Desert card in your graveyard, you may have Sand Strangler deal 3 damage to target creature. Ability ability = new ConditionalInterveningIfTriggeredAbility( new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(3), true), - new OrCondition( - new PermanentsOnTheBattlefieldCondition(new FilterControlledPermanent(filterDesertPermanent)), - new CardsInControllerGraveyardCondition(1, filterDesertCard)), - "When {this} enters the battlefield, if you control a Desert or there is a Desert card in your graveyard, you may have {this} deal 3 damage to target creature."); + DesertControlledOrGraveyardCondition.instance, "When {this} enters the battlefield, " + + "if you control a Desert or there is a Desert card in your graveyard, " + + "you may have {this} deal 3 damage to target creature."); ability.addTarget(new TargetCreaturePermanent()); - this.addAbility(ability); - + this.addAbility(ability.addHint(DesertControlledOrGraveyardCondition.getHint())); } private SandStrangler(final SandStrangler card) { diff --git a/Mage.Sets/src/mage/cards/s/SandsteppeOutcast.java b/Mage.Sets/src/mage/cards/s/SandsteppeOutcast.java index 0b5f0943a72..a845b9811dd 100644 --- a/Mage.Sets/src/mage/cards/s/SandsteppeOutcast.java +++ b/Mage.Sets/src/mage/cards/s/SandsteppeOutcast.java @@ -32,8 +32,7 @@ public final class SandsteppeOutcast extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())); // * Create a 1/1 white Spirit creature token with flying. - Mode mode = new Mode(); - mode.addEffect(new CreateTokenEffect(new SpiritWhiteToken())); + Mode mode = new Mode(new CreateTokenEffect(new SpiritWhiteToken())); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SandstoneOracle.java b/Mage.Sets/src/mage/cards/s/SandstoneOracle.java index da15a23c9e2..c671054a3bc 100644 --- a/Mage.Sets/src/mage/cards/s/SandstoneOracle.java +++ b/Mage.Sets/src/mage/cards/s/SandstoneOracle.java @@ -68,7 +68,7 @@ class SandstoneOracleEffect extends OneShotEffect { MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { TargetOpponent target = new TargetOpponent(true); - if (controller.choose(Outcome.DrawCard, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.DrawCard, target, source, game)) { Player opponent = game.getPlayer(target.getFirstTarget()); if (opponent != null) { game.informPlayers(sourceObject.getLogName() + ": " + controller.getLogName() + " has chosen " + opponent.getLogName()); diff --git a/Mage.Sets/src/mage/cards/s/SandstormCharger.java b/Mage.Sets/src/mage/cards/s/SandstormCharger.java index 099e7cbcb09..a37db036335 100644 --- a/Mage.Sets/src/mage/cards/s/SandstormCharger.java +++ b/Mage.Sets/src/mage/cards/s/SandstormCharger.java @@ -23,7 +23,7 @@ public final class SandstormCharger extends CardImpl { this.toughness = new MageInt(4); // Megamorph {4}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{W}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{W}"), true)); } private SandstormCharger(final SandstormCharger card) { diff --git a/Mage.Sets/src/mage/cards/s/SangriteSurge.java b/Mage.Sets/src/mage/cards/s/SangriteSurge.java index 0ffe91383c4..308918fd88f 100644 --- a/Mage.Sets/src/mage/cards/s/SangriteSurge.java +++ b/Mage.Sets/src/mage/cards/s/SangriteSurge.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.DoubleStrikeAbility; @@ -11,19 +9,23 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class SangriteSurge extends CardImpl { public SangriteSurge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{R}{G}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}{G}"); // Target creature gets +3/+3 and gains double strike until end of turn. - this.getSpellAbility().addEffect(new BoostTargetEffect(3, 3, Duration.EndOfTurn)); - this.getSpellAbility().addEffect(new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new BoostTargetEffect( + 3, 3, Duration.EndOfTurn + ).setText("target creature gets +3/+3")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + DoubleStrikeAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains double strike until end of turn")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/s/SanguineSpy.java b/Mage.Sets/src/mage/cards/s/SanguineSpy.java new file mode 100644 index 00000000000..d21c1ac4426 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SanguineSpy.java @@ -0,0 +1,108 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfYourEndStepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.DifferentManaValuesInGraveCondition; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.hint.common.DifferentManaValuesInGraveHint; +import mage.cards.Card; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.abilities.keyword.MenaceAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author weirddan455 + */ +public final class SanguineSpy extends CardImpl { + + public SanguineSpy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Menace + this.addAbility(new MenaceAbility(false)); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // {1}, Sacrifice another creature: Look at the top card of your library. You may put that card into your graveyard. + Ability ability = new SimpleActivatedAbility(new SanguineSpyEffect(), new GenericManaCost(1)); + ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); + this.addAbility(ability); + + // At the beginning of your end step, if there are five or more mana values among cards in your graveyard, you may pay 2 life. If you do, draw a card. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new BeginningOfYourEndStepTriggeredAbility( + new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new PayLifeCost(2)), + false + ), + DifferentManaValuesInGraveCondition.FIVE, + "At the beginning of your end step, if there are five or more mana values among cards in your graveyard, you may pay 2 life. If you do, draw a card." + ).addHint(DifferentManaValuesInGraveHint.instance)); + } + + private SanguineSpy(final SanguineSpy card) { + super(card); + } + + @Override + public SanguineSpy copy() { + return new SanguineSpy(this); + } +} + +class SanguineSpyEffect extends OneShotEffect { + + public SanguineSpyEffect() { + super(Outcome.Benefit); + this.staticText = "Look at the top card of your library. You may put that card into your graveyard"; + } + + private SanguineSpyEffect(final SanguineSpyEffect effect) { + super(effect); + } + + @Override + public SanguineSpyEffect copy() { + return new SanguineSpyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Card card = player.getLibrary().getFromTop(game); + if (card == null) { + return false; + } + player.lookAtCards("Top card of your library", card, game); + if (player.chooseUse(Outcome.AIDontUseIt, "Put the top card of your library into your graveyard?", source, game)) { + player.moveCards(card, Zone.GRAVEYARD, source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SanityGrinding.java b/Mage.Sets/src/mage/cards/s/SanityGrinding.java index 138cfe56f36..ddbd04d2c34 100644 --- a/Mage.Sets/src/mage/cards/s/SanityGrinding.java +++ b/Mage.Sets/src/mage/cards/s/SanityGrinding.java @@ -54,7 +54,7 @@ class SanityGrindingEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/s/SapphireCharm.java b/Mage.Sets/src/mage/cards/s/SapphireCharm.java index 650bc353d1b..e62200aa6d5 100644 --- a/Mage.Sets/src/mage/cards/s/SapphireCharm.java +++ b/Mage.Sets/src/mage/cards/s/SapphireCharm.java @@ -35,14 +35,12 @@ public final class SapphireCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayer()); // or target creature gains flying until end of turn; - Mode mode = new Mode(); - mode.addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); + Mode mode = new Mode(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or target creature an opponent controls phases out. - mode = new Mode(); - mode.addEffect(new PhaseOutTargetEffect()); + mode = new Mode(new PhaseOutTargetEffect()); mode.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SarkhanDragonsoul.java b/Mage.Sets/src/mage/cards/s/SarkhanDragonsoul.java index ff556006acf..28e355e1dcc 100644 --- a/Mage.Sets/src/mage/cards/s/SarkhanDragonsoul.java +++ b/Mage.Sets/src/mage/cards/s/SarkhanDragonsoul.java @@ -3,7 +3,6 @@ package mage.cards.s; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.DamageTargetEffect; @@ -36,7 +35,7 @@ public final class SarkhanDragonsoul extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SARKHAN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +2: Sarkhan, Dragonsoul deals 1 damage to each opponent and each creature your opponents control. Ability ability = new LoyaltyAbility(new DamagePlayersEffect(1, TargetController.OPPONENT), 2); diff --git a/Mage.Sets/src/mage/cards/s/SarkhanFireblood.java b/Mage.Sets/src/mage/cards/s/SarkhanFireblood.java index 52bb787e3a0..b55b3ff9951 100644 --- a/Mage.Sets/src/mage/cards/s/SarkhanFireblood.java +++ b/Mage.Sets/src/mage/cards/s/SarkhanFireblood.java @@ -2,7 +2,6 @@ package mage.cards.s; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.CreateTokenEffect; @@ -35,7 +34,7 @@ public final class SarkhanFireblood extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SARKHAN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: You may discard a card. If you do, draw a card. this.addAbility(new LoyaltyAbility(new DoIfCostPaid( diff --git a/Mage.Sets/src/mage/cards/s/SarkhanTheDragonspeaker.java b/Mage.Sets/src/mage/cards/s/SarkhanTheDragonspeaker.java index 628e26ff4e8..3bc34e6da73 100644 --- a/Mage.Sets/src/mage/cards/s/SarkhanTheDragonspeaker.java +++ b/Mage.Sets/src/mage/cards/s/SarkhanTheDragonspeaker.java @@ -6,7 +6,6 @@ import mage.MageObjectReference; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; @@ -34,7 +33,7 @@ public final class SarkhanTheDragonspeaker extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SARKHAN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Until end of turn, Sarkhan, the Dragonspeaker becomes a legendary 4/4 red Dragon creature with flying, indestructible, and haste. this.addAbility(new LoyaltyAbility(new SarkhanTheDragonspeakerEffect(), 1)); diff --git a/Mage.Sets/src/mage/cards/s/SarkhanTheMad.java b/Mage.Sets/src/mage/cards/s/SarkhanTheMad.java index 7d51f4caf2f..9948aac728c 100644 --- a/Mage.Sets/src/mage/cards/s/SarkhanTheMad.java +++ b/Mage.Sets/src/mage/cards/s/SarkhanTheMad.java @@ -6,7 +6,6 @@ import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; @@ -37,7 +36,7 @@ public final class SarkhanTheMad extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{B}{R}"); this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SARKHAN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(7)); + this.setStartingLoyalty(7); this.addAbility(new LoyaltyAbility(new SarkhanTheMadRevealAndDrawEffect(), 0)); @@ -156,7 +155,7 @@ class SarkhanTheMadDragonDamageEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - List dragons = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List dragons = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); if (dragons != null && !dragons.isEmpty()) { for (Permanent dragon : dragons) { game.damagePlayerOrPlaneswalker(source.getFirstTarget(), dragon.getPower().getValue(), dragon.getId(), source, game, false, true); diff --git a/Mage.Sets/src/mage/cards/s/SarkhanTheMasterless.java b/Mage.Sets/src/mage/cards/s/SarkhanTheMasterless.java index 2751d320e68..0a3a0bb2228 100644 --- a/Mage.Sets/src/mage/cards/s/SarkhanTheMasterless.java +++ b/Mage.Sets/src/mage/cards/s/SarkhanTheMasterless.java @@ -5,7 +5,6 @@ import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.AttacksAllTriggeredAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; @@ -30,7 +29,7 @@ public final class SarkhanTheMasterless extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SARKHAN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Whenever a creature attacks you or a planeswalker you control, each Dragon you control deals 1 damage to that creature. this.addAbility(new AttacksAllTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/s/SarkhanUnbroken.java b/Mage.Sets/src/mage/cards/s/SarkhanUnbroken.java index 4b3eeb7774a..f756e26b03d 100644 --- a/Mage.Sets/src/mage/cards/s/SarkhanUnbroken.java +++ b/Mage.Sets/src/mage/cards/s/SarkhanUnbroken.java @@ -7,7 +7,6 @@ import java.util.UUID; import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; @@ -42,7 +41,7 @@ public final class SarkhanUnbroken extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SARKHAN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Draw a card, then add one mana of any color. this.addAbility(new LoyaltyAbility(new SarkhanUnbrokenAbility1(), 1)); diff --git a/Mage.Sets/src/mage/cards/s/SarkhanVol.java b/Mage.Sets/src/mage/cards/s/SarkhanVol.java index f9bfb4fc45e..cd4a8018aa1 100644 --- a/Mage.Sets/src/mage/cards/s/SarkhanVol.java +++ b/Mage.Sets/src/mage/cards/s/SarkhanVol.java @@ -1,7 +1,6 @@ package mage.cards.s; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effects; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.UntapTargetEffect; @@ -27,30 +26,34 @@ import java.util.UUID; */ public final class SarkhanVol extends CardImpl { - private static DragonToken dragonToken = new DragonToken(); - public SarkhanVol(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{G}"); this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SARKHAN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Creatures you control get +1/+1 and gain haste until end of turn. - Effects effects1 = new Effects(); - effects1.add(new BoostControlledEffect(1, 1, Duration.EndOfTurn)); - effects1.add(new GainAbilityControlledEffect(HasteAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES)); + Effects effects1 = new Effects(new BoostControlledEffect( + 1, 1, Duration.EndOfTurn + ).setText("creatures you control get +1/+1")); + effects1.add(new GainAbilityControlledEffect( + HasteAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURES + ).setText("and gain haste until end of turn")); this.addAbility(new LoyaltyAbility(effects1, 1)); // -2: Gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn. LoyaltyAbility ability = new LoyaltyAbility(new GainControlTargetEffect(Duration.EndOfTurn), -2); ability.addEffect(new UntapTargetEffect().setText("Untap that creature")); - ability.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn)); + ability.addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("It gains haste until end of turn")); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); // -6: Create five 4/4 red Dragon creature tokens with flying. - this.addAbility(new LoyaltyAbility(new CreateTokenEffect(dragonToken, 5), -6)); + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new DragonToken(), 5), -6)); } private SarkhanVol(final SarkhanVol card) { diff --git a/Mage.Sets/src/mage/cards/s/SarkhansDragonfire.java b/Mage.Sets/src/mage/cards/s/SarkhansDragonfire.java index b07b9f313ac..68d78728e62 100644 --- a/Mage.Sets/src/mage/cards/s/SarkhansDragonfire.java +++ b/Mage.Sets/src/mage/cards/s/SarkhansDragonfire.java @@ -2,13 +2,12 @@ package mage.cards.s; import java.util.UUID; import mage.ObjectColor; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetAnyTarget; @@ -34,12 +33,7 @@ public final class SarkhansDragonfire extends CardImpl { // Look at the top five cards of your library. You may reveal a red card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), filter, - Zone.LIBRARY, false, true, false, Zone.HAND, true, false, false - ).setBackInRandomOrder(true).setText("Look at the top five cards of your library. " - + "You may reveal a red card from among them and put it into your hand. " - + "Put the rest on the bottom of your library in a random order.") - ); + 5, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM).concatBy("
")); } private SarkhansDragonfire(final SarkhansDragonfire card) { diff --git a/Mage.Sets/src/mage/cards/s/SarulfRealmEater.java b/Mage.Sets/src/mage/cards/s/SarulfRealmEater.java index 1bd2c0d63ff..556337e7f38 100644 --- a/Mage.Sets/src/mage/cards/s/SarulfRealmEater.java +++ b/Mage.Sets/src/mage/cards/s/SarulfRealmEater.java @@ -105,7 +105,7 @@ class SarulfRealmEaterEffect extends OneShotEffect { game.getBattlefield() .getActivePermanents( filter, source.getControllerId(), - source.getSourceId(), game + source, game ) .stream() .filter(Objects::nonNull) diff --git a/Mage.Sets/src/mage/cards/s/SatoruUmezawa.java b/Mage.Sets/src/mage/cards/s/SatoruUmezawa.java index ebb07c03d22..d96baf284ea 100644 --- a/Mage.Sets/src/mage/cards/s/SatoruUmezawa.java +++ b/Mage.Sets/src/mage/cards/s/SatoruUmezawa.java @@ -4,9 +4,9 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.NinjutsuAbility; import mage.cards.Card; import mage.cards.CardImpl; @@ -34,7 +34,9 @@ public final class SatoruUmezawa extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(4); - // Whenever you activate a ninjutsu ability, look at the top three cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order. This ability triggers only once each turn. + // Whenever you activate a ninjutsu ability, look at the top three cards of your library. + // Put one of them into your hand and the rest on the bottom of your library in any order. + // This ability triggers only once each turn. this.addAbility(new SatoruUmezawaTriggeredAbility()); // Each creature card in your hand has ninjutsu {2}{U}{B}. @@ -54,10 +56,7 @@ public final class SatoruUmezawa extends CardImpl { class SatoruUmezawaTriggeredAbility extends TriggeredAbilityImpl { SatoruUmezawaTriggeredAbility() { - super(Zone.BATTLEFIELD, new LookLibraryAndPickControllerEffect( - StaticValue.get(3), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.LIBRARY, false, false - )); + super(Zone.BATTLEFIELD, new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.BOTTOM_ANY)); this.setTriggersOnce(true); } @@ -85,10 +84,8 @@ class SatoruUmezawaTriggeredAbility extends TriggeredAbilityImpl { } @Override - public String getRule() { - return "Whenever you activate a ninjutsu ability, look at the top three cards of your library. " + - "Put one of them into your hand and the rest on the bottom of your library in any order. " + - "This ability triggers only once each turn."; + public String getTriggerPhrase() { + return "Whenever you activate a ninjutsu ability, "; } } diff --git a/Mage.Sets/src/mage/cards/s/SatsukiTheLivingLore.java b/Mage.Sets/src/mage/cards/s/SatsukiTheLivingLore.java index 55a3b1bc6b0..30d3a673157 100644 --- a/Mage.Sets/src/mage/cards/s/SatsukiTheLivingLore.java +++ b/Mage.Sets/src/mage/cards/s/SatsukiTheLivingLore.java @@ -37,14 +37,14 @@ public final class SatsukiTheLivingLore extends CardImpl { = new FilterCard("Saga card from your graveyard"); static { - filter.add(Predicates.or( + filter2.add(Predicates.or( SubType.SAGA.getPredicate(), Predicates.and( CardType.ENCHANTMENT.getPredicate(), CardType.CREATURE.getPredicate() ) )); - filter.add(SubType.SAGA.getPredicate()); + filter3.add(SubType.SAGA.getPredicate()); } public SatsukiTheLivingLore(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SatyrWayfinder.java b/Mage.Sets/src/mage/cards/s/SatyrWayfinder.java index 4280b027e89..bff86473e60 100644 --- a/Mage.Sets/src/mage/cards/s/SatyrWayfinder.java +++ b/Mage.Sets/src/mage/cards/s/SatyrWayfinder.java @@ -3,27 +3,18 @@ package mage.cards.s; import java.util.UUID; import mage.MageInt; -import mage.MageObject; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.effects.common.RevealLibraryPickControllerEffect; import mage.cards.CardImpl; 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.Zone; -import mage.filter.common.FilterLandCard; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; +import mage.filter.StaticFilters; /** * - * @author LevelX2 + * @author awjackson */ public final class SatyrWayfinder extends CardImpl { @@ -34,8 +25,10 @@ public final class SatyrWayfinder extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - // When Satyr Wayfinder enters the battlefield, reveal the top four cards of your library. You may put a land card from among them into your hand. Put the rest into your graveyard. - this.addAbility(new EntersBattlefieldTriggeredAbility(new SatyrWayfinderEffect())); + // When Satyr Wayfinder enters the battlefield, reveal the top four cards of your library. + // You may put a land card from among them into your hand. Put the rest into your graveyard. + this.addAbility(new EntersBattlefieldTriggeredAbility(new RevealLibraryPickControllerEffect( + 4, 1, StaticFilters.FILTER_CARD_LAND_A, PutCards.HAND, PutCards.GRAVEYARD))); } private SatyrWayfinder(final SatyrWayfinder card) { @@ -47,49 +40,3 @@ public final class SatyrWayfinder extends CardImpl { return new SatyrWayfinder(this); } } - -class SatyrWayfinderEffect extends OneShotEffect { - - private static final FilterLandCard filterPutInHand = new FilterLandCard("land card to put in hand"); - - public SatyrWayfinderEffect() { - super(Outcome.DrawCard); - this.staticText = "reveal the top four cards of your library. You may put a land card from among them into your hand. Put the rest into your graveyard"; - } - - public SatyrWayfinderEffect(final SatyrWayfinderEffect effect) { - super(effect); - } - - @Override - public SatyrWayfinderEffect copy() { - return new SatyrWayfinderEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller != null && sourceObject != null) { - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 4)); - boolean properCardFound = cards.count(filterPutInHand, source.getControllerId(), source.getSourceId(), game) > 0; - if (!cards.isEmpty()) { - controller.revealCards(sourceObject.getIdName(), cards, game); - TargetCard target = new TargetCard(Zone.LIBRARY, filterPutInHand); - if (properCardFound - && controller.chooseUse(outcome, "Put a land card into your hand?", source, game) - && controller.choose(Outcome.DrawCard, cards, target, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - cards.remove(card); - controller.moveCards(card, Zone.HAND, source, game); - } - - } - controller.moveCards(cards, Zone.GRAVEYARD, source, game); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SavageAlliance.java b/Mage.Sets/src/mage/cards/s/SavageAlliance.java index eed0fc6f8bc..5c2078c4092 100644 --- a/Mage.Sets/src/mage/cards/s/SavageAlliance.java +++ b/Mage.Sets/src/mage/cards/s/SavageAlliance.java @@ -56,16 +56,14 @@ public final class SavageAlliance extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterPlayer).withChooseHint("whose creatures gain trample")); // Savage Alliance deals 2 damage to target creature.; - Mode mode = new Mode(); Effect effect = new DamageTargetEffect(2); effect.setText("{this} deals 2 damage to target creature"); - mode.addEffect(effect); + Mode mode = new Mode(effect); mode.addTarget(new TargetCreaturePermanent(filterCreature).withChooseHint("deals 2 damage to")); this.getSpellAbility().addMode(mode); // Savage Alliance deals 1 damage to each creature target opponent controls. - mode = new Mode(); - mode.addEffect(new SavageAllianceDamageEffect()); + mode = new Mode(new SavageAllianceDamageEffect()); mode.addTarget(new TargetPlayer(1, 1, false, filterOpponent).withChooseHint("whose creatures get dealt 1 damage")); this.getSpellAbility().addMode(mode); } @@ -132,7 +130,7 @@ class SavageAllianceDamageEffect extends OneShotEffect { if (player != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent(); filter.add(new ControllerIdPredicate(player.getId())); - List creatures = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List creatures = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); for (Permanent creature : creatures) { creature.damage(1, source.getSourceId(), source, game, false, true); } diff --git a/Mage.Sets/src/mage/cards/s/SavageBeating.java b/Mage.Sets/src/mage/cards/s/SavageBeating.java index 43c7b117ec3..fda090e7d87 100644 --- a/Mage.Sets/src/mage/cards/s/SavageBeating.java +++ b/Mage.Sets/src/mage/cards/s/SavageBeating.java @@ -34,8 +34,7 @@ public final class SavageBeating extends CardImpl { this.getSpellAbility().addEffect(new GainAbilityControlledEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, false)); // or untap all creatures you control and after this phase, there is an additional combat phase. - Mode mode = new Mode(); - mode.addEffect(new UntapAllControllerEffect(new FilterControlledCreaturePermanent(), "untap all creatures you control")); + Mode mode = new Mode(new UntapAllControllerEffect(new FilterControlledCreaturePermanent(), "untap all creatures you control")); mode.addEffect(new AdditionalCombatPhaseEffect("and after this phase, there is an additional combat phase")); this.getSpellAbility().getModes().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/s/SavageHunger.java b/Mage.Sets/src/mage/cards/s/SavageHunger.java index 0f0969e8ac8..db5d02bc21f 100644 --- a/Mage.Sets/src/mage/cards/s/SavageHunger.java +++ b/Mage.Sets/src/mage/cards/s/SavageHunger.java @@ -1,8 +1,6 @@ - - package mage.cards.s; -import java.util.UUID; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.AttachEffect; @@ -13,23 +11,19 @@ import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.TrampleAbility; 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.constants.*; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class SavageHunger extends CardImpl { - public SavageHunger (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{G}"); + public SavageHunger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); this.subtype.add(SubType.AURA); @@ -38,13 +32,17 @@ public final class SavageHunger extends CardImpl { this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); - SimpleStaticAbility ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 0, Duration.WhileOnBattlefield)); - ability.addEffect(new GainAbilityAttachedEffect(TrampleAbility.getInstance(), AttachmentType.AURA)); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect( + 1, 0, Duration.WhileOnBattlefield + )); + ability.addEffect(new GainAbilityAttachedEffect( + TrampleAbility.getInstance(), AttachmentType.AURA + ).setText("and has trample")); this.addAbility(ability); - this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); + this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{2}"))); } - public SavageHunger (final SavageHunger card) { + public SavageHunger(final SavageHunger card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/s/SavageSilhouette.java b/Mage.Sets/src/mage/cards/s/SavageSilhouette.java index 10fefc893cb..a46ce3a4167 100644 --- a/Mage.Sets/src/mage/cards/s/SavageSilhouette.java +++ b/Mage.Sets/src/mage/cards/s/SavageSilhouette.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -13,36 +11,35 @@ import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; 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.constants.*; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class SavageSilhouette extends CardImpl { public SavageSilhouette(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); this.subtype.add(SubType.AURA); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // Enchanted creature gets +2/+2 and has "{1}{G}: Regenerate this creature." - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{1}{G}")); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, 2, Duration.WhileOnBattlefield))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ability, AttachmentType.AURA))); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect( + 2, 2, Duration.WhileOnBattlefield + )); + ability.addEffect(new GainAbilityAttachedEffect(new SimpleActivatedAbility( + new RegenerateSourceEffect(), new ManaCostsImpl<>("{1}{G}") + ), AttachmentType.AURA).setText("and has \"{1}{G}: Regenerate this creature.\"")); + this.addAbility(ability); } private SavageSilhouette(final SavageSilhouette card) { diff --git a/Mage.Sets/src/mage/cards/s/SavageSummoning.java b/Mage.Sets/src/mage/cards/s/SavageSummoning.java index e4c37e9c9f7..1e141f40841 100644 --- a/Mage.Sets/src/mage/cards/s/SavageSummoning.java +++ b/Mage.Sets/src/mage/cards/s/SavageSummoning.java @@ -209,7 +209,7 @@ class SavageSummoningCantCounterEffect extends ContinuousRuleModifyingEffectImpl @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null) { return "This creature spell can't be countered (" + sourceObject.getName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/s/SavaiTriome.java b/Mage.Sets/src/mage/cards/s/SavaiTriome.java index bf636c48097..b86a70f3d94 100644 --- a/Mage.Sets/src/mage/cards/s/SavaiTriome.java +++ b/Mage.Sets/src/mage/cards/s/SavaiTriome.java @@ -1,7 +1,7 @@ package mage.cards.s; import mage.abilities.common.EntersBattlefieldTappedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.keyword.CyclingAbility; import mage.abilities.mana.BlackManaAbility; import mage.abilities.mana.RedManaAbility; @@ -34,7 +34,7 @@ public final class SavaiTriome extends CardImpl { this.addAbility(new EntersBattlefieldTappedAbility()); // Cycling {3} - this.addAbility(new CyclingAbility(new ManaCostsImpl("{3}"))); + this.addAbility(new CyclingAbility(new GenericManaCost(3))); } private SavaiTriome(final SavaiTriome card) { diff --git a/Mage.Sets/src/mage/cards/s/SavingGrasp.java b/Mage.Sets/src/mage/cards/s/SavingGrasp.java index 775056361de..0c6ff824a9a 100644 --- a/Mage.Sets/src/mage/cards/s/SavingGrasp.java +++ b/Mage.Sets/src/mage/cards/s/SavingGrasp.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.FlashbackAbility; @@ -9,12 +7,12 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TargetController; -import mage.constants.TimingRule; import mage.filter.common.FilterCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class SavingGrasp extends CardImpl { @@ -26,14 +24,13 @@ public final class SavingGrasp extends CardImpl { } public SavingGrasp(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); // Return target creature you own to your hand. this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect().setText("return target creature you own to your hand")); // Flashback {W} - this.addAbility(new FlashbackAbility(this, new ManaCostsImpl("{W}"))); + this.addAbility(new FlashbackAbility(this, new ManaCostsImpl<>("{W}"))); } private SavingGrasp(final SavingGrasp card) { diff --git a/Mage.Sets/src/mage/cards/s/SaviorOfOllenbock.java b/Mage.Sets/src/mage/cards/s/SaviorOfOllenbock.java index 98b39e5a0b7..c27f6a6839d 100644 --- a/Mage.Sets/src/mage/cards/s/SaviorOfOllenbock.java +++ b/Mage.Sets/src/mage/cards/s/SaviorOfOllenbock.java @@ -18,7 +18,7 @@ import mage.game.ExileZone; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; -import mage.target.common.TargetCardInGraveyardOrBattlefield; +import mage.target.common.TargetCardInGraveyardBattlefieldOrStack; import mage.util.CardUtil; import java.util.UUID; @@ -60,7 +60,7 @@ class SaviorOfOllenbockTriggeredAbility extends TriggeredAbilityImpl { SaviorOfOllenbockTriggeredAbility() { super(Zone.BATTLEFIELD, new ExileTargetForSourceEffect()); - this.addTarget(new TargetCardInGraveyardOrBattlefield( + this.addTarget(new TargetCardInGraveyardBattlefieldOrStack( 0, 1, StaticFilters.FILTER_CARD_CREATURE, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE @@ -112,7 +112,7 @@ class SaviorOfOllenbockEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source, -1)); return player != null && exileZone != null && !exileZone.isEmpty() && player.moveCards( exileZone.getCards(game), Zone.BATTLEFIELD, source, game, false, false, true, null diff --git a/Mage.Sets/src/mage/cards/s/SavraQueenOfTheGolgari.java b/Mage.Sets/src/mage/cards/s/SavraQueenOfTheGolgari.java index 540ae0d6397..24ea4611635 100644 --- a/Mage.Sets/src/mage/cards/s/SavraQueenOfTheGolgari.java +++ b/Mage.Sets/src/mage/cards/s/SavraQueenOfTheGolgari.java @@ -115,7 +115,7 @@ class SavraSacrificeEffect extends OneShotEffect { if (player != null && !playerId.equals(source.getControllerId())) { TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Sacrifice, target, source, game); perms.addAll(target.getTargets()); } diff --git a/Mage.Sets/src/mage/cards/s/ScalelordReckoner.java b/Mage.Sets/src/mage/cards/s/ScalelordReckoner.java index cb12d05ce57..38ed0ae8925 100644 --- a/Mage.Sets/src/mage/cards/s/ScalelordReckoner.java +++ b/Mage.Sets/src/mage/cards/s/ScalelordReckoner.java @@ -17,7 +17,6 @@ import mage.filter.common.FilterNonlandPermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; @@ -81,7 +80,7 @@ class ScalelardReckonerTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (game.getOpponents(this.controllerId).contains(event.getPlayerId())) { Permanent creature = game.getPermanent(event.getTargetId()); - if (creature != null && filter.match(creature, getSourceId(), getControllerId(), game)) { + if (creature != null && filter.match(creature, getControllerId(), this, game)) { FilterNonlandPermanent filter = new FilterNonlandPermanent("nonland permanent that player controls"); filter.add(new ControllerIdPredicate(event.getPlayerId())); this.getTargets().clear(); diff --git a/Mage.Sets/src/mage/cards/s/Scapeshift.java b/Mage.Sets/src/mage/cards/s/Scapeshift.java index 350f1ab5a3c..f1227275537 100644 --- a/Mage.Sets/src/mage/cards/s/Scapeshift.java +++ b/Mage.Sets/src/mage/cards/s/Scapeshift.java @@ -45,7 +45,7 @@ class ScapeshiftEffect extends OneShotEffect { public ScapeshiftEffect() { super(Outcome.Neutral); - staticText = "Sacrifice any number of lands. Search your library for that many land cards, put them onto the battlefield tapped, then shuffle"; + staticText = "Sacrifice any number of lands. Search your library for up to that many land cards, put them onto the battlefield tapped, then shuffle"; } public ScapeshiftEffect(final ScapeshiftEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/ScarredPuma.java b/Mage.Sets/src/mage/cards/s/ScarredPuma.java index 13322a8c20d..75aa3dc6816 100644 --- a/Mage.Sets/src/mage/cards/s/ScarredPuma.java +++ b/Mage.Sets/src/mage/cards/s/ScarredPuma.java @@ -68,7 +68,7 @@ public final class ScarredPuma extends CardImpl { @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(source.getSourceId())) { - for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { //excludes itself (https://gatherer.wizards.com/Pages/Card/Details.aspx?multiverseid=23067) if (!Objects.equals(creature.getId(), source.getSourceId())) { ObjectColor color = creature.getColor(game); diff --git a/Mage.Sets/src/mage/cards/s/ScarwoodBandits.java b/Mage.Sets/src/mage/cards/s/ScarwoodBandits.java index 76b7896c63f..18dfd8c8eea 100644 --- a/Mage.Sets/src/mage/cards/s/ScarwoodBandits.java +++ b/Mage.Sets/src/mage/cards/s/ScarwoodBandits.java @@ -97,7 +97,7 @@ class DoUnlessAnyOpponentPaysEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { String message; if (chooseUseText == null) { diff --git a/Mage.Sets/src/mage/cards/s/ScatteredThoughts.java b/Mage.Sets/src/mage/cards/s/ScatteredThoughts.java index 50d1799fe40..494804c3547 100644 --- a/Mage.Sets/src/mage/cards/s/ScatteredThoughts.java +++ b/Mage.Sets/src/mage/cards/s/ScatteredThoughts.java @@ -1,12 +1,10 @@ package mage.cards.s; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import java.util.UUID; @@ -19,10 +17,7 @@ public final class ScatteredThoughts extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}"); // Look at the top four cards of your library. Put two of those cards into your hand and the rest into your graveyard. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(2), - StaticFilters.FILTER_CARD, Zone.LIBRARY, false, false - )); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(4, 2, PutCards.HAND, PutCards.GRAVEYARD)); } private ScatteredThoughts(final ScatteredThoughts card) { diff --git a/Mage.Sets/src/mage/cards/s/ScepterOfCelebration.java b/Mage.Sets/src/mage/cards/s/ScepterOfCelebration.java new file mode 100644 index 00000000000..2f852bc9bc2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ScepterOfCelebration.java @@ -0,0 +1,55 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.CitizenGreenWhiteToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ScepterOfCelebration extends CardImpl { + + public ScepterOfCelebration(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{G}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature gets +2/+0 and has trample. + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 0)); + ability.addEffect(new GainAbilityAttachedEffect( + TrampleAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and has trample")); + this.addAbility(ability); + + // Whenever equipped creature deals combat damage to a player, create that many 1/1 green and white Citizen creature tokens. + this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility(new CreateTokenEffect( + new CitizenGreenWhiteToken(), SavedDamageValue.MANY + ), "equipped", false)); + + // Equip {3} + this.addAbility(new EquipAbility(3)); + } + + private ScepterOfCelebration(final ScepterOfCelebration card) { + super(card); + } + + @Override + public ScepterOfCelebration copy() { + return new ScepterOfCelebration(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SchemingFence.java b/Mage.Sets/src/mage/cards/s/SchemingFence.java new file mode 100644 index 00000000000..673b90b2bd1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SchemingFence.java @@ -0,0 +1,240 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.ManaPoolItem; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetNonlandPermanent; +import mage.util.CardUtil; + +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SchemingFence extends CardImpl { + + public SchemingFence(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // As Scheming Fence enters the battlefield, you may choose a nonland permanent. + this.addAbility(new AsEntersBattlefieldAbility(new SchemingFenceChooseEffect())); + + // Activated abilities of the chosen permanent can't be activated. + this.addAbility(new SimpleStaticAbility(new SchemingFenceDisableEffect())); + + // Scheming Fence has all activated abilities of the chosen permanent except for loyalty abilities. You may spend mana as though it were mana of any color to activate those abilities. + Ability ability = new SimpleStaticAbility(new SchemingFenceGainEffect()); + ability.addEffect(new SchemingFenceManaEffect()); + this.addAbility(ability); + } + + private SchemingFence(final SchemingFence card) { + super(card); + } + + @Override + public SchemingFence copy() { + return new SchemingFence(this); + } +} + +class SchemingFenceChooseEffect extends OneShotEffect { + + public SchemingFenceChooseEffect() { + super(Outcome.UnboostCreature); + this.staticText = "you may choose a nonland permanent"; + } + + public SchemingFenceChooseEffect(final SchemingFenceChooseEffect effect) { + super(effect); + } + + @Override + public SchemingFenceChooseEffect copy() { + return new SchemingFenceChooseEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent schemingFencePermanent = game.getPermanentEntering(source.getSourceId()); + if (controller == null || schemingFencePermanent == null) { + return false; + } + + TargetPermanent target = new TargetNonlandPermanent(0, 1, true); + controller.choose(this.outcome, target, source, game); + Permanent chosenPermanent = game.getPermanent(target.getFirstTarget()); + if (chosenPermanent == null) { + return true; + } + game.getState().setValue( + schemingFencePermanent.getId() + "_chosenPermanent", + new MageObjectReference(chosenPermanent, game) + ); + schemingFencePermanent.addInfo( + "chosen permanent", + CardUtil.addToolTipMarkTags( + "Chosen permanent: " + chosenPermanent.getIdName() + ), game + ); + return true; + } +} + +class SchemingFenceDisableEffect extends ContinuousRuleModifyingEffectImpl { + + public SchemingFenceDisableEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + staticText = "activated abilities of the chosen permanent can't be activated"; + } + + public SchemingFenceDisableEffect(final SchemingFenceDisableEffect effect) { + super(effect); + } + + @Override + public SchemingFenceDisableEffect copy() { + return new SchemingFenceDisableEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ACTIVATE_ABILITY; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent sourcePermanent = game.getState().getPermanent(source.getSourceId()); + if (sourcePermanent == null) { + return false; + } + + MageObjectReference chosenPermanentMOR = (MageObjectReference) game.getState().getValue(sourcePermanent.getId() + "_chosenPermanent"); + if (chosenPermanentMOR == null) { + return false; + } + + return Optional.of(chosenPermanentMOR) + .map(MageObjectReference.class::cast) + .filter(mor -> mor.zoneCounterIsCurrent(game)) + .map(MageObjectReference::getSourceId) // TODO: Are both of this line and the next one necessary? + .map(uuid -> uuid.equals(event.getSourceId())) + .orElse(false); + } +} + +class SchemingFenceGainEffect extends ContinuousEffectImpl { + + SchemingFenceGainEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "{this} has all activated abilities of the chosen permanent except for loyalty abilities."; + } + + private SchemingFenceGainEffect(final SchemingFenceGainEffect effect) { + super(effect); + } + + @Override + public SchemingFenceGainEffect copy() { + return new SchemingFenceGainEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + return false; + } + + MageObjectReference chosenPermanentMOR = (MageObjectReference) game.getState().getValue(source.getSourceId() + "_chosenPermanent"); + if (chosenPermanentMOR == null) { + return false; + } + + Permanent chosenPermanent = Optional.of(chosenPermanentMOR) + .map(MageObjectReference.class::cast) + .map(mor -> mor.getPermanent(game)) + .orElse(null); + if (chosenPermanent == null) { + return false; + } + + for (Ability ability : chosenPermanent.getAbilities(game).getActivatedAbilities(Zone.ALL)) { + if (!(ability instanceof LoyaltyAbility)) { + Ability copied = ability.copy(); + ability.getEffects().setValue("schemingFence", source.getSourceId()); + permanent.addAbility(copied, source.getSourceId(), game); + } + } + return true; + } +} + +class SchemingFenceManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { + + SchemingFenceManaEffect() { + super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "You may spend mana as though it were mana of any color to activate those abilities"; + } + + private SchemingFenceManaEffect(final SchemingFenceManaEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public SchemingFenceManaEffect copy() { + return new SchemingFenceManaEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game, UUID playerId) { + return source.isControlledBy(playerId) + && affectedAbility + .getEffects() + .stream() + .map(effect -> effect.getValue("schemingFence")) + .filter(Objects::nonNull) + .anyMatch(source.getSourceId()::equals); + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + return false; + } + + @Override + public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + return mana.getFirstAvailable(); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ScholarshipSponsor.java b/Mage.Sets/src/mage/cards/s/ScholarshipSponsor.java index b2dbf27f6b9..07adf34acc4 100644 --- a/Mage.Sets/src/mage/cards/s/ScholarshipSponsor.java +++ b/Mage.Sets/src/mage/cards/s/ScholarshipSponsor.java @@ -73,7 +73,7 @@ class ScholarshipSponsorEffect extends OneShotEffect { Map playerMap = game .getBattlefield() .getActivePermanents( - StaticFilters.FILTER_LAND, source.getControllerId(), source.getSourceId(), game + StaticFilters.FILTER_LAND, source.getControllerId(), source, game ) .stream() .map(Controllable::getControllerId) diff --git a/Mage.Sets/src/mage/cards/s/ScionOfDraco.java b/Mage.Sets/src/mage/cards/s/ScionOfDraco.java index 4e22d667d24..835f5bca5ae 100644 --- a/Mage.Sets/src/mage/cards/s/ScionOfDraco.java +++ b/Mage.Sets/src/mage/cards/s/ScionOfDraco.java @@ -4,7 +4,6 @@ import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.DomainValue; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect; @@ -24,8 +23,6 @@ import java.util.UUID; */ public final class ScionOfDraco extends CardImpl { - private static final DynamicValue xValue = new DomainValue(); - public ScionOfDraco(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{12}"); @@ -35,7 +32,7 @@ public final class ScionOfDraco extends CardImpl { // Domain — This spell costs {2} less to cast for each basic land type among lands you control. this.addAbility(new SimpleStaticAbility(Zone.ALL, - new SpellCostReductionForEachSourceEffect(2, xValue) + new SpellCostReductionForEachSourceEffect(2, DomainValue.REGULAR) .setText("this spell costs {2} less to cast for each basic land type among lands you control") ).addHint(DomainHint.instance).setAbilityWord(AbilityWord.DOMAIN)); @@ -78,7 +75,7 @@ class ScionOfDracoEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { for (Permanent permanent : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game )) { ObjectColor color = permanent.getColor(game); if (color.isWhite()) { diff --git a/Mage.Sets/src/mage/cards/s/ScionOfOona.java b/Mage.Sets/src/mage/cards/s/ScionOfOona.java index 6050c7dc240..58876001ac5 100644 --- a/Mage.Sets/src/mage/cards/s/ScionOfOona.java +++ b/Mage.Sets/src/mage/cards/s/ScionOfOona.java @@ -22,7 +22,7 @@ import mage.filter.common.FilterCreaturePermanent; public final class ScionOfOona extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("Faeries"); - private static final FilterCreaturePermanent filterCreature = new FilterCreaturePermanent("Faeries"); + private static final FilterCreaturePermanent filterCreature = new FilterCreaturePermanent("Faerie creatures"); static { filter.add(SubType.FAERIE.getPredicate()); diff --git a/Mage.Sets/src/mage/cards/s/ScornfulAetherLich.java b/Mage.Sets/src/mage/cards/s/ScornfulAetherLich.java index 997144597e9..23dfade8e1d 100644 --- a/Mage.Sets/src/mage/cards/s/ScornfulAetherLich.java +++ b/Mage.Sets/src/mage/cards/s/ScornfulAetherLich.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -12,18 +10,18 @@ import mage.abilities.keyword.VigilanceAbility; 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.constants.SubType; + +import java.util.UUID; /** - * * @author Loki */ public final class ScornfulAetherLich extends CardImpl { public ScornfulAetherLich(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.WIZARD); @@ -31,8 +29,12 @@ public final class ScornfulAetherLich extends CardImpl { this.toughness = new MageInt(4); // {W}{B}: Scornful Aether-Lich gains fear and vigilance until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect(FearAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{W}{B}")); - ability.addEffect(new GainAbilitySourceEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn)); + Ability ability = new SimpleActivatedAbility(new GainAbilitySourceEffect( + FearAbility.getInstance(), Duration.EndOfTurn + ).setText("{this} gains fear"), new ManaCostsImpl<>("{W}{B}")); + ability.addEffect(new GainAbilitySourceEffect( + VigilanceAbility.getInstance(), Duration.EndOfTurn + ).setText("and vigilance until end of turn")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/ScornfulEgotist.java b/Mage.Sets/src/mage/cards/s/ScornfulEgotist.java index 5866692170a..4f25f8af6bf 100644 --- a/Mage.Sets/src/mage/cards/s/ScornfulEgotist.java +++ b/Mage.Sets/src/mage/cards/s/ScornfulEgotist.java @@ -24,7 +24,7 @@ public final class ScornfulEgotist extends CardImpl { this.toughness = new MageInt(1); // Morph {U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{U}"))); } private ScornfulEgotist(final ScornfulEgotist card) { diff --git a/Mage.Sets/src/mage/cards/s/ScourgeOfFleets.java b/Mage.Sets/src/mage/cards/s/ScourgeOfFleets.java index bb41b489d0c..a71fd10567c 100644 --- a/Mage.Sets/src/mage/cards/s/ScourgeOfFleets.java +++ b/Mage.Sets/src/mage/cards/s/ScourgeOfFleets.java @@ -72,12 +72,12 @@ class ScourgeOfFleetsEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - int islands = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int islands = game.getBattlefield().count(filter, source.getControllerId(), source, game); FilterPermanent creatureFilter = new FilterCreaturePermanent(); creatureFilter.add(TargetController.OPPONENT.getControllerPredicate()); creatureFilter.add(new ToughnessPredicate(ComparisonType.FEWER_THAN, islands + 1)); Cards cardsToHand = new CardsImpl(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(creatureFilter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(creatureFilter, source.getControllerId(), source, game)) { cardsToHand.add(permanent); } controller.moveCards(cardsToHand, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/s/ScourgeOfValkas.java b/Mage.Sets/src/mage/cards/s/ScourgeOfValkas.java index b5ce0a50788..c5bd142eb92 100644 --- a/Mage.Sets/src/mage/cards/s/ScourgeOfValkas.java +++ b/Mage.Sets/src/mage/cards/s/ScourgeOfValkas.java @@ -87,7 +87,7 @@ class ScourgeOfValkasDamageEffect extends OneShotEffect { if (controller == null || enteringDragon == null) { return false; } - int dragons = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int dragons = game.getBattlefield().count(filter, source.getControllerId(), source, game); if (dragons < 1) { return true; } diff --git a/Mage.Sets/src/mage/cards/s/ScoutTheBorders.java b/Mage.Sets/src/mage/cards/s/ScoutTheBorders.java index 11b0cf7849b..fbf0a092825 100644 --- a/Mage.Sets/src/mage/cards/s/ScoutTheBorders.java +++ b/Mage.Sets/src/mage/cards/s/ScoutTheBorders.java @@ -1,26 +1,16 @@ - package mage.cards.s; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.effects.common.RevealLibraryPickControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; +import mage.filter.StaticFilters; /** * - * @author LevelX2 + * @author awjackson */ public final class ScoutTheBorders extends CardImpl { @@ -28,7 +18,8 @@ public final class ScoutTheBorders extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); // Reveal the top five cards of your library. You may put a creature or land card from among them into your hand. Put the rest into your graveyard. - this.getSpellAbility().addEffect(new ScoutTheBordersEffect()); + this.getSpellAbility().addEffect(new RevealLibraryPickControllerEffect( + 5, 1, StaticFilters.FILTER_CARD_CREATURE_OR_LAND, PutCards.HAND, PutCards.GRAVEYARD)); } private ScoutTheBorders(final ScoutTheBorders card) { @@ -40,50 +31,3 @@ public final class ScoutTheBorders extends CardImpl { return new ScoutTheBorders(this); } } - -class ScoutTheBordersEffect extends OneShotEffect { - - private static final FilterCard filterPutInHand = new FilterCard("creature or land card to put in hand"); - - static { - filterPutInHand.add(Predicates.or(CardType.CREATURE.getPredicate(), CardType.LAND.getPredicate())); - } - - public ScoutTheBordersEffect() { - super(Outcome.DrawCard); - this.staticText = "Reveal the top five cards of your library. You may put a creature or land card from among them into your hand. Put the rest into your graveyard"; - } - - public ScoutTheBordersEffect(final ScoutTheBordersEffect effect) { - super(effect); - } - - @Override - public ScoutTheBordersEffect copy() { - return new ScoutTheBordersEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5)); - boolean properCardFound = cards.count(filterPutInHand, game) > 0; - if (!cards.isEmpty()) { - controller.revealCards(source, cards, game); - TargetCard target = new TargetCard(Zone.LIBRARY, filterPutInHand); - if (properCardFound && controller.choose(Outcome.DrawCard, cards, target, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - controller.moveCards(card, Zone.HAND, source, game); - cards.remove(card); - } - - } - controller.moveCards(cards, Zone.GRAVEYARD, source, game); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/s/ScoutsWarning.java b/Mage.Sets/src/mage/cards/s/ScoutsWarning.java index baadc72a93c..e874a3bcb39 100644 --- a/Mage.Sets/src/mage/cards/s/ScoutsWarning.java +++ b/Mage.Sets/src/mage/cards/s/ScoutsWarning.java @@ -34,7 +34,7 @@ public final class ScoutsWarning extends CardImpl { this.getSpellAbility().addWatcher(new ScoutsWarningWatcher()); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private ScoutsWarning(final ScoutsWarning card) { diff --git a/Mage.Sets/src/mage/cards/s/Scrambleverse.java b/Mage.Sets/src/mage/cards/s/Scrambleverse.java index 172879164d9..16117b4d358 100644 --- a/Mage.Sets/src/mage/cards/s/Scrambleverse.java +++ b/Mage.Sets/src/mage/cards/s/Scrambleverse.java @@ -56,7 +56,7 @@ class ScrambleverseEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { PlayerList players = game.getState().getPlayersInRange(source.getControllerId(), game); int count = players.size(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterNonlandPermanent(), source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterNonlandPermanent(), source.getControllerId(), source, game)) { ContinuousEffect effect = new GainControlTargetEffect(Duration.Custom, true, players.get(RandomUtil.nextInt(count))); effect.setTargetPointer(new FixedTarget(permanent, game)); game.addEffect(effect, source); diff --git a/Mage.Sets/src/mage/cards/s/Scrapheap.java b/Mage.Sets/src/mage/cards/s/Scrapheap.java index 1d37b3006d0..ad60a4cf31b 100644 --- a/Mage.Sets/src/mage/cards/s/Scrapheap.java +++ b/Mage.Sets/src/mage/cards/s/Scrapheap.java @@ -10,7 +10,6 @@ import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; @@ -65,7 +64,7 @@ class ScrapheapTriggeredAbility extends TriggeredAbilityImpl { if (zEvent.isDiesEvent()) { Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); if (permanent != null && permanent.isOwnedBy(this.getControllerId())) { - if (StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT.match(permanent, sourceId, controllerId, game)) { + if (StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT.match(permanent, controllerId, this, game)) { return true; } } diff --git a/Mage.Sets/src/mage/cards/s/ScrapheapScrounger.java b/Mage.Sets/src/mage/cards/s/ScrapheapScrounger.java index ab283fbae6b..6812c8961d4 100644 --- a/Mage.Sets/src/mage/cards/s/ScrapheapScrounger.java +++ b/Mage.Sets/src/mage/cards/s/ScrapheapScrounger.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.CantBlockAbility; @@ -16,11 +14,12 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author emerald000 */ public final class ScrapheapScrounger extends CardImpl { @@ -28,7 +27,7 @@ public final class ScrapheapScrounger extends CardImpl { private static final FilterCard filter = new FilterCreatureCard("another creature card"); static { - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); } public ScrapheapScrounger(UUID ownerId, CardSetInfo setInfo) { @@ -41,7 +40,7 @@ public final class ScrapheapScrounger extends CardImpl { this.addAbility(new CantBlockAbility()); // {1}{B}, Exile another creature card from your graveyard: Return Scrapheap Scrounger from your graveyard to the battlefield. - Ability ability = new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(false), new ManaCostsImpl<>("{1}{B}")); + Ability ability = new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(false, false), new ManaCostsImpl<>("{1}{B}")); ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(filter))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/ScreamreachBrawler.java b/Mage.Sets/src/mage/cards/s/ScreamreachBrawler.java index da58f92d57b..d1ac4b25811 100644 --- a/Mage.Sets/src/mage/cards/s/ScreamreachBrawler.java +++ b/Mage.Sets/src/mage/cards/s/ScreamreachBrawler.java @@ -23,7 +23,7 @@ public final class ScreamreachBrawler extends CardImpl { this.toughness = new MageInt(3); // Dash {1}{R} - this.addAbility(new DashAbility(this, "{1}{R}")); + this.addAbility(new DashAbility("{1}{R}")); } private ScreamreachBrawler(final ScreamreachBrawler card) { diff --git a/Mage.Sets/src/mage/cards/s/ScreechingSilcaw.java b/Mage.Sets/src/mage/cards/s/ScreechingSilcaw.java index 09eaefac241..600768cfb46 100644 --- a/Mage.Sets/src/mage/cards/s/ScreechingSilcaw.java +++ b/Mage.Sets/src/mage/cards/s/ScreechingSilcaw.java @@ -34,7 +34,7 @@ public final class ScreechingSilcaw extends CardImpl { TriggeredAbility conditional = new ConditionalInterveningIfTriggeredAbility( new DealsCombatDamageToAPlayerTriggeredAbility( new PutLibraryIntoGraveTargetEffect(4), false, true - ), MetalcraftCondition.instance, "Metalcraft — Whenever {this} " + + ), MetalcraftCondition.instance, "Whenever {this} " + "deals combat damage to a player, if you control three or more artifacts, that player mills four cards." ); conditional.setAbilityWord(AbilityWord.METALCRAFT); diff --git a/Mage.Sets/src/mage/cards/s/ScrollRack.java b/Mage.Sets/src/mage/cards/s/ScrollRack.java index a5912f09cdb..c245f5b35fa 100644 --- a/Mage.Sets/src/mage/cards/s/ScrollRack.java +++ b/Mage.Sets/src/mage/cards/s/ScrollRack.java @@ -59,13 +59,13 @@ class ScrollRackEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { FilterCard filter = new FilterCard("card in your hand to exile"); TargetCardInHand target = new TargetCardInHand(0, controller.getHand().size(), filter); target.setRequired(false); int amountExiled = 0; - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) && target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), game)) { + if (target.canChoose(source.getControllerId(), source, game) && target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), source, game)) { if (!target.getTargets().isEmpty()) { for (UUID targetId : target.getTargets()) { Card card = game.getCard(targetId); diff --git a/Mage.Sets/src/mage/cards/s/Scrounge.java b/Mage.Sets/src/mage/cards/s/Scrounge.java index a41d166a8f2..cbfe17926c0 100644 --- a/Mage.Sets/src/mage/cards/s/Scrounge.java +++ b/Mage.Sets/src/mage/cards/s/Scrounge.java @@ -64,7 +64,7 @@ class ScroungeEffect extends OneShotEffect { filter.add(new OwnerIdPredicate(opponent.getId())); TargetCardInGraveyard chosenCard = new TargetCardInGraveyard(filter); chosenCard.setNotTarget(true); - if (chosenCard.canChoose(source.getSourceId(), opponent.getId(), game)) { + if (chosenCard.canChoose(opponent.getId(), source, game)) { opponent.chooseTarget(Outcome.ReturnToHand, chosenCard, source, game); Card card = game.getCard(chosenCard.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/s/ScroungingBandar.java b/Mage.Sets/src/mage/cards/s/ScroungingBandar.java index c4b96834e73..e56ee36c4b4 100644 --- a/Mage.Sets/src/mage/cards/s/ScroungingBandar.java +++ b/Mage.Sets/src/mage/cards/s/ScroungingBandar.java @@ -65,7 +65,7 @@ class ScroungingBandarEffect extends OneShotEffect { public ScroungingBandarEffect() { super(Outcome.Benefit); - this.staticText = "move any number of +1/+1 counters from Scrounging Bandar onto another target creature"; + this.staticText = "you may move any number of +1/+1 counters from Scrounging Bandar onto another target creature"; } public ScroungingBandarEffect(final ScroungingBandarEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/ScryingSheets.java b/Mage.Sets/src/mage/cards/s/ScryingSheets.java index 2ef6b2d97e4..ea79c0cd97a 100644 --- a/Mage.Sets/src/mage/cards/s/ScryingSheets.java +++ b/Mage.Sets/src/mage/cards/s/ScryingSheets.java @@ -68,7 +68,7 @@ class ScryingSheetsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { Card card = controller.getLibrary().getFromTop(game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/s/ScuttlingButler.java b/Mage.Sets/src/mage/cards/s/ScuttlingButler.java new file mode 100644 index 00000000000..874a3cfdb2f --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ScuttlingButler.java @@ -0,0 +1,54 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.constants.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.MulticoloredPredicate; + +/** + * + * @author weirddan455 + */ +public final class ScuttlingButler extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("multicolored permanents"); + + static { + filter.add(MulticoloredPredicate.instance); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + + public ScuttlingButler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); + + this.subtype.add(SubType.CONSTRUCT); + this.power = new MageInt(4); + this.toughness = new MageInt(1); + + // At the beginning of combat on your turn, if you control two or more multicolored permanents, Scuttling Butler gains double strike until end of turn. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new BeginningOfCombatTriggeredAbility(new GainAbilitySourceEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn), TargetController.YOU, false), + condition, + "At the beginning of combat on your turn, if you control two or more multicolored permanents, {this} gains double strike until end of turn." + )); + } + + private ScuttlingButler(final ScuttlingButler card) { + super(card); + } + + @Override + public ScuttlingButler copy() { + return new ScuttlingButler(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ScuttlingSliver.java b/Mage.Sets/src/mage/cards/s/ScuttlingSliver.java index 9532d22d0f3..ba1be036681 100644 --- a/Mage.Sets/src/mage/cards/s/ScuttlingSliver.java +++ b/Mage.Sets/src/mage/cards/s/ScuttlingSliver.java @@ -32,7 +32,7 @@ public final class ScuttlingSliver extends CardImpl { this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( new SimpleActivatedAbility( new UntapSourceEffect().setText("untap this creature"), new GenericManaCost(2) - ), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS) + ), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_SLIVERS) .withForceQuotes() )); } diff --git a/Mage.Sets/src/mage/cards/s/ScytheTiger.java b/Mage.Sets/src/mage/cards/s/ScytheTiger.java index 5e37e5abfff..5162eb79804 100644 --- a/Mage.Sets/src/mage/cards/s/ScytheTiger.java +++ b/Mage.Sets/src/mage/cards/s/ScytheTiger.java @@ -31,7 +31,7 @@ public final class ScytheTiger extends CardImpl { this.addAbility(ShroudAbility.getInstance()); // When Scythe Tiger enters the battlefield, sacrifice it unless you sacrifice a land. - this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_LAND_SHORT_TEXT))))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_LAND_SHORT_TEXT))).setText("sacrifice it unless you sacrifice a land"))); } private ScytheTiger(final ScytheTiger card) { diff --git a/Mage.Sets/src/mage/cards/s/SeaDasherOctopus.java b/Mage.Sets/src/mage/cards/s/SeaDasherOctopus.java index a79023fef81..0fe597505f0 100644 --- a/Mage.Sets/src/mage/cards/s/SeaDasherOctopus.java +++ b/Mage.Sets/src/mage/cards/s/SeaDasherOctopus.java @@ -33,7 +33,7 @@ public final class SeaDasherOctopus extends CardImpl { // Whenever this creature deals combat damage to a player, draw a card. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( new DrawCardSourceControllerEffect(1), false - )); + ).setTriggerPhrase("Whenever this creature deals combat damage to a player, ")); } private SeaDasherOctopus(final SeaDasherOctopus card) { diff --git a/Mage.Sets/src/mage/cards/s/SeaGateOracle.java b/Mage.Sets/src/mage/cards/s/SeaGateOracle.java index 1a39dc8b122..9f4ad41b7d0 100644 --- a/Mage.Sets/src/mage/cards/s/SeaGateOracle.java +++ b/Mage.Sets/src/mage/cards/s/SeaGateOracle.java @@ -1,18 +1,14 @@ - - package mage.cards.s; import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.FilterCard; /** * @@ -28,7 +24,10 @@ public final class SeaGateOracle extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(3); - this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect(StaticValue.get(2), false, StaticValue.get(1), new FilterCard(), Zone.LIBRARY, false, false), false)); + // When Sea Gate Oracle enters the battlefield, look at the top two cards of your library. + // Put one of them into your hand and the other on the bottom of your library. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new LookLibraryAndPickControllerEffect(2, 1, PutCards.HAND, PutCards.BOTTOM_ANY))); } diff --git a/Mage.Sets/src/mage/cards/s/SealedFate.java b/Mage.Sets/src/mage/cards/s/SealedFate.java index ac53d3c82d3..ee8a9cbc91a 100644 --- a/Mage.Sets/src/mage/cards/s/SealedFate.java +++ b/Mage.Sets/src/mage/cards/s/SealedFate.java @@ -1,19 +1,21 @@ package mage.cards.s; -import mage.abilities.dynamicvalue.common.ManacostVariableValue; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetOpponent; import java.util.UUID; /** - * @author jeffwadsworth + * @author awjackson */ public final class SealedFate extends CardImpl { @@ -22,11 +24,7 @@ public final class SealedFate extends CardImpl { // Look at the top X cards of target opponent's library. Exile one of those cards and put the rest back on top of that player's library in any order. this.getSpellAbility().addTarget(new TargetOpponent()); - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(ManacostVariableValue.REGULAR, - false, StaticValue.get(1), - new FilterCard("a card to exile"), Zone.LIBRARY, true, - false, false, Zone.EXILED, - false, true, true)); + this.getSpellAbility().addEffect(new SealedFateEffect()); } private SealedFate(final SealedFate card) { @@ -38,3 +36,48 @@ public final class SealedFate extends CardImpl { return new SealedFate(this); } } + +class SealedFateEffect extends OneShotEffect { + + SealedFateEffect() { + super(Outcome.Detriment); + this.staticText = "Look at the top X cards of target opponent's library. " + + "Exile one of those cards and put the rest back on top of that player's library in any order"; + } + + private SealedFateEffect(final SealedFateEffect effect) { + super(effect); + } + + @Override + public SealedFateEffect copy() { + return new SealedFateEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(source.getFirstTarget()); + int xValue = source.getManaCostsToPay().getX(); + + if (controller == null || opponent == null) { + return false; + } + + Cards cards = new CardsImpl(opponent.getLibrary().getTopCards(game, xValue)); + if (cards.isEmpty()) { + return false; + } + if (cards.size() == 1) { + return controller.moveCards(cards, Zone.EXILED, source, game); + } + TargetCard targetCard = new TargetCardInLibrary(); + controller.choose(outcome, cards, targetCard, game); + Card card = game.getCard(targetCard.getFirstTarget()); + if (card != null) { + controller.moveCards(card, Zone.EXILED, source, game); + cards.remove(card); + } + return controller.putCardsOnTopOfLibrary(cards, game, source, true); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SealockMonster.java b/Mage.Sets/src/mage/cards/s/SealockMonster.java index 79b76c83814..448b3d7e90c 100644 --- a/Mage.Sets/src/mage/cards/s/SealockMonster.java +++ b/Mage.Sets/src/mage/cards/s/SealockMonster.java @@ -5,7 +5,7 @@ import mage.abilities.Ability; import mage.abilities.common.BecomesMonstrousSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.combat.CantAttackUnlessDefenderControllsPermanent; -import mage.abilities.effects.common.continuous.AddCardSubTypeTargetEffect; +import mage.abilities.effects.common.continuous.BecomesBasicLandTargetEffect; import mage.abilities.keyword.MonstrosityAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -40,7 +40,7 @@ public final class SealockMonster extends CardImpl { // When Sealock Monster becomes monstrous, target land becomes an island in addition to its other types. Ability ability = new BecomesMonstrousSourceTriggeredAbility( - new AddCardSubTypeTargetEffect(SubType.ISLAND, Duration.EndOfTurn) + new BecomesBasicLandTargetEffect(Duration.EndOfGame, false, false, SubType.ISLAND) ); ability.addTarget(new TargetLandPermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/SearingBlaze.java b/Mage.Sets/src/mage/cards/s/SearingBlaze.java index b6aa4a0a7f8..f9431bebdc3 100644 --- a/Mage.Sets/src/mage/cards/s/SearingBlaze.java +++ b/Mage.Sets/src/mage/cards/s/SearingBlaze.java @@ -1,14 +1,11 @@ - package mage.cards.s; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Outcome; import mage.filter.StaticFilters; @@ -20,8 +17,11 @@ import mage.target.TargetPermanent; import mage.target.common.TargetPlayerOrPlaneswalker; import mage.watchers.common.LandfallWatcher; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com * @author North */ @@ -53,7 +53,10 @@ class SearingBlazeEffect extends OneShotEffect { public SearingBlazeEffect() { super(Outcome.Damage); - staticText = "{this} deals 1 damage to target player or planeswalker and 1 damage to target creature that player or that planeswalker's controller controls. \nLandfall - If you had a land enter the battlefield under your control this turn, {this} deals 3 damage to that player or planeswalker and 3 damage to that creature instead."; + staticText = "{this} deals 1 damage to target player or planeswalker and 1 damage to target creature " + + "that player or that planeswalker's controller controls.
" + AbilityWord.LANDFALL.formatWord() + + "If you had a land enter the battlefield under your control this turn, {this} deals 3 damage " + + "to that player or planeswalker and 3 damage to that creature instead."; } public SearingBlazeEffect(final SearingBlazeEffect effect) { @@ -107,10 +110,10 @@ class SearingBlazeTarget extends TargetPermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set availablePossibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set availablePossibleTargets = super.possibleTargets(sourceControllerId, source, game); Set possibleTargets = new HashSet<>(); - MageObject object = game.getObject(sourceId); + MageObject object = game.getObject(source); if (object instanceof StackObject) { UUID playerId = ((StackObject) object).getStackAbility().getFirstTarget(); Player player = game.getPlayerOrPlaneswalkerController(playerId); diff --git a/Mage.Sets/src/mage/cards/s/SeascapeAerialist.java b/Mage.Sets/src/mage/cards/s/SeascapeAerialist.java index 04d886b4824..9264f779836 100644 --- a/Mage.Sets/src/mage/cards/s/SeascapeAerialist.java +++ b/Mage.Sets/src/mage/cards/s/SeascapeAerialist.java @@ -20,7 +20,7 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class SeascapeAerialist extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Ally creatures you control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("have Ally creatures you control"); static { filter.add(SubType.ALLY.getPredicate()); @@ -36,7 +36,7 @@ public final class SeascapeAerialist extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(3); - this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new GainAbilityAllEffect(FlyingAbility.getInstance(), Duration.EndOfTurn, filter), true)); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new GainAbilityAllEffect(FlyingAbility.getInstance(), Duration.EndOfTurn, filter), true).setAbilityWord(null)); } private SeascapeAerialist(final SeascapeAerialist card) { diff --git a/Mage.Sets/src/mage/cards/s/Seasinger.java b/Mage.Sets/src/mage/cards/s/Seasinger.java index 8c934c32b80..8549bfd61d1 100644 --- a/Mage.Sets/src/mage/cards/s/Seasinger.java +++ b/Mage.Sets/src/mage/cards/s/Seasinger.java @@ -81,6 +81,6 @@ enum SeasingerPredicate implements ObjectSourcePlayerPredicate { @Override public boolean apply(ObjectSourcePlayer input, Game game) { - return game.getBattlefield().contains(filter, input.getSourceId(), input.getObject().getControllerId(), game, 1); + return game.getBattlefield().contains(filter, input.getSourceId(), input.getObject().getControllerId(), input.getSource(), game, 1); } } diff --git a/Mage.Sets/src/mage/cards/s/SeasonsPast.java b/Mage.Sets/src/mage/cards/s/SeasonsPast.java index efdc6f6abc5..8ca77de851e 100644 --- a/Mage.Sets/src/mage/cards/s/SeasonsPast.java +++ b/Mage.Sets/src/mage/cards/s/SeasonsPast.java @@ -64,7 +64,7 @@ class SeasonsPastEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { SeasonsPastTarget target = new SeasonsPastTarget(); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); controller.moveCards(new CardsImpl(target.getTargets()), Zone.HAND, source, game); return true; } @@ -83,7 +83,7 @@ class SeasonsPastTarget extends TargetCardInYourGraveyard { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set usedCMC = new HashSet<>(); for (UUID targetId : this.getTargets()) { Card card = game.getCard(targetId); @@ -91,7 +91,7 @@ class SeasonsPastTarget extends TargetCardInYourGraveyard { usedCMC.add(card.getManaValue()); } } - Set possibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); Set leftPossibleTargets = new HashSet<>(); for (UUID targetId : possibleTargets) { Card card = game.getCard(targetId); diff --git a/Mage.Sets/src/mage/cards/s/SecludedCourtyard.java b/Mage.Sets/src/mage/cards/s/SecludedCourtyard.java new file mode 100644 index 00000000000..90041f9719f --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SecludedCourtyard.java @@ -0,0 +1,118 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.cards.s; + +import java.util.UUID; +import mage.ConditionalMana; +import mage.MageObject; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.abilities.mana.ColorlessManaAbility; +import mage.abilities.mana.ConditionalAnyColorManaAbility; +import mage.abilities.mana.builder.ConditionalManaBuilder; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.players.Player; + +/** + * @author jeffwadsworth + */ +public final class SecludedCourtyard extends CardImpl { + + public SecludedCourtyard(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // As Secluded Courtyard enters the battlefield, choose a creature type. + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.Benefit))); + + // // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // Add one mana of any color. Spend this mana only to cast a creature spell of the chosen type or activate an ability of a creature or creature card of the chosen type. + this.addAbility(new ConditionalAnyColorManaAbility(new TapSourceCost(), 1, new SecludedCourtyardManaBuilder(), true)); + } + + private SecludedCourtyard(final SecludedCourtyard card) { + super(card); + } + + @Override + public SecludedCourtyard copy() { + return new SecludedCourtyard(this); + } +} + +class SecludedCourtyardManaBuilder extends ConditionalManaBuilder { + + SubType creatureType; + + @Override + public ConditionalManaBuilder setMana(Mana mana, Ability source, Game game) { + SubType subType = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game); + if (subType != null) { + creatureType = subType; + } + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source); + if (controller != null + && sourceObject != null + && mana.getAny() == 0) { + game.informPlayers(controller.getLogName() + " produces " + mana.toString() + " with " + sourceObject.getLogName() + + " (can only be spent to cast creatures of type " + creatureType + " and activate an ability of a creature or creature card of the chosen type)"); + } + return super.setMana(mana, source, game); + } + + @Override + public ConditionalMana build(Object... options) { + return new SecludedCourtyardConditionalMana(this.mana, creatureType); + } + + @Override + public String getRule() { + return "Spend this mana only to cast a creature spell of the chosen type or activate an ability of a creature or creature card of the chosen type"; + } +} + +class SecludedCourtyardConditionalMana extends ConditionalMana { + + SubType creatureType; + + public SecludedCourtyardConditionalMana(Mana mana, SubType creatureType) { + super(mana); + staticText = "Spend this mana only to cast a creature spell of the chosen type or activate an ability of a creature or creature card of the chosen type"; + addCondition(new SecludedCourtyardManaCondition(creatureType)); + } +} + +class SecludedCourtyardManaCondition implements Condition { + + SubType creatureType; + + SecludedCourtyardManaCondition(SubType creatureType) { + this.creatureType = creatureType; + } + + @Override + public boolean apply(Game game, Ability source) { + MageObject object = game.getObject(source); + // casting a creature card or using its ability + if (creatureType != null + && object != null + && object.hasSubtype(creatureType, game)) { + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SecondSunrise.java b/Mage.Sets/src/mage/cards/s/SecondSunrise.java index 7d8a17e573f..06e28e9a8dc 100644 --- a/Mage.Sets/src/mage/cards/s/SecondSunrise.java +++ b/Mage.Sets/src/mage/cards/s/SecondSunrise.java @@ -72,7 +72,7 @@ class SecondSunriseEffect extends OneShotEffect { continue; } result |= player.moveCards(player.getGraveyard().getCards( - filter, source.getSourceId(), source.getControllerId(), game + filter, source.getControllerId(), source, game ), Zone.BATTLEFIELD, source, game); } return result; diff --git a/Mage.Sets/src/mage/cards/s/SecretSalvage.java b/Mage.Sets/src/mage/cards/s/SecretSalvage.java index b348f065587..928cb2b2fed 100644 --- a/Mage.Sets/src/mage/cards/s/SecretSalvage.java +++ b/Mage.Sets/src/mage/cards/s/SecretSalvage.java @@ -1,9 +1,11 @@ package mage.cards.s; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -23,13 +25,15 @@ import java.util.UUID; */ public final class SecretSalvage extends CardImpl { + private static final FilterCard filter = new FilterNonlandCard("nonland card from your graveyard"); + public SecretSalvage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}{B}"); // Exile target nonland card from your graveyard. Search your library for any number of cards with the same name as that card, // reveal them, and put them into your hand. Then shuffle your library. getSpellAbility().addEffect(new SecretSalvageEffect()); - getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterNonlandCard("nonland card from your graveyard"))); + getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); } private SecretSalvage(final SecretSalvage card) { @@ -46,8 +50,9 @@ class SecretSalvageEffect extends OneShotEffect { public SecretSalvageEffect() { super(Outcome.DrawCard); - staticText = "Exile target nonland card from your graveyard. Search your library for any number of cards with the same name as that card, " - + "reveal them, and put them into your hand. Then shuffle"; + staticText = "Exile target nonland card from your graveyard. " + + "Search your library for any number of cards with the same name as that card, " + + "reveal them, put them into your hand, then shuffle"; } public SecretSalvageEffect(final SecretSalvageEffect effect) { @@ -62,34 +67,16 @@ class SecretSalvageEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { - Card targetCard = game.getCard(getTargetPointer().getFirst(game, source)); - if (targetCard != null) { - controller.moveCards(targetCard, Zone.EXILED, source, game); - - String nameToSearch = CardUtil.getCardNameForSameNameSearch(targetCard); - FilterCard nameFilter = new FilterCard(); - nameFilter.add(new NamePredicate(nameToSearch)); - - TargetCardInLibrary target = new TargetCardInLibrary(0, Integer.MAX_VALUE, nameFilter); - if (controller.searchLibrary(target, source, game)) { - if (!target.getTargets().isEmpty()) { - Cards cards = new CardsImpl(); - for (UUID cardId : target.getTargets()) { - Card card = controller.getLibrary().remove(cardId, game); - if (card != null) { - cards.add(card); - } - } - controller.revealCards(sourceObject.getIdName(), cards, game); - controller.moveCards(cards, Zone.HAND, source, game); - } - controller.shuffleLibrary(source, game); - return true; - } - } + Card targetCard = game.getCard(getTargetPointer().getFirst(game, source)); + if (controller == null || targetCard == null) { + return false; } - return false; + controller.moveCards(targetCard, Zone.EXILED, source, game); + String nameToSearch = CardUtil.getCardNameForSameNameSearch(targetCard); + FilterCard nameFilter = new FilterCard("card named " + nameToSearch); + nameFilter.add(new NamePredicate(nameToSearch)); + return new SearchLibraryPutInHandEffect(new TargetCardInLibrary( + 0, Integer.MAX_VALUE, nameFilter + ), true, true).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/s/SecurityBypass.java b/Mage.Sets/src/mage/cards/s/SecurityBypass.java new file mode 100644 index 00000000000..161dd0119ec --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SecurityBypass.java @@ -0,0 +1,76 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalRestrictionEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.combat.CantBeBlockedAttachedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SecurityBypass extends CardImpl { + + public SecurityBypass(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // As long as enchanted creature is attacking alone, it can't be blocked. + this.addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect( + new CantBeBlockedAttachedEffect(AttachmentType.AURA), SecurityBypassCondition.instance, + "as long as enchanted creature is attacking alone, it can't be blocked" + ))); + + // Enchanted creature has "Whenever this creature deals combat damage to a player, it connives." + this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( + new DealsCombatDamageToAPlayerTriggeredAbility(new ConniveSourceEffect(), false) + .setTriggerPhrase("Whenever this creature deals combat damage to a player, "), + AttachmentType.AURA, Duration.WhileOnBattlefield, "enchanted creature has " + + "\"Whenever this creature deals combat damage to a player, it connives.\" " + + "(Its controller draws a card, then discards a card. If they discarded a nonland card, " + + "they put a +1/+1 counter on this creature.)" + ))); + } + + private SecurityBypass(final SecurityBypass card) { + super(card); + } + + @Override + public SecurityBypass copy() { + return new SecurityBypass(this); + } +} + +enum SecurityBypassCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Permanent aura = source.getSourcePermanentIfItStillExists(game); + return aura != null + && game.getCombat().attacksAlone() + && game.getCombat().getAttackers().contains(aura.getAttachedTo()); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SecurityRhox.java b/Mage.Sets/src/mage/cards/s/SecurityRhox.java new file mode 100644 index 00000000000..4da2c0ce9bc --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SecurityRhox.java @@ -0,0 +1,47 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.costs.AlternativeCostSourceAbility; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SecurityRhox extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.TREASURE, ""); + + public SecurityRhox(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}"); + + this.subtype.add(SubType.RHINO); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // You may pay {R}{G} rather than pay this spell's mana cost. Spend only mana produced by Treasures to cast it this way. + ManaCost cost = new ManaCostsImpl<>("{R}{G}"); + cost.setSourceFilter(filter); + this.addAbility(new AlternativeCostSourceAbility( + cost, null, "You may pay {R}{G} rather than pay this spell's mana cost. " + + "Spend only mana produced by Treasures to cast it this way." + )); + } + + private SecurityRhox(final SecurityRhox card) { + super(card); + } + + @Override + public SecurityRhox copy() { + return new SecurityRhox(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SeeRed.java b/Mage.Sets/src/mage/cards/s/SeeRed.java index 49e4f259f2b..1670a99ed80 100644 --- a/Mage.Sets/src/mage/cards/s/SeeRed.java +++ b/Mage.Sets/src/mage/cards/s/SeeRed.java @@ -55,7 +55,7 @@ public final class SeeRed extends CardImpl { // At the beginning of your end step, if you didn't attack with a creature this turn, sacrifice See Red. this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone.BATTLEFIELD, new SacrificeSourceEffect(), TargetController.YOU), + new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new SacrificeSourceEffect(), TargetController.YOU), new InvertCondition(ControllerAttackedThisTurnCondition.instance), "At the beginning of your end step, if you didn't attack with a creature this turn, sacrifice {this}."), new AttackedThisTurnWatcher()); } diff --git a/Mage.Sets/src/mage/cards/s/SeeTheUnwritten.java b/Mage.Sets/src/mage/cards/s/SeeTheUnwritten.java index a7f687d95fa..b491278f6ef 100644 --- a/Mage.Sets/src/mage/cards/s/SeeTheUnwritten.java +++ b/Mage.Sets/src/mage/cards/s/SeeTheUnwritten.java @@ -1,41 +1,38 @@ package mage.cards.s; -import mage.abilities.Ability; -import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.effects.common.RevealLibraryPickControllerEffect; import mage.abilities.hint.common.FerociousHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; import java.util.UUID; /** - * @author LevelX2 + * @author awjackson */ public final class SeeTheUnwritten extends CardImpl { + private static final String rule = "Reveal the top eight cards of your library. " + + "You may put a creature card from among them onto the battlefield. Put the rest into your graveyard.
" + + AbilityWord.FEROCIOUS.formatWord() + "If " + FerociousCondition.instance.toString() + + ", you may put two creature cards onto the battlefield instead of one"; + public SeeTheUnwritten(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}{G}"); // Reveal the top eight cards of your library. You may put a creature card from among them onto the battlefield. Put the rest into your graveyard. // Ferocious — If you control a creature with power 4 or greater, you may put two creature cards onto the battlefield instead of one. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new SeeTheUnwrittenEffect(1), - new SeeTheUnwrittenEffect(2), - new InvertCondition(FerociousCondition.instance), - "Reveal the top eight cards of your library. You may put a creature card from among them onto the battlefield. Put the rest into your graveyard." - + "
Ferocious — If you control a creature with power 4 or greater, you may put two creature cards onto the battlefield instead of one")); + new RevealLibraryPickControllerEffect(8, 2, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.BATTLEFIELD, PutCards.GRAVEYARD), + new RevealLibraryPickControllerEffect(8, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.BATTLEFIELD, PutCards.GRAVEYARD), + FerociousCondition.instance, rule + )); this.getSpellAbility().addHint(FerociousHint.instance); } @@ -48,51 +45,3 @@ public final class SeeTheUnwritten extends CardImpl { return new SeeTheUnwritten(this); } } - -class SeeTheUnwrittenEffect extends OneShotEffect { - - private final int numberOfCardsToPutIntoPlay; - - public SeeTheUnwrittenEffect(int numberOfCardsToPutIntoPlay) { - super(Outcome.DrawCard); - this.numberOfCardsToPutIntoPlay = numberOfCardsToPutIntoPlay; - this.staticText = "Reveal the top eight cards of your library. You may put " - + (numberOfCardsToPutIntoPlay == 1 ? "a creature card" : "two creature cards") - + " from among them onto the battlefield. Put the rest into your graveyard"; - } - - public SeeTheUnwrittenEffect(final SeeTheUnwrittenEffect effect) { - super(effect); - this.numberOfCardsToPutIntoPlay = effect.numberOfCardsToPutIntoPlay; - } - - @Override - public SeeTheUnwrittenEffect copy() { - return new SeeTheUnwrittenEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 8)); - int creatureCardsFound = cards.count(StaticFilters.FILTER_CARD_CREATURE, game); - if (!cards.isEmpty()) { - controller.revealCards(source, cards, game); - if (creatureCardsFound > 0 && controller.chooseUse(outcome, "Put creature(s) into play?", source, game)) { - int cardsToChoose = Math.min(numberOfCardsToPutIntoPlay, creatureCardsFound); - TargetCard target = new TargetCard(cardsToChoose, cardsToChoose, Zone.LIBRARY, StaticFilters.FILTER_CARD_CREATURE); - if (controller.choose(Outcome.PutCreatureInPlay, cards, target, game)) { - Cards toBattlefield = new CardsImpl(target.getTargets()); - controller.moveCards(toBattlefield, Zone.BATTLEFIELD, source, game); - cards.removeAll(toBattlefield); - } - } - controller.moveCards(cards, Zone.GRAVEYARD, source, game); - } - return true; - } - return false; - } - -} diff --git a/Mage.Sets/src/mage/cards/s/SeedcradleWitch.java b/Mage.Sets/src/mage/cards/s/SeedcradleWitch.java index a06280bbb35..295b0056a41 100644 --- a/Mage.Sets/src/mage/cards/s/SeedcradleWitch.java +++ b/Mage.Sets/src/mage/cards/s/SeedcradleWitch.java @@ -31,7 +31,7 @@ public final class SeedcradleWitch extends CardImpl { // {2}{G}{W}: Target creature gets +3/+3 until end of turn. Untap that creature. SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(3, 3, Duration.EndOfTurn), new ManaCostsImpl("{2}{G}{W}")); - ability.addEffect(new UntapTargetEffect()); + ability.addEffect(new UntapTargetEffect().setText("untap that creature")); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SeedlingCharm.java b/Mage.Sets/src/mage/cards/s/SeedlingCharm.java index 73a3f5fba73..78e58abe867 100644 --- a/Mage.Sets/src/mage/cards/s/SeedlingCharm.java +++ b/Mage.Sets/src/mage/cards/s/SeedlingCharm.java @@ -42,13 +42,11 @@ public final class SeedlingCharm extends CardImpl { this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent(filter1)); // or regenerate target green creature - Mode mode = new Mode(); - mode.addEffect(new RegenerateTargetEffect()); + Mode mode = new Mode(new RegenerateTargetEffect()); mode.addTarget(new TargetPermanent(filter2)); this.getSpellAbility().addMode(mode); // or target creature gains trample until end of turn. - mode = new Mode(); - mode.addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn)); + mode = new Mode(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SeekTheWilds.java b/Mage.Sets/src/mage/cards/s/SeekTheWilds.java index 2e03bc00e8d..e7ed6ed28f7 100644 --- a/Mage.Sets/src/mage/cards/s/SeekTheWilds.java +++ b/Mage.Sets/src/mage/cards/s/SeekTheWilds.java @@ -1,14 +1,12 @@ - package mage.cards.s; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; /** * @@ -16,18 +14,12 @@ import mage.filter.predicate.Predicates; */ public final class SeekTheWilds extends CardImpl { - private static final FilterCard filter = new FilterCard("a creature or land card"); - - static { - filter.add(Predicates.or(CardType.CREATURE.getPredicate(), CardType.LAND.getPredicate())); - } - public SeekTheWilds(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{G}"); // Look at the top four cards of your library. You may reveal a creature or land card from among them and put it into your hand. Put the rest on the bottom of your library in any order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(4), false, StaticValue.get(1), filter, false)); - + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + 4, 1, StaticFilters.FILTER_CARD_CREATURE_OR_LAND, PutCards.HAND, PutCards.BOTTOM_ANY)); } private SeekTheWilds(final SeekTheWilds card) { diff --git a/Mage.Sets/src/mage/cards/s/SeethingPathblazer.java b/Mage.Sets/src/mage/cards/s/SeethingPathblazer.java index e1ffa05c121..2d98395c8de 100644 --- a/Mage.Sets/src/mage/cards/s/SeethingPathblazer.java +++ b/Mage.Sets/src/mage/cards/s/SeethingPathblazer.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -14,31 +12,31 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.target.common.TargetControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; /** - * * @author Loki */ public final class SeethingPathblazer extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Elemental"); - - static { - filter.add(SubType.ELEMENTAL.getPredicate()); - } + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.ELEMENTAL, "Elemental"); public SeethingPathblazer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.subtype.add(SubType.ELEMENTAL); this.subtype.add(SubType.WARRIOR); this.power = new MageInt(2); this.toughness = new MageInt(2); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(2, 0, Duration.EndOfTurn), new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, false))); - ability.addEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn)); + Ability ability = new SimpleActivatedAbility(new BoostSourceEffect( + 2, 0, Duration.EndOfTurn + ).setText("{this} gets +2/+0"), new SacrificeTargetCost(new TargetControlledPermanent(filter))); + ability.addEffect(new GainAbilitySourceEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains first strike until end of turn")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SefrisOfTheHiddenWays.java b/Mage.Sets/src/mage/cards/s/SefrisOfTheHiddenWays.java index eeb7310b841..6ddb6ca649c 100644 --- a/Mage.Sets/src/mage/cards/s/SefrisOfTheHiddenWays.java +++ b/Mage.Sets/src/mage/cards/s/SefrisOfTheHiddenWays.java @@ -1,9 +1,9 @@ package mage.cards.s; -import java.util.Set; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.CompletedDungeonTriggeredAbility; +import mage.abilities.common.PutCardIntoGraveFromAnywhereAllTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.effects.keyword.VentureIntoTheDungeonEffect; import mage.cards.CardImpl; @@ -11,24 +11,21 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; +import mage.constants.TargetController; +import mage.filter.FilterCard; import mage.filter.StaticFilters; +import mage.filter.common.FilterCreatureCard; import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; -import mage.cards.Card; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.ZoneChangeGroupEvent; -import mage.game.permanent.Permanent; /** * @author TheElk801 */ public final class SefrisOfTheHiddenWays extends CardImpl { + private static final FilterCard filter = new FilterCreatureCard("one or more creature cards"); + public SefrisOfTheHiddenWays(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}{B}"); @@ -39,8 +36,8 @@ public final class SefrisOfTheHiddenWays extends CardImpl { this.toughness = new MageInt(3); // Whenever one or more creature cards are put into your graveyard from anywhere, venture into the dungeon. This ability triggers only once each turn. - this.addAbility(new SefrisOfTheHiddenWaysTriggeredAbility( - new VentureIntoTheDungeonEffect().setText("") + this.addAbility(new PutCardIntoGraveFromAnywhereAllTriggeredAbility( + new VentureIntoTheDungeonEffect(), false, filter, TargetController.YOU ).setTriggersOnce(true)); // Create Undead — Whenever you complete a dungeon, return target creature card from your graveyard to the battlefield. @@ -58,55 +55,3 @@ public final class SefrisOfTheHiddenWays extends CardImpl { return new SefrisOfTheHiddenWays(this); } } - -class SefrisOfTheHiddenWaysTriggeredAbility extends TriggeredAbilityImpl { - - public SefrisOfTheHiddenWaysTriggeredAbility(Effect effect) { - super(Zone.ALL, effect, false); - } - - public SefrisOfTheHiddenWaysTriggeredAbility(final SefrisOfTheHiddenWaysTriggeredAbility ability) { - super(ability); - } - - @Override - public SefrisOfTheHiddenWaysTriggeredAbility copy() { - return new SefrisOfTheHiddenWaysTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ZONE_CHANGE_GROUP; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Boolean applies = false; - /* - Sefris of the Hidden Ways must be on the battlefield for its first ability to trigger. - It does not trigger when Sefris goes to the graveyard from the battlefield, even if other - creature cards also went to the graveyard at the same time. - */ - Permanent sourceCard = game.getPermanent(sourceId); - if (((ZoneChangeGroupEvent) event).getToZone() != Zone.GRAVEYARD - || sourceCard == null) { - return false; - } - ZoneChangeGroupEvent zEvent = (ZoneChangeGroupEvent) event; - Set cards = zEvent.getCards(); - for (Card card : cards) { - if (card.isCreature(game) - && (Card) sourceCard != card // 603.6c, 603.10a, and 603.10. - && !card.isCopy() - && card.isOwnedBy(controllerId)) { - applies = true; - } - } - return applies; - } - - @Override - public String getTriggerPhrase() { - return "Whenever one or more creature cards are put into your graveyard from anywhere, venture into the dungeon."; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SegmentedKrotiq.java b/Mage.Sets/src/mage/cards/s/SegmentedKrotiq.java index 4e7dffb3294..78d228ac51c 100644 --- a/Mage.Sets/src/mage/cards/s/SegmentedKrotiq.java +++ b/Mage.Sets/src/mage/cards/s/SegmentedKrotiq.java @@ -23,7 +23,7 @@ public final class SegmentedKrotiq extends CardImpl { this.toughness = new MageInt(5); // Megamorph {6}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{6}{G}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{6}{G}"), true)); } private SegmentedKrotiq(final SegmentedKrotiq card) { diff --git a/Mage.Sets/src/mage/cards/s/SehtsTiger.java b/Mage.Sets/src/mage/cards/s/SehtsTiger.java index fc88912d280..88140819e39 100644 --- a/Mage.Sets/src/mage/cards/s/SehtsTiger.java +++ b/Mage.Sets/src/mage/cards/s/SehtsTiger.java @@ -68,7 +68,7 @@ class SehtsTigerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); ChoiceColor choice = new ChoiceColor(); if (controller != null && mageObject != null && controller.choose(Outcome.Protect, choice, game)) { game.informPlayers(mageObject.getLogName() + ": " + controller.getLogName() + " has chosen " + choice.getChoice()); diff --git a/Mage.Sets/src/mage/cards/s/SeizeTheSpotlight.java b/Mage.Sets/src/mage/cards/s/SeizeTheSpotlight.java new file mode 100644 index 00000000000..77c228bdbee --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SeizeTheSpotlight.java @@ -0,0 +1,118 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.TreasureToken; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTargets; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SeizeTheSpotlight extends CardImpl { + + public SeizeTheSpotlight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); + + // Each opponent chooses fame or fortune. For each player who chose fame, gain control of a creature that player controls until end of turn. Untap those creatures and they gain haste until end of turn. For each player who chose fortune, you draw a card and create a Treasure token. + this.getSpellAbility().addEffect(new SeizeTheSpotlightEffect()); + } + + private SeizeTheSpotlight(final SeizeTheSpotlight card) { + super(card); + } + + @Override + public SeizeTheSpotlight copy() { + return new SeizeTheSpotlight(this); + } +} + +class SeizeTheSpotlightEffect extends OneShotEffect { + + SeizeTheSpotlightEffect() { + super(Outcome.Benefit); + staticText = "each opponent chooses fame or fortune. For each player who chose fame, " + + "gain control of a creature that player controls until end of turn. " + + "Untap those creatures and they gain haste until end of turn. " + + "For each player who chose fortune, you draw a card and create a Treasure token"; + } + + private SeizeTheSpotlightEffect(final SeizeTheSpotlightEffect effect) { + super(effect); + } + + @Override + public SeizeTheSpotlightEffect copy() { + return new SeizeTheSpotlightEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + List fame = new ArrayList<>(); + int fortune = 0; + for (UUID playerId : game.getOpponents(source.getControllerId())) { + Player opponent = game.getPlayer(playerId); + if (opponent == null) { + continue; + } + boolean choseFame = opponent.chooseUse(Outcome.Detriment, "Choose fame (give a creature) or fortune (give a card and a treasure)", null, "Fame", "Fortune", source, game); + game.informPlayers(opponent.getLogName() + " chooses " + (choseFame ? "fame" : "fortune")); + if (choseFame) { + fame.add(opponent); + } else { + fortune++; + } + } + List permanents = new ArrayList<>(); + for (Player opponent : fame) { + FilterPermanent filter = new FilterCreaturePermanent("creature controlled by " + opponent.getName()); + filter.add(new ControllerIdPredicate(opponent.getId())); + TargetPermanent target = new TargetPermanent(filter); + target.setNotTarget(true); + if (!target.canChoose(source.getSourceId(), source, game)) { + continue; + } + controller.choose(outcome, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null) { + continue; + } + permanent.untap(game); + permanents.add(permanent); + } + if (!permanents.isEmpty()) { + game.addEffect(new GainControlTargetEffect(Duration.EndOfTurn) + .setTargetPointer(new FixedTargets(permanents, game)), source); + game.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance()) + .setTargetPointer(new FixedTargets(permanents, game)), source); + } + if (fortune > 0) { + controller.drawCards(fortune, source, game); + new TreasureToken().putOntoBattlefield(fortune, game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SejiriMerfolk.java b/Mage.Sets/src/mage/cards/s/SejiriMerfolk.java index b36a6cc4589..ebc9b54a4d5 100644 --- a/Mage.Sets/src/mage/cards/s/SejiriMerfolk.java +++ b/Mage.Sets/src/mage/cards/s/SejiriMerfolk.java @@ -1,9 +1,9 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; @@ -13,25 +13,20 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; +import java.util.UUID; + /** - * * @author North, nantuko */ public final class SejiriMerfolk extends CardImpl { - private static final String rule1 = "As long as you control a Plains, {this} has first strike."; - private static final String rule2 = "As long as you control a Plains, {this} has lifelink."; - private static final FilterControlledPermanent filter = new FilterControlledPermanent("Plains"); - - static { - filter.add(SubType.PLAINS.getPredicate()); - } + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.PLAINS); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); public SejiriMerfolk(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.MERFOLK); this.subtype.add(SubType.SOLDIER); @@ -39,11 +34,14 @@ public final class SejiriMerfolk extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(1); - ConditionalContinuousEffect effect1 = new ConditionalContinuousEffect(new GainAbilitySourceEffect(LifelinkAbility.getInstance()), new PermanentsOnTheBattlefieldCondition(filter), rule1); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect1)); - ConditionalContinuousEffect effect2 = new ConditionalContinuousEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance()), new PermanentsOnTheBattlefieldCondition(filter), rule2); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect2)); - + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(LifelinkAbility.getInstance()), condition, + "as long as you control a Plains, {this} has first strike" + )); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect( + FirstStrikeAbility.getInstance()), condition, "and lifelink" + )); + this.addAbility(ability); } private SejiriMerfolk(final SejiriMerfolk card) { diff --git a/Mage.Sets/src/mage/cards/s/SelectiveMemory.java b/Mage.Sets/src/mage/cards/s/SelectiveMemory.java index e4b7d72c035..09a967673d7 100644 --- a/Mage.Sets/src/mage/cards/s/SelectiveMemory.java +++ b/Mage.Sets/src/mage/cards/s/SelectiveMemory.java @@ -1,28 +1,28 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; -import mage.filter.common.FilterNonlandCard; +import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author North */ public final class SelectiveMemory extends CardImpl { public SelectiveMemory(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}"); // Search your library for any number of nonland cards and exile them. Then shuffle your library. this.getSpellAbility().addEffect(new SelectiveMemoryEffect()); @@ -57,20 +57,17 @@ class SelectiveMemoryEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - TargetCardInLibrary target = new TargetCardInLibrary(0, Integer.MAX_VALUE, new FilterNonlandCard()); - if (player.searchLibrary(target, source, game)) { - for (UUID targetId : target.getTargets()) { - Card card = player.getLibrary().remove(targetId, game); - if (card != null) { - card.moveToExile(null, "", source, game); - } - } - } - - player.shuffleLibrary(source, game); - return true; + if (player == null) { + return false; } - return false; + TargetCardInLibrary target = new TargetCardInLibrary( + 0, Integer.MAX_VALUE, StaticFilters.FILTER_CARDS_NON_LAND + ); + player.searchLibrary(target, source, game); + Cards cards = new CardsImpl(target.getTargets()); + cards.retainZone(Zone.LIBRARY, game); + player.moveCards(cards, Zone.EXILED, source, game); + player.shuffleLibrary(source, game); + return true; } } diff --git a/Mage.Sets/src/mage/cards/s/SelesnyaCharm.java b/Mage.Sets/src/mage/cards/s/SelesnyaCharm.java index c0f56e7d5e7..2c996db5cc3 100644 --- a/Mage.Sets/src/mage/cards/s/SelesnyaCharm.java +++ b/Mage.Sets/src/mage/cards/s/SelesnyaCharm.java @@ -45,14 +45,12 @@ public final class SelesnyaCharm extends CardImpl { this.getSpellAbility().getTargets().add(new TargetCreaturePermanent()); // or exile target creature with power 5 or greater; - Mode mode = new Mode(); - mode.addEffect(new ExileTargetEffect()); + Mode mode = new Mode(new ExileTargetEffect()); mode.addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addMode(mode); // or create a 2/2 white Knight creature token with vigilance. - mode = new Mode(); - mode.addEffect(new CreateTokenEffect(new KnightToken())); + mode = new Mode(new CreateTokenEffect(new KnightToken())); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SelfAssembler.java b/Mage.Sets/src/mage/cards/s/SelfAssembler.java index f6b61704083..a2f0ab77514 100644 --- a/Mage.Sets/src/mage/cards/s/SelfAssembler.java +++ b/Mage.Sets/src/mage/cards/s/SelfAssembler.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.Effect; @@ -11,22 +9,24 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author fireshoes */ public final class SelfAssembler extends CardImpl { - private static final FilterCard filter = new FilterCard("an Assembly-Worker card"); + private static final FilterCard filter = new FilterCreatureCard("an Assembly-Worker creature card"); static { filter.add(SubType.ASSEMBLY_WORKER.getPredicate()); } public SelfAssembler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{5}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{5}"); this.subtype.add(SubType.ASSEMBLY_WORKER); this.power = new MageInt(4); this.toughness = new MageInt(4); @@ -34,7 +34,7 @@ public final class SelfAssembler extends CardImpl { // When Self-Assembler enters the battlefield, you may search your library for an Assembly-Worker creature card, reveal it, put it into your hand, // then shuffle your library. Effect effect = new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0, 1, filter), true, true); - effect.setText("you may search your library for an Assembly-Worker card, reveal it, put it into your hand, then shuffle"); + effect.setText("you may search your library for an Assembly-Worker creature card, reveal it, put it into your hand, then shuffle"); this.addAbility(new EntersBattlefieldTriggeredAbility(effect, true)); } diff --git a/Mage.Sets/src/mage/cards/s/SelfInflictedWound.java b/Mage.Sets/src/mage/cards/s/SelfInflictedWound.java index d8949beecf1..594623c51a6 100644 --- a/Mage.Sets/src/mage/cards/s/SelfInflictedWound.java +++ b/Mage.Sets/src/mage/cards/s/SelfInflictedWound.java @@ -73,7 +73,7 @@ class SelfInflictedWoundEffect extends OneShotEffect { filter.add(Predicates.or(new ColorPredicate(ObjectColor.GREEN), new ColorPredicate(ObjectColor.WHITE))); TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), targetOpponent.getId(), game)) { + if (target.canChoose(targetOpponent.getId(), source, game)) { targetOpponent.chooseTarget(Outcome.Sacrifice, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/s/SelflessGlyphweaver.java b/Mage.Sets/src/mage/cards/s/SelflessGlyphweaver.java index 51dfff39c29..2efa24a8c87 100644 --- a/Mage.Sets/src/mage/cards/s/SelflessGlyphweaver.java +++ b/Mage.Sets/src/mage/cards/s/SelflessGlyphweaver.java @@ -82,7 +82,7 @@ class DeadlyVanityEffect extends OneShotEffect { } TargetPermanent target = new TargetCreatureOrPlaneswalker(); target.setNotTarget(true); - controller.choose(outcome, target, source.getId(), game); + controller.choose(outcome, target, source, game); FilterPermanent filter = new FilterCreatureOrPlaneswalkerPermanent(); UUID targetId = target.getFirstTarget(); diff --git a/Mage.Sets/src/mage/cards/s/SelflessSamurai.java b/Mage.Sets/src/mage/cards/s/SelflessSamurai.java index fcbb9a6e273..af1921c859a 100644 --- a/Mage.Sets/src/mage/cards/s/SelflessSamurai.java +++ b/Mage.Sets/src/mage/cards/s/SelflessSamurai.java @@ -13,7 +13,10 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.TargetPermanent; import java.util.UUID; @@ -23,6 +26,13 @@ import java.util.UUID; */ public final class SelflessSamurai extends CardImpl { + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("another target creature you control"); + + static { + filter.add(AnotherPredicate.instance); + } + public SelflessSamurai(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); @@ -42,7 +52,7 @@ public final class SelflessSamurai extends CardImpl { Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect( IndestructibleAbility.getInstance(), Duration.EndOfTurn ), new SacrificeSourceCost()); - ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SelvalasEnforcer.java b/Mage.Sets/src/mage/cards/s/SelvalasEnforcer.java index d3ae7a8bc19..28f30b8e364 100644 --- a/Mage.Sets/src/mage/cards/s/SelvalasEnforcer.java +++ b/Mage.Sets/src/mage/cards/s/SelvalasEnforcer.java @@ -11,6 +11,7 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Outcome; @@ -36,7 +37,7 @@ public final class SelvalasEnforcer extends CardImpl { // For each nonland card revealed this way, put a +1/+1 counter on Selvala's Enforcer. Then each player draws a card. Ability ability = new EntersBattlefieldTriggeredAbility(new SelvalasEnforcerEffect(), false); ability.addEffect(new DrawCardAllEffect(1).setText("Then each player draws a card")); - ability.withFlavorWord("Parley"); + ability.setAbilityWord(AbilityWord.PARLEY); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SenTriplets.java b/Mage.Sets/src/mage/cards/s/SenTriplets.java index 2a84343b025..9b75c134bed 100644 --- a/Mage.Sets/src/mage/cards/s/SenTriplets.java +++ b/Mage.Sets/src/mage/cards/s/SenTriplets.java @@ -79,7 +79,7 @@ class SenTripletsRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (targetPlayer != null && mageObject != null) { return "This turn you can't cast spells or activate abilities" + " (" + mageObject.getLogName() + ')'; @@ -129,7 +129,7 @@ class SenTripletsPlayFromOpponentsHandEffect extends AsThoughEffectImpl { public SenTripletsPlayFromOpponentsHandEffect() { super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); - staticText = "You may play cards from that player's hand this turn"; + staticText = "You may play lands and cast spells from that player's hand this turn"; } public SenTripletsPlayFromOpponentsHandEffect(final SenTripletsPlayFromOpponentsHandEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/SengirNosferatu.java b/Mage.Sets/src/mage/cards/s/SengirNosferatu.java index 7bf5b366653..519c4d1cc32 100644 --- a/Mage.Sets/src/mage/cards/s/SengirNosferatu.java +++ b/Mage.Sets/src/mage/cards/s/SengirNosferatu.java @@ -87,7 +87,7 @@ class ReturnSengirNosferatuEffect extends OneShotEffect { } Target target = new TargetCardInExile(filter); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), controller.getId(), game)) { + if (!target.canChoose(controller.getId(), source, game)) { return false; } controller.chooseTarget(Outcome.PutCreatureInPlay, target, source, game); diff --git a/Mage.Sets/src/mage/cards/s/SenseisDiviningTop.java b/Mage.Sets/src/mage/cards/s/SenseisDiviningTop.java index cf5c4aefbb6..57086f00417 100644 --- a/Mage.Sets/src/mage/cards/s/SenseisDiviningTop.java +++ b/Mage.Sets/src/mage/cards/s/SenseisDiviningTop.java @@ -4,7 +4,7 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LookLibraryControllerEffect; @@ -26,7 +26,7 @@ public final class SenseisDiviningTop extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); // {1}: Look at the top three cards of your library, then put them back in any order. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new LookLibraryControllerEffect(3, false, true), new ManaCostsImpl("{1}"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new LookLibraryControllerEffect(3), new GenericManaCost(1))); // {T}: Draw a card, then put Sensei's Divining Top on top of its owner's library. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new TapSourceCost()); ability.addEffect(new SenseisDiviningTopEffect()); diff --git a/Mage.Sets/src/mage/cards/s/SenselessRage.java b/Mage.Sets/src/mage/cards/s/SenselessRage.java index 37eb244e02d..4379ae8d86c 100644 --- a/Mage.Sets/src/mage/cards/s/SenselessRage.java +++ b/Mage.Sets/src/mage/cards/s/SenselessRage.java @@ -39,7 +39,7 @@ public final class SenselessRage extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(2, 2, Duration.WhileOnBattlefield))); // Madness {1}{R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{1}{R}"))); } private SenselessRage(final SenselessRage card) { diff --git a/Mage.Sets/src/mage/cards/s/Sentinel.java b/Mage.Sets/src/mage/cards/s/Sentinel.java index e9bb3c425b0..d0204672a2f 100644 --- a/Mage.Sets/src/mage/cards/s/Sentinel.java +++ b/Mage.Sets/src/mage/cards/s/Sentinel.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -11,42 +9,40 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.SetToughnessSourceEffect; 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.SubLayer; -import mage.constants.Zone; +import mage.constants.*; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.BlockedByIdPredicate; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Sentinel extends CardImpl { + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature blocking or blocked by {this}"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.EITHER); + } + public Sentinel(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); this.subtype.add(SubType.SHAPESHIFTER); this.power = new MageInt(1); this.toughness = new MageInt(1); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking or blocked by Sentinel"); - filter.add(Predicates.or(new BlockedByIdPredicate(this.getId()), - new BlockingAttackerIdPredicate(this.getId()))); // 0: Change Sentinel's base toughness to 1 plus the power of target creature blocking or blocked by Sentinel. (This effect lasts indefinitely.) - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SentinelEffect(), new GenericManaCost(0)); - ability.addTarget(new TargetCreaturePermanent(filter)); + Ability ability = new SimpleActivatedAbility(new SentinelEffect(), new GenericManaCost(0)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); - } private Sentinel(final Sentinel card) { diff --git a/Mage.Sets/src/mage/cards/s/SentinelSliver.java b/Mage.Sets/src/mage/cards/s/SentinelSliver.java index e6dfac198ea..708dd9fddff 100644 --- a/Mage.Sets/src/mage/cards/s/SentinelSliver.java +++ b/Mage.Sets/src/mage/cards/s/SentinelSliver.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -11,24 +9,27 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author Plopman */ public final class SentinelSliver extends CardImpl { public SentinelSliver(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add(SubType.SLIVER); this.power = new MageInt(2); this.toughness = new MageInt(2); // Sliver creatures you control have vigilance. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, new FilterControlledCreaturePermanent(SubType.SLIVER, "Sliver creatures you control ")))); + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_SLIVERS + ))); } private SentinelSliver(final SentinelSliver card) { diff --git a/Mage.Sets/src/mage/cards/s/SequesteredStash.java b/Mage.Sets/src/mage/cards/s/SequesteredStash.java index ee0d2b06278..2e25e499af6 100644 --- a/Mage.Sets/src/mage/cards/s/SequesteredStash.java +++ b/Mage.Sets/src/mage/cards/s/SequesteredStash.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; @@ -16,19 +14,20 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SequesteredStash extends CardImpl { public SequesteredStash(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // {R}: Add {C}. this.addAbility(new ColorlessManaAbility()); @@ -74,11 +73,11 @@ class SequesteredStashEffect extends OneShotEffect { if (controller == null) { return false; } - TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard")); + TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + if (target.canChoose(source.getControllerId(), source, game) && controller.chooseUse(outcome, "Put an artifact card from your graveyard to library?", source, game) - && controller.choose(outcome, target, source.getSourceId(), game)) { + && controller.choose(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { controller.moveCards(card, Zone.LIBRARY, source, game); diff --git a/Mage.Sets/src/mage/cards/s/SerendibDjinn.java b/Mage.Sets/src/mage/cards/s/SerendibDjinn.java index 84e430bd213..0a703b3dddf 100644 --- a/Mage.Sets/src/mage/cards/s/SerendibDjinn.java +++ b/Mage.Sets/src/mage/cards/s/SerendibDjinn.java @@ -72,8 +72,8 @@ class SerendibDjinnEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Target target = new TargetControlledPermanent(1, 1, new FilterControlledLandPermanent(), true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - controller.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + if (target.canChoose(controller.getId(), source, game)) { + controller.choose(Outcome.Sacrifice, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.sacrifice(source, game); diff --git a/Mage.Sets/src/mage/cards/s/SereneMaster.java b/Mage.Sets/src/mage/cards/s/SereneMaster.java index 56629a3f2ec..b52985a7815 100644 --- a/Mage.Sets/src/mage/cards/s/SereneMaster.java +++ b/Mage.Sets/src/mage/cards/s/SereneMaster.java @@ -4,6 +4,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BlocksSourceTriggeredAbility; +import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessTargetEffect; @@ -14,11 +15,9 @@ import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.BlockedByIdPredicate; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.Target; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; @@ -28,6 +27,13 @@ import mage.target.targetpointer.FixedTarget; */ public final class SereneMaster extends CardImpl { + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creature it's blocking"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.BLOCKED_BY); + } + public SereneMaster(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add(SubType.HUMAN); @@ -37,8 +43,9 @@ public final class SereneMaster extends CardImpl { this.toughness = new MageInt(2); // Whenever Serene Master blocks, exchange its power and the power of target creature it's blocking until end of combat. - this.addAbility(new BlocksSourceTriggeredAbility(new SereneMasterEffect(), false)); - + Ability ability = new BlocksSourceTriggeredAbility(new SereneMasterEffect()); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); } private SereneMaster(final SereneMaster card) { @@ -69,31 +76,19 @@ class SereneMasterEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); Permanent sourceCreature = game.getPermanent(source.getSourceId()); - if (controller != null && sourceCreature != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature it's blocking"); - filter.add(new BlockedByIdPredicate((source.getSourceId()))); - Target target = new TargetCreaturePermanent(filter); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - if (controller.chooseTarget(outcome, target, source, game)) { - Permanent attackingCreature = game.getPermanent(target.getFirstTarget()); - if (attackingCreature != null) { - int newSourcePower = attackingCreature.getPower().getValue(); - int newAttackerPower = sourceCreature.getPower().getValue(); - ContinuousEffect effect = new SetPowerToughnessTargetEffect(newSourcePower, sourceCreature.getToughness().getValue(), Duration.EndOfCombat); - effect.setTargetPointer(new FixedTarget(source.getSourceId(), game)); - game.addEffect(effect, source); - effect = new SetPowerToughnessTargetEffect(newAttackerPower, attackingCreature.getToughness().getValue(), Duration.EndOfCombat); - effect.setTargetPointer(new FixedTarget(attackingCreature.getId(), game)); - game.addEffect(effect, source); - return true; - } - } - } - + Permanent attackingCreature = game.getPermanent(targetPointer.getFirst(game, source)); + if (sourceCreature != null && attackingCreature != null) { + StaticValue newSourcePower = StaticValue.get(attackingCreature.getPower().getValue()); + StaticValue newAttackerPower = StaticValue.get(sourceCreature.getPower().getValue()); + ContinuousEffect effect = new SetPowerToughnessTargetEffect(newSourcePower, null, Duration.EndOfCombat); + effect.setTargetPointer(new FixedTarget(source.getSourceId(), game)); + game.addEffect(effect, source); + effect = new SetPowerToughnessTargetEffect(newAttackerPower, null, Duration.EndOfCombat); + effect.setTargetPointer(new FixedTarget(attackingCreature.getId(), game)); + game.addEffect(effect, source); + return true; } return false; } - } diff --git a/Mage.Sets/src/mage/cards/s/SereneSunset.java b/Mage.Sets/src/mage/cards/s/SereneSunset.java new file mode 100644 index 00000000000..157e5d9a9eb --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SereneSunset.java @@ -0,0 +1,47 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.effects.common.PreventDamageByTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.game.Game; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SereneSunset extends CardImpl { + + public SereneSunset(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{G}"); + + // Prevent all combat damage X target creatures would deal this turn. + this.getSpellAbility().addEffect(new PreventDamageByTargetEffect(Duration.EndOfTurn, true) + .setText("prevent all combat damage X target creatures would deal this turn")); + this.getSpellAbility().setTargetAdjuster(SereneSunsetAdjuster.instance); + } + + private SereneSunset(final SereneSunset card) { + super(card); + } + + @Override + public SereneSunset copy() { + return new SereneSunset(this); + } +} + +enum SereneSunsetAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(ability.getManaCostsToPay().getX())); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SerpentineBasilisk.java b/Mage.Sets/src/mage/cards/s/SerpentineBasilisk.java index ecf2ab7db97..2a8681b9087 100644 --- a/Mage.Sets/src/mage/cards/s/SerpentineBasilisk.java +++ b/Mage.Sets/src/mage/cards/s/SerpentineBasilisk.java @@ -31,7 +31,7 @@ public final class SerpentineBasilisk extends CardImpl { new CreateDelayedTriggeredAbilityEffect( new AtTheEndOfCombatDelayedTriggeredAbility(new DestroyTargetEffect("destroy that creature at end of combat")), true), false, true)); // Morph {1}{G}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{G}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{G}{G}"))); } private SerpentineBasilisk(final SerpentineBasilisk card) { diff --git a/Mage.Sets/src/mage/cards/s/SerpentsSoulJar.java b/Mage.Sets/src/mage/cards/s/SerpentsSoulJar.java index 53de04b4551..0210def2ebb 100644 --- a/Mage.Sets/src/mage/cards/s/SerpentsSoulJar.java +++ b/Mage.Sets/src/mage/cards/s/SerpentsSoulJar.java @@ -14,6 +14,7 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; +import mage.game.ExileZone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -21,7 +22,9 @@ import mage.players.Player; import mage.util.CardUtil; import mage.watchers.Watcher; -import java.util.*; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; /** * @author TheElk801 @@ -35,8 +38,8 @@ public final class SerpentsSoulJar extends CardImpl { // Whenever an Elf you control dies, exile it. this.addAbility(new DiesCreatureTriggeredAbility( - new SerpentsSoulJarExileEffect(), false, filter, true) - ); + new SerpentsSoulJarExileEffect(), false, filter, true + )); // {T}, Pay 2 life: Until end of turn, you may cast a creature spell from among cards exiled with Serpent's Soul-Jar. Ability ability = new SimpleActivatedAbility(new SerpentsSoulJarCastFromExileEffect(), new TapSourceCost()); @@ -78,13 +81,11 @@ class SerpentsSoulJarExileEffect extends OneShotEffect { if (player == null || permanent == null || card == null) { return false; } - MageObjectReference mor = new MageObjectReference(permanent, game); - player.moveCards(card, Zone.EXILED, source, game); - String exileId = "serpentsSoulJar_" + mor.getSourceId() + mor.getZoneChangeCounter(); - if (game.getState().getValue(exileId) == null) { - game.getState().setValue(exileId, new HashSet()); - } - ((Set) game.getState().getValue(exileId)).add(new MageObjectReference(card, game)); + player.moveCardsToExile( + card, source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); return true; } } @@ -113,28 +114,16 @@ class SerpentsSoulJarCastFromExileEffect extends AsThoughEffectImpl { @Override public void init(Ability source, Game game) { super.init(source, game); - SerpentsSoulJarWatcher watcher = game.getState().getWatcher(SerpentsSoulJarWatcher.class); - if (watcher != null) { - watcher.addPlayable(source, game); - } + SerpentsSoulJarWatcher.addPlayable(source, game); } @Override public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { - SerpentsSoulJarWatcher watcher = game.getState().getWatcher(SerpentsSoulJarWatcher.class); - if (watcher == null || !watcher.checkPermission(affectedControllerId, source, game)) { + if (!SerpentsSoulJarWatcher.checkPermission(affectedControllerId, source, game)) { return false; } - Object value = game.getState().getValue( - "serpentsSoulJar_" + source.getSourceId() + source.getSourceObjectZoneChangeCounter() - ); - if (!(value instanceof Set)) { - discard(); - return false; - } - Set morSet = (Set) value; - if (game.getState().getZone(sourceId) != Zone.EXILED - || morSet.stream().noneMatch(mor -> mor.refersTo(sourceId, game))) { + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + if (exileZone == null || !exileZone.contains(sourceId)) { return false; } Card card = game.getCard(sourceId); @@ -168,24 +157,27 @@ class SerpentsSoulJarWatcher extends Watcher { super.reset(); } - boolean checkPermission(UUID playerId, Ability source, Game game) { + static boolean checkPermission(UUID playerId, Ability source, Game game) { if (!playerId.equals(source.getControllerId())) { return false; } - MageObjectReference mor = new MageObjectReference( - source.getSourceId(), source.getSourceObjectZoneChangeCounter(), game - ); - if (!morMap.containsKey(mor)) { - return false; - } - return morMap.get(mor).getOrDefault(playerId, 0) > 0; + MageObjectReference mor = new MageObjectReference(source); + SerpentsSoulJarWatcher watcher = game.getState().getWatcher(SerpentsSoulJarWatcher.class); + return watcher + .morMap + .containsKey(mor) + && watcher + .morMap + .get(mor) + .getOrDefault(playerId, 0) > 0; } - void addPlayable(Ability source, Game game) { - MageObjectReference mor = new MageObjectReference( - source.getSourceId(), source.getSourceObjectZoneChangeCounter(), game - ); - morMap.computeIfAbsent(mor, m -> new HashMap<>()) + static void addPlayable(Ability source, Game game) { + MageObjectReference mor = new MageObjectReference(source); + game.getState() + .getWatcher(SerpentsSoulJarWatcher.class) + .morMap + .computeIfAbsent(mor, m -> new HashMap<>()) .compute(source.getControllerId(), CardUtil::setOrIncrementValue); } } diff --git a/Mage.Sets/src/mage/cards/s/SerraTheBenevolent.java b/Mage.Sets/src/mage/cards/s/SerraTheBenevolent.java index bcffe715a31..38c30822e0e 100644 --- a/Mage.Sets/src/mage/cards/s/SerraTheBenevolent.java +++ b/Mage.Sets/src/mage/cards/s/SerraTheBenevolent.java @@ -1,7 +1,6 @@ package mage.cards.s; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; @@ -36,7 +35,7 @@ public final class SerraTheBenevolent extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SERRA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +2: Creatures you control with flying get +1/+1 until end of turn. this.addAbility(new LoyaltyAbility(new BoostControlledEffect(1, 1, Duration.EndOfTurn, filter) diff --git a/Mage.Sets/src/mage/cards/s/SerrasEmissary.java b/Mage.Sets/src/mage/cards/s/SerrasEmissary.java index 60f167c508e..8af200f52fd 100644 --- a/Mage.Sets/src/mage/cards/s/SerrasEmissary.java +++ b/Mage.Sets/src/mage/cards/s/SerrasEmissary.java @@ -78,7 +78,7 @@ class SerrasEmissaryEffect extends ContinuousEffectImpl { controller.addAbility(ability); for (Permanent permanent : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game )) { permanent.addAbility(ability, source.getSourceId(), game); } diff --git a/Mage.Sets/src/mage/cards/s/SetonKrosanProtector.java b/Mage.Sets/src/mage/cards/s/SetonKrosanProtector.java index 6567bd0e992..7843de81e3c 100644 --- a/Mage.Sets/src/mage/cards/s/SetonKrosanProtector.java +++ b/Mage.Sets/src/mage/cards/s/SetonKrosanProtector.java @@ -80,7 +80,7 @@ class SetonKrosanProtectorManaEffect extends BasicManaEffect { public List getNetMana(Game game, Ability source) { if (game != null && game.inCheckPlayableState()) { // Because the ability can be used multiple times, multiply with untapped druids - int count = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int count = game.getBattlefield().count(filter, source.getControllerId(), source, game); List netMana = new ArrayList<>(); if (count > 0) { netMana.add(Mana.GreenMana(count)); diff --git a/Mage.Sets/src/mage/cards/s/SettleTheScore.java b/Mage.Sets/src/mage/cards/s/SettleTheScore.java index 3032e317110..0d28a8f8e74 100644 --- a/Mage.Sets/src/mage/cards/s/SettleTheScore.java +++ b/Mage.Sets/src/mage/cards/s/SettleTheScore.java @@ -71,7 +71,7 @@ class SettleTheScoreEffect extends OneShotEffect { return false; } TargetPermanent target = new TargetPermanent(filter); - if (target.choose(Outcome.Benefit, player.getId(), source.getSourceId(), game)) { + if (target.choose(Outcome.Benefit, player.getId(), source.getSourceId(), source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.addCounters(CounterType.LOYALTY.createInstance(2), source.getControllerId(), source, game); diff --git a/Mage.Sets/src/mage/cards/s/SevenTailMentor.java b/Mage.Sets/src/mage/cards/s/SevenTailMentor.java index f6a7fa74a1a..36bddfaa18e 100644 --- a/Mage.Sets/src/mage/cards/s/SevenTailMentor.java +++ b/Mage.Sets/src/mage/cards/s/SevenTailMentor.java @@ -21,7 +21,7 @@ import java.util.UUID; */ public final class SevenTailMentor extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent("creature or Vehicle"); + private static final FilterPermanent filter = new FilterControlledPermanent("creature or Vehicle you control"); static { filter.add(Predicates.or( diff --git a/Mage.Sets/src/mage/cards/s/SeverTheBloodline.java b/Mage.Sets/src/mage/cards/s/SeverTheBloodline.java index 4c94dc9d2e3..ae27c60569e 100644 --- a/Mage.Sets/src/mage/cards/s/SeverTheBloodline.java +++ b/Mage.Sets/src/mage/cards/s/SeverTheBloodline.java @@ -8,7 +8,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.TimingRule; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.NamePredicate; @@ -74,7 +73,7 @@ class SeverTheBloodlineEffect extends OneShotEffect { } else { filter.add(new NamePredicate(targetPermanent.getName())); } - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { controller.moveCardToExileWithInfo(permanent, null, "", source, game, Zone.BATTLEFIELD, true); } return true; diff --git a/Mage.Sets/src/mage/cards/s/SewerCrocodile.java b/Mage.Sets/src/mage/cards/s/SewerCrocodile.java new file mode 100644 index 00000000000..71262d8589c --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SewerCrocodile.java @@ -0,0 +1,63 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.DifferentManaValuesInGraveCondition; +import mage.abilities.costs.CostAdjuster; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; +import mage.abilities.hint.common.DifferentManaValuesInGraveHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.game.Game; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SewerCrocodile extends CardImpl { + + public SewerCrocodile(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}"); + + this.subtype.add(SubType.CROCODILE); + this.power = new MageInt(4); + this.toughness = new MageInt(6); + + // {3}{U}: Sewer Crocodile can't be blocked this turn. This ability costs {3} less to activate if there are five or more mana values among cards in your graveyard. + Ability ability = new SimpleActivatedAbility( + new CantBeBlockedSourceEffect(Duration.EndOfTurn), new ManaCostsImpl<>("{3}{U}") + ); + ability.addEffect(new InfoEffect("This ability costs {3} less to activate " + + "if there are five or more mana values among cards in your graveyard")); + ability.setCostAdjuster(SewerCrocodileAdjuster.instance); + this.addAbility(ability.addHint(DifferentManaValuesInGraveHint.instance)); + } + + private SewerCrocodile(final SewerCrocodile card) { + super(card); + } + + @Override + public SewerCrocodile copy() { + return new SewerCrocodile(this); + } +} + +enum SewerCrocodileAdjuster implements CostAdjuster { + instance; + + @Override + public void adjustCosts(Ability ability, Game game) { + if (DifferentManaValuesInGraveCondition.FIVE.apply(game, ability)) { + CardUtil.reduceCost(ability, 3); + } + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShaakHerd.java b/Mage.Sets/src/mage/cards/s/ShaakHerd.java index 693b00f6f38..0bdf7a4076c 100644 --- a/Mage.Sets/src/mage/cards/s/ShaakHerd.java +++ b/Mage.Sets/src/mage/cards/s/ShaakHerd.java @@ -11,7 +11,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.common.TargetCardInYourGraveyard; /** @@ -23,7 +23,7 @@ public final class ShaakHerd extends CardImpl { private static final FilterCard filter = new FilterCard("another target creature card"); static { - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); } public ShaakHerd(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/ShacklesOfTreachery.java b/Mage.Sets/src/mage/cards/s/ShacklesOfTreachery.java index 06667a49972..fd4e874b817 100644 --- a/Mage.Sets/src/mage/cards/s/ShacklesOfTreachery.java +++ b/Mage.Sets/src/mage/cards/s/ShacklesOfTreachery.java @@ -61,7 +61,7 @@ class ShacklesOfTreacheryTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean apply(ObjectSourcePlayer input, Game game) { - Permanent permanent = game.getPermanent(input.getSourceId()); + Permanent permanent = input.getSource().getSourcePermanentIfItStillExists(game); return permanent != null && permanent.getAttachments().contains(input.getObject().getId()); } } diff --git a/Mage.Sets/src/mage/cards/s/ShadowAlleyDenizen.java b/Mage.Sets/src/mage/cards/s/ShadowAlleyDenizen.java index 82bffd74294..769ae1b0c86 100644 --- a/Mage.Sets/src/mage/cards/s/ShadowAlleyDenizen.java +++ b/Mage.Sets/src/mage/cards/s/ShadowAlleyDenizen.java @@ -5,6 +5,7 @@ import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.IntimidateAbility; import mage.cards.CardImpl; @@ -39,12 +40,10 @@ public final class ShadowAlleyDenizen extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - // Whenever another black creature enters the battlefield under your control, target creature gains intimidate until end of turn. - Ability ability = new EntersBattlefieldAllTriggeredAbility( - Zone.BATTLEFIELD, - new GainAbilityTargetEffect(IntimidateAbility.getInstance(), Duration.EndOfTurn), - filter, false, null, true); + Effect effect = new GainAbilityTargetEffect(IntimidateAbility.getInstance(), Duration.EndOfTurn); + effect.setText("target creature gains intimidate until end of turn. (It can't be blocked except by artifact creatures and/or creatures that share a color with it.)"); + Ability ability = new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, effect, filter, false, null, true); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/ShadowOfDoubt.java b/Mage.Sets/src/mage/cards/s/ShadowOfDoubt.java index 19c3cea0f09..75a2a3f8641 100644 --- a/Mage.Sets/src/mage/cards/s/ShadowOfDoubt.java +++ b/Mage.Sets/src/mage/cards/s/ShadowOfDoubt.java @@ -27,7 +27,7 @@ public final class ShadowOfDoubt extends CardImpl { // Players can't search libraries this turn. this.getSpellAbility().addEffect(new LibrariesCantBeSearchedEffect()); // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private ShadowOfDoubt(final ShadowOfDoubt card) { diff --git a/Mage.Sets/src/mage/cards/s/ShadowOfMortality.java b/Mage.Sets/src/mage/cards/s/ShadowOfMortality.java new file mode 100644 index 00000000000..89a0b1faa0b --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShadowOfMortality.java @@ -0,0 +1,73 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ShadowOfMortality extends CardImpl { + + private static final Hint hint = new ValueHint("Current net life loss", ShadowOfMortalityValue.instance); + + public ShadowOfMortality(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{13}{B}{B}"); + + this.subtype.add(SubType.AVATAR); + this.power = new MageInt(7); + this.toughness = new MageInt(7); + + // If your life total is less than your starting life total, this spell costs {X} less to cast, where X is the difference. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, + new SpellCostReductionForEachSourceEffect( + 1, ShadowOfMortalityValue.instance + ).setText("if your life total is less than your starting life total, " + + "this spell costs {X} less to cast, where X is the difference") + ).addHint(hint)); + } + + private ShadowOfMortality(final ShadowOfMortality card) { + super(card); + } + + @Override + public ShadowOfMortality copy() { + return new ShadowOfMortality(this); + } +} + +enum ShadowOfMortalityValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Player player = game.getPlayer(sourceAbility.getControllerId()); + return player != null ? Math.max(game.getStartingLife() - player.getLife(), 0) : 0; + } + + @Override + public ShadowOfMortalityValue copy() { + return this; + } + + @Override + public String getMessage() { + return ""; + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShadowgrangeArchfiend.java b/Mage.Sets/src/mage/cards/s/ShadowgrangeArchfiend.java new file mode 100644 index 00000000000..74faa038b0c --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShadowgrangeArchfiend.java @@ -0,0 +1,136 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.MadnessAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * @author Alex-Vasile + */ +public final class ShadowgrangeArchfiend extends CardImpl { + public ShadowgrangeArchfiend(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{B}"); + this.subtype.add(SubType.DEMON); + + this.power = new MageInt(8); + this.toughness = new MageInt(4); + + // When Shadowgrange Archfiend enters the battlefield, + // each opponent sacrifices a creature with the greatest power among creatures they control. + // You gain life equal to the greatest power among creatures sacrificed this way. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ShadowgrangeArchfiendEffect())); + + // Madness—{2}{B}, Pay 8 life. + MadnessAbility madnessAbility = new MadnessAbility(new ManaCostsImpl<>("{2}{B}"), 8); + this.addAbility(madnessAbility); + } + + private ShadowgrangeArchfiend(final ShadowgrangeArchfiend card) { super(card); } + + @Override + public ShadowgrangeArchfiend copy() { return new ShadowgrangeArchfiend(this); } +} + +class ShadowgrangeArchfiendEffect extends OneShotEffect { + + public ShadowgrangeArchfiendEffect() { + super(Outcome.Benefit); + this.staticText = "each opponent sacrifices a creature with the greatest power among creatures they control. " + + "You gain life equal to the greatest power among creatures sacrificed this way"; + } + + private ShadowgrangeArchfiendEffect(final ShadowgrangeArchfiendEffect effect) { super(effect); } + + @Override + public ShadowgrangeArchfiendEffect copy() { return new ShadowgrangeArchfiendEffect(this); } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) {return false; } + + List toSacrifice = new ArrayList<>(); + + // Iterate through each opponent + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + if (!controller.hasOpponent(playerId, game)) { continue; } + + Player opponent = game.getPlayer(playerId); + if (opponent == null) { continue; } + + int greatestPower = Integer.MIN_VALUE; + int numberOfCreatures = 0; + Permanent creatureToSacrifice = null; + + // Iterature through each creature + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game)) { + if (permanent.getPower().getValue() > greatestPower) { + greatestPower = permanent.getPower().getValue(); + numberOfCreatures = 1; + creatureToSacrifice = permanent; + } else if (permanent.getPower().getValue() == greatestPower) { + numberOfCreatures++; + } + } + + // If multiple creatures are tied for having the greatest power + if (numberOfCreatures > 1) { + FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent( + "creature to sacrifice with power equal to " + greatestPower); + filter.add(new PowerPredicate(ComparisonType.EQUAL_TO, greatestPower)); + Target target = new TargetControlledCreaturePermanent(filter); + if (opponent.choose(outcome, target, source, game)) { + creatureToSacrifice = game.getPermanent(target.getFirstTarget()); + } + } + + if (creatureToSacrifice != null) { + toSacrifice.add(creatureToSacrifice); + } + } + + int greatestPowerAmongAllCreaturesSacked = Integer.MIN_VALUE; + int powerOfCurrentCreature; + + // Sack the creatures and save the greaterest power amoung those which were sacked + for (Permanent permanent : toSacrifice) { + powerOfCurrentCreature = permanent.getPower().getValue(); + + // Try to sack it + if (permanent.sacrifice(source, game)) { + if (powerOfCurrentCreature > greatestPowerAmongAllCreaturesSacked) { + greatestPowerAmongAllCreaturesSacked = powerOfCurrentCreature; + } + } + } + + // Gain life equal to the power of greatest creature sacked, if it is positive + if (greatestPowerAmongAllCreaturesSacked > 0) { + new GainLifeEffect(greatestPowerAmongAllCreaturesSacked).apply(game, source); + } + + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShadowsVerdict.java b/Mage.Sets/src/mage/cards/s/ShadowsVerdict.java index f8ef523afa4..cab7c293ccb 100644 --- a/Mage.Sets/src/mage/cards/s/ShadowsVerdict.java +++ b/Mage.Sets/src/mage/cards/s/ShadowsVerdict.java @@ -87,7 +87,7 @@ class ShadowsVerdictEffect extends OneShotEffect { game.getBattlefield() .getActivePermanents( filter, source.getControllerId(), - source.getSourceId(), game + source, game ).stream() .forEach(cards::add); game.getState() diff --git a/Mage.Sets/src/mage/cards/s/ShadrixSilverquill.java b/Mage.Sets/src/mage/cards/s/ShadrixSilverquill.java index 05d41cf56cd..109e9826b61 100644 --- a/Mage.Sets/src/mage/cards/s/ShadrixSilverquill.java +++ b/Mage.Sets/src/mage/cards/s/ShadrixSilverquill.java @@ -118,7 +118,7 @@ class ShadrixSilverquillEffect extends OneShotEffect { } for (Permanent permanent : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getFirstTarget(), source.getSourceId(), game + source.getFirstTarget(), source, game )) { if (permanent == null) { continue; diff --git a/Mage.Sets/src/mage/cards/s/ShakedownHeavy.java b/Mage.Sets/src/mage/cards/s/ShakedownHeavy.java new file mode 100644 index 00000000000..bd4261bce79 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShakedownHeavy.java @@ -0,0 +1,85 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ShakedownHeavy extends CardImpl { + + public ShakedownHeavy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(6); + this.toughness = new MageInt(4); + + // Menace + this.addAbility(new MenaceAbility(false)); + + // Whenever Shakedown Heavy attacks, defending player may have you draw a card. If they do, untap Shakedown Heavy and remove it from combat. + this.addAbility(new AttacksTriggeredAbility( + new ShakedownHeavyEffect(), false, null, SetTargetPointer.PLAYER + )); + } + + private ShakedownHeavy(final ShakedownHeavy card) { + super(card); + } + + @Override + public ShakedownHeavy copy() { + return new ShakedownHeavy(this); + } +} + +class ShakedownHeavyEffect extends OneShotEffect { + + ShakedownHeavyEffect() { + super(Outcome.Benefit); + staticText = "defending player may have you draw a card. If they do, untap {this} and remove it from combat"; + } + + private ShakedownHeavyEffect(final ShakedownHeavyEffect effect) { + super(effect); + } + + @Override + public ShakedownHeavyEffect copy() { + return new ShakedownHeavyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player defender = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (controller == null || defender == null || !defender.chooseUse( + outcome, "Have " + controller.getName() + " draw a card?", source, game + )) { + return false; + } + controller.drawCards(1, source, game); + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent != null) { + permanent.untap(game); + permanent.removeFromCombat(game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShaleskinPlower.java b/Mage.Sets/src/mage/cards/s/ShaleskinPlower.java index 06d4c812c02..2e76ea2b864 100644 --- a/Mage.Sets/src/mage/cards/s/ShaleskinPlower.java +++ b/Mage.Sets/src/mage/cards/s/ShaleskinPlower.java @@ -27,7 +27,7 @@ public final class ShaleskinPlower extends CardImpl { this.toughness = new MageInt(2); // Morph {4}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{R}"))); // When Shaleskin Plower is turned face up, destroy target land. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new DestroyTargetEffect()); ability.addTarget(new TargetLandPermanent()); diff --git a/Mage.Sets/src/mage/cards/s/ShamanEnKor.java b/Mage.Sets/src/mage/cards/s/ShamanEnKor.java index f66e8fc8077..0561458fd8b 100644 --- a/Mage.Sets/src/mage/cards/s/ShamanEnKor.java +++ b/Mage.Sets/src/mage/cards/s/ShamanEnKor.java @@ -86,7 +86,7 @@ class ShamanEnKorRedirectFromTargetEffect extends RedirectionEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null) { TargetSource target = new TargetSource(); - target.choose(Outcome.PreventDamage, player.getId(), source.getSourceId(), game); + target.choose(Outcome.PreventDamage, player.getId(), source.getSourceId(), source, game); this.sourceObject = new MageObjectReference(target.getFirstTarget(), game); } else { discard(); @@ -102,7 +102,7 @@ class ShamanEnKorRedirectFromTargetEffect extends RedirectionEffect { 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 (filter.match(permanent, permanent.getControllerId(), source, game)) { if (sourceObject.equals(new MageObjectReference(event.getSourceId(), game))) { redirectTarget = new TargetPermanent(); redirectTarget.add(source.getSourceId(), game); diff --git a/Mage.Sets/src/mage/cards/s/ShaperParasite.java b/Mage.Sets/src/mage/cards/s/ShaperParasite.java index 891421e6585..d41caa1c260 100644 --- a/Mage.Sets/src/mage/cards/s/ShaperParasite.java +++ b/Mage.Sets/src/mage/cards/s/ShaperParasite.java @@ -35,7 +35,7 @@ public final class ShaperParasite extends CardImpl { this.toughness = new MageInt(3); // Morph {2}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{U}"))); // When Shaper Parasite is turned face up, target creature gets +2/-2 or -2/+2 until end of turn. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new ShaperParasiteEffect()); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/s/ShapeshiftersMarrow.java b/Mage.Sets/src/mage/cards/s/ShapeshiftersMarrow.java index 2752086927d..b1934ecd59d 100644 --- a/Mage.Sets/src/mage/cards/s/ShapeshiftersMarrow.java +++ b/Mage.Sets/src/mage/cards/s/ShapeshiftersMarrow.java @@ -56,7 +56,7 @@ public final class ShapeshiftersMarrow extends CardImpl { @Override public boolean apply(Game game, Ability source) { Player activePlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (activePlayer != null && sourceObject != null) { Card card = activePlayer.getLibrary().getFromTop(game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/s/ShareTheSpoils.java b/Mage.Sets/src/mage/cards/s/ShareTheSpoils.java new file mode 100644 index 00000000000..e62853cb08b --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShareTheSpoils.java @@ -0,0 +1,373 @@ +package mage.cards.s; + +import mage.MageIdentifier; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.*; +import mage.cards.*; +import mage.constants.*; +import mage.game.ExileZone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.ManaPoolItem; +import mage.players.Player; +import mage.players.PlayerList; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author Alex-Vasile + */ +public final class ShareTheSpoils extends CardImpl { + + public ShareTheSpoils(UUID ownderId, CardSetInfo setInfo) { + super(ownderId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + + // When Share the Spoils enters the battlefield or an opponent loses the game, + // exile the top card of each player’s library.exile the top card of each player’s library. + this.addAbility(new ShareTheSpoilsExileETBAndPlayerLossAbility()); + + // During each player’s turn, that player may play a land or cast a spell from among cards exiled with Share the Spoils, + // and they may spend mana as though it were mana of any color to cast that spell. + Ability castAbility = new SimpleStaticAbility(new ShareTheSpoilsPlayExiledCardEffect()); + castAbility.setIdentifier(MageIdentifier.ShareTheSpoilsWatcher); + this.addAbility(castAbility, new ShareTheSpoilsWatcher()); + + // When they do, exile the top card of their library. + Ability exileCardWhenPlayedACard = new ShareTheSpoilsExileCardWhenPlayACardAbility(); + this.addAbility(exileCardWhenPlayedACard); + } + + private ShareTheSpoils(final ShareTheSpoils card) { + super(card); + } + + @Override + public ShareTheSpoils copy() { + return new ShareTheSpoils(this); + } +} + +//-- Exile from Everyone --// +class ShareTheSpoilsExileETBAndPlayerLossAbility extends TriggeredAbilityImpl { + + ShareTheSpoilsExileETBAndPlayerLossAbility() { + super(Zone.BATTLEFIELD, new ShareTheSpoilsExileCardFromEveryoneEffect()); + } + + private ShareTheSpoilsExileETBAndPlayerLossAbility(final ShareTheSpoilsExileETBAndPlayerLossAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD || + event.getType() == GameEvent.EventType.LOST || // Player conceedes + event.getType() == GameEvent.EventType.LOSES; // Player loses by all other means + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + // The card that entered the battlefield was this one + if (event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD) { + return event.getTargetId().equals(getSourceId()); + } + + // A player lost the game + return true; + } + + @Override + public TriggeredAbility copy() { + return new ShareTheSpoilsExileETBAndPlayerLossAbility(this); + } + + @Override + public String getRule() { + return "When {this} enters the battlefield or an opponent loses the game, " + + "exile the top card of each player's library."; + } +} + +class ShareTheSpoilsExileCardFromEveryoneEffect extends OneShotEffect { + + public ShareTheSpoilsExileCardFromEveryoneEffect() { + super(Outcome.Exile); + } + + public ShareTheSpoilsExileCardFromEveryoneEffect(final ShareTheSpoilsExileCardFromEveryoneEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + if (source == null) { + return false; + } + + PlayerList players = game.getState().getPlayersInRange(source.getControllerId(), game); + for (UUID playerId : players) { + Player player = game.getPlayer(playerId); + if (player == null) { + continue; + } + + Card topLibraryCard = player.getLibrary().getFromTop(game); + if (topLibraryCard == null) { + continue; + } + + boolean moved = player.moveCardsToExile( + topLibraryCard, + source, + game, + true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + + if (moved) { + ShareTheSpoilsSpendAnyManaEffect effect = new ShareTheSpoilsSpendAnyManaEffect(); + effect.setTargetPointer(new FixedTarget(topLibraryCard, game)); + game.addEffect(effect, source); + } + } + return true; + } + + @Override + public ShareTheSpoilsExileCardFromEveryoneEffect copy() { + return new ShareTheSpoilsExileCardFromEveryoneEffect(this); + } +} + +//-- Play a card Exiled by Share the Spoils --// +class ShareTheSpoilsPlayExiledCardEffect extends AsThoughEffectImpl { + + ShareTheSpoilsPlayExiledCardEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.PutCardInPlay); + staticText = "During each player's turn, " + + "that player may play a land or cast a spell from among cards exiled with {this}, " + + "and they may spend mana as though it were mana of any color to cast that spell. " + + "When they do, exile the top card of their library."; + } + + private ShareTheSpoilsPlayExiledCardEffect(final ShareTheSpoilsPlayExiledCardEffect effect) { + super(effect); + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + // Have to play on your turn + if (!game.getActivePlayerId().equals(affectedControllerId)) { + return false; + } + + // Not in exile + if (game.getState().getZone(CardUtil.getMainCardId(game, sourceId)) != Zone.EXILED) { + return false; + } + + // TODO: This is a workaround for #8706, remove when that's fixed. + int zoneChangeCounter = game.getState().getZoneChangeCounter(source.getSourceId()); + // Not a card exiled with this Share the Spoils + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter)); + if (exileZone == null) { + return false; + } + if (!exileZone.contains(CardUtil.getMainCardId(game, sourceId))) { + return false; + } + + ShareTheSpoilsWatcher watcher = game.getState().getWatcher(ShareTheSpoilsWatcher.class); + if (watcher == null) { + return false; + } + + return watcher.hasNotUsedAbilityThisTurn(); + } + + @Override + public ShareTheSpoilsPlayExiledCardEffect copy() { + return new ShareTheSpoilsPlayExiledCardEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } +} + +//-- Spend mana as any color --// +class ShareTheSpoilsSpendAnyManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { + + ShareTheSpoilsSpendAnyManaEffect() { + super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.WhileOnBattlefield, Outcome.Benefit); + } + + private ShareTheSpoilsSpendAnyManaEffect(final ShareTheSpoilsSpendAnyManaEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public ShareTheSpoilsSpendAnyManaEffect copy() { + return new ShareTheSpoilsSpendAnyManaEffect(this); + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + UUID mainCardId = CardUtil.getMainCardId(game, sourceId); + + if (getTargetPointer() == null) { + return false; + } + UUID targetUUID = ((FixedTarget) getTargetPointer()).getTarget(); + + // Not the right card + if (mainCardId != targetUUID) { + return false; + } + + int mainCardZCC = game.getState().getZoneChangeCounter(mainCardId); + int targetZCC = game.getState().getZoneChangeCounter(targetUUID); + + if (mainCardZCC <= targetZCC + 1) { + // card moved one zone, from exile to being cast + return true; + } else { + // card moved zones, effect can be discarded + this.discard(); + return false; + } + } + + @Override + public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + return mana.getFirstAvailable(); + } +} + +//-- Exile another card when a card is played that was exiled with Share the Spoils --// +class ShareTheSpoilsExileCardWhenPlayACardAbility extends TriggeredAbilityImpl { + + ShareTheSpoilsExileCardWhenPlayACardAbility() { + super(Zone.BATTLEFIELD, new ShareTheSpoilsExileSingleCardEffect()); + setRuleVisible(false); + } + + private ShareTheSpoilsExileCardWhenPlayACardAbility(final ShareTheSpoilsExileCardWhenPlayACardAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SPELL_CAST || event.getType() == GameEvent.EventType.LAND_PLAYED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.hasApprovingIdentifier(MageIdentifier.ShareTheSpoilsWatcher); + } + + @Override + public TriggeredAbility copy() { + return new ShareTheSpoilsExileCardWhenPlayACardAbility(this); + } + + @Override + public String getTriggerPhrase() { + return "When they do"; + } +} + +class ShareTheSpoilsExileSingleCardEffect extends OneShotEffect { + + ShareTheSpoilsExileSingleCardEffect() { + super(Outcome.Exile); + staticText = ", exile the top card of their library"; + } + + @Override + public boolean apply(Game game, Ability source) { + if (source == null) { + return false; + } + + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + + Card topLibraryCard = player.getLibrary().getFromTop(game); + if (topLibraryCard == null) { + return false; + } + + boolean moved = player.moveCardsToExile( + topLibraryCard, + source, + game, + true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + + if (moved) { + ShareTheSpoilsSpendAnyManaEffect effect = new ShareTheSpoilsSpendAnyManaEffect(); + effect.setTargetPointer(new FixedTarget(topLibraryCard, game)); + game.addEffect(effect, source); + } + return moved; + } + + private ShareTheSpoilsExileSingleCardEffect(final ShareTheSpoilsExileSingleCardEffect effect) { + super(effect); + } + + @Override + public ShareTheSpoilsExileSingleCardEffect copy() { + return new ShareTheSpoilsExileSingleCardEffect(this); + } +} + +class ShareTheSpoilsWatcher extends Watcher { + + private boolean usedThisTurn; + + public ShareTheSpoilsWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.SPELL_CAST && event.getType() != GameEvent.EventType.LAND_PLAYED) { + return; + } + + if (event.hasApprovingIdentifier(MageIdentifier.ShareTheSpoilsWatcher)) { + usedThisTurn = true; + } + } + + @Override + public void reset() { + super.reset(); + usedThisTurn = false; + } + + public boolean hasNotUsedAbilityThisTurn() { + return !usedThisTurn; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SharedAnimosity.java b/Mage.Sets/src/mage/cards/s/SharedAnimosity.java index c4eb000b72d..66b2b9ea496 100644 --- a/Mage.Sets/src/mage/cards/s/SharedAnimosity.java +++ b/Mage.Sets/src/mage/cards/s/SharedAnimosity.java @@ -69,7 +69,7 @@ class SharedAnimosityEffect extends OneShotEffect { FilterPermanent filter = new FilterAttackingCreature(); filter.add(new SharesCreatureTypePredicate(permanent)); filter.add(AnotherPredicate.instance); - int count = game.getBattlefield().count(filter, permanent.getId(), source.getControllerId(), game); + int count = game.getBattlefield().count(filter, source.getControllerId(), source, game); if (count > 0) { game.addEffect(new BoostTargetEffect( count, 0, Duration.EndOfTurn diff --git a/Mage.Sets/src/mage/cards/s/SharedFate.java b/Mage.Sets/src/mage/cards/s/SharedFate.java index 3d9943ab38c..5e17258b97b 100644 --- a/Mage.Sets/src/mage/cards/s/SharedFate.java +++ b/Mage.Sets/src/mage/cards/s/SharedFate.java @@ -12,7 +12,6 @@ import mage.constants.*; import mage.game.ExileZone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetOpponent; @@ -66,7 +65,7 @@ class SharedFateReplacementEffect extends ReplacementEffectImpl { Player playerToDraw = game.getPlayer(event.getPlayerId()); if (playerToDraw != null && sourcePermanent != null) { TargetOpponent target = new TargetOpponent(true); - if (playerToDraw.choose(Outcome.DrawCard, target, source.getSourceId(), game)) { + if (playerToDraw.choose(Outcome.DrawCard, target, source, game)) { Player chosenPlayer = game.getPlayer(target.getFirstTarget()); if (chosenPlayer != null) { Card card = chosenPlayer.getLibrary().getFromTop(game); diff --git a/Mage.Sets/src/mage/cards/s/SharedSummons.java b/Mage.Sets/src/mage/cards/s/SharedSummons.java index 10e0cc3c560..56d0673270c 100644 --- a/Mage.Sets/src/mage/cards/s/SharedSummons.java +++ b/Mage.Sets/src/mage/cards/s/SharedSummons.java @@ -1,18 +1,13 @@ package mage.cards.s; -import mage.abilities.Ability; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; import mage.constants.CardType; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; -import mage.game.Game; -import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCardWithDifferentNameInLibrary; -import java.util.Objects; import java.util.UUID; /** @@ -20,12 +15,14 @@ import java.util.UUID; */ public final class SharedSummons extends CardImpl { + private static final FilterCard filter = new FilterCreatureCard("creature cards with different names"); + public SharedSummons(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{G}{G}"); // Search your library for up to two creature cards with different names, reveal them, put them into your hand, then shuffle your library. this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect( - new SharedSummonsTarget(), true, true + new TargetCardWithDifferentNameInLibrary(0, 2, filter), true, true )); } @@ -38,40 +35,3 @@ public final class SharedSummons extends CardImpl { return new SharedSummons(this); } } - -class SharedSummonsTarget extends TargetCardInLibrary { - - private static final FilterCard filter2 = new FilterCreatureCard("creature cards with different names"); - - SharedSummonsTarget() { - super(0, 2, filter2); - } - - private SharedSummonsTarget(final SharedSummonsTarget target) { - super(target); - } - - @Override - public SharedSummonsTarget copy() { - return new SharedSummonsTarget(this); - } - - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Cards cards, Game game) { - Card card = cards.get(id, game); - if (card == null || !card.isCreature(game)) { - return false; - } - - if (!filter.match(card, playerId, game)) { - return false; - } - - return this - .getTargets() - .stream() - .map(game::getCard) - .filter(Objects::nonNull) - .noneMatch(c -> c != null && c.getName().equals(card.getName())); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SharuumTheHegemon.java b/Mage.Sets/src/mage/cards/s/SharuumTheHegemon.java index 564be3652ee..6d17ea8f450 100644 --- a/Mage.Sets/src/mage/cards/s/SharuumTheHegemon.java +++ b/Mage.Sets/src/mage/cards/s/SharuumTheHegemon.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -12,17 +10,18 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author North */ public final class SharuumTheHegemon extends CardImpl { public SharuumTheHegemon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}{W}{U}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{W}{U}{B}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SPHINX); @@ -34,7 +33,7 @@ public final class SharuumTheHegemon extends CardImpl { // When Sharuum the Hegemon enters the battlefield, you may return target artifact card from your graveyard to the battlefield. Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), true); - ability.addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/ShatterTheSky.java b/Mage.Sets/src/mage/cards/s/ShatterTheSky.java index 72b3ff9f46a..ccb5f6948b3 100644 --- a/Mage.Sets/src/mage/cards/s/ShatterTheSky.java +++ b/Mage.Sets/src/mage/cards/s/ShatterTheSky.java @@ -69,7 +69,7 @@ class ShatterTheSkyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { game.getBattlefield() - .getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game) + .getActivePermanents(filter, source.getControllerId(), source, game) .stream() .map(Controllable::getControllerId) .distinct() diff --git a/Mage.Sets/src/mage/cards/s/ShatteredSeraph.java b/Mage.Sets/src/mage/cards/s/ShatteredSeraph.java new file mode 100644 index 00000000000..90b9f357550 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShatteredSeraph.java @@ -0,0 +1,46 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.GiveManaAbilityAndCastSourceAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ShatteredSeraph extends CardImpl { + + public ShatteredSeraph(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{U}{B}"); + + this.subtype.add(SubType.ANGEL); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Shattered Seraph enters the battlefield, you gain 3 life. + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3))); + + // {2}, Exile Shattered Seraph from your hand: Target land gains "{T}: Add {W}, {U}, or {B}" until Shattered Seraph is cast from exile. You may cast Shattered Seraph for as long as it remains exiled. + this.addAbility(new GiveManaAbilityAndCastSourceAbility("WUB")); + } + + private ShatteredSeraph(final ShatteredSeraph card) { + super(card); + } + + @Override + public ShatteredSeraph copy() { + return new ShatteredSeraph(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShattergangBrothers.java b/Mage.Sets/src/mage/cards/s/ShattergangBrothers.java index 16498be66b1..7fb2e529752 100644 --- a/Mage.Sets/src/mage/cards/s/ShattergangBrothers.java +++ b/Mage.Sets/src/mage/cards/s/ShattergangBrothers.java @@ -97,7 +97,7 @@ class ShattergangBrothersEffect extends OneShotEffect { if (player != null) { TargetControlledPermanent target = new TargetControlledPermanent(filter); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), playerId, game) + if (target.canChoose(playerId, source, game) && player.chooseTarget(outcome, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/s/ShatteringSpree.java b/Mage.Sets/src/mage/cards/s/ShatteringSpree.java index 71ad446089e..de4ad775c55 100644 --- a/Mage.Sets/src/mage/cards/s/ShatteringSpree.java +++ b/Mage.Sets/src/mage/cards/s/ShatteringSpree.java @@ -19,7 +19,7 @@ public final class ShatteringSpree extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{R}"); // Replicate {R} - this.addAbility(new ReplicateAbility(this, "{R}")); + this.addAbility(new ReplicateAbility("{R}")); // Destroy target artifact. this.getSpellAbility().addEffect(new DestroyTargetEffect(false)); this.getSpellAbility().addTarget(new TargetArtifactPermanent()); diff --git a/Mage.Sets/src/mage/cards/s/ShaukuEndbringer.java b/Mage.Sets/src/mage/cards/s/ShaukuEndbringer.java index 1ce2bcf9176..4a563f3ddd3 100644 --- a/Mage.Sets/src/mage/cards/s/ShaukuEndbringer.java +++ b/Mage.Sets/src/mage/cards/s/ShaukuEndbringer.java @@ -90,6 +90,6 @@ class ShaukuEndbringerEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { return permanent.getId().equals(source.getSourceId()) && - game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0; + game.getBattlefield().count(filter, source.getControllerId(), source, game) > 0; } } diff --git a/Mage.Sets/src/mage/cards/s/ShellOfTheLastKappa.java b/Mage.Sets/src/mage/cards/s/ShellOfTheLastKappa.java index 1eade2f0432..36b9ceda84c 100644 --- a/Mage.Sets/src/mage/cards/s/ShellOfTheLastKappa.java +++ b/Mage.Sets/src/mage/cards/s/ShellOfTheLastKappa.java @@ -1,22 +1,18 @@ package mage.cards.s; -import java.util.UUID; -import mage.ApprovingObject; 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.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SuperType; import mage.constants.Zone; -import mage.filter.FilterCard; import mage.filter.FilterSpell; +import mage.filter.StaticFilters; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.filter.predicate.Predicates; @@ -27,11 +23,11 @@ import mage.game.stack.StackObject; import mage.players.Player; import mage.target.Target; import mage.target.TargetSpell; -import mage.target.common.TargetCardInExile; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ShellOfTheLastKappa extends CardImpl { @@ -50,16 +46,18 @@ public final class ShellOfTheLastKappa extends CardImpl { addSuperType(SuperType.LEGENDARY); // {3}, {tap}: Exile target instant or sorcery spell that targets you. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new ShellOfTheLastKappaEffect(), new ManaCostsImpl("{3}")); + Ability ability = new SimpleActivatedAbility( + new ShellOfTheLastKappaEffect(), new GenericManaCost(3) + ); ability.addCost(new TapSourceCost()); Target target = new TargetSpell(filter); ability.addTarget(target); this.addAbility(ability); // {3}, {tap}, Sacrifice Shell of the Last Kappa: You may cast a card // exiled with Shell of the Last Kappa without paying its mana cost. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new ShellOfTheLastKappaCastEffect(), new ManaCostsImpl("{3}")); + ability = new SimpleActivatedAbility( + new ShellOfTheLastKappaCastEffect(), new GenericManaCost(3) + ); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); @@ -118,7 +116,7 @@ class ShellOfTheLastKappaCastEffect extends OneShotEffect { public ShellOfTheLastKappaCastEffect() { super(Outcome.PlayForFree); - this.staticText = "You may cast a card exiled with {this} without paying its mana cost"; + this.staticText = "You may cast a spell from among cards exiled with {this} without paying its mana cost"; } public ShellOfTheLastKappaCastEffect(final ShellOfTheLastKappaCastEffect effect) { @@ -134,25 +132,11 @@ class ShellOfTheLastKappaCastEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (controller != null - && sourcePermanent != null) { - TargetCardInExile target = new TargetCardInExile(new FilterCard(), - CardUtil.getExileZoneId(game, source.getSourceId(), sourcePermanent.getZoneChangeCounter(game))); - if (controller.choose(Outcome.PlayForFree, game.getExile() - .getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), - sourcePermanent.getZoneChangeCounter(game))), target, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null - && controller.chooseUse(outcome, "Cast " + card.getLogName() + " without paying its mana cost?", source, game)) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - return cardWasCast; - } - } + if (controller == null || sourcePermanent == null) { + return false; } - return false; + Cards cards = new CardsImpl(game.getExile().getExileZone(CardUtil.getExileZoneId(game, source))); + return CardUtil.castSpellWithAttributesForFree(controller, source, game, cards, StaticFilters.FILTER_CARD); } } diff --git a/Mage.Sets/src/mage/cards/s/ShelldockIsle.java b/Mage.Sets/src/mage/cards/s/ShelldockIsle.java index 5a16505a061..3fbc09f3700 100644 --- a/Mage.Sets/src/mage/cards/s/ShelldockIsle.java +++ b/Mage.Sets/src/mage/cards/s/ShelldockIsle.java @@ -1,6 +1,7 @@ package mage.cards.s; import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInAnyLibraryCondition; @@ -28,7 +29,8 @@ public final class ShelldockIsle extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // Hideaway - this.addAbility(new HideawayAbility()); + this.addAbility(new HideawayAbility(4)); + this.addAbility(new EntersBattlefieldTappedAbility()); // {tap}: Add {U}. this.addAbility(new BlueManaAbility()); diff --git a/Mage.Sets/src/mage/cards/s/ShelteringAncient.java b/Mage.Sets/src/mage/cards/s/ShelteringAncient.java index 6c60f4a01cc..a5c2d0743a8 100644 --- a/Mage.Sets/src/mage/cards/s/ShelteringAncient.java +++ b/Mage.Sets/src/mage/cards/s/ShelteringAncient.java @@ -71,7 +71,7 @@ class ShelteringAncientCost extends CostImpl { Player controller = game.getPlayer(controllerId); if (controller != null) { Target target = new TargetCreaturePermanent(1, 1, filter, true); - if (target.choose(Outcome.BoostCreature, controllerId, source.getSourceId(), game)) { + if (target.choose(Outcome.BoostCreature, controllerId, source.getSourceId(), source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.addCounters(CounterType.P1P1.createInstance(), controllerId, ability, game); diff --git a/Mage.Sets/src/mage/cards/s/ShieldOfTheOversoul.java b/Mage.Sets/src/mage/cards/s/ShieldOfTheOversoul.java index d371b8b838d..8af2a2d6c0d 100644 --- a/Mage.Sets/src/mage/cards/s/ShieldOfTheOversoul.java +++ b/Mage.Sets/src/mage/cards/s/ShieldOfTheOversoul.java @@ -42,7 +42,7 @@ public final class ShieldOfTheOversoul extends CardImpl { this.addAbility(ability); // As long as enchanted creature is green, it gets +1/+1 and is indestructible. SimpleStaticAbility greenAbility = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostEnchantedEffect(1, 1), new EnchantedCreatureColorCondition(ObjectColor.GREEN), "As long as enchanted creature is green, it gets +1/+1")); - greenAbility.addEffect(new ConditionalContinuousEffect(new GainAbilityAttachedEffect(IndestructibleAbility.getInstance() ,AttachmentType.AURA), new EnchantedCreatureColorCondition(ObjectColor.GREEN), "and is indestructible")); + greenAbility.addEffect(new ConditionalContinuousEffect(new GainAbilityAttachedEffect(IndestructibleAbility.getInstance() ,AttachmentType.AURA), new EnchantedCreatureColorCondition(ObjectColor.GREEN), "and has indestructible")); this.addAbility(greenAbility); // As long as enchanted creature is white, it gets +1/+1 and has flying. SimpleStaticAbility whiteAbility = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostEnchantedEffect(1, 1), new EnchantedCreatureColorCondition(ObjectColor.WHITE), "As long as enchanted creature is white, it gets +1/+1")); diff --git a/Mage.Sets/src/mage/cards/s/ShieldOfTheRighteous.java b/Mage.Sets/src/mage/cards/s/ShieldOfTheRighteous.java index 9a693669b1a..edf4ebccd62 100644 --- a/Mage.Sets/src/mage/cards/s/ShieldOfTheRighteous.java +++ b/Mage.Sets/src/mage/cards/s/ShieldOfTheRighteous.java @@ -1,7 +1,6 @@ - package mage.cards.s; -import java.util.UUID; +import mage.abilities.Ability; import mage.abilities.common.BlocksAttachedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; @@ -14,13 +13,13 @@ 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.Zone; +import mage.constants.SubType; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class ShieldOfTheRighteous extends CardImpl { @@ -30,11 +29,17 @@ public final class ShieldOfTheRighteous extends CardImpl { this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +0/+2 and has vigilance. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(0, 2))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(VigilanceAbility.getInstance(), AttachmentType.EQUIPMENT))); + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(0, 2)); + ability.addEffect(new GainAbilityAttachedEffect( + VigilanceAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and has vigilance")); + this.addAbility(ability); // Whenever equipped creature blocks a creature, that creature doesn't untap during its controller's next untap step. - this.addAbility(new BlocksAttachedTriggeredAbility(new DontUntapInControllersNextUntapStepTargetEffect("that creature"), "equipped", false, false, true)); + this.addAbility(new BlocksAttachedTriggeredAbility( + new DontUntapInControllersNextUntapStepTargetEffect("that creature"), + "equipped", false, false, true + )); // Equip {2} this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2), new TargetControlledCreaturePermanent(), false)); diff --git a/Mage.Sets/src/mage/cards/s/ShieldedAetherThief.java b/Mage.Sets/src/mage/cards/s/ShieldedAetherThief.java index abebd970341..43546ff001d 100644 --- a/Mage.Sets/src/mage/cards/s/ShieldedAetherThief.java +++ b/Mage.Sets/src/mage/cards/s/ShieldedAetherThief.java @@ -35,7 +35,7 @@ public final class ShieldedAetherThief extends CardImpl { this.addAbility(FlashAbility.getInstance()); // Whenever Shield Aether Thief blocks, you get {E}. - this.addAbility(new BlocksSourceTriggeredAbility(new GetEnergyCountersControllerEffect(1), false, true)); + this.addAbility(new BlocksSourceTriggeredAbility(new GetEnergyCountersControllerEffect(1), false)); // {T}, Pay {E}{E}{E}: Draw a card. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/s/ShieldhideDragon.java b/Mage.Sets/src/mage/cards/s/ShieldhideDragon.java index 79bd73c9b26..24479120184 100644 --- a/Mage.Sets/src/mage/cards/s/ShieldhideDragon.java +++ b/Mage.Sets/src/mage/cards/s/ShieldhideDragon.java @@ -43,7 +43,7 @@ public final class ShieldhideDragon extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // Megamorph {5}{W}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{5}{W}{W}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{5}{W}{W}"), true)); // When Shieldhide Dragon is turned face up, put a +1/+1 counter on each other Dragon you control. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter), false, false)); diff --git a/Mage.Sets/src/mage/cards/s/ShieldmageAdvocate.java b/Mage.Sets/src/mage/cards/s/ShieldmageAdvocate.java index 3300e14c638..be2dd1d68fe 100644 --- a/Mage.Sets/src/mage/cards/s/ShieldmageAdvocate.java +++ b/Mage.Sets/src/mage/cards/s/ShieldmageAdvocate.java @@ -82,7 +82,7 @@ class ShieldmageAdvocateEffect extends PreventionEffectImpl { @Override public void init(Ability source, Game game) { - this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/s/ShiftingLoyalties.java b/Mage.Sets/src/mage/cards/s/ShiftingLoyalties.java index 360516f3d97..837b2e86035 100644 --- a/Mage.Sets/src/mage/cards/s/ShiftingLoyalties.java +++ b/Mage.Sets/src/mage/cards/s/ShiftingLoyalties.java @@ -69,11 +69,11 @@ class TargetPermanentsThatShareCardType extends TargetPermanent { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { Set cardTypes = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); if (targetSource != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { for (CardType cardType : permanent.getCardType(game)) { if (cardTypes.contains(cardType)) { diff --git a/Mage.Sets/src/mage/cards/s/ShiftingShadow.java b/Mage.Sets/src/mage/cards/s/ShiftingShadow.java index a10eba3cba0..348066d4230 100644 --- a/Mage.Sets/src/mage/cards/s/ShiftingShadow.java +++ b/Mage.Sets/src/mage/cards/s/ShiftingShadow.java @@ -1,40 +1,27 @@ - package mage.cards.s; -import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.Effect; +import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.HasteAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; -import mage.constants.AttachmentType; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.TargetController; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.cards.*; +import mage.constants.*; 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; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * - * @author Saga + * @author TheElk801 */ public final class ShiftingShadow extends CardImpl { @@ -50,13 +37,7 @@ public final class ShiftingShadow extends CardImpl { // Enchanted creature has haste and “At the beginning of your upkeep, destroy this creature. Reveal cards from the top of your library until you reveal a creature card. // Put that card onto the battlefield and attach Shifting Shadow to it, then put all other cards revealed this way on the bottom of your library in a random order.” - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(HasteAbility.getInstance(), AttachmentType.AURA)); - Effect effect = new GainAbilityAttachedEffect(new BeginningOfUpkeepTriggeredAbility( - new ShiftingShadowEffect(this.getId()), TargetController.YOU, false), AttachmentType.AURA); - effect.setText("and \"At the beginning of your upkeep, destroy this creature. Reveal cards from the top of your library until you reveal a creature card. " - + "Put that card onto the battlefield and attach {this} to it, then put all other cards revealed this way on the bottom of your library in a random order.\""); - ability.addEffect(effect); - this.addAbility(ability); + this.addAbility(new SimpleStaticAbility(new ShiftingShadowGainEffect())); } private ShiftingShadow(final ShiftingShadow card) { @@ -69,75 +50,108 @@ public final class ShiftingShadow extends CardImpl { } } -class ShiftingShadowEffect extends OneShotEffect { +class ShiftingShadowGainEffect extends ContinuousEffectImpl { - private final UUID auraId; - - public ShiftingShadowEffect(UUID auraId) { - super(Outcome.PutCreatureInPlay); - this.staticText = "destroy this creature. Reveal cards from the top of your library until you reveal a creature card. " - + "Put that card onto the battlefield and attach {this} to it, then put all other cards revealed this way on the bottom of your library in a random order"; - this.auraId = auraId; + ShiftingShadowGainEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "enchanted creature has haste and \"At the beginning of your upkeep, " + + "destroy this creature. Reveal cards from the top of your library until you reveal a creature card. " + + "Put that card onto the battlefield and attach {this} to it, then put all other cards " + + "revealed this way on the bottom of your library in a random order.\""; } - public ShiftingShadowEffect(final ShiftingShadowEffect effect, UUID auraId) { + private ShiftingShadowGainEffect(final ShiftingShadowGainEffect effect) { super(effect); - this.auraId = auraId; } @Override - public ShiftingShadowEffect copy() { - return new ShiftingShadowEffect(this, auraId); + public ShiftingShadowGainEffect copy() { + return new ShiftingShadowGainEffect(this); } @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent enchanted = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (controller != null && enchanted != null) { - Permanent aura = null; - int index = 0; - while (aura == null && index < enchanted.getAttachments().size()) { - UUID attached = enchanted.getAttachments().get(index); - if (attached.equals(auraId)) { - aura = game.getPermanentOrLKIBattlefield(attached); - } else { - index += 1; - } - } - if (aura != null) { - enchanted.destroy(source, game, false); - // Because this effect has two steps, we have to call the processAction method here, so that triggered effects of the target going to graveyard go to the stack - // If we don't do it here, gained triggered effects to the target will be removed from the following moveCards method and the applyEffcts done there. - // Example: {@link org.mage.test.commander.duel.MairsilThePretenderTest#MairsilThePretenderTest Test} - game.getState().processAction(game); - - Cards revealed = new CardsImpl(); - Cards otherCards = new CardsImpl(); - for (Card card : controller.getLibrary().getCards(game)) { - revealed.add(card); - if (card != null && card.isCreature(game)) { - controller.moveCards(card, Zone.BATTLEFIELD, source, game); - Permanent newEnchanted = game.getPermanent(card.getId()); - FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - filter.add(new PermanentIdPredicate(card.getId())); - Target target = new TargetControlledCreaturePermanent(filter); - if (newEnchanted != null) { - target.addTarget(newEnchanted.getId(), source, game); - aura.getSpellAbility().getTargets().clear(); - aura.getSpellAbility().getTargets().add(target); - newEnchanted.addAttachment(aura.getId(), source, game); - } - break; - } else { - otherCards.add(card); - } - } - controller.revealCards(enchanted.getIdName(), revealed, game); - controller.putCardsOnBottomOfLibrary(otherCards, game, source, false); - return true; - } + Permanent aura = source.getSourcePermanentIfItStillExists(game); + if (aura == null) { + return false; } - return false; + Permanent permanent = game.getPermanent(aura.getAttachedTo()); + if (permanent == null) { + return false; + } + permanent.addAbility(HasteAbility.getInstance(), source.getSourceId(), game); + permanent.addAbility(new BeginningOfUpkeepTriggeredAbility( + new ShiftingShadowEffect(aura, game), TargetController.YOU, false + ), source.getSourceId(), game); + return true; + } +} + +class ShiftingShadowEffect extends OneShotEffect { + + private final MageObjectReference mor; + private final String name; + + ShiftingShadowEffect(Permanent permanent, Game game) { + super(Outcome.Benefit); + this.mor = new MageObjectReference(permanent, game); + this.name = permanent.getName(); + } + + private ShiftingShadowEffect(final ShiftingShadowEffect effect) { + super(effect); + this.mor = effect.mor; + this.name = effect.name; + } + + @Override + public ShiftingShadowEffect copy() { + return new ShiftingShadowEffect(this); + } + + private static Card getCard(Player player, Cards cards, Game game) { + for (Card card : player.getLibrary().getCards(game)) { + cards.add(card); + if (card.isCreature(game)) { + return card; + } + } + return null; + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent != null) { + permanent.destroy(source, game); + game.getState().processAction(game); + } + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return true; + } + Cards cards = new CardsImpl(); + Card card = getCard(player, cards, game); + player.revealCards(source, cards, game); + Permanent creature; + if (card != null) { + player.moveCards(card, Zone.BATTLEFIELD, source, game); + creature = game.getPermanent(card.getId()); + } else { + creature = null; + } + if (creature != null && mor.zoneCounterIsCurrent(game)) { + creature.addAttachment(mor.getSourceId(), source, game); + } + cards.retainZone(Zone.LIBRARY, game); + player.putCardsOnBottomOfLibrary(cards, game, source, false); + return true; + } + + @Override + public String getText(Mode mode) { + return "destroy this creature. Reveal cards from the top of your library until you reveal a creature card. " + + "Put that card onto the battlefield and attach " + name + " to it, then put all other cards " + + "revealed this way on the bottom of your library in a random order."; } } diff --git a/Mage.Sets/src/mage/cards/s/ShiftingSky.java b/Mage.Sets/src/mage/cards/s/ShiftingSky.java index 62c144f66e6..c9ff5bd52d3 100644 --- a/Mage.Sets/src/mage/cards/s/ShiftingSky.java +++ b/Mage.Sets/src/mage/cards/s/ShiftingSky.java @@ -69,7 +69,7 @@ class ShiftingSkyEffect extends ContinuousEffectImpl { if (color == null) { return false; } - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { perm.getColor(game).setColor(color); } return true; diff --git a/Mage.Sets/src/mage/cards/s/ShiftyDoppelganger.java b/Mage.Sets/src/mage/cards/s/ShiftyDoppelganger.java index 14cee0558f3..0979c20eba2 100644 --- a/Mage.Sets/src/mage/cards/s/ShiftyDoppelganger.java +++ b/Mage.Sets/src/mage/cards/s/ShiftyDoppelganger.java @@ -1,36 +1,29 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.MageObject; +import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.costs.common.ExileSourceCost; 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.HasteAbility; 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.constants.*; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInHand; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class ShiftyDoppelganger extends CardImpl { @@ -43,10 +36,9 @@ public final class ShiftyDoppelganger extends CardImpl { this.toughness = new MageInt(1); // {3}{U}, Exile Shifty Doppelganger: You may put a creature card from your hand onto the battlefield. If you do, that creature gains haste until end of turn. At the beginning of the next end step, sacrifice that creature. If you do, return Shifty Doppelganger to the battlefield. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ShiftyDoppelgangerExileEffect(), new ManaCostsImpl("{3}{U}")); - ability.addCost(new ExileSourceCost(true)); + Ability ability = new SimpleActivatedAbility(new ShiftyDoppelgangerExileEffect(), new ManaCostsImpl<>("{3}{U}")); + ability.addCost(new ExileSourceCost()); this.addAbility(ability); - } private ShiftyDoppelganger(final ShiftyDoppelganger card) { @@ -63,10 +55,12 @@ class ShiftyDoppelgangerExileEffect extends OneShotEffect { public ShiftyDoppelgangerExileEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "You may put a creature card from your hand onto the battlefield. If you do, that creature gains haste until end of turn. At the beginning of the next end step, sacrifice that creature. If you do, return {this} to the battlefield"; + this.staticText = "You may put a creature card from your hand onto the battlefield. If you do, " + + "that creature gains haste until end of turn. At the beginning of the next end step, " + + "sacrifice that creature. If you do, return {this} to the battlefield"; } - public ShiftyDoppelgangerExileEffect(final ShiftyDoppelgangerExileEffect effect) { + private ShiftyDoppelgangerExileEffect(final ShiftyDoppelgangerExileEffect effect) { super(effect); } @@ -77,56 +71,52 @@ class ShiftyDoppelgangerExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - FilterCreatureCard filter = new FilterCreatureCard("a creature card"); - boolean putCreature = false; - UUID creatureId = UUID.randomUUID(); Player player = game.getPlayer(source.getControllerId()); - if (player != null && player.chooseUse(Outcome.PutCardInPlay, "Put " + filter.getMessage() + " from your hand onto the battlefield?", source, game)) { - TargetCardInHand target = new TargetCardInHand(filter); - if (player.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - putCreature = player.moveCards(card, Zone.BATTLEFIELD, source, game); - if (putCreature) { - creatureId = card.getId(); - } - } - } + if (player == null + || player.getHand().count(StaticFilters.FILTER_CARD_CREATURE, game) < 1 + || !player.chooseUse( + Outcome.PutCardInPlay, "Put a creature card " + + "from your hand onto the battlefield?", source, game + )) { + return false; } - if (putCreature) { - Permanent creature = game.getPermanent(creatureId); - if (creature != null) { - ContinuousEffect hasteEffect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); - hasteEffect.setTargetPointer(new FixedTarget(creature, game)); - game.addEffect(hasteEffect, source); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility( - new ShiftyDoppelgangerReturnEffect(creature.getId(), creature.getZoneChangeCounter(game), (int) game.getState().getValue(source.getSourceId().toString()))); - game.addDelayedTriggeredAbility(delayedAbility, source); - } + TargetCardInHand target = new TargetCardInHand(StaticFilters.FILTER_CARD_CREATURE); + player.choose(Outcome.PutCreatureInPlay, player.getHand(), target, game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return false; } + player.moveCards(card, Zone.BATTLEFIELD, source, game); + Permanent creature = game.getPermanent(card.getId()); + if (creature == null) { + return false; + } + game.addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setTargetPointer(new FixedTarget(creature, game)), source); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new ShiftyDoppelgangerReturnEffect(creature, source, game) + ), source); return true; } } class ShiftyDoppelgangerReturnEffect extends OneShotEffect { - private final UUID creatureId; - private final int creatureZoneCount; - private final int sourceZoneCount; + private final MageObjectReference creatureMor; + private final MageObjectReference sourceMor; - ShiftyDoppelgangerReturnEffect(UUID creatureId, int creatureZoneCount, int sourceZoneCount) { + ShiftyDoppelgangerReturnEffect(Permanent creature, Ability source, Game game) { super(Outcome.Benefit); this.staticText = "sacrifice that creature. If you do, return {this} to the battlefield"; - this.creatureId = creatureId; - this.creatureZoneCount = creatureZoneCount; - this.sourceZoneCount = sourceZoneCount; + this.creatureMor = new MageObjectReference(creature, game); + this.sourceMor = new MageObjectReference(source, 1); } - ShiftyDoppelgangerReturnEffect(final ShiftyDoppelgangerReturnEffect effect) { + private ShiftyDoppelgangerReturnEffect(final ShiftyDoppelgangerReturnEffect effect) { super(effect); - this.creatureId = effect.creatureId; - this.creatureZoneCount = effect.creatureZoneCount; - this.sourceZoneCount = effect.sourceZoneCount; + this.creatureMor = effect.creatureMor; + this.sourceMor = effect.sourceMor; } @Override @@ -136,14 +126,16 @@ class ShiftyDoppelgangerReturnEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent creature = game.getPermanent(creatureId); + Permanent creature = creatureMor.getPermanent(game); Player player = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (creature != null && creature.getZoneChangeCounter(game) == this.creatureZoneCount && creature.sacrifice(source, game)) { - if (player != null && sourceObject != null && sourceObject.getZoneChangeCounter(game) == this.sourceZoneCount) { - player.moveCards(game.getCard(source.getSourceId()), Zone.BATTLEFIELD, source, game); - } + if (creature == null || player == null + || !creature.sacrifice(source, game)) { + return false; } - return false; + Card sourceCard = sourceMor.getCard(game); + if (sourceCard != null) { + player.moveCards(sourceCard, Zone.BATTLEFIELD, source, game); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/s/ShigekiJukaiVisionary.java b/Mage.Sets/src/mage/cards/s/ShigekiJukaiVisionary.java new file mode 100644 index 00000000000..7a2cab81925 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShigekiJukaiVisionary.java @@ -0,0 +1,82 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.ReturnToHandFromBattlefieldSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.effects.common.RevealLibraryPickControllerEffect; +import mage.abilities.keyword.ChannelAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ShigekiJukaiVisionary extends CardImpl { + + public ShigekiJukaiVisionary(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{1}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SNAKE); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // {1}{G}, {T}, Return Shigeki, Jukai Visionary to its owner's hand: Reveal the top four cards of your library. + // You may put a land card from among them onto the battlefield tapped. Put the rest into your graveyard. + Ability ability = new SimpleActivatedAbility( + new RevealLibraryPickControllerEffect( + 4, 1, + StaticFilters.FILTER_CARD_LAND_A, + PutCards.BATTLEFIELD_TAPPED, + PutCards.GRAVEYARD), + new ManaCostsImpl<>("{1}{G}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new ReturnToHandFromBattlefieldSourceCost()); + this.addAbility(ability); + + // Channel — {X}{X}{G}{G}, Discard Shigeki: Return X target nonlegendary cards from your graveyard to your hand. + this.addAbility(new ChannelAbility( + "{X}{X}{G}{G}", new ReturnFromGraveyardToHandTargetEffect() + .setText("return X target nonlegendary cards from your graveyard to your hand") + ).setTargetAdjuster(ShigekiJukaiVisionaryAdjuster.instance)); + } + + private ShigekiJukaiVisionary(final ShigekiJukaiVisionary card) { + super(card); + } + + @Override + public ShigekiJukaiVisionary copy() { + return new ShigekiJukaiVisionary(this); + } +} + +enum ShigekiJukaiVisionaryAdjuster implements TargetAdjuster { + instance; + private static final FilterCard filter = new FilterCard("nonlegendary cards from your graveyard"); + + static { + filter.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCardInYourGraveyard(ability.getManaCostsToPay().getX(), filter)); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShimatsuTheBloodcloaked.java b/Mage.Sets/src/mage/cards/s/ShimatsuTheBloodcloaked.java index 8cb41f8aa12..a897c99eb32 100644 --- a/Mage.Sets/src/mage/cards/s/ShimatsuTheBloodcloaked.java +++ b/Mage.Sets/src/mage/cards/s/ShimatsuTheBloodcloaked.java @@ -80,7 +80,7 @@ class ShimatsuTheBloodcloakedEffect extends ReplacementEffectImpl { Player controller = game.getPlayer(source.getControllerId()); if (creature != null && controller != null) { Target target = new TargetControlledPermanent(0, Integer.MAX_VALUE, new FilterControlledPermanent(), true); - if (!target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (!target.canChoose(source.getControllerId(), source, game)) { return false; } controller.chooseTarget(Outcome.Detriment, target, source, game); diff --git a/Mage.Sets/src/mage/cards/s/ShimianNightStalker.java b/Mage.Sets/src/mage/cards/s/ShimianNightStalker.java index 3772d5f7abd..360147f92b4 100644 --- a/Mage.Sets/src/mage/cards/s/ShimianNightStalker.java +++ b/Mage.Sets/src/mage/cards/s/ShimianNightStalker.java @@ -79,7 +79,7 @@ class ShimianNightStalkerRedirectDamageEffect extends RedirectionEffect { 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 (filter.match(permanent, permanent.getControllerId(), source, game)) { if (event.getSourceId() != null && event.getTargetId() != null) { if (event.getSourceId().equals(getTargetPointer().getFirst(game, source)) && event.getTargetId().equals(source.getControllerId())) { diff --git a/Mage.Sets/src/mage/cards/s/ShimianSpecter.java b/Mage.Sets/src/mage/cards/s/ShimianSpecter.java index aa019301a50..163dd983c23 100644 --- a/Mage.Sets/src/mage/cards/s/ShimianSpecter.java +++ b/Mage.Sets/src/mage/cards/s/ShimianSpecter.java @@ -93,7 +93,7 @@ class ShimianSpecterEffect extends OneShotEffect { TargetCard target = new TargetCard(Zone.HAND, new FilterNonlandCard()); target.setNotTarget(true); Card chosenCard = null; - if (target.canChoose(source.getSourceId(), controller.getId(), game) + if (target.canChoose(controller.getId(), source, game) && controller.chooseTarget(Outcome.Benefit, targetPlayer.getHand(), target, source, game)) { chosenCard = game.getCard(target.getFirstTarget()); } diff --git a/Mage.Sets/src/mage/cards/s/ShimmerOfPossibility.java b/Mage.Sets/src/mage/cards/s/ShimmerOfPossibility.java index 5b3056dc541..9cd5ddfc375 100644 --- a/Mage.Sets/src/mage/cards/s/ShimmerOfPossibility.java +++ b/Mage.Sets/src/mage/cards/s/ShimmerOfPossibility.java @@ -1,12 +1,10 @@ package mage.cards.s; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import java.util.UUID; @@ -19,10 +17,7 @@ public final class ShimmerOfPossibility extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}"); // Look at the top four cards of your library. Put one of them into your hand and the rest on the bottom of your library in a random order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(1), StaticFilters.FILTER_CARD, Zone.LIBRARY, - false, false, false, Zone.HAND, false, false, false - ).setBackInRandomOrder(true)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(4, 1, PutCards.HAND, PutCards.BOTTOM_RANDOM)); } private ShimmerOfPossibility(final ShimmerOfPossibility card) { diff --git a/Mage.Sets/src/mage/cards/s/Shinewend.java b/Mage.Sets/src/mage/cards/s/Shinewend.java index 3891cc5d504..cee7c93558a 100644 --- a/Mage.Sets/src/mage/cards/s/Shinewend.java +++ b/Mage.Sets/src/mage/cards/s/Shinewend.java @@ -36,10 +36,10 @@ public final class Shinewend extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Shinewend enters the battlefield with a +1/+1 counter on it. - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)))); - + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), "with a +1/+1 counter on it")); + // {1}{W}, Remove a +1/+1 counter from Shinewend: Destroy target enchantment. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new ManaCostsImpl("{1}{W}")); + Ability ability = new SimpleActivatedAbility( new DestroyTargetEffect(), new ManaCostsImpl<>("{1}{W}")); ability.addCost(new RemoveCountersSourceCost(CounterType.P1P1.createInstance(1))); ability.addTarget(new TargetEnchantmentPermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/ShiningShoal.java b/Mage.Sets/src/mage/cards/s/ShiningShoal.java index 7685e0eae52..ee5887fe1a0 100644 --- a/Mage.Sets/src/mage/cards/s/ShiningShoal.java +++ b/Mage.Sets/src/mage/cards/s/ShiningShoal.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageObject; import mage.ObjectColor; import mage.abilities.Ability; @@ -16,8 +14,6 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterOwnedCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.events.GameEvent; @@ -27,24 +23,33 @@ import mage.target.TargetSource; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetCardInHand; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ShiningShoal extends CardImpl { + private static final FilterOwnedCard filter + = new FilterOwnedCard("a white card with mana value X from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + } + public ShiningShoal(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{W}{W}"); this.subtype.add(SubType.ARCANE); // You may exile a white card with converted mana cost X from your hand rather than pay Shining Shoal's mana cost - FilterOwnedCard filter = new FilterOwnedCard("a white card with mana value X from your hand"); - filter.add(new ColorPredicate(ObjectColor.WHITE)); - filter.add(Predicates.not(new CardIdPredicate(this.getId()))); // the exile cost can never be paid with the card itself - this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter), true))); + this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost( + new TargetCardInHand(filter), true + ))); // The next X damage that a source of your choice would deal to you and/or creatures you control this turn is dealt to any target instead. - this.getSpellAbility().addEffect(new ShiningShoalRedirectDamageTargetEffect(Duration.EndOfTurn, ExileFromHandCostCardConvertedMana.instance)); + this.getSpellAbility().addEffect(new ShiningShoalRedirectDamageTargetEffect( + Duration.EndOfTurn, ExileFromHandCostCardConvertedMana.instance + )); this.getSpellAbility().addTarget(new TargetSource()); this.getSpellAbility().addTarget(new TargetAnyTarget()); } @@ -129,5 +134,4 @@ class ShiningShoalRedirectDamageTargetEffect extends RedirectDamageFromSourceToT } return false; } - } diff --git a/Mage.Sets/src/mage/cards/s/ShinkaGatekeeper.java b/Mage.Sets/src/mage/cards/s/ShinkaGatekeeper.java index 20f608fa9f3..6a73703d067 100644 --- a/Mage.Sets/src/mage/cards/s/ShinkaGatekeeper.java +++ b/Mage.Sets/src/mage/cards/s/ShinkaGatekeeper.java @@ -1,16 +1,13 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealtDamageToSourceTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.DamageControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.game.Game; -import mage.players.Player; import java.util.UUID; @@ -28,7 +25,8 @@ public final class ShinkaGatekeeper extends CardImpl { this.toughness = new MageInt(2); // Whenever Shinka Gatekeeper is dealt damage, it deals that much damage to you. - this.addAbility(new DealtDamageToSourceTriggeredAbility(new ShinkaGatekeeperDealDamageEffect(), false, false)); + this.addAbility(new DealtDamageToSourceTriggeredAbility( + new DamageControllerEffect(SavedDamageValue.MUCH, "it"), false)); } private ShinkaGatekeeper(final ShinkaGatekeeper card) { @@ -40,33 +38,3 @@ public final class ShinkaGatekeeper extends CardImpl { return new ShinkaGatekeeper(this); } } - -class ShinkaGatekeeperDealDamageEffect extends OneShotEffect { - - public ShinkaGatekeeperDealDamageEffect() { - super(Outcome.Damage); - this.staticText = "it deals that much damage to you"; - } - - public ShinkaGatekeeperDealDamageEffect(final ShinkaGatekeeperDealDamageEffect effect) { - super(effect); - } - - @Override - public ShinkaGatekeeperDealDamageEffect copy() { - return new ShinkaGatekeeperDealDamageEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int amount = (Integer) getValue("damage"); - if (amount > 0) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - player.damage(amount, source.getSourceId(), source, game); - return true; - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/s/ShinyImpetus.java b/Mage.Sets/src/mage/cards/s/ShinyImpetus.java index f02de1301c2..2f0eef20584 100644 --- a/Mage.Sets/src/mage/cards/s/ShinyImpetus.java +++ b/Mage.Sets/src/mage/cards/s/ShinyImpetus.java @@ -2,9 +2,10 @@ package mage.cards.s; import mage.abilities.Ability; import mage.abilities.common.AttacksAttachedTriggeredAbility; -import mage.abilities.common.GoadAttachedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.combat.GoadAttachedEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; @@ -37,7 +38,9 @@ public final class ShinyImpetus extends CardImpl { this.addAbility(ability); // Enchanted creature gets +2/+2 and is goaded. - this.addAbility(new GoadAttachedAbility(new BoostEnchantedEffect(2, 2))); + ability = new SimpleStaticAbility(new BoostEnchantedEffect(2, 2)); + ability.addEffect(new GoadAttachedEffect()); + this.addAbility(ability); // Whenever enchanted creature attacks, you create a Treasure token. this.addAbility(new AttacksAttachedTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/s/ShipwreckLooter.java b/Mage.Sets/src/mage/cards/s/ShipwreckLooter.java index 7976888aa4e..74b45ec082a 100644 --- a/Mage.Sets/src/mage/cards/s/ShipwreckLooter.java +++ b/Mage.Sets/src/mage/cards/s/ShipwreckLooter.java @@ -32,8 +32,7 @@ public final class ShipwreckLooter extends CardImpl { // Raid - When Shipwreck Looter enters the battlefield,if you attacked this turn, you may draw a card. If you do, discard a card. Ability ability = new ConditionalInterveningIfTriggeredAbility( new EntersBattlefieldTriggeredAbility(new DrawDiscardControllerEffect(1, 1, true)), - RaidCondition.instance, - "Raid — When {this} enters the battlefield, if you attacked this turn, you may draw a card. If you do, discard a card."); + RaidCondition.instance, "When {this} enters the battlefield, if you attacked this turn, you may draw a card. If you do, discard a card."); ability.setAbilityWord(AbilityWord.RAID); ability.addHint(RaidHint.instance); this.addAbility(ability, new PlayerAttackedWatcher()); diff --git a/Mage.Sets/src/mage/cards/s/ShireiShizosCaretaker.java b/Mage.Sets/src/mage/cards/s/ShireiShizosCaretaker.java index d030d0a960f..a9c17b62b5e 100644 --- a/Mage.Sets/src/mage/cards/s/ShireiShizosCaretaker.java +++ b/Mage.Sets/src/mage/cards/s/ShireiShizosCaretaker.java @@ -1,30 +1,38 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlTargetEffect; -import mage.cards.Card; +import mage.abilities.condition.common.SourceOnBattlefieldCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.ZoneChangeEvent; -import mage.game.permanent.Permanent; -import mage.target.targetpointer.FixedTarget; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; import java.util.UUID; /** - * @author emerald000 + * @author TheElk801 */ public final class ShireiShizosCaretaker extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(TargetController.YOU.getOwnerPredicate()); + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 2)); + } + + private static final String rule1 = "you may return that card to the battlefield " + + "t the beginning of the next end step if {this} is still on the battlefield"; + private static final String rule2 = "Whenever a creature with power 1 or less " + + "is put into your graveyard from the battlefield, "; + public ShireiShizosCaretaker(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); addSuperType(SuperType.LEGENDARY); @@ -34,7 +42,12 @@ public final class ShireiShizosCaretaker extends CardImpl { this.toughness = new MageInt(2); // Whenever a creature with power 1 or less is put into your graveyard from the battlefield, you may return that card to the battlefield at the beginning of the next end step if Shirei, Shizo's Caretaker is still on the battlefield. - this.addAbility(new ShireiShizosCaretakerTriggeredAbility(this.getId())); + this.addAbility(new DiesCreatureTriggeredAbility(new CreateDelayedTriggeredAbilityEffect( + new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ConditionalOneShotEffect( + new ReturnFromGraveyardToBattlefieldTargetEffect(), SourceOnBattlefieldCondition.instance, + "you may return that card to the battlefield if {this} is still on the battlefield" + ), TargetController.ANY, null, true) + ).setText(rule1), false, filter, true).setTriggerPhrase(rule2)); } private ShireiShizosCaretaker(final ShireiShizosCaretaker card) { @@ -46,110 +59,3 @@ public final class ShireiShizosCaretaker extends CardImpl { return new ShireiShizosCaretaker(this); } } - -class ShireiShizosCaretakerTriggeredAbility extends TriggeredAbilityImpl { - - ShireiShizosCaretakerTriggeredAbility(UUID shireiId) { - super(Zone.BATTLEFIELD, new ShireiShizosCaretakerEffect(shireiId), false); - } - - ShireiShizosCaretakerTriggeredAbility(final ShireiShizosCaretakerTriggeredAbility ability) { - super(ability); - } - - @Override - public ShireiShizosCaretakerTriggeredAbility copy() { - return new ShireiShizosCaretakerTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ZONE_CHANGE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - Permanent LKIpermanent = game.getPermanentOrLKIBattlefield(zEvent.getTargetId()); - Card card = game.getCard(zEvent.getTargetId()); - if (card != null - && LKIpermanent != null - && card.isOwnedBy(this.controllerId) - && zEvent.isDiesEvent() - && card.isCreature(game) - && LKIpermanent.getPower().getValue() <= 1) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(zEvent.getTargetId())); - } - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever a creature with power 1 or less is put into your graveyard from the battlefield, you may return that card to the battlefield at the beginning of the next end step if Shirei, Shizo's Caretaker is still on the battlefield."; - } -} - -class ShireiShizosCaretakerEffect extends OneShotEffect { - - protected final UUID shireiId; - - ShireiShizosCaretakerEffect(UUID shireiId) { - super(Outcome.PutCreatureInPlay); - this.staticText = "you may return that card to the battlefield at the beginning of the next end step if {this} is still on the battlefield."; - this.shireiId = shireiId; - } - - ShireiShizosCaretakerEffect(final ShireiShizosCaretakerEffect effect) { - super(effect); - this.shireiId = effect.shireiId; - } - - @Override - public ShireiShizosCaretakerEffect copy() { - return new ShireiShizosCaretakerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Card card = game.getCard(this.getTargetPointer().getFirst(game, source)); - if (card != null) { - Effect effect = new ShireiShizosCaretakerReturnEffect(shireiId); - effect.setText("return that card to the battlefield if {this} is still on the battlefield"); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); - delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(card, game)); - game.addDelayedTriggeredAbility(delayedAbility, source); - return true; - } - return false; - } -} - -class ShireiShizosCaretakerReturnEffect extends ReturnToBattlefieldUnderYourControlTargetEffect { - - protected final UUID shireiId; - - ShireiShizosCaretakerReturnEffect(UUID shireiId) { - this.shireiId = shireiId; - } - - ShireiShizosCaretakerReturnEffect(final ShireiShizosCaretakerReturnEffect effect) { - super(effect); - this.shireiId = effect.shireiId; - } - - @Override - public ShireiShizosCaretakerReturnEffect copy() { - return new ShireiShizosCaretakerReturnEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - if (game.getBattlefield().containsPermanent(shireiId)) { - return super.apply(game, source); - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/s/ShockmawDragon.java b/Mage.Sets/src/mage/cards/s/ShockmawDragon.java index ce34126d46a..54ff2020af1 100644 --- a/Mage.Sets/src/mage/cards/s/ShockmawDragon.java +++ b/Mage.Sets/src/mage/cards/s/ShockmawDragon.java @@ -2,19 +2,13 @@ package mage.cards.s; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageAllControlledTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; /** * @@ -31,8 +25,11 @@ public final class ShockmawDragon extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - // Whenever Shockmaw Dragon deals combat damage to a player, it deals 1 damage to each creature that player controls. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new ShockmawDragonEffect(), false, true)); + // Whenever Shockmaw Dragon deals combat damage to a player, + // it deals 1 damage to each creature that player controls. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DamageAllControlledTargetEffect(1, "it"), + false, true)); } private ShockmawDragon(final ShockmawDragon card) { @@ -44,36 +41,3 @@ public final class ShockmawDragon extends CardImpl { return new ShockmawDragon(this); } } - -class ShockmawDragonEffect extends OneShotEffect { - - public ShockmawDragonEffect() { - super(Outcome.Damage); - staticText = "it deals 1 damage to each creature that player controls"; - } - - public ShockmawDragonEffect(final ShockmawDragonEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(targetPointer.getFirst(game, source)); - if (player != null) { - int amount = (Integer) getValue("damage"); - if (amount > 0) { - for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, player.getId(), game)) { - creature.damage(1, source.getSourceId(), source, game, false, true); - } - } - return true; - } - return false; - } - - @Override - public ShockmawDragonEffect copy() { - return new ShockmawDragonEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/s/ShorecrasherElemental.java b/Mage.Sets/src/mage/cards/s/ShorecrasherElemental.java index 7ad5d64daff..1996ca14089 100644 --- a/Mage.Sets/src/mage/cards/s/ShorecrasherElemental.java +++ b/Mage.Sets/src/mage/cards/s/ShorecrasherElemental.java @@ -44,7 +44,7 @@ public final class ShorecrasherElemental extends CardImpl { this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ShorecrasherElementalBoostEffect(), new ManaCostsImpl("{1}"))); // Megamorph {4}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{U}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{U}"), true)); } diff --git a/Mage.Sets/src/mage/cards/s/ShorecrasherMimic.java b/Mage.Sets/src/mage/cards/s/ShorecrasherMimic.java index 7c286d1f834..59c2e846234 100644 --- a/Mage.Sets/src/mage/cards/s/ShorecrasherMimic.java +++ b/Mage.Sets/src/mage/cards/s/ShorecrasherMimic.java @@ -32,7 +32,7 @@ public final class ShorecrasherMimic extends CardImpl { filter.add(new ColorPredicate(ObjectColor.BLUE)); } - private String rule = "Whenever you cast a spell that's both green and blue, {this} has base power and toughness 5/3 until end of turn and gains trample until end of turn."; + private static final String rule = "Whenever you cast a spell that's both green and blue, {this} has base power and toughness 5/3 until end of turn and gains trample until end of turn."; public ShorecrasherMimic(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G/U}"); diff --git a/Mage.Sets/src/mage/cards/s/ShorikaiGenesisEngine.java b/Mage.Sets/src/mage/cards/s/ShorikaiGenesisEngine.java new file mode 100644 index 00000000000..ecbaf2acea7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShorikaiGenesisEngine.java @@ -0,0 +1,57 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.CanBeYourCommanderAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.keyword.CrewAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.game.permanent.token.PilotToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ShorikaiGenesisEngine extends CardImpl { + + public ShorikaiGenesisEngine(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{W}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(8); + this.toughness = new MageInt(8); + + // {1}, {T}: Draw two cards, then discard a card. Create a 1/1 colorless Pilot creature token with "This creature crews Vehicles as though its power were 2 greater." + Ability ability = new SimpleActivatedAbility( + new DrawDiscardControllerEffect(2, 1), new GenericManaCost(1) + ); + ability.addEffect(new CreateTokenEffect(new PilotToken())); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + + // Crew 8 + this.addAbility(new CrewAbility(8)); + + // Shorikai, Genesis Engine can be your commander. + this.addAbility(CanBeYourCommanderAbility.getInstance()); + } + + private ShorikaiGenesisEngine(final ShorikaiGenesisEngine card) { + super(card); + } + + @Override + public ShorikaiGenesisEngine copy() { + return new ShorikaiGenesisEngine(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShrewdHatchling.java b/Mage.Sets/src/mage/cards/s/ShrewdHatchling.java index 6145a57fc7e..efa72457f56 100644 --- a/Mage.Sets/src/mage/cards/s/ShrewdHatchling.java +++ b/Mage.Sets/src/mage/cards/s/ShrewdHatchling.java @@ -5,19 +5,19 @@ import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.SpellCastAllTriggeredAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.combat.CantBeBlockedByTargetSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.FilterSpell; import mage.filter.predicate.mageobject.ColorPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -27,19 +27,14 @@ import java.util.UUID; */ public final class ShrewdHatchling extends CardImpl { - private static final FilterSpell filter = new FilterSpell("blue spell"); - private static final FilterSpell filter2 = new FilterSpell("red spell"); + private static final FilterSpell filterBlueSpell = new FilterSpell("a blue spell"); + private static final FilterSpell filterRedSpell = new FilterSpell("a red spell"); static { - filter.add(TargetController.YOU.getControllerPredicate()); - filter.add(new ColorPredicate(ObjectColor.BLUE)); - filter2.add(TargetController.YOU.getControllerPredicate()); - filter2.add(new ColorPredicate(ObjectColor.RED)); + filterBlueSpell.add(new ColorPredicate(ObjectColor.BLUE)); + filterRedSpell.add(new ColorPredicate(ObjectColor.RED)); } - private String rule = "Whenever you cast a blue spell, remove a -1/-1 counter from Shrewd Hatchling."; - private String rule2 = "Whenever you cast a red spell, remove a -1/-1 counter from Shrewd Hatchling."; - public ShrewdHatchling(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U/R}"); this.subtype.add(SubType.ELEMENTAL); @@ -48,18 +43,27 @@ public final class ShrewdHatchling extends CardImpl { this.toughness = new MageInt(6); // Shrewd Hatchling enters the battlefield with four -1/-1 counters on it. - this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance(4)))); + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect( + CounterType.M1M1.createInstance(4) + ), "with four -1/-1 counters on it")); - // {UR}: Target creature can't block Shrewd Hatchling this turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ShrewdHatchlingEffect(), new ManaCostsImpl("{U/R}")); + // {U/R}: Target creature can't block Shrewd Hatchling this turn. + Ability ability = new SimpleActivatedAbility( + new CantBeBlockedByTargetSourceEffect(Duration.EndOfTurn), + new ManaCostsImpl<>("{U/R}") + ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); // Whenever you cast a blue spell, remove a -1/-1 counter from Shrewd Hatchling. - this.addAbility(new SpellCastAllTriggeredAbility(new RemoveCounterSourceEffect(CounterType.M1M1.createInstance()), filter, false, rule)); + this.addAbility(new SpellCastControllerTriggeredAbility( + new RemoveCounterSourceEffect(CounterType.M1M1.createInstance()), filterBlueSpell, false + )); // Whenever you cast a red spell, remove a -1/-1 counter from Shrewd Hatchling. - this.addAbility(new SpellCastAllTriggeredAbility(new RemoveCounterSourceEffect(CounterType.M1M1.createInstance()), filter2, false, rule2)); + this.addAbility(new SpellCastControllerTriggeredAbility( + new RemoveCounterSourceEffect(CounterType.M1M1.createInstance()), filterRedSpell, false + )); } @@ -72,32 +76,3 @@ public final class ShrewdHatchling extends CardImpl { return new ShrewdHatchling(this); } } - -class ShrewdHatchlingEffect extends RestrictionEffect { - - public ShrewdHatchlingEffect() { - super(Duration.EndOfTurn); - staticText = "Target creature can't block {this} this turn"; - } - - public ShrewdHatchlingEffect(final ShrewdHatchlingEffect effect) { - super(effect); - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - return permanent.getId().equals(source.getSourceId()); - } - - @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { - UUID targetId = source.getFirstTarget(); - return targetId == null || !blocker.getId().equals(targetId); - } - - @Override - public ShrewdHatchlingEffect copy() { - return new ShrewdHatchlingEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/s/ShrivelingRot.java b/Mage.Sets/src/mage/cards/s/ShrivelingRot.java index 96293421139..18bb8ed59db 100644 --- a/Mage.Sets/src/mage/cards/s/ShrivelingRot.java +++ b/Mage.Sets/src/mage/cards/s/ShrivelingRot.java @@ -37,8 +37,7 @@ public final class ShrivelingRot extends CardImpl { this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new ShrivelingRotDestroyTriggeredAbility())); // Until end of turn, whenever a creature dies, that creature's controller loses life equal to its toughness. - Mode mode = new Mode(); - mode.addEffect(new CreateDelayedTriggeredAbilityEffect(new ShrivelingRotLoseLifeTriggeredAbility())); + Mode mode = new Mode(new CreateDelayedTriggeredAbilityEffect(new ShrivelingRotLoseLifeTriggeredAbility())); this.getSpellAbility().getModes().addMode(mode); // Entwine {2}{B} diff --git a/Mage.Sets/src/mage/cards/s/ShroudedLore.java b/Mage.Sets/src/mage/cards/s/ShroudedLore.java index 029746b868a..137463dca14 100644 --- a/Mage.Sets/src/mage/cards/s/ShroudedLore.java +++ b/Mage.Sets/src/mage/cards/s/ShroudedLore.java @@ -72,7 +72,7 @@ class ShroudedLoreEffect extends OneShotEffect { do { chosenCard = new TargetCardInGraveyard(filter); chosenCard.setNotTarget(true); - if (chosenCard.canChoose(source.getSourceId(), opponent.getId(), game)) { + if (chosenCard.canChoose(opponent.getId(), source, game)) { opponent.chooseTarget(Outcome.ReturnToHand, chosenCard, source, game); card = game.getCard(chosenCard.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/s/ShuDefender.java b/Mage.Sets/src/mage/cards/s/ShuDefender.java index 7900c35b4d1..e4d3fc2d686 100644 --- a/Mage.Sets/src/mage/cards/s/ShuDefender.java +++ b/Mage.Sets/src/mage/cards/s/ShuDefender.java @@ -1,4 +1,3 @@ - package mage.cards.s; import java.util.UUID; @@ -8,8 +7,8 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; /** * @@ -25,7 +24,7 @@ public final class ShuDefender extends CardImpl { this.toughness = new MageInt(2); // Whenever Shu Defender blocks, it gets +0/+2 until end of turn. - this.addAbility(new BlocksSourceTriggeredAbility(new BoostSourceEffect(0, 2, Duration.EndOfTurn), false)); + this.addAbility(new BlocksSourceTriggeredAbility(new BoostSourceEffect(0, 2, Duration.EndOfTurn, "it"))); } private ShuDefender(final ShuDefender card) { diff --git a/Mage.Sets/src/mage/cards/s/SianiEyeOfTheStorm.java b/Mage.Sets/src/mage/cards/s/SianiEyeOfTheStorm.java index 5e0cdaa38f1..d78079e8247 100644 --- a/Mage.Sets/src/mage/cards/s/SianiEyeOfTheStorm.java +++ b/Mage.Sets/src/mage/cards/s/SianiEyeOfTheStorm.java @@ -84,7 +84,7 @@ class SianiEyeOfTheStormEffect extends OneShotEffect { if (player == null) { return false; } - int count = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int count = game.getBattlefield().count(filter, source.getControllerId(), source, game); return count > 0 && player.scry(count, source, game); } } diff --git a/Mage.Sets/src/mage/cards/s/SibsigMuckdraggers.java b/Mage.Sets/src/mage/cards/s/SibsigMuckdraggers.java index 4233048fb54..28c896aedc4 100644 --- a/Mage.Sets/src/mage/cards/s/SibsigMuckdraggers.java +++ b/Mage.Sets/src/mage/cards/s/SibsigMuckdraggers.java @@ -5,6 +5,7 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.DelveAbility; import mage.cards.CardImpl; @@ -29,7 +30,7 @@ public final class SibsigMuckdraggers extends CardImpl { // Delve 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 ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), false); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SickeningShoal.java b/Mage.Sets/src/mage/cards/s/SickeningShoal.java index 20a19d76676..fd781fba8c5 100644 --- a/Mage.Sets/src/mage/cards/s/SickeningShoal.java +++ b/Mage.Sets/src/mage/cards/s/SickeningShoal.java @@ -1,4 +1,3 @@ - package mage.cards.s; import mage.ObjectColor; @@ -14,8 +13,6 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.filter.common.FilterOwnedCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCreaturePermanent; @@ -23,25 +20,29 @@ import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** - * * @author LevelX2 */ public final class SickeningShoal extends CardImpl { + private static final FilterOwnedCard filter + = new FilterOwnedCard("a black card with mana value X from your hand"); + private static final DynamicValue xValue = new SignInversionDynamicValue(ExileFromHandCostCardConvertedMana.instance); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + } + public SickeningShoal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{B}{B}"); this.subtype.add(SubType.ARCANE); - // You may exile a black card with converted mana cost X from your hand rather than pay Sickening Shoal's mana cost. - FilterOwnedCard filter = new FilterOwnedCard("a black card with mana value X from your hand"); - filter.add(new ColorPredicate(ObjectColor.BLACK)); - filter.add(Predicates.not(new CardIdPredicate(this.getId()))); // the exile cost can never be paid with the card itself - this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter), true))); + this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost( + new TargetCardInHand(filter), true + ))); // Target creature gets -X/-X until end of turn. - DynamicValue x = new SignInversionDynamicValue(ExileFromHandCostCardConvertedMana.instance); - this.getSpellAbility().addEffect(new BoostTargetEffect(x, x, Duration.EndOfTurn, true)); + this.getSpellAbility().addEffect(new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn, true)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/s/SidarKondoOfJamuraa.java b/Mage.Sets/src/mage/cards/s/SidarKondoOfJamuraa.java index 261c0b6ada8..58043523b8d 100644 --- a/Mage.Sets/src/mage/cards/s/SidarKondoOfJamuraa.java +++ b/Mage.Sets/src/mage/cards/s/SidarKondoOfJamuraa.java @@ -92,7 +92,7 @@ class SidarKondoOfJamuraaCantBlockCreaturesSourceEffect extends RestrictionEffec if (attacker == null) { return true; } - return !filter.match(attacker, source.getSourceId(), source.getControllerId(), game); + return !filter.match(attacker, source.getControllerId(), source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/s/SidewinderNaga.java b/Mage.Sets/src/mage/cards/s/SidewinderNaga.java index 0c91b348567..e97a4cf85d8 100644 --- a/Mage.Sets/src/mage/cards/s/SidewinderNaga.java +++ b/Mage.Sets/src/mage/cards/s/SidewinderNaga.java @@ -6,6 +6,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; +import mage.abilities.condition.common.DesertControlledOrGraveyardCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.continuous.BoostSourceEffect; @@ -38,11 +39,15 @@ public final class SidewinderNaga extends CardImpl { this.toughness = new MageInt(2); // As long as you control a Desert or there is a Desert card in your graveyard, Sidewinder Naga gets +1/+0 and has trample. - ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new BoostSourceEffect(1, 0, Duration.WhileOnBattlefield), new DesertInGYorBFCondition(), "As long as you control a Desert or there is a Desert card in your graveyard, {this} gets +1/+0 "); - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); - ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); - ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(TrampleAbility.getInstance(), Duration.WhileOnBattlefield), new DesertInGYorBFCondition(), "and has trample")); - this.addAbility(ability); + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(1, 0, Duration.WhileOnBattlefield), + DesertControlledOrGraveyardCondition.instance, "As long as you control a Desert " + + "or there is a Desert card in your graveyard, {this} gets +1/+0 " + )); + ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect( + TrampleAbility.getInstance(), Duration.WhileOnBattlefield + ),DesertControlledOrGraveyardCondition.instance, "and has trample")); + this.addAbility(ability.addHint(DesertControlledOrGraveyardCondition.getHint())); } private SidewinderNaga(final SidewinderNaga card) { @@ -54,33 +59,3 @@ public final class SidewinderNaga extends CardImpl { return new SidewinderNaga(this); } } - -class DesertInGYorBFCondition implements Condition { - - private static final FilterCard filter = new FilterCard(); - - static { - filter.add(SubType.DESERT.getPredicate()); - } - - private static final FilterControlledLandPermanent filter2 = new FilterControlledLandPermanent("a desert"); - - static { - filter2.add(SubType.DESERT.getPredicate()); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - for (Card card : player.getGraveyard().getCards(game)) { - if (filter.match(card, game)) { - return true; - } - } - } - - PermanentsOnBattlefieldCount count = new PermanentsOnBattlefieldCount(filter2); - return count.calculate(game, source, null) >= 1; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SidisisPet.java b/Mage.Sets/src/mage/cards/s/SidisisPet.java index 3785073bc27..7872976acc9 100644 --- a/Mage.Sets/src/mage/cards/s/SidisisPet.java +++ b/Mage.Sets/src/mage/cards/s/SidisisPet.java @@ -29,7 +29,7 @@ public final class SidisisPet extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // Morph {1}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{1}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl<>("{1}{B}"))); } private SidisisPet(final SidisisPet card) { diff --git a/Mage.Sets/src/mage/cards/s/SiegeDragon.java b/Mage.Sets/src/mage/cards/s/SiegeDragon.java index f206729d37c..f8e0b76f1af 100644 --- a/Mage.Sets/src/mage/cards/s/SiegeDragon.java +++ b/Mage.Sets/src/mage/cards/s/SiegeDragon.java @@ -19,7 +19,6 @@ import mage.filter.predicate.mageobject.AbilityPredicate; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; /** @@ -127,7 +126,7 @@ class SiegeDragonDamageEffect extends OneShotEffect { FilterCreaturePermanent filter = new FilterCreaturePermanent(); filter.add(new ControllerIdPredicate(defendingPlayerId)); filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); for (Permanent permanent : permanents) { permanent.damage(2, source.getSourceId(), source, game, false, true); } diff --git a/Mage.Sets/src/mage/cards/s/SiegeModification.java b/Mage.Sets/src/mage/cards/s/SiegeModification.java index 14cf7531d19..89add34aa5e 100644 --- a/Mage.Sets/src/mage/cards/s/SiegeModification.java +++ b/Mage.Sets/src/mage/cards/s/SiegeModification.java @@ -23,7 +23,7 @@ import mage.target.TargetPermanent; */ public final class SiegeModification extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("creature or vehicle"); + private static final FilterPermanent filter = new FilterPermanent("creature or Vehicle"); static { filter.add(Predicates.or(CardType.CREATURE.getPredicate(), diff --git a/Mage.Sets/src/mage/cards/s/SiegeOfTowers.java b/Mage.Sets/src/mage/cards/s/SiegeOfTowers.java index 621a611d9da..36896ebc8df 100644 --- a/Mage.Sets/src/mage/cards/s/SiegeOfTowers.java +++ b/Mage.Sets/src/mage/cards/s/SiegeOfTowers.java @@ -32,7 +32,7 @@ public final class SiegeOfTowers extends CardImpl { // Replicate {1}{R} - this.addAbility(new ReplicateAbility(this, "{1}{R}")); + this.addAbility(new ReplicateAbility("{1}{R}")); // Target Mountain becomes a 3/1 creature. It's still a land. Effect effect = new BecomesCreatureTargetEffect(new CreatureToken(3, 1), false, true, Duration.EndOfGame); diff --git a/Mage.Sets/src/mage/cards/s/SiegeStriker.java b/Mage.Sets/src/mage/cards/s/SiegeStriker.java index 9d6aabe710e..9ae6771a37b 100644 --- a/Mage.Sets/src/mage/cards/s/SiegeStriker.java +++ b/Mage.Sets/src/mage/cards/s/SiegeStriker.java @@ -73,8 +73,8 @@ class SiegeStrikerEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { int tappedAmount = 0; TargetCreaturePermanent target = new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) - && target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), game)) { + if (target.canChoose(source.getControllerId(), source, game) + && target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), source, game)) { for (UUID creatureId : target.getTargets()) { Permanent creature = game.getPermanent(creatureId); if (creature != null) { diff --git a/Mage.Sets/src/mage/cards/s/SigardaChampionOfLight.java b/Mage.Sets/src/mage/cards/s/SigardaChampionOfLight.java index 7875c82d9c8..b56554d104b 100644 --- a/Mage.Sets/src/mage/cards/s/SigardaChampionOfLight.java +++ b/Mage.Sets/src/mage/cards/s/SigardaChampionOfLight.java @@ -5,8 +5,8 @@ import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CovenCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.hint.common.CovenHint; import mage.abilities.keyword.FlyingAbility; @@ -51,12 +51,11 @@ public final class SigardaChampionOfLight extends CardImpl { 1, 1, Duration.WhileOnBattlefield, filter ))); - // Coven — Whenever Sigarda attacks, if you control three or more creatures with different powers, look at the top five cards of your library. You may reveal a Human creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. + // Coven — Whenever Sigarda attacks, if you control three or more creatures with different powers, + // look at the top five cards of your library. You may reveal a Human creature card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), filter2, - Zone.LIBRARY, false, true, false, Zone.HAND, true - ).setBackInRandomOrder(true)), CovenCondition.instance, "Whenever {this} attacks, " + + new AttacksTriggeredAbility(new LookLibraryAndPickControllerEffect(5, 1, filter2, PutCards.HAND, PutCards.BOTTOM_RANDOM)), CovenCondition.instance, "Whenever {this} attacks, " + "if you control three or more creatures with different powers, look at the top five cards " + "of your library. You may reveal a Human creature card from among them and put it into your hand. " + "Put the rest on the bottom of your library in a random order." diff --git a/Mage.Sets/src/mage/cards/s/SigardasSummons.java b/Mage.Sets/src/mage/cards/s/SigardasSummons.java index 3b54c8be211..b142aa72d2d 100644 --- a/Mage.Sets/src/mage/cards/s/SigardasSummons.java +++ b/Mage.Sets/src/mage/cards/s/SigardasSummons.java @@ -55,7 +55,7 @@ class SigardasSummonsEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { for (Permanent permanent : game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_CONTROLLED_CREATURE_P1P1, source.getControllerId(), source.getSourceId(), game + StaticFilters.FILTER_CONTROLLED_CREATURE_P1P1, source.getControllerId(), source, game )) { switch (layer) { case TypeChangingEffects_4: diff --git a/Mage.Sets/src/mage/cards/s/SigardasVanguard.java b/Mage.Sets/src/mage/cards/s/SigardasVanguard.java index 848778c0dce..78db6bae4df 100644 --- a/Mage.Sets/src/mage/cards/s/SigardasVanguard.java +++ b/Mage.Sets/src/mage/cards/s/SigardasVanguard.java @@ -80,7 +80,7 @@ class SigardasVanguardEffect extends OneShotEffect { return false; } TargetPermanent target = new TargetCreaturesWithDifferentPowers(); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); if (target.getTargets().isEmpty()) { return false; } diff --git a/Mage.Sets/src/mage/cards/s/SigardianZealot.java b/Mage.Sets/src/mage/cards/s/SigardianZealot.java index 8a1ba21af81..df8e32d5479 100644 --- a/Mage.Sets/src/mage/cards/s/SigardianZealot.java +++ b/Mage.Sets/src/mage/cards/s/SigardianZealot.java @@ -79,7 +79,7 @@ class SigardianZealotEffect extends OneShotEffect { return false; } TargetPermanent target = new TargetCreaturesWithDifferentPowers(); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Cards cards = new CardsImpl(target.getTargets()); if (cards.isEmpty()) { return false; diff --git a/Mage.Sets/src/mage/cards/s/SightBeyondSight.java b/Mage.Sets/src/mage/cards/s/SightBeyondSight.java index d04c88983cb..3fe8b4a48e1 100644 --- a/Mage.Sets/src/mage/cards/s/SightBeyondSight.java +++ b/Mage.Sets/src/mage/cards/s/SightBeyondSight.java @@ -1,15 +1,12 @@ - package mage.cards.s; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.ReboundAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.FilterCard; /** * @@ -20,9 +17,9 @@ public final class SightBeyondSight extends CardImpl { public SightBeyondSight(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{U}"); - // Look at the top two cards of your library. Put of them into your hand and the other on the bottom of your library. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(2), false, StaticValue.get(1), new FilterCard(), Zone.LIBRARY, false, false)); - + // Look at the top two cards of your library. Put one of them into your hand and the other on the bottom of your library. + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(2, 1, PutCards.HAND, PutCards.BOTTOM_ANY)); + // Rebound this.addAbility(new ReboundAbility()); } diff --git a/Mage.Sets/src/mage/cards/s/SigilCaptain.java b/Mage.Sets/src/mage/cards/s/SigilCaptain.java index 01922dd7443..8cf8dc21064 100644 --- a/Mage.Sets/src/mage/cards/s/SigilCaptain.java +++ b/Mage.Sets/src/mage/cards/s/SigilCaptain.java @@ -83,6 +83,6 @@ class SigilCaptainTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever a creature enters the battlefield under your control, if that creature is 1/1, put two +1/+1 counters on it"; + return "Whenever a creature enters the battlefield under your control, if that creature is 1/1, put two +1/+1 counters on it."; } } diff --git a/Mage.Sets/src/mage/cards/s/SigilOfValor.java b/Mage.Sets/src/mage/cards/s/SigilOfValor.java index c166c545d9a..aea9436e7d6 100644 --- a/Mage.Sets/src/mage/cards/s/SigilOfValor.java +++ b/Mage.Sets/src/mage/cards/s/SigilOfValor.java @@ -1,6 +1,5 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.costs.mana.GenericManaCost; @@ -10,23 +9,19 @@ import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.keyword.EquipAbility; 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.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardIdPredicate; -import static mage.filter.predicate.permanent.ControllerControlsIslandPredicate.filter; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SigilOfValor extends CardImpl { @@ -110,7 +105,7 @@ class SigilOfValorCount implements DynamicValue { if (equipment != null && equipment.getAttachedTo() != null) { FilterPermanent filterPermanent = new FilterControlledCreaturePermanent(); filterPermanent.add(Predicates.not(new CardIdPredicate(equipment.getAttachedTo()))); - return game.getBattlefield().count(filterPermanent, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + return game.getBattlefield().count(filterPermanent, sourceAbility.getControllerId(), sourceAbility, game); } return 0; } @@ -127,6 +122,6 @@ class SigilOfValorCount implements DynamicValue { @Override public String getMessage() { - return filter.getMessage(); + return ""; } } diff --git a/Mage.Sets/src/mage/cards/s/Silence.java b/Mage.Sets/src/mage/cards/s/Silence.java index 99f2f84b6ae..0220cbb5091 100644 --- a/Mage.Sets/src/mage/cards/s/Silence.java +++ b/Mage.Sets/src/mage/cards/s/Silence.java @@ -60,7 +60,7 @@ class SilenceEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast spells this turn (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/s/SilentBladeOni.java b/Mage.Sets/src/mage/cards/s/SilentBladeOni.java index a9a95eec106..b2ae3ca57ee 100644 --- a/Mage.Sets/src/mage/cards/s/SilentBladeOni.java +++ b/Mage.Sets/src/mage/cards/s/SilentBladeOni.java @@ -3,21 +3,20 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.NinjutsuAbility; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; +import mage.util.CardUtil; import java.util.UUID; -import mage.ApprovingObject; /** * @author LevelX2 @@ -56,8 +55,8 @@ class SilentBladeOniEffect extends OneShotEffect { SilentBladeOniEffect() { super(Outcome.PlayForFree); - this.staticText = "look at that player's hand. " - + "You may cast a nonland card in it without paying that card's mana cost"; + this.staticText = "look at that player's hand. You may cast a spell " + + "from among those cards without paying its mana cost"; } private SilentBladeOniEffect(final SilentBladeOniEffect effect) { @@ -71,32 +70,15 @@ class SilentBladeOniEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); - if (opponent == null - || controller == null) { + Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (controller == null || opponent == null) { return false; } - Cards cardsInHand = new CardsImpl(); - cardsInHand.addAll(opponent.getHand()); - if (cardsInHand.isEmpty()) { - return true; - } - TargetCard target = new TargetCard( - 0, 1, Zone.HAND, StaticFilters.FILTER_CARD_A_NON_LAND + controller.lookAtCards(opponent.getName(), opponent.getHand(), game); + return CardUtil.castSpellWithAttributesForFree( + controller, source, game, new CardsImpl(opponent.getHand()), + StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY ); - if (!controller.chooseUse(outcome, "Cast a card from " + opponent.getName() + "'s hand?", source, game) - || !controller.chooseTarget(outcome, cardsInHand, target, source, game)) { - return true; - } - Card card = game.getCard(target.getFirstTarget()); - if (card == null) { - return false; - } - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - return cardWasCast; } } diff --git a/Mage.Sets/src/mage/cards/s/SilentSpecter.java b/Mage.Sets/src/mage/cards/s/SilentSpecter.java index 6413be75ae7..f33626cb3e9 100644 --- a/Mage.Sets/src/mage/cards/s/SilentSpecter.java +++ b/Mage.Sets/src/mage/cards/s/SilentSpecter.java @@ -31,7 +31,7 @@ public final class SilentSpecter extends CardImpl { // Whenever Silent Specter deals combat damage to a player, that player discards two cards. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DiscardTargetEffect(2), false, true)); // Morph {3}{B}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{B}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{B}{B}"))); } private SilentSpecter(final SilentSpecter card) { diff --git a/Mage.Sets/src/mage/cards/s/SilhanaWayfinder.java b/Mage.Sets/src/mage/cards/s/SilhanaWayfinder.java index 34d46a83aee..9b8114685b9 100644 --- a/Mage.Sets/src/mage/cards/s/SilhanaWayfinder.java +++ b/Mage.Sets/src/mage/cards/s/SilhanaWayfinder.java @@ -2,15 +2,13 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; import java.util.UUID; @@ -19,16 +17,6 @@ import java.util.UUID; */ public final class SilhanaWayfinder extends CardImpl { - private static final FilterCard filter - = new FilterCard("a creature or land card"); - - static { - filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.LAND.getPredicate() - )); - } - public SilhanaWayfinder(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); @@ -37,15 +25,11 @@ public final class SilhanaWayfinder extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(1); - // When Silhana Wayfinder enters the battlefield, look at the top four cards of your library. You may reveal a creature or land card from among them and put it on top of your library. Put the rest on the bottom of your library in a random order. + // When Silhana Wayfinder enters the battlefield, look at the top four cards of your library. + // You may reveal a creature or land card from among them and put it on top of your library. + // Put the rest on the bottom of your library in a random order. this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(1), filter, Zone.LIBRARY, false, - true, true, Zone.LIBRARY, false, true, false - ).setBackInRandomOrder(true).setText("look at the top four cards of your library. " + - "You may reveal a creature or land card from among them " + - "and put it on top of your library. Put the rest " + - "on the bottom of your library in a random order."), false - )); + 4, 1, StaticFilters.FILTER_CARD_CREATURE_OR_LAND, PutCards.TOP_ANY, PutCards.BOTTOM_RANDOM))); } private SilhanaWayfinder(final SilhanaWayfinder card) { diff --git a/Mage.Sets/src/mage/cards/s/Silkguard.java b/Mage.Sets/src/mage/cards/s/Silkguard.java new file mode 100644 index 00000000000..c22d3a855b7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Silkguard.java @@ -0,0 +1,74 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.ModifiedPredicate; +import mage.game.Game; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Silkguard extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledPermanent("Auras, Equipment, and modified creatures"); + + static { + filter.add(Predicates.or( + SubType.AURA.getPredicate(), + SubType.EQUIPMENT.getPredicate(), + Predicates.and( + ModifiedPredicate.instance, + CardType.CREATURE.getPredicate() + ) + )); + } + + public Silkguard(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{G}"); + + // Put a +1/+1 counter on each of up to X target creatures you control. + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on each of up to X target creatures you control")); + this.getSpellAbility().setTargetAdjuster(SilkguardAdjuster.instance); + + // Auras, Equipment, and modified creatures you control gain hexproof until end of turn. + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + HexproofAbility.getInstance(), Duration.EndOfTurn, filter + ).concatBy("
")); + } + + private Silkguard(final Silkguard card) { + super(card); + } + + @Override + public Silkguard copy() { + return new Silkguard(this); + } +} + +enum SilkguardAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetControlledCreaturePermanent(0, ability.getManaCostsToPay().getX())); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SilkweaverElite.java b/Mage.Sets/src/mage/cards/s/SilkweaverElite.java index 6995058b501..df1a5fa6aad 100644 --- a/Mage.Sets/src/mage/cards/s/SilkweaverElite.java +++ b/Mage.Sets/src/mage/cards/s/SilkweaverElite.java @@ -1,9 +1,6 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.RevoltCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; @@ -16,6 +13,8 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.watchers.common.RevoltWatcher; +import java.util.UUID; + /** * @author JRHerlehy */ @@ -33,14 +32,11 @@ public final class SilkweaverElite extends CardImpl { this.addAbility(ReachAbility.getInstance()); // Revolt — When Silkweaver Elite enters the battlefield, if a permanent you controlled left the battlefield this turn, draw a card. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( - new DrawCardSourceControllerEffect(1), false), RevoltCondition.instance, - "Revolt — When {this} enters the battlefield, if a permanent you controlled left" - + " the battlefield this turn, draw a card."); - ability.setAbilityWord(AbilityWord.REVOLT); - ability.addWatcher(new RevoltWatcher()); - this.addAbility(ability); - + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), false), + RevoltCondition.instance, "When {this} enters the battlefield, " + + "if a permanent you controlled left the battlefield this turn, draw a card." + ).setAbilityWord(AbilityWord.REVOLT), new RevoltWatcher()); } private SilkweaverElite(final SilkweaverElite card) { diff --git a/Mage.Sets/src/mage/cards/s/SilumgarAssassin.java b/Mage.Sets/src/mage/cards/s/SilumgarAssassin.java index c0d1f3314fd..7ec71e11a42 100644 --- a/Mage.Sets/src/mage/cards/s/SilumgarAssassin.java +++ b/Mage.Sets/src/mage/cards/s/SilumgarAssassin.java @@ -45,7 +45,7 @@ public final class SilumgarAssassin extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeBlockedByCreaturesWithGreaterPowerEffect())); // Megamorph {2}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{B}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{B}"), true)); // When Silumgar Assassin is turned face up, destroy target creature with power 3 or less an opponent controls. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new DestroyTargetEffect(), false); diff --git a/Mage.Sets/src/mage/cards/s/SilumgarSpellEater.java b/Mage.Sets/src/mage/cards/s/SilumgarSpellEater.java index 1baa6a02c22..08fdd03aee7 100644 --- a/Mage.Sets/src/mage/cards/s/SilumgarSpellEater.java +++ b/Mage.Sets/src/mage/cards/s/SilumgarSpellEater.java @@ -29,7 +29,7 @@ public final class SilumgarSpellEater extends CardImpl { this.toughness = new MageInt(3); // Megamorph {4}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{U}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{U}"), true)); // When Silumgar Spell-Eater is turned face up, counter target spell unless its controller pays {3}. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new CounterUnlessPaysEffect(new GenericManaCost(3)), false, false); diff --git a/Mage.Sets/src/mage/cards/s/SilumgarsCommand.java b/Mage.Sets/src/mage/cards/s/SilumgarsCommand.java index 02f04a0d2b4..d6b8d036457 100644 --- a/Mage.Sets/src/mage/cards/s/SilumgarsCommand.java +++ b/Mage.Sets/src/mage/cards/s/SilumgarsCommand.java @@ -40,20 +40,17 @@ public final class SilumgarsCommand extends CardImpl { this.getSpellAbility().getTargets().add(new TargetSpell(StaticFilters.FILTER_SPELL_NON_CREATURE)); // or Return target permanent to its owner's hand; - Mode mode = new Mode(); - mode.addEffect(new ReturnToHandTargetEffect()); + Mode mode = new Mode(new ReturnToHandTargetEffect()); mode.addTarget(new TargetPermanent()); this.getSpellAbility().getModes().addMode(mode); // or Target creature gets -3/-3 until end of turn; - mode = new Mode(); - mode.addEffect(new BoostTargetEffect(-3, -3, Duration.EndOfTurn)); + mode = new Mode(new BoostTargetEffect(-3, -3, Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().getModes().addMode(mode); // or Destroy target planeswalker. - mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetPermanent(filter2)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SilundiVision.java b/Mage.Sets/src/mage/cards/s/SilundiVision.java index bcf1340b10a..463c0506526 100644 --- a/Mage.Sets/src/mage/cards/s/SilundiVision.java +++ b/Mage.Sets/src/mage/cards/s/SilundiVision.java @@ -1,15 +1,13 @@ package mage.cards.s; import mage.abilities.common.EntersBattlefieldTappedAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.mana.BlueManaAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.ModalDoubleFacesCard; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import java.util.UUID; @@ -30,16 +28,8 @@ public final class SilundiVision extends ModalDoubleFacesCard { // Instant // Look at the top six cards of your library. You may reveal an instant or sorcery card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. - this.getLeftHalfCard().getSpellAbility().addEffect( - new LookLibraryAndPickControllerEffect( - StaticValue.get(6), false, StaticValue.get(1), - StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, Zone.LIBRARY, - false, true, false, Zone.HAND, - true, false, false - ).setBackInRandomOrder(true).setText("Look at the top six cards of your library. " + - "You may reveal an instant or sorcery card from among them " + - "and put it into your hand. Put the rest on the bottom of your library in a random order.") - ); + this.getLeftHalfCard().getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + 6, 1, StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, PutCards.HAND, PutCards.BOTTOM_RANDOM)); // 2. // Silundi Isle diff --git a/Mage.Sets/src/mage/cards/s/SilverFurMaster.java b/Mage.Sets/src/mage/cards/s/SilverFurMaster.java index 44712b2b001..b21dc4ce87e 100644 --- a/Mage.Sets/src/mage/cards/s/SilverFurMaster.java +++ b/Mage.Sets/src/mage/cards/s/SilverFurMaster.java @@ -43,7 +43,7 @@ public final class SilverFurMaster extends CardImpl { // Ninjutsu abilities you activate cost {1} less to activate. this.addAbility(new SimpleStaticAbility(new AbilitiesCostReductionControllerEffect( NinjutsuAbility.class, "Ninjutsu" - ))); + ).setText("ninjutsu abilities you activate cost {1} less to activate"))); // Other Ninja and Rogue creatures you control get +1/+1 this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( diff --git a/Mage.Sets/src/mage/cards/s/SilvergillAdept.java b/Mage.Sets/src/mage/cards/s/SilvergillAdept.java index 12ef83ebb46..a28f9dd284b 100644 --- a/Mage.Sets/src/mage/cards/s/SilvergillAdept.java +++ b/Mage.Sets/src/mage/cards/s/SilvergillAdept.java @@ -80,7 +80,7 @@ class SilvergillAdeptCost extends CostImpl { if (player.getHand().count(filter, game) > 0 && player.chooseUse(Outcome.Benefit, "Reveal a Merfolk card? Otherwise pay {3}.", ability, game)) { TargetCardInHand target = new TargetCardInHand(filter); - if (player.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + if (player.choose(Outcome.Benefit, target, source, game)) { Card card = player.getHand().get(target.getFirstTarget(), game); if (card != null) { paid = true; diff --git a/Mage.Sets/src/mage/cards/s/SimicCharm.java b/Mage.Sets/src/mage/cards/s/SimicCharm.java index e96fff37d2a..a9eca52671b 100644 --- a/Mage.Sets/src/mage/cards/s/SimicCharm.java +++ b/Mage.Sets/src/mage/cards/s/SimicCharm.java @@ -28,12 +28,10 @@ public final class SimicCharm extends CardImpl { this.getSpellAbility().addEffect(new BoostTargetEffect(3, 3, Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); //permanents you control gain hexproof until end of turn - Mode mode = new Mode(); - mode.addEffect(new GainAbilityControlledEffect(HexproofAbility.getInstance(), Duration.EndOfTurn)); + Mode mode = new Mode(new GainAbilityControlledEffect(HexproofAbility.getInstance(), Duration.EndOfTurn)); this.getSpellAbility().addMode(mode); //return target creature to its owner's hand. - Mode mode2 = new Mode(); - mode2.addEffect(new ReturnToHandTargetEffect()); + Mode mode2 = new Mode(new ReturnToHandTargetEffect()); mode2.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode2); diff --git a/Mage.Sets/src/mage/cards/s/SimicGuildmage.java b/Mage.Sets/src/mage/cards/s/SimicGuildmage.java index aaa757e9285..f29b9cfe9c2 100644 --- a/Mage.Sets/src/mage/cards/s/SimicGuildmage.java +++ b/Mage.Sets/src/mage/cards/s/SimicGuildmage.java @@ -191,8 +191,8 @@ class MoveAuraEffect extends OneShotEffect { filterChoice.add(new ControllerIdPredicate(fromPermanent.getControllerId())); filterChoice.add(Predicates.not(new PermanentIdPredicate(fromPermanent.getId()))); chosenPermanentToAttachAuras.setTargetName("a different " + filterChoice.getMessage() + " with the same controller as the " + filterChoice.getMessage() + " the target aura is attached to"); - if (chosenPermanentToAttachAuras.canChoose(source.getSourceId(), source.getControllerId(), game) - && controller.choose(Outcome.Neutral, chosenPermanentToAttachAuras, source.getSourceId(), game)) { + if (chosenPermanentToAttachAuras.canChoose(source.getControllerId(), source, game) + && controller.choose(Outcome.Neutral, chosenPermanentToAttachAuras, source, game)) { Permanent permanentToAttachAura = game.getPermanent(chosenPermanentToAttachAuras.getFirstTarget()); if (permanentToAttachAura != null) { // Check for protection diff --git a/Mage.Sets/src/mage/cards/s/Simoon.java b/Mage.Sets/src/mage/cards/s/Simoon.java index c80b24b4724..dcde950b68f 100644 --- a/Mage.Sets/src/mage/cards/s/Simoon.java +++ b/Mage.Sets/src/mage/cards/s/Simoon.java @@ -62,7 +62,7 @@ class SimoonEffect extends OneShotEffect { if (player != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent(); filter.add(new ControllerIdPredicate(player.getId())); - List creatures = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List creatures = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); for (Permanent creature : creatures) { creature.damage(1, source.getSourceId(), source, game, false, true); } diff --git a/Mage.Sets/src/mage/cards/s/SingleCombat.java b/Mage.Sets/src/mage/cards/s/SingleCombat.java index b854a8abea6..dd1dc7b1bf0 100644 --- a/Mage.Sets/src/mage/cards/s/SingleCombat.java +++ b/Mage.Sets/src/mage/cards/s/SingleCombat.java @@ -82,7 +82,7 @@ class SingleCombatEffect extends OneShotEffect { } Target target = new TargetPermanent(filter); target.setNotTarget(true); - if (player.choose(outcome, target, source.getSourceId(), game)) { + if (player.choose(outcome, target, source, game)) { filterSac.add(Predicates.not(new PermanentIdPredicate(target.getFirstTarget()))); } } diff --git a/Mage.Sets/src/mage/cards/s/SinkingFeeling.java b/Mage.Sets/src/mage/cards/s/SinkingFeeling.java index 5d216b1ead1..eb5098dc990 100644 --- a/Mage.Sets/src/mage/cards/s/SinkingFeeling.java +++ b/Mage.Sets/src/mage/cards/s/SinkingFeeling.java @@ -47,8 +47,8 @@ public final class SinkingFeeling extends CardImpl { // Enchanted creature has "{1}, Put a -1/-1 counter on this creature: Untap this creature. Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new UntapSourceEffect(), new ManaCostsImpl("{1}")); - ability2.addCost(new PutCountersSourceCost(CounterType.M1M1.createInstance())); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ability2, AttachmentType.AURA, Duration.Custom, "Enchanted creature has \"{1}, Put a -1/-1 counter on this creature: Untap this creature."))); + ability2.addCost(new PutCountersSourceCost(CounterType.M1M1.createInstance()).setText("put a -1/-1 counter on this creature")); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ability2, AttachmentType.AURA, Duration.Custom, "Enchanted creature has \"{1}, Put a -1/-1 counter on this creature: Untap this creature.\""))); } diff --git a/Mage.Sets/src/mage/cards/s/SinuousStriker.java b/Mage.Sets/src/mage/cards/s/SinuousStriker.java index 080d79a3c57..7dd8401ee02 100644 --- a/Mage.Sets/src/mage/cards/s/SinuousStriker.java +++ b/Mage.Sets/src/mage/cards/s/SinuousStriker.java @@ -1,7 +1,7 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -10,15 +10,16 @@ import mage.abilities.keyword.EternalizeAbility; 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.constants.SubType; + +import java.util.UUID; public final class SinuousStriker extends CardImpl { - private static String rule = "Eternalize - {3}{U}{U}, Discard a card ({3}{U}{U}, Discard a card, Exile this card from your graveyard: Create a token that's a copy of it, except it's a 4/4 black Zombie"; + private static final String rule = "Eternalize — {3}{U}{U}, Discard a card. ({3}{U}{U}, Discard a card, Exile this card from your graveyard: Create a token that's a copy of it, except it's a 4/4 black Zombie)"; - public SinuousStriker(UUID ownerId, CardSetInfo cardSetInfo){ + public SinuousStriker(UUID ownerId, CardSetInfo cardSetInfo) { super(ownerId, cardSetInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); subtype.add(SubType.NAGA); subtype.add(SubType.WARRIOR); @@ -27,19 +28,22 @@ public final class SinuousStriker extends CardImpl { toughness = new MageInt(2); //U : Sinious Striker gets +1/-1 until end of turn - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(+1, -1, Duration.EndOfTurn), new ManaCostsImpl("{U}"))); + this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect( + +1, -1, Duration.EndOfTurn + ), new ManaCostsImpl<>("{U}"))); //Eternalize 3UU, Discard a card - EternalizeAbility ability = new EternalizeAbility(new ManaCostsImpl("{3}{U}{U}"), this, rule); + Ability ability = new EternalizeAbility(new ManaCostsImpl<>("{3}{U}{U}"), this, rule); ability.addCost(new DiscardCardCost()); this.addAbility(ability); } - public SinuousStriker(final SinuousStriker sinuousStriker){ + private SinuousStriker(final SinuousStriker sinuousStriker) { super(sinuousStriker); } - public SinuousStriker copy(){ + @Override + public SinuousStriker copy() { return new SinuousStriker(this); } } diff --git a/Mage.Sets/src/mage/cards/s/SionaCaptainOfThePyleas.java b/Mage.Sets/src/mage/cards/s/SionaCaptainOfThePyleas.java index f9b6a388f14..b1c6047c7e6 100644 --- a/Mage.Sets/src/mage/cards/s/SionaCaptainOfThePyleas.java +++ b/Mage.Sets/src/mage/cards/s/SionaCaptainOfThePyleas.java @@ -3,9 +3,9 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -42,14 +42,7 @@ public final class SionaCaptainOfThePyleas extends CardImpl { // When Siona, Captain of the Pyleas enters the battlefield, look at the top seven cards of your library. You may reveal an Aura card among them and put it into your hand. Put the rest on the bottom of your library in a random order. this.addAbility(new EntersBattlefieldTriggeredAbility( - new LookLibraryAndPickControllerEffect( - StaticValue.get(7), false, StaticValue.get(1), filter, - Zone.LIBRARY, false, true, false, Zone.HAND, - true, false, false - ).setBackInRandomOrder(true).setText("look at the top seven cards of your library. " + - "You may reveal an Aura card from among them and put it into your hand. " + - "Put the rest on the bottom of your library in a random order.") - )); + new LookLibraryAndPickControllerEffect(7, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM))); // Whenever an Aura you control becomes attached to a creature you control, create a 1/1 white Human Soldier creature token. this.addAbility(new SionaCaptainOfThePyleasAbility()); @@ -95,7 +88,7 @@ class SionaCaptainOfThePyleasAbility extends TriggeredAbilityImpl { @Override public String getRule() { return "Whenever an Aura you control becomes attached to a creature you control, " + - "create a 1/1 white Human Soldier creature token"; + "create a 1/1 white Human Soldier creature token."; } @Override diff --git a/Mage.Sets/src/mage/cards/s/SirenStormtamer.java b/Mage.Sets/src/mage/cards/s/SirenStormtamer.java index 8e5b4d30a47..666f896b65f 100644 --- a/Mage.Sets/src/mage/cards/s/SirenStormtamer.java +++ b/Mage.Sets/src/mage/cards/s/SirenStormtamer.java @@ -82,7 +82,7 @@ class SirenStormtamerTargetObject extends TargetObject { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { return canChoose(sourceControllerId, game); } @@ -114,8 +114,8 @@ class SirenStormtamerTargetObject extends TargetObject { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, - Game game) { + public Set possibleTargets(UUID sourceControllerId, + Ability source, Game game) { return possibleTargets(sourceControllerId, game); } diff --git a/Mage.Sets/src/mage/cards/s/SistersOfStoneDeath.java b/Mage.Sets/src/mage/cards/s/SistersOfStoneDeath.java index 286a1218b15..4706a8877e0 100644 --- a/Mage.Sets/src/mage/cards/s/SistersOfStoneDeath.java +++ b/Mage.Sets/src/mage/cards/s/SistersOfStoneDeath.java @@ -1,36 +1,43 @@ package mage.cards.s; -import java.util.LinkedList; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.ExileTargetForSourceEffect; import mage.abilities.effects.common.combat.MustBeBlockedByTargetSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.CardsImpl; import mage.constants.*; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.BlockedByIdPredicate; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; import mage.game.ExileZone; import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; +import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.LinkedList; +import java.util.UUID; /** * @author jeffwadsworth */ public final class SistersOfStoneDeath extends CardImpl { - private UUID exileId = UUID.randomUUID(); + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature blocking or blocked by {this}"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.EITHER); + } public SistersOfStoneDeath(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}{G}{G}"); @@ -41,21 +48,17 @@ public final class SistersOfStoneDeath extends CardImpl { this.toughness = new MageInt(5); // {G}: Target creature blocks Sisters of Stone Death this turn if able. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MustBeBlockedByTargetSourceEffect(), new ManaCostsImpl("{G}")); + Ability ability = new SimpleActivatedAbility(new MustBeBlockedByTargetSourceEffect(), new ManaCostsImpl<>("{G}")); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); // {B}{G}: Exile target creature blocking or blocked by Sisters of Stone Death. - Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(exileId, this.getIdName()), new ManaCostsImpl("{B}{G}")); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking or blocked by Sisters of Stone Death"); - filter.add(Predicates.or(new BlockedByIdPredicate(this.getId()), - new BlockingAttackerIdPredicate(this.getId()))); - ability2.addTarget(new TargetCreaturePermanent(filter)); + Ability ability2 = new SimpleActivatedAbility(new ExileTargetForSourceEffect(), new ManaCostsImpl<>("{B}{G}")); + ability2.addTarget(new TargetPermanent(filter)); this.addAbility(ability2); // {2}{B}: Put a creature card exiled with Sisters of Stone Death onto the battlefield under your control. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new SistersOfStoneDeathEffect(exileId), new ManaCostsImpl("{2}{B}"))); - + this.addAbility(new SimpleActivatedAbility(new SistersOfStoneDeathEffect(), new ManaCostsImpl<>("{2}{B}"))); } private SistersOfStoneDeath(final SistersOfStoneDeath card) { @@ -70,17 +73,13 @@ public final class SistersOfStoneDeath extends CardImpl { class SistersOfStoneDeathEffect extends OneShotEffect { - private final UUID exileId; - - public SistersOfStoneDeathEffect(UUID exileId) { + public SistersOfStoneDeathEffect() { super(Outcome.PutCreatureInPlay); - this.exileId = exileId; staticText = "Put a creature card exiled with {this} onto the battlefield under your control"; } public SistersOfStoneDeathEffect(final SistersOfStoneDeathEffect effect) { super(effect); - this.exileId = effect.exileId; } @Override @@ -89,7 +88,7 @@ class SistersOfStoneDeathEffect extends OneShotEffect { TargetCard target = new TargetCard(Zone.EXILED, StaticFilters.FILTER_CARD_CREATURE); Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - ExileZone exile = game.getExile().getExileZone(exileId); + ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); if (exile != null) { LinkedList cards = new LinkedList<>(exile); for (UUID cardId : cards) { diff --git a/Mage.Sets/src/mage/cards/s/SizzlingSoloist.java b/Mage.Sets/src/mage/cards/s/SizzlingSoloist.java new file mode 100644 index 00000000000..806846152e5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SizzlingSoloist.java @@ -0,0 +1,90 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AllianceAbility; +import mage.abilities.effects.RequirementEffect; +import mage.abilities.effects.common.IfAbilityHasResolvedXTimesEffect; +import mage.abilities.effects.common.combat.CantBlockTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SizzlingSoloist extends CardImpl { + + public SizzlingSoloist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Alliance — Whenever another creature enters the battlefield under your control, target creature an opponent controls can't block this turn. If this is the second time this ability has resolved this turn, that creature attacks during its controller's next combat phase if able. + Ability ability = new AllianceAbility(new CantBlockTargetEffect(Duration.EndOfTurn)); + ability.addEffect(new IfAbilityHasResolvedXTimesEffect( + Outcome.Benefit, 2, new SizzlingSoloistEffect() + )); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private SizzlingSoloist(final SizzlingSoloist card) { + super(card); + } + + @Override + public SizzlingSoloist copy() { + return new SizzlingSoloist(this); + } +} + +class SizzlingSoloistEffect extends RequirementEffect { + + public SizzlingSoloistEffect() { + super(Duration.Custom); + staticText = "that creature attacks during its controller's next combat phase if able"; + } + + public SizzlingSoloistEffect(final SizzlingSoloistEffect effect) { + super(effect); + } + + @Override + public SizzlingSoloistEffect copy() { + return new SizzlingSoloistEffect(this); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return getTargetPointer().getFirst(game, source).equals(permanent.getId()); + } + + @Override + public boolean isInactive(Ability source, Game game) { + if (game.getPermanent(getTargetPointer().getFirst(game, source)) == null) { + return true; + } + return game.isActivePlayer(game.getControllerId(getTargetPointer().getFirst(game, source))) + && game.getPhase().getType() == TurnPhase.COMBAT + && game.getStep().getType() == PhaseStep.END_COMBAT; + } + + @Override + public boolean mustAttack(Game game) { + return true; + } + + @Override + public boolean mustBlock(Game game) { + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SkallaWolf.java b/Mage.Sets/src/mage/cards/s/SkallaWolf.java index 71f039f4d08..c2ac49b9363 100644 --- a/Mage.Sets/src/mage/cards/s/SkallaWolf.java +++ b/Mage.Sets/src/mage/cards/s/SkallaWolf.java @@ -4,13 +4,12 @@ import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.ColorPredicate; @@ -34,15 +33,11 @@ public final class SkallaWolf extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(3); - // When Skalla Wolf enters the battlefield, look at the top five cards of your library. You may reveal a green card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. + // When Skalla Wolf enters the battlefield, look at the top five cards of your library. + // You may reveal a green card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. this.addAbility(new EntersBattlefieldTriggeredAbility( - new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), filter, - Zone.LIBRARY, false, true, false, Zone.HAND, true, false, false - ).setBackInRandomOrder(true).setText("look at the top five cards of your library. " - + "You may reveal a green card from among them and put it into your hand. " - + "Put the rest on the bottom of your library in a random order.") - )); + new LookLibraryAndPickControllerEffect(5, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM))); } private SkallaWolf(final SkallaWolf card) { diff --git a/Mage.Sets/src/mage/cards/s/SkeletonShard.java b/Mage.Sets/src/mage/cards/s/SkeletonShard.java index 017b33c7075..01f58335229 100644 --- a/Mage.Sets/src/mage/cards/s/SkeletonShard.java +++ b/Mage.Sets/src/mage/cards/s/SkeletonShard.java @@ -7,7 +7,7 @@ import mage.abilities.costs.OrCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -33,11 +33,10 @@ public final class SkeletonShard extends CardImpl { // {3}, {tap} or {B}, {tap}: Return target artifact creature card from your graveyard to your hand. Ability ability = new SimpleActivatedAbility( - new ReturnToHandTargetEffect(), + new ReturnFromGraveyardToHandTargetEffect(), new OrCost( - new CompositeCost(new GenericManaCost(3), new TapSourceCost(), "{3}, {T}"), - new CompositeCost(new ManaCostsImpl<>("{B}"), new TapSourceCost(), "{B}, {T}"), - "{3}, {T} or {B}, {T}" + "{3}, {T} or {B}, {T}", new CompositeCost(new GenericManaCost(3), new TapSourceCost(), "{3}, {T}"), + new CompositeCost(new ManaCostsImpl<>("{B}"), new TapSourceCost(), "{B}, {T}") ) ); ability.addTarget(new TargetCardInYourGraveyard(filter)); diff --git a/Mage.Sets/src/mage/cards/s/Skinshifter.java b/Mage.Sets/src/mage/cards/s/Skinshifter.java index 8019094272a..692da1bf1de 100644 --- a/Mage.Sets/src/mage/cards/s/Skinshifter.java +++ b/Mage.Sets/src/mage/cards/s/Skinshifter.java @@ -35,12 +35,10 @@ public final class Skinshifter extends CardImpl { new ManaCostsImpl<>("{G}")); ability.getModes().setChooseText("Choose one. Activate only once each turn."); - Mode mode = new Mode(); - mode.addEffect(new BecomesCreatureSourceEffect(new BirdToken(), "", Duration.EndOfTurn)); + Mode mode = new Mode(new BecomesCreatureSourceEffect(new BirdToken(), "", Duration.EndOfTurn)); ability.addMode(mode); - mode = new Mode(); - mode.addEffect(new BecomesCreatureSourceEffect(new PlantToken(), "", Duration.EndOfTurn)); + mode = new Mode(new BecomesCreatureSourceEffect(new PlantToken(), "", Duration.EndOfTurn)); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/Skinthinner.java b/Mage.Sets/src/mage/cards/s/Skinthinner.java index 2f442022d5e..052190c5f5d 100644 --- a/Mage.Sets/src/mage/cards/s/Skinthinner.java +++ b/Mage.Sets/src/mage/cards/s/Skinthinner.java @@ -27,7 +27,7 @@ public final class Skinthinner extends CardImpl { this.toughness = new MageInt(1); // Morph {3}{B}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{B}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{B}{B}"))); // When Skinthinner is turned face up, destroy target nonblack creature. It can't be regenerated. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new DestroyTargetEffect(true)); ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_NON_BLACK)); diff --git a/Mage.Sets/src/mage/cards/s/SkirkCommando.java b/Mage.Sets/src/mage/cards/s/SkirkCommando.java index 746253a5161..d44a07d1c98 100644 --- a/Mage.Sets/src/mage/cards/s/SkirkCommando.java +++ b/Mage.Sets/src/mage/cards/s/SkirkCommando.java @@ -35,7 +35,7 @@ public final class SkirkCommando extends CardImpl { this.addAbility(new SkirkCommandoTriggeredAbility()); //Morph {2}{R} (You may cast this card face down as a 2/2 creature for 3. Turn it face up any time for its morph cost.) - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{R}"))); } diff --git a/Mage.Sets/src/mage/cards/s/SkirkDrillSergeant.java b/Mage.Sets/src/mage/cards/s/SkirkDrillSergeant.java index b76b0be17ae..ef086d3db47 100644 --- a/Mage.Sets/src/mage/cards/s/SkirkDrillSergeant.java +++ b/Mage.Sets/src/mage/cards/s/SkirkDrillSergeant.java @@ -82,7 +82,7 @@ class SkirkDrillSergeantEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/s/SkirkMarauder.java b/Mage.Sets/src/mage/cards/s/SkirkMarauder.java index fd811d16df6..397940e73ca 100644 --- a/Mage.Sets/src/mage/cards/s/SkirkMarauder.java +++ b/Mage.Sets/src/mage/cards/s/SkirkMarauder.java @@ -27,7 +27,7 @@ public final class SkirkMarauder extends CardImpl { this.toughness = new MageInt(1); // Morph {2}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{R}"))); // When Skirk Marauder is turned face up, it deals 2 damage to any target. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new DamageTargetEffect(2, "it")); diff --git a/Mage.Sets/src/mage/cards/s/SkirkVolcanist.java b/Mage.Sets/src/mage/cards/s/SkirkVolcanist.java index d130eeb8114..0d9c5b13e97 100644 --- a/Mage.Sets/src/mage/cards/s/SkirkVolcanist.java +++ b/Mage.Sets/src/mage/cards/s/SkirkVolcanist.java @@ -34,7 +34,7 @@ public final class SkirkVolcanist extends CardImpl { this.toughness = new MageInt(1); // Morph-Sacrifice two Mountains. - this.addAbility(new MorphAbility(this, new SacrificeTargetCost(new TargetControlledPermanent(2, filter)))); + this.addAbility(new MorphAbility(new SacrificeTargetCost(new TargetControlledPermanent(2, filter)))); // When Skirk Volcanist is turned face up, it deals 3 damage divided as you choose among one, two, or three target creatures. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new DamageMultiEffect(3, "it")); diff --git a/Mage.Sets/src/mage/cards/s/SkittishValesk.java b/Mage.Sets/src/mage/cards/s/SkittishValesk.java index 0eec5f02451..04d609547cb 100644 --- a/Mage.Sets/src/mage/cards/s/SkittishValesk.java +++ b/Mage.Sets/src/mage/cards/s/SkittishValesk.java @@ -35,7 +35,7 @@ public final class SkittishValesk extends CardImpl { this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new SkittishValeskEffect(), TargetController.YOU, false)); // Morph {5}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{5}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{5}{R}"))); } private SkittishValesk(final SkittishValesk card) { diff --git a/Mage.Sets/src/mage/cards/s/SkizzikSurger.java b/Mage.Sets/src/mage/cards/s/SkizzikSurger.java index e7bbd3c140e..32c666976f8 100644 --- a/Mage.Sets/src/mage/cards/s/SkizzikSurger.java +++ b/Mage.Sets/src/mage/cards/s/SkizzikSurger.java @@ -28,7 +28,7 @@ public final class SkizzikSurger extends CardImpl { // Haste this.addAbility(HasteAbility.getInstance()); // Echo-Sacrifice two lands. - this.addAbility(new EchoAbility(new SacrificeTargetCost(new TargetControlledPermanent(2, 2, new FilterControlledLandPermanent("two lands"), true)))); + this.addAbility(new EchoAbility(new SacrificeTargetCost(new TargetControlledPermanent(2, 2, new FilterControlledLandPermanent("lands"), true)))); } private SkizzikSurger(final SkizzikSurger card) { diff --git a/Mage.Sets/src/mage/cards/s/SkophosReaver.java b/Mage.Sets/src/mage/cards/s/SkophosReaver.java index 977aea32ff5..88bc8571346 100644 --- a/Mage.Sets/src/mage/cards/s/SkophosReaver.java +++ b/Mage.Sets/src/mage/cards/s/SkophosReaver.java @@ -35,7 +35,7 @@ public final class SkophosReaver extends CardImpl { ))); // Madness {1}{R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{1}{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{1}{R}"))); } private SkophosReaver(final SkophosReaver card) { diff --git a/Mage.Sets/src/mage/cards/s/Skred.java b/Mage.Sets/src/mage/cards/s/Skred.java index 0f544bb905e..7199c679eb5 100644 --- a/Mage.Sets/src/mage/cards/s/Skred.java +++ b/Mage.Sets/src/mage/cards/s/Skred.java @@ -61,7 +61,7 @@ class SkredDamageEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int amount = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int amount = game.getBattlefield().count(filter, source.getControllerId(), source, game); Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); if(amount > 0) { if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/s/SkulkingKiller.java b/Mage.Sets/src/mage/cards/s/SkulkingKiller.java index 846b8c88f97..539c62fe0d1 100644 --- a/Mage.Sets/src/mage/cards/s/SkulkingKiller.java +++ b/Mage.Sets/src/mage/cards/s/SkulkingKiller.java @@ -68,7 +68,7 @@ class SkulkingKillerEffect extends OneShotEffect { Permanent permanent = game.getPermanent(source.getFirstTarget()); if (permanent == null || game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getSourceId(), permanent.getControllerId(), game + permanent.getControllerId(), source, game ) > 1) { return false; } diff --git a/Mage.Sets/src/mage/cards/s/SkulkingKnight.java b/Mage.Sets/src/mage/cards/s/SkulkingKnight.java index 38c44083893..8a6c0ededa5 100644 --- a/Mage.Sets/src/mage/cards/s/SkulkingKnight.java +++ b/Mage.Sets/src/mage/cards/s/SkulkingKnight.java @@ -28,7 +28,7 @@ public final class SkulkingKnight extends CardImpl { // Flanking this.addAbility(new FlankingAbility()); // When Skulking Knight becomes the target of a spell or ability, sacrifice it. - this.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect())); + this.addAbility(new BecomesTargetTriggeredAbility(new SacrificeSourceEffect().setText("sacrifice it"))); } private SkulkingKnight(final SkulkingKnight card) { diff --git a/Mage.Sets/src/mage/cards/s/SkullOfOrm.java b/Mage.Sets/src/mage/cards/s/SkullOfOrm.java index 20add1936af..c93935363ed 100644 --- a/Mage.Sets/src/mage/cards/s/SkullOfOrm.java +++ b/Mage.Sets/src/mage/cards/s/SkullOfOrm.java @@ -1,36 +1,34 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Plopman */ public final class SkullOfOrm extends CardImpl { private static final FilterCard filter = new FilterCard("enchantment card from your graveyard"); - + static { filter.add(CardType.ENCHANTMENT.getPredicate()); } - + public SkullOfOrm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // {5}, {tap}: Return target enchantment card from your graveyard to your hand. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{5}")); + Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl<>("{5}")); ability.addTarget(new TargetCardInYourGraveyard(filter)); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/SkullmaneBaku.java b/Mage.Sets/src/mage/cards/s/SkullmaneBaku.java index 1bfd43999e3..738cc6fbb39 100644 --- a/Mage.Sets/src/mage/cards/s/SkullmaneBaku.java +++ b/Mage.Sets/src/mage/cards/s/SkullmaneBaku.java @@ -1,4 +1,3 @@ - package mage.cards.s; import java.util.UUID; @@ -6,33 +5,30 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; -import mage.abilities.costs.Cost; import mage.abilities.costs.common.RemoveVariableCountersSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.RemovedCountersForCostValue; +import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.FixedTarget; /** * @author LevelX2 */ public final class SkullmaneBaku extends CardImpl { + private static final DynamicValue xValue = new SignInversionDynamicValue(RemovedCountersForCostValue.instance); + public SkullmaneBaku(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); this.subtype.add(SubType.SPIRIT); @@ -44,9 +40,9 @@ public final class SkullmaneBaku extends CardImpl { this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true)); // {1}, {T}, Remove X ki counters from Skullmane Baku: Target creature gets -X/-X until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SkullmaneBakuUnboostEffect(), new GenericManaCost(1)); + Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); - ability.addCost(new RemoveVariableCountersSourceCost(CounterType.KI.createInstance(1))); + ability.addCost(new RemoveVariableCountersSourceCost(CounterType.KI.createInstance())); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } @@ -59,39 +55,4 @@ public final class SkullmaneBaku extends CardImpl { public SkullmaneBaku copy() { return new SkullmaneBaku(this); } - - static class SkullmaneBakuUnboostEffect extends OneShotEffect { - - public SkullmaneBakuUnboostEffect() { - super(Outcome.UnboostCreature); - staticText = "Target creature gets -X/-X until end of turn"; - } - - public SkullmaneBakuUnboostEffect(SkullmaneBakuUnboostEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - int numberToUnboost = 0; - for (Cost cost : source.getCosts()) { - if (cost instanceof RemoveVariableCountersSourceCost) { - numberToUnboost = ((RemoveVariableCountersSourceCost) cost).getAmount() * -1; - } - } - Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (creature != null && numberToUnboost != 0) { - ContinuousEffect effect = new BoostTargetEffect(numberToUnboost, numberToUnboost, Duration.EndOfTurn); - effect.setTargetPointer(new FixedTarget(creature, game)); - game.addEffect(effect, source); - } - return true; - } - - @Override - public SkullmaneBakuUnboostEffect copy() { - return new SkullmaneBakuUnboostEffect(this); - } - - } } diff --git a/Mage.Sets/src/mage/cards/s/Skullwinder.java b/Mage.Sets/src/mage/cards/s/Skullwinder.java index 4ad191e5dfe..42d10ad0ace 100644 --- a/Mage.Sets/src/mage/cards/s/Skullwinder.java +++ b/Mage.Sets/src/mage/cards/s/Skullwinder.java @@ -76,14 +76,14 @@ class SkullwinderEffect extends OneShotEffect { MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { TargetOpponent targetOpponent = new TargetOpponent(true); - if (controller.choose(Outcome.Detriment, targetOpponent, source.getSourceId(), game)) { + if (controller.choose(Outcome.Detriment, targetOpponent, source, game)) { Player opponent = game.getPlayer(targetOpponent.getFirstTarget()); if (opponent != null) { game.informPlayers(sourceObject.getLogName() + ": " + controller.getLogName() + " has chosen " + opponent.getLogName()); // That player returns a card from their graveyard to their hand TargetCardInYourGraveyard targetCard = new TargetCardInYourGraveyard(new FilterCard("a card from your graveyard to return to your hand")); targetCard.setNotTarget(true); - if (opponent.choose(outcome, targetCard, source.getSourceId(), game)) { + if (opponent.choose(outcome, targetCard, source, game)) { Card card = game.getCard(targetCard.getFirstTarget()); if (card != null) { opponent.moveCards(card, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/s/SkyCrier.java b/Mage.Sets/src/mage/cards/s/SkyCrier.java new file mode 100644 index 00000000000..125ae3e13b2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SkyCrier.java @@ -0,0 +1,55 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.DrawCardTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SkyCrier extends CardImpl { + + public SkyCrier(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // {3}{W}: You and target opponent each draw a card. + Ability ability = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(1).setText("you"), new ManaCostsImpl<>("{3}{W}") + ); + ability.addEffect(new DrawCardTargetEffect(1).setText("and target opponent each draw a card")); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + private SkyCrier(final SkyCrier card) { + super(card); + } + + @Override + public SkyCrier copy() { + return new SkyCrier(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SkybridgeTowers.java b/Mage.Sets/src/mage/cards/s/SkybridgeTowers.java new file mode 100644 index 00000000000..ad76cc72984 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SkybridgeTowers.java @@ -0,0 +1,50 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; +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.DrawCardSourceControllerEffect; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SkybridgeTowers extends CardImpl { + + public SkybridgeTowers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Skybridge Towers enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {W} or {U}. + this.addAbility(new WhiteManaAbility()); + this.addAbility(new BlueManaAbility()); + + // {2}{W}{U}, {T}, Sacrifice Skybridge Towers: Draw a card. + Ability ability = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{2}{W}{U}") + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private SkybridgeTowers(final SkybridgeTowers card) { + super(card); + } + + @Override + public SkybridgeTowers copy() { + return new SkybridgeTowers(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SkyshroudWarBeast.java b/Mage.Sets/src/mage/cards/s/SkyshroudWarBeast.java index 33993c19f18..c3c4440b518 100644 --- a/Mage.Sets/src/mage/cards/s/SkyshroudWarBeast.java +++ b/Mage.Sets/src/mage/cards/s/SkyshroudWarBeast.java @@ -78,7 +78,7 @@ class SkyshroudWarBeastEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - MageObject target = game.getObject(source.getSourceId()); + MageObject target = game.getObject(source); if (target != null) { UUID playerId = (UUID) game.getState().getValue(source.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY); FilterLandPermanent filter = FilterLandPermanent.nonbasicLand(); diff --git a/Mage.Sets/src/mage/cards/s/Slagstorm.java b/Mage.Sets/src/mage/cards/s/Slagstorm.java index 88f321ef459..bb6fb9f0928 100644 --- a/Mage.Sets/src/mage/cards/s/Slagstorm.java +++ b/Mage.Sets/src/mage/cards/s/Slagstorm.java @@ -21,8 +21,7 @@ public final class Slagstorm extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{R}{R}"); this.getSpellAbility().addEffect(new DamageAllEffect(3, new FilterCreaturePermanent())); - Mode mode = new Mode(); - mode.addEffect(new DamagePlayersEffect(3)); + Mode mode = new Mode(new DamagePlayersEffect(3)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SlaveOfBolas.java b/Mage.Sets/src/mage/cards/s/SlaveOfBolas.java index 11b11e50ca9..74a7ba4000e 100644 --- a/Mage.Sets/src/mage/cards/s/SlaveOfBolas.java +++ b/Mage.Sets/src/mage/cards/s/SlaveOfBolas.java @@ -1,9 +1,6 @@ - package mage.cards.s; -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.SacrificeTargetEffect; @@ -21,8 +18,9 @@ import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class SlaveOfBolas extends CardImpl { @@ -31,9 +29,11 @@ public final class SlaveOfBolas extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U/R}{B}"); // Gain control of target creature. Untap that creature. It gains haste until end of turn. Sacrifice it at the beginning of the next end step. - this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.Custom)); this.getSpellAbility().addEffect(new UntapTargetEffect().setText("Untap that creature")); - this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn).setText("It gains haste until end of turn")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("It gains haste until end of turn")); this.getSpellAbility().addEffect(new SlaveOfBolasEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } @@ -67,13 +67,13 @@ class SlaveOfBolasEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent != null) { - SacrificeTargetEffect sacrificeEffect = new SacrificeTargetEffect("sacrifice this", source.getControllerId()); - sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect); - game.addDelayedTriggeredAbility(delayedAbility, source); - return true; + if (permanent == null) { + return false; } - return false; + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new SacrificeTargetEffect("sacrifice this", source.getControllerId()) + .setTargetPointer(new FixedTarget(permanent, game)) + ), source); + return true; } } diff --git a/Mage.Sets/src/mage/cards/s/SleepOfTheDead.java b/Mage.Sets/src/mage/cards/s/SleepOfTheDead.java index 0d443a2e442..0a736726d62 100644 --- a/Mage.Sets/src/mage/cards/s/SleepOfTheDead.java +++ b/Mage.Sets/src/mage/cards/s/SleepOfTheDead.java @@ -20,7 +20,7 @@ public final class SleepOfTheDead extends CardImpl { // Tap target creature. It doesn't untap during its controller's next untap step. this.getSpellAbility().addEffect(new TapTargetEffect()); - this.getSpellAbility().addEffect(new DontUntapInControllersNextUntapStepTargetEffect()); + this.getSpellAbility().addEffect(new DontUntapInControllersNextUntapStepTargetEffect("it")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Escape—{2}{U}, Exile three other cards from your graveyard. diff --git a/Mage.Sets/src/mage/cards/s/SleepWithTheFishes.java b/Mage.Sets/src/mage/cards/s/SleepWithTheFishes.java new file mode 100644 index 00000000000..bc20568cd81 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SleepWithTheFishes.java @@ -0,0 +1,55 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect; +import mage.abilities.effects.common.TapEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.permanent.token.FishToken; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SleepWithTheFishes extends CardImpl { + + public SleepWithTheFishes(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.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // When Sleep with the Fishes enters the battlefield, tap enchanted creature and you create a 1/1 blue Fish creature token with "This creature can't be blocked." + Ability ability = new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect()); + ability.addEffect(new CreateTokenEffect(new FishToken()).concatBy("and you")); + this.addAbility(ability); + + // Enchanted creature doesn't untap during its controller's untap step. + this.addAbility(new SimpleStaticAbility(new DontUntapInControllersUntapStepEnchantedEffect())); + } + + private SleepWithTheFishes(final SleepWithTheFishes card) { + super(card); + } + + @Override + public SleepWithTheFishes copy() { + return new SleepWithTheFishes(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SleightOfHand.java b/Mage.Sets/src/mage/cards/s/SleightOfHand.java index a822f03a460..bc85f30e586 100644 --- a/Mage.Sets/src/mage/cards/s/SleightOfHand.java +++ b/Mage.Sets/src/mage/cards/s/SleightOfHand.java @@ -1,27 +1,23 @@ - package mage.cards.s; -import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.FilterCard; + +import java.util.UUID; /** - * * @author North */ public final class SleightOfHand extends CardImpl { public SleightOfHand(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}"); // Look at the top two cards of your library. Put one of them into your hand and the other on the bottom of your library. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(2), false, StaticValue.get(1), new FilterCard(), Zone.LIBRARY, false, false)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(2, 1, PutCards.HAND, PutCards.BOTTOM_ANY)); } private SleightOfHand(final SleightOfHand card) { diff --git a/Mage.Sets/src/mage/cards/s/SlinkingGiant.java b/Mage.Sets/src/mage/cards/s/SlinkingGiant.java index dc9a0af3747..f5d58e3e95b 100644 --- a/Mage.Sets/src/mage/cards/s/SlinkingGiant.java +++ b/Mage.Sets/src/mage/cards/s/SlinkingGiant.java @@ -28,7 +28,7 @@ public final class SlinkingGiant extends CardImpl { this.addAbility(WitherAbility.getInstance()); // Whenever Slinking Giant blocks or becomes blocked, it gets -3/-0 until end of turn. - this.addAbility(new BlocksOrBecomesBlockedSourceTriggeredAbility(new BoostSourceEffect(-3, 0, Duration.EndOfTurn), false)); + this.addAbility(new BlocksOrBecomesBlockedSourceTriggeredAbility(new BoostSourceEffect(-3, 0, Duration.EndOfTurn).setText("it gets -3/-0 until end of turn"), false).setTriggerPhrase("Whenever {this} blocks or becomes blocked, ")); } private SlinkingGiant(final SlinkingGiant card) { diff --git a/Mage.Sets/src/mage/cards/s/SlipOutTheBack.java b/Mage.Sets/src/mage/cards/s/SlipOutTheBack.java new file mode 100644 index 00000000000..15add8b4e47 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SlipOutTheBack.java @@ -0,0 +1,35 @@ +package mage.cards.s; + +import mage.abilities.effects.common.PhaseOutTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SlipOutTheBack extends CardImpl { + + public SlipOutTheBack(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); + + // Put a +1/+1 counter on target creature. It phases out. + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + this.getSpellAbility().addEffect(new PhaseOutTargetEffect("it")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private SlipOutTheBack(final SlipOutTheBack card) { + super(card); + } + + @Override + public SlipOutTheBack copy() { + return new SlipOutTheBack(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SlipperyBogbonder.java b/Mage.Sets/src/mage/cards/s/SlipperyBogbonder.java index fe6c3c7c103..09807275293 100644 --- a/Mage.Sets/src/mage/cards/s/SlipperyBogbonder.java +++ b/Mage.Sets/src/mage/cards/s/SlipperyBogbonder.java @@ -95,12 +95,12 @@ class SlipperyBogbonderEffect extends OneShotEffect { FilterPermanent filterPermanent = filter.copy(); filterPermanent.add(Predicates.not(new PermanentIdPredicate(source.getFirstTarget()))); if (player == null || creature == null || game.getBattlefield().count( - filterPermanent, source.getSourceId(), source.getControllerId(), game + filterPermanent, source.getControllerId(), source, game ) < 1) { return false; } TargetPermanent target = new TargetPermanent(0, Integer.MAX_VALUE, filterPermanent, true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); List permanents = target .getTargets() .stream() diff --git a/Mage.Sets/src/mage/cards/s/SlipstreamSerpent.java b/Mage.Sets/src/mage/cards/s/SlipstreamSerpent.java index d656a21b7f8..03fb381a452 100644 --- a/Mage.Sets/src/mage/cards/s/SlipstreamSerpent.java +++ b/Mage.Sets/src/mage/cards/s/SlipstreamSerpent.java @@ -38,7 +38,7 @@ public final class SlipstreamSerpent extends CardImpl { new SacrificeSourceEffect())); // Morph {5}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{5}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{5}{U}"))); } private SlipstreamSerpent(final SlipstreamSerpent card) { diff --git a/Mage.Sets/src/mage/cards/s/Slithermuse.java b/Mage.Sets/src/mage/cards/s/Slithermuse.java index 20618815588..2a76763c235 100644 --- a/Mage.Sets/src/mage/cards/s/Slithermuse.java +++ b/Mage.Sets/src/mage/cards/s/Slithermuse.java @@ -77,7 +77,7 @@ class SlithermuseEffect extends OneShotEffect { if (player != null && permanent != null) { TargetOpponent target = new TargetOpponent(); target.setNotTarget(true); - if (player.choose(this.outcome, target, source.getSourceId(), game)) { + if (player.choose(this.outcome, target, source, game)) { Player chosenPlayer = game.getPlayer(target.getFirstTarget()); if (chosenPlayer != null) { game.informPlayers(permanent.getName() + ": " + player.getLogName() + " has chosen " + chosenPlayer.getLogName()); diff --git a/Mage.Sets/src/mage/cards/s/SliverHivelord.java b/Mage.Sets/src/mage/cards/s/SliverHivelord.java index 93106c9dcb3..b2acb06e413 100644 --- a/Mage.Sets/src/mage/cards/s/SliverHivelord.java +++ b/Mage.Sets/src/mage/cards/s/SliverHivelord.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -9,14 +7,14 @@ import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SliverHivelord extends CardImpl { @@ -30,10 +28,10 @@ public final class SliverHivelord extends CardImpl { this.toughness = new MageInt(5); // Sliver creatures you control have indestructible. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new GainAbilityControlledEffect(IndestructibleAbility.getInstance(), - Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS))); - + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_SLIVERS + ))); } private SliverHivelord(final SliverHivelord card) { diff --git a/Mage.Sets/src/mage/cards/s/SliverOverlord.java b/Mage.Sets/src/mage/cards/s/SliverOverlord.java index bbbb935432b..5fedf523a92 100644 --- a/Mage.Sets/src/mage/cards/s/SliverOverlord.java +++ b/Mage.Sets/src/mage/cards/s/SliverOverlord.java @@ -42,7 +42,7 @@ public final class SliverOverlord extends CardImpl { this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true, true), new ManaCostsImpl("{3}"))); // {3}: Gain control of target Sliver. - Ability ability = (new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainControlTargetEffect(Duration.EndOfGame), new ManaCostsImpl("{3}"))); + Ability ability = (new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainControlTargetEffect(Duration.Custom), new ManaCostsImpl("{3}"))); Target target = new TargetPermanent(new FilterCreaturePermanent(SubType.SLIVER,"Sliver")); ability.addTarget(target); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/SludgeMonster.java b/Mage.Sets/src/mage/cards/s/SludgeMonster.java index 42d3a095551..eb3ebe87dcc 100644 --- a/Mage.Sets/src/mage/cards/s/SludgeMonster.java +++ b/Mage.Sets/src/mage/cards/s/SludgeMonster.java @@ -87,7 +87,7 @@ class SludgeMonsterEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { for (Permanent permanent : game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game )) { switch (layer) { case AbilityAddingRemovingEffects_6: diff --git a/Mage.Sets/src/mage/cards/s/SludgeStrider.java b/Mage.Sets/src/mage/cards/s/SludgeStrider.java index 53e6fdb4ad0..e6861cfbff2 100644 --- a/Mage.Sets/src/mage/cards/s/SludgeStrider.java +++ b/Mage.Sets/src/mage/cards/s/SludgeStrider.java @@ -76,7 +76,7 @@ class SludgeStriderTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD) { Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null && filter.match(permanent, getSourceId(), getControllerId(), game)) { + if (permanent != null && filter.match(permanent, getControllerId(), this, game)) { return true; } } @@ -88,7 +88,7 @@ class SludgeStriderTriggeredAbility extends TriggeredAbilityImpl { if (permanent == null) { permanent = (Permanent) game.getLastKnownInformation(targetId, Zone.BATTLEFIELD); } - return permanent != null && filter.match(permanent, getSourceId(), getControllerId(), game); + return permanent != null && filter.match(permanent, getControllerId(), this, game); } } return false; diff --git a/Mage.Sets/src/mage/cards/s/SmokeSpiritsAid.java b/Mage.Sets/src/mage/cards/s/SmokeSpiritsAid.java new file mode 100644 index 00000000000..8091e3c926e --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SmokeSpiritsAid.java @@ -0,0 +1,91 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.SmokeBlessingToken; +import mage.game.permanent.token.Token; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SmokeSpiritsAid extends CardImpl { + + public SmokeSpiritsAid(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{R}"); + + // For each of up to X target creatures, create a red Aura enchantment token named Smoke Blessing attached to that creature. Those tokens have enchant creature and "When enchanted creature dies, it deals 1 damage to its controller and you create a Treasure token." + this.getSpellAbility().addEffect(new SmokeSpiritsAidEffect()); + this.getSpellAbility().setTargetAdjuster(SmokeSpiritsAidAdjuster.instance); + } + + private SmokeSpiritsAid(final SmokeSpiritsAid card) { + super(card); + } + + @Override + public SmokeSpiritsAid copy() { + return new SmokeSpiritsAid(this); + } +} + +enum SmokeSpiritsAidAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + if (ability.getManaCostsToPay().getX() > 0) { + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(0, ability.getManaCostsToPay().getX())); + } + } +} + +class SmokeSpiritsAidEffect extends OneShotEffect { + + SmokeSpiritsAidEffect() { + super(Outcome.Benefit); + staticText = "for each of up to X target creatures, create a red Aura enchantment token " + + "named Smoke Blessing attached to that creature. Those tokens have enchant creature and " + + "\"When enchanted creature dies, it deals 1 damage to its controller and you create a Treasure token.\""; + } + + private SmokeSpiritsAidEffect(final SmokeSpiritsAidEffect effect) { + super(effect); + } + + @Override + public SmokeSpiritsAidEffect copy() { + return new SmokeSpiritsAidEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Token token = new SmokeBlessingToken(); + for (UUID targetId : getTargetPointer().getTargets(game, source)) { + Permanent permanent = game.getPermanent(targetId); + if (permanent == null) { + continue; + } + token.putOntoBattlefield(1, game, source); + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent aura = game.getPermanent(tokenId); + if (aura == null) { + continue; + } + aura.getAbilities().get(0).getTargets().get(0).add(targetId, game); + aura.getAbilities().get(0).getEffects().get(0).apply(game, aura.getAbilities().get(0)); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SmokeTeller.java b/Mage.Sets/src/mage/cards/s/SmokeTeller.java index d015a603401..5c2c3921145 100644 --- a/Mage.Sets/src/mage/cards/s/SmokeTeller.java +++ b/Mage.Sets/src/mage/cards/s/SmokeTeller.java @@ -78,7 +78,7 @@ class SmokeTellerLookFaceDownEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (player == null || mageObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/s/Smokebraider.java b/Mage.Sets/src/mage/cards/s/Smokebraider.java index 3ed7e6438f8..b24dafc8460 100644 --- a/Mage.Sets/src/mage/cards/s/Smokebraider.java +++ b/Mage.Sets/src/mage/cards/s/Smokebraider.java @@ -71,7 +71,7 @@ class SmokebraiderManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object != null && object.hasSubtype(SubType.ELEMENTAL, game)) { return true; } diff --git a/Mage.Sets/src/mage/cards/s/Smokestack.java b/Mage.Sets/src/mage/cards/s/Smokestack.java index 64900704a14..2f96c27ac3d 100644 --- a/Mage.Sets/src/mage/cards/s/Smokestack.java +++ b/Mage.Sets/src/mage/cards/s/Smokestack.java @@ -72,9 +72,9 @@ class SmokestackEffect extends OneShotEffect { Target target = new TargetControlledPermanent(amount, amount, new FilterControlledPermanent(), true); //A spell or ability could have removed the only legal target this player //had, if thats the case this ability should fizzle. - if (target.canChoose(source.getSourceId(), activePlayer.getId(), game)) { - while (!target.isChosen() && target.canChoose(source.getSourceId(), activePlayer.getId(), game) && activePlayer.canRespond()) { - activePlayer.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + if (target.canChoose(activePlayer.getId(), source, game)) { + while (!target.isChosen() && target.canChoose(activePlayer.getId(), source, game) && activePlayer.canRespond()) { + activePlayer.choose(Outcome.Sacrifice, target, source, game); } for (int idx = 0; idx < target.getTargets().size(); idx++) { diff --git a/Mage.Sets/src/mage/cards/s/Snapback.java b/Mage.Sets/src/mage/cards/s/Snapback.java index 07157766c7d..ff0a902980b 100644 --- a/Mage.Sets/src/mage/cards/s/Snapback.java +++ b/Mage.Sets/src/mage/cards/s/Snapback.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.costs.AlternativeCostSourceAbility; import mage.abilities.costs.common.ExileFromHandCost; @@ -10,28 +8,30 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterOwnedCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author emerald000 */ public final class Snapback extends CardImpl { - public Snapback(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); + private static final FilterOwnedCard filter + = new FilterOwnedCard("a blue card from your hand"); + static { + filter.add(new ColorPredicate(ObjectColor.BLUE)); + } + + public Snapback(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // You may exile a blue card from your hand rather than pay Snapback's mana cost. - FilterOwnedCard filterCardInHand = new FilterOwnedCard("a blue card from your hand"); - filterCardInHand.add(new ColorPredicate(ObjectColor.BLUE)); - filterCardInHand.add(Predicates.not(new CardIdPredicate(this.getId()))); - this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filterCardInHand)))); - + this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter)))); + // Return target creature to its owner's hand. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/s/SnappingThragg.java b/Mage.Sets/src/mage/cards/s/SnappingThragg.java index d18c30f2e99..490e959fdbd 100644 --- a/Mage.Sets/src/mage/cards/s/SnappingThragg.java +++ b/Mage.Sets/src/mage/cards/s/SnappingThragg.java @@ -36,7 +36,7 @@ public final class SnappingThragg extends CardImpl { this.addAbility(new SnappingThraggTriggeredAbility()); // Morph {4}{R}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{R}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{R}{R}"))); } diff --git a/Mage.Sets/src/mage/cards/s/Snarespinner.java b/Mage.Sets/src/mage/cards/s/Snarespinner.java index d39154b512e..0715e6da8e2 100644 --- a/Mage.Sets/src/mage/cards/s/Snarespinner.java +++ b/Mage.Sets/src/mage/cards/s/Snarespinner.java @@ -1,7 +1,7 @@ package mage.cards.s; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.ReachAbility; @@ -10,9 +10,8 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; import java.util.UUID; @@ -21,6 +20,12 @@ import java.util.UUID; */ public final class Snarespinner extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + public Snarespinner(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); @@ -32,7 +37,7 @@ public final class Snarespinner extends CardImpl { this.addAbility(ReachAbility.getInstance()); // Whenever Snarespinner blocks a creature with flying, Snarespinner gets +2/+0 until end of turn. - this.addAbility(new SnarespinnerTriggeredAbility()); + this.addAbility(new BlocksCreatureTriggeredAbility(new BoostSourceEffect(2, 0, Duration.EndOfTurn), filter, false)); } private Snarespinner(final Snarespinner card) { @@ -43,36 +48,4 @@ public final class Snarespinner extends CardImpl { public Snarespinner copy() { return new Snarespinner(this); } -} - -class SnarespinnerTriggeredAbility extends TriggeredAbilityImpl { - - SnarespinnerTriggeredAbility() { - super(Zone.BATTLEFIELD, new BoostSourceEffect(2, 0, Duration.EndOfTurn), false); - } - - private SnarespinnerTriggeredAbility(final SnarespinnerTriggeredAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.BLOCKER_DECLARED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return event.getSourceId().equals(this.getSourceId()) - && game.getPermanent(event.getTargetId()).getAbilities().containsKey(FlyingAbility.getInstance().getId()); - } - - @Override - public String getRule() { - return "Whenever {this} blocks a creature with flying, {this} gets +2/+0 until end of turn."; - } - - @Override - public SnarespinnerTriggeredAbility copy() { - return new SnarespinnerTriggeredAbility(this); - } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SnarlingUndorak.java b/Mage.Sets/src/mage/cards/s/SnarlingUndorak.java index 2c6d6465d95..8f4a57db5f5 100644 --- a/Mage.Sets/src/mage/cards/s/SnarlingUndorak.java +++ b/Mage.Sets/src/mage/cards/s/SnarlingUndorak.java @@ -40,7 +40,7 @@ public final class SnarlingUndorak extends CardImpl { ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); // Morph {1}{G}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{G}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{G}{G}"))); } private SnarlingUndorak(final SnarlingUndorak card) { diff --git a/Mage.Sets/src/mage/cards/s/SneakAttack.java b/Mage.Sets/src/mage/cards/s/SneakAttack.java index 1f832a7ab5c..2df5981e8aa 100644 --- a/Mage.Sets/src/mage/cards/s/SneakAttack.java +++ b/Mage.Sets/src/mage/cards/s/SneakAttack.java @@ -74,7 +74,7 @@ class SneakAttackEffect extends OneShotEffect { return true; } TargetCardInHand target = new TargetCardInHand(StaticFilters.FILTER_CARD_CREATURE); - if (!controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + if (!controller.choose(Outcome.PutCreatureInPlay, target, source, game)) { return true; } Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/s/SnoopingNewsie.java b/Mage.Sets/src/mage/cards/s/SnoopingNewsie.java new file mode 100644 index 00000000000..f5f03d60fec --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SnoopingNewsie.java @@ -0,0 +1,59 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.DifferentManaValuesInGraveCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.MillCardsControllerEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.DifferentManaValuesInGraveHint; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SnoopingNewsie extends CardImpl { + + public SnoopingNewsie(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Snooping Newsie enters the battlefield, mill two cards. + this.addAbility(new EntersBattlefieldTriggeredAbility(new MillCardsControllerEffect(2))); + + // As long as there are five or more mana values among cards in your graveyard, Snooping Newsie gets +1/+1 and has lifelink. + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), + DifferentManaValuesInGraveCondition.FIVE, "as long as there are " + + "five or more mana values among cards in your graveyard, {this} gets +1/+1" + )); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(LifelinkAbility.getInstance()), + DifferentManaValuesInGraveCondition.FIVE, "and has lifelink" + )); + this.addAbility(ability.addHint(DifferentManaValuesInGraveHint.instance)); + } + + private SnoopingNewsie(final SnoopingNewsie card) { + super(card); + } + + @Override + public SnoopingNewsie copy() { + return new SnoopingNewsie(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SnowhornRider.java b/Mage.Sets/src/mage/cards/s/SnowhornRider.java index ad798dd990f..cd543fbe5cf 100644 --- a/Mage.Sets/src/mage/cards/s/SnowhornRider.java +++ b/Mage.Sets/src/mage/cards/s/SnowhornRider.java @@ -28,7 +28,7 @@ public final class SnowhornRider extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); // Morph {2}{G}{U}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{G}{U}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{G}{U}{R}"))); } private SnowhornRider(final SnowhornRider card) { diff --git a/Mage.Sets/src/mage/cards/s/SocialClimber.java b/Mage.Sets/src/mage/cards/s/SocialClimber.java new file mode 100644 index 00000000000..8d60426f659 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SocialClimber.java @@ -0,0 +1,38 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.AllianceAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SocialClimber extends CardImpl { + + public SocialClimber(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Alliance — Whenever another creature enters the battlefield under your control, you gain 1 life. + this.addAbility(new AllianceAbility(new GainLifeEffect(1))); + } + + private SocialClimber(final SocialClimber card) { + super(card); + } + + @Override + public SocialClimber copy() { + return new SocialClimber(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SokenzanCrucibleOfDefiance.java b/Mage.Sets/src/mage/cards/s/SokenzanCrucibleOfDefiance.java index 78fa7718c1b..9ed9f3e443a 100644 --- a/Mage.Sets/src/mage/cards/s/SokenzanCrucibleOfDefiance.java +++ b/Mage.Sets/src/mage/cards/s/SokenzanCrucibleOfDefiance.java @@ -3,7 +3,6 @@ package mage.cards.s; import mage.abilities.Ability; import mage.abilities.costs.costadjusters.LegendaryCreatureCostAdjuster; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.ChannelAbility; import mage.abilities.keyword.HasteAbility; @@ -34,9 +33,9 @@ public final class SokenzanCrucibleOfDefiance extends CardImpl { this.addAbility(new RedManaAbility()); // Channel — {3}{R}, Discard Sokenzan, Crucible of Defiance: Create two colorless 1/1 Spirit creature tokens. They gain haste until end of turn. This ability costs {1} less to activate for each legendary creature you control. - Ability ability = new ChannelAbility("{3}{R}", new CreateTokenEffect(new SpiritToken(), 2)); + Ability ability = new ChannelAbility("{3}{R}", new SokenzanCrucibleOfDefianceEffect()); ability.setCostAdjuster(LegendaryCreatureCostAdjuster.instance); - this.addAbility(ability); + this.addAbility(ability.addHint(LegendaryCreatureCostAdjuster.getHint())); } private SokenzanCrucibleOfDefiance(final SokenzanCrucibleOfDefiance card) { @@ -53,7 +52,7 @@ class SokenzanCrucibleOfDefianceEffect extends OneShotEffect { SokenzanCrucibleOfDefianceEffect() { super(Outcome.Benefit); - staticText = "create two colorless 1/1 Spirit creature tokens. They gain haste until end of turn. " + + staticText = "create two 1/1 colorless Spirit creature tokens. They gain haste until end of turn. " + "This ability costs {1} less to activate for each legendary creature you control"; } diff --git a/Mage.Sets/src/mage/cards/s/SolarTide.java b/Mage.Sets/src/mage/cards/s/SolarTide.java index 721b8080a79..414708c2a24 100644 --- a/Mage.Sets/src/mage/cards/s/SolarTide.java +++ b/Mage.Sets/src/mage/cards/s/SolarTide.java @@ -36,8 +36,7 @@ public final class SolarTide extends CardImpl { this.getSpellAbility().addEffect(new DestroyAllEffect(filter1)); // or destroy all creatures with power 3 or greater. - Mode mode = new Mode(); - mode.addEffect(new DestroyAllEffect(filter2)); + Mode mode = new Mode(new DestroyAllEffect(filter2)); this.getSpellAbility().getModes().addMode(mode); // Entwine-Sacrifice two lands. diff --git a/Mage.Sets/src/mage/cards/s/SoldeviMachinist.java b/Mage.Sets/src/mage/cards/s/SoldeviMachinist.java index afdaba0e44a..931b58d835a 100644 --- a/Mage.Sets/src/mage/cards/s/SoldeviMachinist.java +++ b/Mage.Sets/src/mage/cards/s/SoldeviMachinist.java @@ -75,7 +75,7 @@ class ArtifactAbilityManaCondition extends ManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { if (source != null && source.getAbilityType() == AbilityType.ACTIVATED) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object != null && object.isArtifact(game)) { return true; } diff --git a/Mage.Sets/src/mage/cards/s/SoldeviSteamBeast.java b/Mage.Sets/src/mage/cards/s/SoldeviSteamBeast.java index 4271fed44e3..aaa5bc6a884 100644 --- a/Mage.Sets/src/mage/cards/s/SoldeviSteamBeast.java +++ b/Mage.Sets/src/mage/cards/s/SoldeviSteamBeast.java @@ -1,4 +1,3 @@ - package mage.cards.s; import java.util.UUID; @@ -34,7 +33,7 @@ public final class SoldeviSteamBeast extends CardImpl { this.addAbility(ability); // {2}: Regenerate Soldevi Steam Beast. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new GenericManaCost(3))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new GenericManaCost(2))); } private SoldeviSteamBeast(final SoldeviSteamBeast card) { diff --git a/Mage.Sets/src/mage/cards/s/Solfatara.java b/Mage.Sets/src/mage/cards/s/Solfatara.java index fad0047d17b..0d1f712f79c 100644 --- a/Mage.Sets/src/mage/cards/s/Solfatara.java +++ b/Mage.Sets/src/mage/cards/s/Solfatara.java @@ -68,7 +68,7 @@ class SolfataraEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't play lands this turn (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/s/SolitaryCamel.java b/Mage.Sets/src/mage/cards/s/SolitaryCamel.java index f8e20814b88..9290f217c4b 100644 --- a/Mage.Sets/src/mage/cards/s/SolitaryCamel.java +++ b/Mage.Sets/src/mage/cards/s/SolitaryCamel.java @@ -1,13 +1,8 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.OrCondition; -import mage.abilities.condition.common.CardsInControllerGraveyardCondition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.condition.common.DesertControlledOrGraveyardCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.LifelinkAbility; @@ -15,24 +10,14 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.common.FilterControlledPermanent; + +import java.util.UUID; /** - * * @author spjspj */ public final class SolitaryCamel extends CardImpl { - private static final FilterControlledPermanent filterDesertPermanent = new FilterControlledPermanent("Desert"); - private static final FilterCard filterDesertCard = new FilterCard("Desert card"); - - static { - filterDesertPermanent.add(SubType.DESERT.getPredicate()); - filterDesertCard.add(SubType.DESERT.getPredicate()); - } - public SolitaryCamel(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); @@ -41,13 +26,11 @@ public final class SolitaryCamel extends CardImpl { this.toughness = new MageInt(2); // Solitary Camel has lifelink as long as you control a desert or there is a desert card in your graveyard. - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( new GainAbilitySourceEffect(LifelinkAbility.getInstance()), - new OrCondition( - new PermanentsOnTheBattlefieldCondition(new FilterControlledPermanent(filterDesertPermanent)), - new CardsInControllerGraveyardCondition(1, filterDesertCard)), - "{this} has lifelink as long as you control a desert or there is a desert card in your graveyard.")); - this.addAbility(ability); + DesertControlledOrGraveyardCondition.instance, "{this} has lifelink as long as " + + "you control a desert or there is a desert card in your graveyard." + )).addHint(DesertControlledOrGraveyardCondition.getHint())); } private SolitaryCamel(final SolitaryCamel card) { diff --git a/Mage.Sets/src/mage/cards/s/SongOfSerenity.java b/Mage.Sets/src/mage/cards/s/SongOfSerenity.java index 953646afb31..17247495746 100644 --- a/Mage.Sets/src/mage/cards/s/SongOfSerenity.java +++ b/Mage.Sets/src/mage/cards/s/SongOfSerenity.java @@ -72,6 +72,6 @@ class SongOfSerenityRestrictionEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filter.match(permanent, source.getControllerId(), source, game); } } diff --git a/Mage.Sets/src/mage/cards/s/SootfeatherFlock.java b/Mage.Sets/src/mage/cards/s/SootfeatherFlock.java index 3927f63ec3d..566a0316102 100644 --- a/Mage.Sets/src/mage/cards/s/SootfeatherFlock.java +++ b/Mage.Sets/src/mage/cards/s/SootfeatherFlock.java @@ -26,7 +26,7 @@ public final class SootfeatherFlock extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Morph {3}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{B}"))); } private SootfeatherFlock(final SootfeatherFlock card) { diff --git a/Mage.Sets/src/mage/cards/s/Soothsaying.java b/Mage.Sets/src/mage/cards/s/Soothsaying.java index 99ac9526421..5b5294375e5 100644 --- a/Mage.Sets/src/mage/cards/s/Soothsaying.java +++ b/Mage.Sets/src/mage/cards/s/Soothsaying.java @@ -29,7 +29,7 @@ public final class Soothsaying extends CardImpl { // {X}: Look at the top X cards of your library, then put them back in any order. Effect effect = new LookLibraryControllerEffect(ManacostVariableValue.REGULAR); effect.setText("Look at the top X cards of your library, then put them back in any order"); - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("X"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{X}"))); } private Soothsaying(final Soothsaying card) { diff --git a/Mage.Sets/src/mage/cards/c/ChiefJimHopper.java b/Mage.Sets/src/mage/cards/s/SophinaSpearsageDeserter.java similarity index 83% rename from Mage.Sets/src/mage/cards/c/ChiefJimHopper.java rename to Mage.Sets/src/mage/cards/s/SophinaSpearsageDeserter.java index b6c0192a0f2..a37d62dff78 100644 --- a/Mage.Sets/src/mage/cards/c/ChiefJimHopper.java +++ b/Mage.Sets/src/mage/cards/s/SophinaSpearsageDeserter.java @@ -1,4 +1,4 @@ -package mage.cards.c; +package mage.cards.s; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; @@ -21,7 +21,7 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class ChiefJimHopper extends CardImpl { +public final class SophinaSpearsageDeserter extends CardImpl { private static final FilterPermanent filter = new FilterAttackingCreature(); @@ -31,7 +31,7 @@ public final class ChiefJimHopper extends CardImpl { private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); - public ChiefJimHopper(UUID ownerId, CardSetInfo setInfo) { + public SophinaSpearsageDeserter(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{W}"); this.addSuperType(SuperType.LEGENDARY); @@ -51,12 +51,12 @@ public final class ChiefJimHopper extends CardImpl { this.addAbility(FriendsForeverAbility.getInstance()); } - private ChiefJimHopper(final ChiefJimHopper card) { + private SophinaSpearsageDeserter(final SophinaSpearsageDeserter card) { super(card); } @Override - public ChiefJimHopper copy() { - return new ChiefJimHopper(this); + public SophinaSpearsageDeserter copy() { + return new SophinaSpearsageDeserter(this); } } diff --git a/Mage.Sets/src/mage/cards/s/SorcererClass.java b/Mage.Sets/src/mage/cards/s/SorcererClass.java index 98ae21ab217..a6ddd0736c0 100644 --- a/Mage.Sets/src/mage/cards/s/SorcererClass.java +++ b/Mage.Sets/src/mage/cards/s/SorcererClass.java @@ -116,7 +116,7 @@ class SorcererClassManaCondition extends ManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { if (source instanceof SpellAbility) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && object.isInstantOrSorcery(game); } return source instanceof ClassLevelAbility; diff --git a/Mage.Sets/src/mage/cards/s/SorcerousSpyglass.java b/Mage.Sets/src/mage/cards/s/SorcerousSpyglass.java index 1c3aabe8775..b0ec479da6d 100644 --- a/Mage.Sets/src/mage/cards/s/SorcerousSpyglass.java +++ b/Mage.Sets/src/mage/cards/s/SorcerousSpyglass.java @@ -63,10 +63,10 @@ class SorcerousSpyglassEntersEffect extends ChooseACardNameEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null) { TargetOpponent target = new TargetOpponent(true); - if (player.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + if (player.choose(Outcome.Benefit, target, source, game)) { Player opponent = game.getPlayer(target.getFirstTarget()); if (opponent != null) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); player.lookAtCards(sourceObject != null ? sourceObject.getIdName() : null, opponent.getHand(), game); player.chooseUse(Outcome.Benefit, "Press Ok to name a card", "You won't be able to resize the window showing opponents hand once you do", diff --git a/Mage.Sets/src/mage/cards/s/SorinGrimNemesis.java b/Mage.Sets/src/mage/cards/s/SorinGrimNemesis.java index 3f480e66256..ddd6121791a 100644 --- a/Mage.Sets/src/mage/cards/s/SorinGrimNemesis.java +++ b/Mage.Sets/src/mage/cards/s/SorinGrimNemesis.java @@ -2,7 +2,6 @@ package mage.cards.s; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.GetXLoyaltyValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; @@ -28,7 +27,7 @@ public final class SorinGrimNemesis extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SORIN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(6)); + this.setStartingLoyalty(6); // +1: Reveal the top card of your library and put that card into your hand. Each opponent loses life equal to its converted mana cost. this.addAbility(new LoyaltyAbility(new SorinGrimNemesisRevealEffect(), 1)); diff --git a/Mage.Sets/src/mage/cards/s/SorinImperiousBloodlord.java b/Mage.Sets/src/mage/cards/s/SorinImperiousBloodlord.java index e1a7394fd9c..b5431960c15 100644 --- a/Mage.Sets/src/mage/cards/s/SorinImperiousBloodlord.java +++ b/Mage.Sets/src/mage/cards/s/SorinImperiousBloodlord.java @@ -2,7 +2,6 @@ package mage.cards.s; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.effects.OneShotEffect; @@ -52,7 +51,7 @@ public final class SorinImperiousBloodlord extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SORIN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Target creature you control gains deathtouch and lifelink until end of turn. If it's a Vampire, put a +1/+1 counter on it. Ability ability = new LoyaltyAbility(new SorinImperiousBloodlordEffect(), 1); diff --git a/Mage.Sets/src/mage/cards/s/SorinLordOfInnistrad.java b/Mage.Sets/src/mage/cards/s/SorinLordOfInnistrad.java index 0c4afea24bd..5a32d0a34a8 100644 --- a/Mage.Sets/src/mage/cards/s/SorinLordOfInnistrad.java +++ b/Mage.Sets/src/mage/cards/s/SorinLordOfInnistrad.java @@ -6,7 +6,6 @@ import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -46,7 +45,7 @@ public final class SorinLordOfInnistrad extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SORIN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Create a 1/1 black Vampire creature token with lifelink. this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new SorinLordOfInnistradVampireToken()), 1)); diff --git a/Mage.Sets/src/mage/cards/s/SorinMarkov.java b/Mage.Sets/src/mage/cards/s/SorinMarkov.java index ec6f36d0976..4ca04ea6b31 100644 --- a/Mage.Sets/src/mage/cards/s/SorinMarkov.java +++ b/Mage.Sets/src/mage/cards/s/SorinMarkov.java @@ -4,7 +4,6 @@ package mage.cards.s; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.GainLifeEffect; @@ -32,11 +31,11 @@ public final class SorinMarkov extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SORIN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +2: Sorin Markov deals 2 damage to any target and you gain 2 life. LoyaltyAbility ability1 = new LoyaltyAbility(new DamageTargetEffect(2), 2); - ability1.addEffect(new GainLifeEffect(2)); + ability1.addEffect(new GainLifeEffect(2).concatBy("and")); ability1.addTarget(new TargetAnyTarget()); this.addAbility(ability1); diff --git a/Mage.Sets/src/mage/cards/s/SorinSolemnVisitor.java b/Mage.Sets/src/mage/cards/s/SorinSolemnVisitor.java index c4db2f47e8f..16670a0dfb4 100644 --- a/Mage.Sets/src/mage/cards/s/SorinSolemnVisitor.java +++ b/Mage.Sets/src/mage/cards/s/SorinSolemnVisitor.java @@ -3,7 +3,6 @@ package mage.cards.s; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -31,7 +30,7 @@ public final class SorinSolemnVisitor extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SORIN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Until your next turn, creatures you control get +1/+0 and gain lifelink. Effect effect = new BoostControlledEffect(1, 0, Duration.UntilYourNextTurn, StaticFilters.FILTER_PERMANENT_CREATURES); diff --git a/Mage.Sets/src/mage/cards/s/SorinTheMirthless.java b/Mage.Sets/src/mage/cards/s/SorinTheMirthless.java index bdb1a4a0563..9985c1a51cf 100644 --- a/Mage.Sets/src/mage/cards/s/SorinTheMirthless.java +++ b/Mage.Sets/src/mage/cards/s/SorinTheMirthless.java @@ -4,7 +4,6 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DamageTargetEffect; @@ -27,7 +26,7 @@ public final class SorinTheMirthless extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SORIN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Look at the top card of your library. You may reveal that card and put it into your hand. If you do, you lose life equal to its mana value. this.addAbility(new LoyaltyAbility(new SorinTheMirthlessEffect(), 1)); diff --git a/Mage.Sets/src/mage/cards/s/SorinVampireLord.java b/Mage.Sets/src/mage/cards/s/SorinVampireLord.java index e82870f88db..0be6b50ddad 100644 --- a/Mage.Sets/src/mage/cards/s/SorinVampireLord.java +++ b/Mage.Sets/src/mage/cards/s/SorinVampireLord.java @@ -2,7 +2,6 @@ package mage.cards.s; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.DamageTargetEffect; @@ -35,7 +34,7 @@ public final class SorinVampireLord extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SORIN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Up to one target creature gets +2/+0 until end of turn. Ability ability = new LoyaltyAbility(new BoostTargetEffect(2, 0), 1); diff --git a/Mage.Sets/src/mage/cards/s/SorinVengefulBloodlord.java b/Mage.Sets/src/mage/cards/s/SorinVengefulBloodlord.java index a19cba0367f..fad3bfe7b01 100644 --- a/Mage.Sets/src/mage/cards/s/SorinVengefulBloodlord.java +++ b/Mage.Sets/src/mage/cards/s/SorinVengefulBloodlord.java @@ -2,7 +2,6 @@ package mage.cards.s; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.costs.Cost; @@ -39,7 +38,7 @@ public final class SorinVengefulBloodlord extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SORIN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // As long as it's your turn, creatures and planeswalkers you control have lifelink. this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( diff --git a/Mage.Sets/src/mage/cards/s/SorrowsPath.java b/Mage.Sets/src/mage/cards/s/SorrowsPath.java index 29d8fc9ba71..7f6deeaffb6 100644 --- a/Mage.Sets/src/mage/cards/s/SorrowsPath.java +++ b/Mage.Sets/src/mage/cards/s/SorrowsPath.java @@ -44,7 +44,7 @@ public final class SorrowsPath extends CardImpl { // {T}: Choose two target blocking creatures an opponent controls. If each of those creatures could block all creatures that the other is blocking, remove both of them from combat. Each one then blocks all creatures the other was blocking. Ability ability = new SimpleActivatedAbility(new SorrowsPathSwitchBlockersEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanentSameController(2, 2, filter, false)); + ability.addTarget(new TargetCreaturePermanentSameController(2, filter)); this.addAbility(ability); // Whenever Sorrow's Path becomes tapped, it deals 2 damage to you and each creature you control. diff --git a/Mage.Sets/src/mage/cards/s/SoulCollector.java b/Mage.Sets/src/mage/cards/s/SoulCollector.java index 8595cf79ccc..a59acd0df5e 100644 --- a/Mage.Sets/src/mage/cards/s/SoulCollector.java +++ b/Mage.Sets/src/mage/cards/s/SoulCollector.java @@ -31,7 +31,7 @@ public final class SoulCollector extends CardImpl { this.addAbility(new DealtDamageAndDiedTriggeredAbility(new ReturnToBattlefieldUnderYourControlTargetEffect())); // Morph {B}{B}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{B}{B}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{B}{B}{B}"))); } private SoulCollector(final SoulCollector card) { diff --git a/Mage.Sets/src/mage/cards/s/SoulFoundry.java b/Mage.Sets/src/mage/cards/s/SoulFoundry.java index 0cfa5ac01d2..931c716c28b 100644 --- a/Mage.Sets/src/mage/cards/s/SoulFoundry.java +++ b/Mage.Sets/src/mage/cards/s/SoulFoundry.java @@ -14,6 +14,7 @@ import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -38,7 +39,7 @@ public final class SoulFoundry extends CardImpl { // Imprint - When Soul Foundry enters the battlefield, you may exile a creature card from your hand. this.addAbility(new EntersBattlefieldTriggeredAbility( new SoulFoundryImprintEffect(), true) - .withFlavorWord("Imprint") + .setAbilityWord(AbilityWord.IMPRINT) ); // {X}, {T}: Create a token that's a copy of the exiled card. X is the converted mana cost of that card. @@ -107,7 +108,7 @@ class SoulFoundryImprintEffect extends OneShotEffect { if (controller != null) { if (!controller.getHand().isEmpty()) { TargetCard target = new TargetCard(Zone.HAND, filter); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + if (target.canChoose(source.getControllerId(), source, game) && controller.choose(Outcome.Benefit, controller.getHand(), target, game)) { Card card = controller.getHand().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/s/SoulLink.java b/Mage.Sets/src/mage/cards/s/SoulLink.java index 3713ebe0a68..b77f6e96e09 100644 --- a/Mage.Sets/src/mage/cards/s/SoulLink.java +++ b/Mage.Sets/src/mage/cards/s/SoulLink.java @@ -1,11 +1,9 @@ - package mage.cards.s; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.common.DealsDamageAttachedTriggeredAbility; import mage.abilities.common.DealtDamageAttachedTriggeredAbility; -import mage.abilities.dynamicvalue.common.NumericSetToEffectValues; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.keyword.EnchantAbility; @@ -32,13 +30,13 @@ public final class SoulLink extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // Whenever enchanted creature deals damage, you gain that much life. this.addAbility(new DealsDamageAttachedTriggeredAbility(Zone.BATTLEFIELD, - new GainLifeEffect(new NumericSetToEffectValues("that much", "damage")), false)); + new GainLifeEffect(SavedDamageValue.MUCH), false)); // Whenever enchanted creature is dealt damage, you gain that much life. - this.addAbility(new DealtDamageAttachedTriggeredAbility(new GainLifeEffect(new NumericSetToEffectValues("that much", "damage")), false)); + this.addAbility(new DealtDamageAttachedTriggeredAbility(new GainLifeEffect(SavedDamageValue.MUCH), false)); } private SoulLink(final SoulLink card) { diff --git a/Mage.Sets/src/mage/cards/s/SoulManipulation.java b/Mage.Sets/src/mage/cards/s/SoulManipulation.java index 42ccfffa3db..691442605f8 100644 --- a/Mage.Sets/src/mage/cards/s/SoulManipulation.java +++ b/Mage.Sets/src/mage/cards/s/SoulManipulation.java @@ -29,8 +29,7 @@ public final class SoulManipulation extends CardImpl { this.getSpellAbility().addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_CREATURE).withChooseHint("counter it")); // and/or return target creature card from your graveyard to your hand. - Mode mode = new Mode(); - mode.addEffect(new ReturnFromGraveyardToHandTargetEffect()); + Mode mode = new Mode(new ReturnFromGraveyardToHandTargetEffect()); mode.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD).withChooseHint("return it to hand")); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/s/SoulOfEmancipation.java b/Mage.Sets/src/mage/cards/s/SoulOfEmancipation.java new file mode 100644 index 00000000000..7db0c5cb74d --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SoulOfEmancipation.java @@ -0,0 +1,105 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.Controllable; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.Angel33Token; +import mage.target.TargetPermanent; + +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class SoulOfEmancipation extends CardImpl { + + private static final FilterPermanent filter = new FilterNonlandPermanent("other nonland permanents"); + + static { + filter.add(AnotherPredicate.instance); + } + + public SoulOfEmancipation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{W}{U}"); + + this.subtype.add(SubType.AVATAR); + this.power = new MageInt(5); + this.toughness = new MageInt(7); + + // When Soul of Emancipation enters the battlefield, destroy up to three other target nonland permanents. For each of those permanents, its controller creates a 3/3 white Angel creature token with flying. + Ability ability = new EntersBattlefieldTriggeredAbility(new SoulOfEmancipationEffect()); + ability.addTarget(new TargetPermanent(0, 3, filter)); + this.addAbility(ability); + } + + private SoulOfEmancipation(final SoulOfEmancipation card) { + super(card); + } + + @Override + public SoulOfEmancipation copy() { + return new SoulOfEmancipation(this); + } +} + +class SoulOfEmancipationEffect extends OneShotEffect { + + SoulOfEmancipationEffect() { + super(Outcome.Benefit); + staticText = "destroy up to three other target nonland permanents. For each of those permanents, " + + "its controller creates a 3/3 white Angel creature token with flying"; + } + + private SoulOfEmancipationEffect(final SoulOfEmancipationEffect effect) { + super(effect); + } + + @Override + public SoulOfEmancipationEffect copy() { + return new SoulOfEmancipationEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + List permanents = this + .getTargetPointer() + .getTargets(game, source) + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (permanents.isEmpty()) { + return false; + } + Map playerMap = permanents + .stream() + .collect(Collectors.toMap( + Controllable::getControllerId, + x -> 1, + Integer::sum + )); + for (Permanent permanent : permanents) { + permanent.destroy(source, game); + } + for (Map.Entry entry : playerMap.entrySet()) { + new Angel33Token().putOntoBattlefield(entry.getValue(), game, source, entry.getKey()); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SoulOfShandalar.java b/Mage.Sets/src/mage/cards/s/SoulOfShandalar.java index 76a85000581..cff9b243d55 100644 --- a/Mage.Sets/src/mage/cards/s/SoulOfShandalar.java +++ b/Mage.Sets/src/mage/cards/s/SoulOfShandalar.java @@ -118,16 +118,16 @@ class SoulOfShandalarTarget extends TargetPermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set availablePossibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set availablePossibleTargets = super.possibleTargets(sourceControllerId, source, game); Set possibleTargets = new HashSet<>(); - MageObject object = game.getObject(sourceId); + MageObject object = game.getObject(source); for (StackObject item : game.getState().getStack()) { - if (item.getId().equals(sourceId)) { + if (item.getId().equals(source.getSourceId())) { object = item; } - if (item.getSourceId().equals(sourceId)) { + if (item.getSourceId().equals(source.getSourceId())) { object = item; } } diff --git a/Mage.Sets/src/mage/cards/s/SoulReap.java b/Mage.Sets/src/mage/cards/s/SoulReap.java index f43e3b84089..e555ecec3d6 100644 --- a/Mage.Sets/src/mage/cards/s/SoulReap.java +++ b/Mage.Sets/src/mage/cards/s/SoulReap.java @@ -1,19 +1,14 @@ - package mage.cards.s; -import java.util.UUID; +import mage.MageObjectReference; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.condition.Condition; -import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.WatcherScope; -import mage.filter.FilterSpell; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; @@ -26,9 +21,10 @@ import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import mage.watchers.Watcher; +import java.util.*; + /** - * - * @author jeffwadsworth + * @author TheElk801 */ public final class SoulReap extends CardImpl { @@ -38,17 +34,13 @@ public final class SoulReap extends CardImpl { filter.add(Predicates.not(new ColorPredicate(ObjectColor.GREEN))); } - private String rule = "Its controller loses 3 life if you've cast another black spell this turn"; - public SoulReap(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); // Destroy target nongreen creature. Its controller loses 3 life if you've cast another black spell this turn. - this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addEffect(new SoulReapEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); - this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new SoulReapEffect(), new CastBlackSpellThisTurnCondition(), rule)); - this.getSpellAbility().addWatcher(new SoulReapWatcher(this.getId())); - + this.getSpellAbility().addWatcher(new SoulReapWatcher()); } private SoulReap(final SoulReap card) { @@ -61,59 +53,12 @@ public final class SoulReap extends CardImpl { } } -class CastBlackSpellThisTurnCondition implements Condition { - - @Override - public boolean apply(Game game, Ability source) { - SoulReapWatcher watcher = game.getState().getWatcher(SoulReapWatcher.class, source.getControllerId()); - if (watcher != null) { - return watcher.conditionMet(); - } - return false; - } -} - -class SoulReapWatcher extends Watcher { - - private static final FilterSpell filter = new FilterSpell(); - - static { - filter.add(new ColorPredicate(ObjectColor.BLACK)); - } - - private UUID cardId; - - public SoulReapWatcher(UUID cardId) { - super(WatcherScope.PLAYER); - this.cardId = cardId; - } - - @Override - public void watch(GameEvent event, Game game) { - if (condition == true) { //no need to check - condition has already occured - return; - } - if (event.getType() == GameEvent.EventType.SPELL_CAST - && controllerId.equals(event.getPlayerId())) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (!spell.getSourceId().equals(cardId) && filter.match(spell, game)) { - condition = true; - } - } - } - - @Override - public void reset() { - super.reset(); - condition = false; - } -} - class SoulReapEffect extends OneShotEffect { public SoulReapEffect() { super(Outcome.Detriment); - this.staticText = "Its controller loses 3 life if you've cast another black spell this turn"; + this.staticText = "destroy target nongreen creature. Its controller " + + "loses 3 life if you've cast another black spell this turn"; } public SoulReapEffect(final SoulReapEffect effect) { @@ -127,14 +72,55 @@ class SoulReapEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent creature = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); - if (creature != null) { - Player controller = game.getPlayer(creature.getControllerId()); - if (controller != null) { - controller.loseLife(3, game, source, false); - return true; - } + Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (creature == null) { + return false; } - return false; + creature.destroy(source, game); + if (!SoulReapWatcher.checkSpell(source, game)) { + return true; + } + Player controller = game.getPlayer(creature.getControllerId()); + if (controller != null) { + controller.loseLife(3, game, source, false); + } + return true; + } +} + +class SoulReapWatcher extends Watcher { + + private final Map> spellMap = new HashMap<>(); + private static final List emptyList = new ArrayList<>(); + + SoulReapWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != EventType.SPELL_CAST) { + return; + } + Spell spell = game.getSpell(event.getSourceId()); + if (spell != null && spell.getColor(game).isBlack()) { + spellMap.computeIfAbsent(event.getPlayerId(), x -> new ArrayList<>()) + .add(new MageObjectReference(event.getSourceId(), game)); + } + } + + @Override + public void reset() { + super.reset(); + spellMap.clear(); + } + + static boolean checkSpell(Ability source, Game game) { + return game.getState() + .getWatcher(SoulReapWatcher.class) + .spellMap + .getOrDefault(source.getControllerId(), emptyList) + .stream() + .anyMatch(mor -> !mor.refersTo(source, game)); } } diff --git a/Mage.Sets/src/mage/cards/s/SoulShatter.java b/Mage.Sets/src/mage/cards/s/SoulShatter.java index b690afb3380..77030b36cd0 100644 --- a/Mage.Sets/src/mage/cards/s/SoulShatter.java +++ b/Mage.Sets/src/mage/cards/s/SoulShatter.java @@ -1,19 +1,13 @@ package mage.cards.s; -import mage.MageObject; import mage.abilities.effects.common.SacrificeOpponentsEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.TargetController; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; -import mage.filter.predicate.ObjectSourcePlayer; -import mage.filter.predicate.ObjectSourcePlayerPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.filter.predicate.permanent.MaxManaValueControlledPermanentPredicate; -import java.util.Objects; import java.util.UUID; /** @@ -27,7 +21,7 @@ public final class SoulShatter extends CardImpl { ); static { - filter.add(SoulShatterPredicate.instance); + filter.add(MaxManaValueControlledPermanentPredicate.instance); } public SoulShatter(UUID ownerId, CardSetInfo setInfo) { @@ -46,25 +40,3 @@ public final class SoulShatter extends CardImpl { return new SoulShatter(this); } } - -enum SoulShatterPredicate implements ObjectSourcePlayerPredicate { - instance; - - private static final FilterPermanent filter = new FilterCreatureOrPlaneswalkerPermanent(); - - static { - filter.add(TargetController.YOU.getControllerPredicate()); - } - - @Override - public boolean apply(ObjectSourcePlayer input, Game game) { - int cmc = game.getBattlefield() - .getActivePermanents(filter, input.getPlayerId(), game) - .stream() - .filter(Objects::nonNull) - .mapToInt(MageObject::getManaValue) - .max() - .orElse(0); - return input.getObject().getManaValue() >= cmc; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SoulStairExpedition.java b/Mage.Sets/src/mage/cards/s/SoulStairExpedition.java index 8f03fab0226..a6be5ffaa24 100644 --- a/Mage.Sets/src/mage/cards/s/SoulStairExpedition.java +++ b/Mage.Sets/src/mage/cards/s/SoulStairExpedition.java @@ -6,7 +6,7 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.CompositeCost; import mage.abilities.costs.common.RemoveCountersSourceCost; import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -30,7 +30,7 @@ public final class SoulStairExpedition extends CardImpl { // Remove three quest counters from Soul Stair Expedition and sacrifice it: Return up to two target creature cards from your graveyard to your hand. Ability ability = new SimpleActivatedAbility( - new ReturnToHandTargetEffect(), + new ReturnFromGraveyardToHandTargetEffect(), new CompositeCost( new RemoveCountersSourceCost(CounterType.QUEST.createInstance(3)), new SacrificeSourceCost(), diff --git a/Mage.Sets/src/mage/cards/s/SoulcipherBoard.java b/Mage.Sets/src/mage/cards/s/SoulcipherBoard.java index 1f476a6b796..3566861d1b3 100644 --- a/Mage.Sets/src/mage/cards/s/SoulcipherBoard.java +++ b/Mage.Sets/src/mage/cards/s/SoulcipherBoard.java @@ -9,8 +9,8 @@ import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; @@ -19,7 +19,6 @@ 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.StaticFilters; @@ -43,10 +42,9 @@ public final class SoulcipherBoard extends CardImpl { )); // {1}{U}, {T}: Look at the top two cards of your library. Put one of them into your graveyard. - Ability ability = new SimpleActivatedAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(2), false, StaticValue.get(1), StaticFilters.FILTER_CARD, - Zone.LIBRARY, true, false, false, Zone.GRAVEYARD, false - ).setText("look at the top two cards of your library. Put one of them into your graveyard"), new ManaCostsImpl<>("{1}{U}")); + Ability ability = new SimpleActivatedAbility( + new LookLibraryAndPickControllerEffect(2, 1, PutCards.GRAVEYARD, PutCards.TOP_ANY), + new ManaCostsImpl<>("{1}{U}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/SoulfireEruption.java b/Mage.Sets/src/mage/cards/s/SoulfireEruption.java index 9b04b7aee81..f9df35d37e4 100644 --- a/Mage.Sets/src/mage/cards/s/SoulfireEruption.java +++ b/Mage.Sets/src/mage/cards/s/SoulfireEruption.java @@ -13,6 +13,7 @@ import mage.players.Player; import mage.target.Target; import mage.target.common.TargetAnyTarget; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; import java.util.Collection; import java.util.UUID; @@ -119,6 +120,7 @@ class SoulfireEruptionCastEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + objectId = CardUtil.getMainCardId(game, objectId); // for split cards return source.isControlledBy(affectedControllerId) && objectId.equals(getTargetPointer().getFirst(game, source)); } diff --git a/Mage.Sets/src/mage/cards/s/SoulhunterRakshasa.java b/Mage.Sets/src/mage/cards/s/SoulhunterRakshasa.java index 2065ee9a530..dbc8ab39489 100644 --- a/Mage.Sets/src/mage/cards/s/SoulhunterRakshasa.java +++ b/Mage.Sets/src/mage/cards/s/SoulhunterRakshasa.java @@ -75,7 +75,7 @@ class SoulhunterRakshasaEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int amount = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int amount = game.getBattlefield().count(filter, source.getControllerId(), source, game); if (amount > 0) { Player player = game.getPlayer(source.getFirstTarget()); if (player != null) { diff --git a/Mage.Sets/src/mage/cards/s/SoullessOne.java b/Mage.Sets/src/mage/cards/s/SoullessOne.java index 7d64872e1a7..cca6e6920d3 100644 --- a/Mage.Sets/src/mage/cards/s/SoullessOne.java +++ b/Mage.Sets/src/mage/cards/s/SoullessOne.java @@ -56,7 +56,7 @@ class SoullessOneDynamicCount implements DynamicValue { zombiesBattlefield.add(SubType.ZOMBIE.getPredicate()); zombiesInGraveyard.add(SubType.ZOMBIE.getPredicate()); - int count = game.getBattlefield().count(zombiesBattlefield, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + int count = game.getBattlefield().count(zombiesBattlefield, sourceAbility.getControllerId(), sourceAbility, game); for (UUID playerId : game.getState().getPlayersInRange(sourceAbility.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { diff --git a/Mage.Sets/src/mage/cards/s/Soulquake.java b/Mage.Sets/src/mage/cards/s/Soulquake.java index b60cc69a706..97a05099b35 100644 --- a/Mage.Sets/src/mage/cards/s/Soulquake.java +++ b/Mage.Sets/src/mage/cards/s/Soulquake.java @@ -65,7 +65,7 @@ class SoulquakeEffect extends OneShotEffect { return false; } Set cardsToHand = new LinkedHashSet<>(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { cardsToHand.add((Card) permanent); } for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { diff --git a/Mage.Sets/src/mage/cards/s/SoulstealerAxe.java b/Mage.Sets/src/mage/cards/s/SoulstealerAxe.java new file mode 100644 index 00000000000..addb47b7869 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SoulstealerAxe.java @@ -0,0 +1,81 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SoulstealerAxe extends CardImpl { + + public SoulstealerAxe(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature has trample. + this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( + TrampleAbility.getInstance(), AttachmentType.EQUIPMENT + ))); + + // Whenever equipped creature deals combat damage to a player, seek a card with mana value equal to that damage. + this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility( + new SoulstealerAxeEffect(), "equipped", false + )); + + // Equip {2} + this.addAbility(new EquipAbility(2)); + } + + private SoulstealerAxe(final SoulstealerAxe card) { + super(card); + } + + @Override + public SoulstealerAxe copy() { + return new SoulstealerAxe(this); + } +} + +class SoulstealerAxeEffect extends OneShotEffect { + + SoulstealerAxeEffect() { + super(Outcome.Benefit); + staticText = "seek a card with mana value equal to that damage"; + } + + private SoulstealerAxeEffect(final SoulstealerAxeEffect effect) { + super(effect); + } + + @Override + public SoulstealerAxeEffect copy() { + return new SoulstealerAxeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int damage = (Integer) getValue("damage"); + FilterCard filter = new FilterCard(); + filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, damage)); + return player.seekCard(filter, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SoultetherGolem.java b/Mage.Sets/src/mage/cards/s/SoultetherGolem.java index 450ac7f5828..22c9e0fb01d 100644 --- a/Mage.Sets/src/mage/cards/s/SoultetherGolem.java +++ b/Mage.Sets/src/mage/cards/s/SoultetherGolem.java @@ -1,11 +1,9 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.VanishingSacrificeAbility; import mage.abilities.keyword.VanishingUpkeepAbility; @@ -19,8 +17,9 @@ import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import java.util.UUID; + /** - * * @author fireshoes */ public final class SoultetherGolem extends CardImpl { @@ -33,7 +32,7 @@ public final class SoultetherGolem extends CardImpl { } public SoultetherGolem(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); this.subtype.add(SubType.GOLEM); this.power = new MageInt(3); this.toughness = new MageInt(3); @@ -46,7 +45,7 @@ public final class SoultetherGolem extends CardImpl { this.addAbility(new VanishingSacrificeAbility()); // Whenever another creature enters the battlefield under your control, put a time counter on Soultether Golem. - this.addAbility(new EntersBattlefieldAllTriggeredAbility( + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.TIME.createInstance(1)), filter, diff --git a/Mage.Sets/src/mage/cards/s/SovereignsOfLostAlara.java b/Mage.Sets/src/mage/cards/s/SovereignsOfLostAlara.java index b6f8cfb5367..a615474118e 100644 --- a/Mage.Sets/src/mage/cards/s/SovereignsOfLostAlara.java +++ b/Mage.Sets/src/mage/cards/s/SovereignsOfLostAlara.java @@ -37,7 +37,7 @@ public final class SovereignsOfLostAlara extends CardImpl { this.addAbility(new ExaltedAbility()); // Whenever a creature you control attacks alone, you may search your library for an Aura card that could enchant that creature, put it onto the battlefield attached to that creature, then shuffle your library. - this.addAbility(new AttacksAloneControlledTriggeredAbility(new SovereignsOfLostAlaraEffect())); + this.addAbility(new AttacksAloneControlledTriggeredAbility(new SovereignsOfLostAlaraEffect(), true, true)); } private SovereignsOfLostAlara(final SovereignsOfLostAlara card) { @@ -54,7 +54,7 @@ class SovereignsOfLostAlaraEffect extends OneShotEffect { public SovereignsOfLostAlaraEffect() { super(Outcome.BoostCreature); - staticText = "you may search your library for an Aura card that could enchant that creature, put it onto the battlefield attached to that creature, then shuffle"; + staticText = "search your library for an Aura card that could enchant that creature, put it onto the battlefield attached to that creature, then shuffle"; } public SovereignsOfLostAlaraEffect(final SovereignsOfLostAlaraEffect effect) { @@ -66,22 +66,21 @@ class SovereignsOfLostAlaraEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent attackingCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); if (controller != null && attackingCreature != null) { - FilterCard filter = new FilterCard("aura that could enchant the lone attacking creature"); + FilterCard filter = new FilterCard("Aura card that could enchant " + attackingCreature.getName()); filter.add(SubType.AURA.getPredicate()); filter.add(new AuraCardCanAttachToPermanentId(attackingCreature.getId())); - if (controller.chooseUse(Outcome.Benefit, "Search your library?", source, game)) { - TargetCardInLibrary target = new TargetCardInLibrary(filter); - target.setNotTarget(true); - if (controller.searchLibrary(target, source, game)) { - if (target.getFirstTarget() != null) { - Card aura = game.getCard(target.getFirstTarget()); - game.getState().setValue("attachTo:" + aura.getId(), attackingCreature); - controller.moveCards(aura, Zone.BATTLEFIELD, source, game); - return attackingCreature.addAttachment(aura.getId(), source, game); - } + TargetCardInLibrary target = new TargetCardInLibrary(filter); + target.setNotTarget(true); + if (controller.searchLibrary(target, source, game)) { + if (target.getFirstTarget() != null) { + Card aura = game.getCard(target.getFirstTarget()); + game.getState().setValue("attachTo:" + aura.getId(), attackingCreature); + controller.moveCards(aura, Zone.BATTLEFIELD, source, game); + attackingCreature.addAttachment(aura.getId(), source, game); } } controller.shuffleLibrary(source, game); + return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/s/SparasAdjudicators.java b/Mage.Sets/src/mage/cards/s/SparasAdjudicators.java new file mode 100644 index 00000000000..73a4e430a37 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SparasAdjudicators.java @@ -0,0 +1,49 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.GiveManaAbilityAndCastSourceAbility; +import mage.abilities.effects.common.combat.CantAttackBlockTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SparasAdjudicators extends CardImpl { + + public SparasAdjudicators(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{W}{U}"); + + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // When Spara's Adjudicators enters the battlefield, target creature an opponent controls can't attack or block until your next turn. + Ability ability = new EntersBattlefieldTriggeredAbility( + new CantAttackBlockTargetEffect(Duration.UntilYourNextTurn) + ); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + + // {2}, Exile Spara's Adjudicators from your hand: Target land gains "{T}: Add {G}, {W}, or {U}" until Spara's Adjudicators is cast from exile. You may cast Spara's Adjudicators for as long as it remains exiled. + this.addAbility(new GiveManaAbilityAndCastSourceAbility("GWU")); + } + + private SparasAdjudicators(final SparasAdjudicators card) { + super(card); + } + + @Override + public SparasAdjudicators copy() { + return new SparasAdjudicators(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SparasHeadquarters.java b/Mage.Sets/src/mage/cards/s/SparasHeadquarters.java new file mode 100644 index 00000000000..445d1fb86ff --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SparasHeadquarters.java @@ -0,0 +1,48 @@ +package mage.cards.s; + +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.keyword.CyclingAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SparasHeadquarters extends CardImpl { + + public SparasHeadquarters(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + this.subtype.add(SubType.FOREST); + this.subtype.add(SubType.PLAINS); + this.subtype.add(SubType.ISLAND); + + // ({T}: Add {G}, {W}, or {U}.) + this.addAbility(new GreenManaAbility()); + this.addAbility(new WhiteManaAbility()); + this.addAbility(new BlueManaAbility()); + + // Spara's Headquarters enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // Cycling {3} + this.addAbility(new CyclingAbility(new GenericManaCost(3))); + } + + private SparasHeadquarters(final SparasHeadquarters card) { + super(card); + } + + @Override + public SparasHeadquarters copy() { + return new SparasHeadquarters(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SparkFiend.java b/Mage.Sets/src/mage/cards/s/SparkFiend.java index 800544b13d7..71fe8ce7efd 100644 --- a/Mage.Sets/src/mage/cards/s/SparkFiend.java +++ b/Mage.Sets/src/mage/cards/s/SparkFiend.java @@ -68,7 +68,7 @@ class SparkFiendEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { int roll = controller.rollDice(outcome, source, game, 6, 2, 0).stream().mapToInt(x -> x).sum(); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject instanceof Permanent) { Permanent sourcePermanent = (Permanent) mageObject; if (roll == 2 || roll == 3 || roll == 12) { @@ -113,7 +113,7 @@ class SparkFiendUpkeepEffect extends OneShotEffect { if (game.getState().getValue("SparkFiend" + source.getSourceId().toString()) != null && (Integer) game.getState().getValue("SparkFiend" + source.getSourceId().toString()) != 0) { int roll = controller.rollDice(outcome, source, game, 6, 2, 0).stream().mapToInt(x -> x).sum(); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject instanceof Permanent) { Permanent sourcePermanent = (Permanent) mageObject; if (roll == 7) { diff --git a/Mage.Sets/src/mage/cards/s/SparkHarvest.java b/Mage.Sets/src/mage/cards/s/SparkHarvest.java index 9a3062e78e1..4466c10ae66 100644 --- a/Mage.Sets/src/mage/cards/s/SparkHarvest.java +++ b/Mage.Sets/src/mage/cards/s/SparkHarvest.java @@ -22,8 +22,8 @@ public final class SparkHarvest extends CardImpl { // As an additional cost to cast this spell, sacrifice a creature or pay {3}{B}. this.getSpellAbility().addCost(new OrCost( - new SacrificeTargetCost(new TargetControlledCreaturePermanent()), - new ManaCostsImpl<>("{3}{B}"), "sacrifice a creature or pay {3}{B}" + "sacrifice a creature or pay {3}{B}", new SacrificeTargetCost(new TargetControlledCreaturePermanent()), + new ManaCostsImpl<>("{3}{B}") )); // Destroy target creature or planeswalker. diff --git a/Mage.Sets/src/mage/cards/s/SparkmageApprentice.java b/Mage.Sets/src/mage/cards/s/SparkmageApprentice.java index 9af910cee4a..1fc00d76a1f 100644 --- a/Mage.Sets/src/mage/cards/s/SparkmageApprentice.java +++ b/Mage.Sets/src/mage/cards/s/SparkmageApprentice.java @@ -25,7 +25,7 @@ public final class SparkmageApprentice extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(1), false); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(1, "it"), false); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/Spawnbroker.java b/Mage.Sets/src/mage/cards/s/Spawnbroker.java index 58a9da3fa49..d9c342f7a27 100644 --- a/Mage.Sets/src/mage/cards/s/Spawnbroker.java +++ b/Mage.Sets/src/mage/cards/s/Spawnbroker.java @@ -69,11 +69,11 @@ class TargetControlledCreatureWithPowerGreaterOrLessThanOpponentPermanent extend } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); if(targetSource != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { possibleTargets.add(permanent.getId()); } @@ -118,12 +118,12 @@ class SpawnbrokerSecondTarget extends TargetPermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); if (firstTarget != null) { - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); if(targetSource != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { if (firstTarget.getPower().getValue() >= permanent.getPower().getValue()) { possibleTargets.add(permanent.getId()); diff --git a/Mage.Sets/src/mage/cards/s/SpeakeasyServer.java b/Mage.Sets/src/mage/cards/s/SpeakeasyServer.java new file mode 100644 index 00000000000..14d36d0d880 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpeakeasyServer.java @@ -0,0 +1,75 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author weirddan455 + */ +public final class SpeakeasyServer extends CardImpl { + + public SpeakeasyServer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); + + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Speakeasy Server enters the battlefield, you gain 1 life for each other creature you control. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SpeakeasyServerEffect())); + } + + private SpeakeasyServer(final SpeakeasyServer card) { + super(card); + } + + @Override + public SpeakeasyServer copy() { + return new SpeakeasyServer(this); + } +} + +class SpeakeasyServerEffect extends OneShotEffect { + + public SpeakeasyServerEffect() { + super(Outcome.GainLife); + this.staticText = "you gain 1 life for each other creature you control"; + } + + private SpeakeasyServerEffect(final SpeakeasyServerEffect effect) { + super(effect); + } + + @Override + public SpeakeasyServerEffect copy() { + return new SpeakeasyServerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + UUID controllerId = source.getControllerId(); + Player controller = game.getPlayer(controllerId); + if (controller == null) { + return false; + } + controller.gainLife(game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, controllerId, source, game), game, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpectralArcanist.java b/Mage.Sets/src/mage/cards/s/SpectralArcanist.java new file mode 100644 index 00000000000..14323e6474d --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpectralArcanist.java @@ -0,0 +1,164 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.*; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.Objects; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpectralArcanist extends CardImpl { + + public SpectralArcanist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.SPIRIT); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Spectral Arcanist enters the battlefield, you may cast an instant or sorcery spell with mana value less than or equal to the number of Spirits you control from a graveyard without paying its mana cost. If that spell would be put into a graveyard, exile it instead. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SpectralArcanistCastEffect()) + .addHint(SpectralArcanistCastEffect.getHint())); + } + + private SpectralArcanist(final SpectralArcanist card) { + super(card); + } + + @Override + public SpectralArcanist copy() { + return new SpectralArcanist(this); + } +} + +class SpectralArcanistCastEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SPIRIT); + private static final Hint hint = new ValueHint("Spirits you control", new PermanentsOnBattlefieldCount(filter)); + + SpectralArcanistCastEffect() { + super(Outcome.Benefit); + staticText = "you may cast an instant or sorcery spell with mana value less than or equal to " + + "the number of Spirits you control from a graveyard without paying its mana cost. " + + "If that spell would be put into a graveyard, exile it instead"; + } + + private SpectralArcanistCastEffect(final SpectralArcanistCastEffect effect) { + super(effect); + } + + @Override + public SpectralArcanistCastEffect copy() { + return new SpectralArcanistCastEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + FilterCard filterCard = new FilterInstantOrSorceryCard(); + filterCard.add(new ManaValuePredicate( + ComparisonType.FEWER_THAN, + game.getBattlefield().count(filter, source.getControllerId(), source, game) + )); + Cards cards = new CardsImpl(); + game.getState() + .getPlayersInRange(source.getControllerId(), game) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .map(Player::getGraveyard) + .forEach(cards::addAll); + return CardUtil.castSpellWithAttributesForFree( + player, source, game, cards, filterCard, + SpectralArcanistTracker.instance + ); + } + + public static Hint getHint() { + return hint; + } +} + +enum SpectralArcanistTracker implements CardUtil.SpellCastTracker { + instance; + + @Override + public boolean checkCard(Card card, Game game) { + return true; + } + + @Override + public void addCard(Card card, Ability source, Game game) { + game.addEffect(new SpectralArcanistReplacementEffect(card, game), source); + } +} + +class SpectralArcanistReplacementEffect extends ReplacementEffectImpl { + + private final MageObjectReference mor; + + SpectralArcanistReplacementEffect(Card card, Game game) { + super(Duration.EndOfTurn, Outcome.Exile); + this.mor = new MageObjectReference(card.getMainCard(), game); + } + + private SpectralArcanistReplacementEffect(final SpectralArcanistReplacementEffect effect) { + super(effect); + this.mor = effect.mor; + } + + @Override + public SpectralArcanistReplacementEffect copy() { + return new SpectralArcanistReplacementEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + Card card = mor.getCard(game); + return controller != null + && card != null + && controller.moveCards(card, Zone.EXILED, source, game); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + return zEvent.getToZone() == Zone.GRAVEYARD + && zEvent.getTargetId().equals(mor.getSourceId()); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpectralDeluge.java b/Mage.Sets/src/mage/cards/s/SpectralDeluge.java index 5bc96cc27d7..50927bfd3cf 100644 --- a/Mage.Sets/src/mage/cards/s/SpectralDeluge.java +++ b/Mage.Sets/src/mage/cards/s/SpectralDeluge.java @@ -62,6 +62,6 @@ enum SpectralDelugePredicate implements ObjectSourcePlayerPredicate .getValue() <= game .getBattlefield() - .count(filter, input.getSourceId(), input.getPlayerId(), game); + .count(filter, input.getPlayerId(), input.getSource(), game); } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SpectralSliver.java b/Mage.Sets/src/mage/cards/s/SpectralSliver.java index b617abfbaf5..f2777d2e113 100644 --- a/Mage.Sets/src/mage/cards/s/SpectralSliver.java +++ b/Mage.Sets/src/mage/cards/s/SpectralSliver.java @@ -33,7 +33,7 @@ public final class SpectralSliver extends CardImpl { // All Sliver creatures have "{2}: This creature gets +1/+1 until end of turn." Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 1, Duration.EndOfTurn).setText("this creature gets +1/+1 until end of turn"), new ManaCostsImpl("{2}")); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS))); } private SpectralSliver(final SpectralSliver card) { diff --git a/Mage.Sets/src/mage/cards/s/SpellContortion.java b/Mage.Sets/src/mage/cards/s/SpellContortion.java index 40f4de29a1b..3c007175bd4 100644 --- a/Mage.Sets/src/mage/cards/s/SpellContortion.java +++ b/Mage.Sets/src/mage/cards/s/SpellContortion.java @@ -27,7 +27,7 @@ public final class SpellContortion extends CardImpl { // Counter target spell unless its controller pays {2}. Draw a card for each time Spell Contortion was kicked. this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(new GenericManaCost(2))); - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(MultikickerCount.instance)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(MultikickerCount.instance).setText("draw a card for each time {this} was kicked")); this.getSpellAbility().addTarget(new TargetSpell()); } diff --git a/Mage.Sets/src/mage/cards/s/SpellRupture.java b/Mage.Sets/src/mage/cards/s/SpellRupture.java index e56e0bf547a..c110ad6b8f1 100644 --- a/Mage.Sets/src/mage/cards/s/SpellRupture.java +++ b/Mage.Sets/src/mage/cards/s/SpellRupture.java @@ -67,7 +67,7 @@ class SpellRuptureCounterUnlessPaysEffect extends OneShotEffect { if (spell != null) { Player player = game.getPlayer(spell.getControllerId()); Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (player != null && controller != null && sourceObject != null) { int maxPower = new GreatestPowerCountCreatureYouControl().calculate(game, source, this); Cost cost = ManaUtil.createManaCost(maxPower, true); diff --git a/Mage.Sets/src/mage/cards/s/SpellSwindle.java b/Mage.Sets/src/mage/cards/s/SpellSwindle.java index b3a27b0bcb2..a284209fc04 100644 --- a/Mage.Sets/src/mage/cards/s/SpellSwindle.java +++ b/Mage.Sets/src/mage/cards/s/SpellSwindle.java @@ -2,7 +2,6 @@ package mage.cards.s; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -58,7 +57,7 @@ class SpellSwindleEffect extends OneShotEffect { StackObject stackObject = game.getStack().getStackObject(targetPointer.getFirst(game, source)); if (stackObject != null) { game.getStack().counter(source.getFirstTarget(), source, game); - return new CreateTokenEffect(new TreasureToken(), stackObject.getManaValue()).apply(game, source); + return new TreasureToken().putOntoBattlefield(stackObject.getManaValue(), game, source); } return false; } diff --git a/Mage.Sets/src/mage/cards/s/SpellSyphon.java b/Mage.Sets/src/mage/cards/s/SpellSyphon.java index db160c2781e..575ba034f7e 100644 --- a/Mage.Sets/src/mage/cards/s/SpellSyphon.java +++ b/Mage.Sets/src/mage/cards/s/SpellSyphon.java @@ -74,7 +74,7 @@ class SpellSyphonEffect extends OneShotEffect { Player player = game.getPlayer(spell.getControllerId()); Player controller = game.getPlayer(source.getControllerId()); if (player != null && controller != null) { - int amount = game.getBattlefield().count(filter, source.getSourceId(), controller.getId(), game); + int amount = game.getBattlefield().count(filter, controller.getId(), source, game); if (amount == 0) { game.informPlayers("Spell Syphon: no blue permanents in controller's battlefield."); } else { diff --git a/Mage.Sets/src/mage/cards/s/Spellbinder.java b/Mage.Sets/src/mage/cards/s/Spellbinder.java index 3888794fd76..2222d711529 100644 --- a/Mage.Sets/src/mage/cards/s/Spellbinder.java +++ b/Mage.Sets/src/mage/cards/s/Spellbinder.java @@ -11,15 +11,11 @@ import mage.abilities.keyword.EquipAbility; 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.constants.*; import mage.filter.FilterCard; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetCard; @@ -40,7 +36,7 @@ public final class Spellbinder extends CardImpl { // an instant card from your hand. this.addAbility(new EntersBattlefieldTriggeredAbility( new SpellbinderImprintEffect(), true) - .withFlavorWord("Imprint") + .setAbilityWord(AbilityWord.IMPRINT) ); // Whenever equipped creature deals combat damage to a player, you may @@ -122,7 +118,7 @@ class SpellbinderImprintEffect extends OneShotEffect { if (controller != null) { if (!controller.getHand().isEmpty()) { TargetCard target = new TargetCard(Zone.HAND, filter); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + if (target.canChoose(source.getControllerId(), source, game) && controller.choose(Outcome.Benefit, controller.getHand(), target, game)) { Card card = controller.getHand().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/s/SpellbindingSoprano.java b/Mage.Sets/src/mage/cards/s/SpellbindingSoprano.java new file mode 100644 index 00000000000..bcf248ac1f1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpellbindingSoprano.java @@ -0,0 +1,55 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.abilities.keyword.EncoreAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpellbindingSoprano extends CardImpl { + + private static final FilterCard filter = new FilterCard("instant and sorcery spells"); + + static { + filter.add(Predicates.or( + CardType.INSTANT.getPredicate(), + CardType.SORCERY.getPredicate() + )); + } + + public SpellbindingSoprano(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.BARD); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever Spellbinding Soprano attacks, instant and sorcery spells you cast this turn cost {1} less to cast. + this.addAbility(new AttacksTriggeredAbility(new SpellsCostReductionControllerEffect(filter, 1).setDuration(Duration.EndOfTurn))); + + // Encore {3}{R} + this.addAbility(new EncoreAbility(new ManaCostsImpl<>("{3}{R}"))); + } + + private SpellbindingSoprano(final SpellbindingSoprano card) { + super(card); + } + + @Override + public SpellbindingSoprano copy() { + return new SpellbindingSoprano(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpellboundDragon.java b/Mage.Sets/src/mage/cards/s/SpellboundDragon.java index 5e1ea5767c6..1d8be705919 100644 --- a/Mage.Sets/src/mage/cards/s/SpellboundDragon.java +++ b/Mage.Sets/src/mage/cards/s/SpellboundDragon.java @@ -73,7 +73,7 @@ class SpellboundDragonEffect extends OneShotEffect { if(you != null) { you.drawCards(1, source, game); TargetDiscard target = new TargetDiscard(you.getId()); - you.choose(Outcome.Discard, target, source.getSourceId(), game); + you.choose(Outcome.Discard, target, source, game); Card card = you.getHand().get(target.getFirstTarget(), game); if (card != null && you.discard(card, false, source, game)) { int cmc = card.getManaValue(); diff --git a/Mage.Sets/src/mage/cards/s/SpellkeeperWeird.java b/Mage.Sets/src/mage/cards/s/SpellkeeperWeird.java index ec66f16cadc..68130bbe234 100644 --- a/Mage.Sets/src/mage/cards/s/SpellkeeperWeird.java +++ b/Mage.Sets/src/mage/cards/s/SpellkeeperWeird.java @@ -6,7 +6,7 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -34,7 +34,7 @@ public final class SpellkeeperWeird extends CardImpl { // {2}, {T}, Sacrifice Spellkeeper Weird: Return target instant or sorcery card from your graveyard to your hand. Ability ability = new SimpleActivatedAbility( - new ReturnToHandTargetEffect(), new GenericManaCost(2) + new ReturnFromGraveyardToHandTargetEffect(), new GenericManaCost(2) ); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); diff --git a/Mage.Sets/src/mage/cards/s/Spellshift.java b/Mage.Sets/src/mage/cards/s/Spellshift.java index 2d0f5622767..97721c2aaa4 100644 --- a/Mage.Sets/src/mage/cards/s/Spellshift.java +++ b/Mage.Sets/src/mage/cards/s/Spellshift.java @@ -51,7 +51,7 @@ class SpellshiftEffect extends OneShotEffect { public SpellshiftEffect() { super(Outcome.Detriment); - this.staticText = "Its controller reveals cards from the top of their library until they reveal an instant or sorcery card. That player may cast that card without paying its mana cost. Then they shuffle"; + this.staticText = "Its controller reveals cards from the top of their library until they reveal an instant or sorcery card. That player may cast that card without paying its mana cost. Then the player shuffles"; } public SpellshiftEffect(final SpellshiftEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/Spellskite.java b/Mage.Sets/src/mage/cards/s/Spellskite.java index f96b3ef70d4..07fe08f4fe7 100644 --- a/Mage.Sets/src/mage/cards/s/Spellskite.java +++ b/Mage.Sets/src/mage/cards/s/Spellskite.java @@ -67,7 +67,7 @@ class SpellskiteEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { StackObject stackObject = game.getStack().getStackObject(source.getFirstTarget()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (stackObject != null && sourceObject != null) { Targets targets = new Targets(); Ability sourceAbility; diff --git a/Mage.Sets/src/mage/cards/s/SpellweaverHelix.java b/Mage.Sets/src/mage/cards/s/SpellweaverHelix.java index 7089e4dc6bc..48a18480251 100644 --- a/Mage.Sets/src/mage/cards/s/SpellweaverHelix.java +++ b/Mage.Sets/src/mage/cards/s/SpellweaverHelix.java @@ -8,6 +8,7 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -41,7 +42,7 @@ public final class SpellweaverHelix extends CardImpl { // Imprint - When Spellweaver Helix enters the battlefield, you may exile two target sorcery cards from a single graveyard. Ability ability = new EntersBattlefieldTriggeredAbility(new SpellweaverHelixImprintEffect(), true); ability.addTarget(new TargetCardInASingleGraveyard(2, 2, filter)); - ability.withFlavorWord("Imprint"); + ability.setAbilityWord(AbilityWord.IMPRINT); this.addAbility(ability); // Whenever a player casts a card, if it has the same name as one of the cards exiled with Spellweaver Helix, you may copy the other. If you do, you may cast the copy without paying its mana cost. diff --git a/Mage.Sets/src/mage/cards/s/SpellweaverVolute.java b/Mage.Sets/src/mage/cards/s/SpellweaverVolute.java index 029ae9eb710..77617b686a8 100644 --- a/Mage.Sets/src/mage/cards/s/SpellweaverVolute.java +++ b/Mage.Sets/src/mage/cards/s/SpellweaverVolute.java @@ -103,8 +103,8 @@ class SpellweaverVoluteEffect extends OneShotEffect { FilterCard filter = new FilterCard("instant card in a graveyard"); filter.add(CardType.INSTANT.getPredicate()); TargetCardInGraveyard auraTarget = new TargetCardInGraveyard(filter); - if (auraTarget.canChoose(source.getSourceId(), controller.getId(), game)) { - controller.choose(Outcome.Benefit, auraTarget, source.getSourceId(), game); + if (auraTarget.canChoose(controller.getId(), source, game)) { + controller.choose(Outcome.Benefit, auraTarget, source, game); Card newAuraTarget = game.getCard(auraTarget.getFirstTarget()); if (newAuraTarget != null) { if (enchantedCard.getId().equals(newAuraTarget.getId())) { diff --git a/Mage.Sets/src/mage/cards/s/SphinxOfMagosi.java b/Mage.Sets/src/mage/cards/s/SphinxOfMagosi.java index 103534a8011..caadfbe9c63 100644 --- a/Mage.Sets/src/mage/cards/s/SphinxOfMagosi.java +++ b/Mage.Sets/src/mage/cards/s/SphinxOfMagosi.java @@ -31,7 +31,7 @@ public final class SphinxOfMagosi extends CardImpl { this.toughness = new MageInt(6); this.addAbility(FlyingAbility.getInstance()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{2}{U}")); - ability.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance())); + ability.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance()).concatBy(", then")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SphinxSummoner.java b/Mage.Sets/src/mage/cards/s/SphinxSummoner.java index 18953df564c..39deab74c4c 100644 --- a/Mage.Sets/src/mage/cards/s/SphinxSummoner.java +++ b/Mage.Sets/src/mage/cards/s/SphinxSummoner.java @@ -36,7 +36,7 @@ public final class SphinxSummoner extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // When Sphinx Summoner enters the battlefield, you may search your library for an artifact creature card, reveal it, and put it into your hand. If you do, shuffle your library. - this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true, false), true)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true), true)); } private SphinxSummoner(final SphinxSummoner card) { diff --git a/Mage.Sets/src/mage/cards/s/SphinxsDecree.java b/Mage.Sets/src/mage/cards/s/SphinxsDecree.java index 2a954e26951..87e5ccb28c2 100644 --- a/Mage.Sets/src/mage/cards/s/SphinxsDecree.java +++ b/Mage.Sets/src/mage/cards/s/SphinxsDecree.java @@ -93,7 +93,7 @@ class SphinxsDecreeCantCastEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast instant or sorcery spells this turn (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/s/SpiderUmbra.java b/Mage.Sets/src/mage/cards/s/SpiderUmbra.java index e231e773a53..450a8efac39 100644 --- a/Mage.Sets/src/mage/cards/s/SpiderUmbra.java +++ b/Mage.Sets/src/mage/cards/s/SpiderUmbra.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; @@ -16,26 +14,31 @@ import mage.constants.*; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class SpiderUmbra extends CardImpl { public SpiderUmbra(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}"); this.subtype.add(SubType.AURA); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // Enchanted creature gets +1/+1 and has reach. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 1, Duration.WhileOnBattlefield))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ReachAbility.getInstance(), AttachmentType.AURA))); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect( + 1, 1, Duration.WhileOnBattlefield + )); + ability.addEffect(new GainAbilityAttachedEffect( + ReachAbility.getInstance(), AttachmentType.AURA + ).setText("and has reach")); + this.addAbility(ability); this.addAbility(new TotemArmorAbility()); } diff --git a/Mage.Sets/src/mage/cards/s/SpidersilkNet.java b/Mage.Sets/src/mage/cards/s/SpidersilkNet.java index 1e528d381c8..d37634d9743 100644 --- a/Mage.Sets/src/mage/cards/s/SpidersilkNet.java +++ b/Mage.Sets/src/mage/cards/s/SpidersilkNet.java @@ -1,7 +1,6 @@ - package mage.cards.s; -import java.util.UUID; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.continuous.BoostEquippedEffect; @@ -12,22 +11,26 @@ 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.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author North */ public final class SpidersilkNet extends CardImpl { public SpidersilkNet(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{0}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{0}"); this.subtype.add(SubType.EQUIPMENT); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(0, 2))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ReachAbility.getInstance(), AttachmentType.EQUIPMENT))); + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(0, 2)); + ability.addEffect(new GainAbilityAttachedEffect( + ReachAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and has reach")); + this.addAbility(ability); + this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2))); } diff --git a/Mage.Sets/src/mage/cards/s/SpikeTiller.java b/Mage.Sets/src/mage/cards/s/SpikeTiller.java index c280ad938e9..489dc318354 100644 --- a/Mage.Sets/src/mage/cards/s/SpikeTiller.java +++ b/Mage.Sets/src/mage/cards/s/SpikeTiller.java @@ -45,7 +45,7 @@ public final class SpikeTiller extends CardImpl { this.addAbility(ability); // {2}, Remove a +1/+1 counter from Spike Tiller: Target land becomes a 2/2 creature that's still a land. Put a +1/+1 counter on it. - Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureTargetEffect(new CreatureToken(2, 2), false, true, Duration.EndOfGame).setText("Target land becomes a 2/2 creature that's still a land. "), new GenericManaCost(2)); + Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureTargetEffect(new CreatureToken(2, 2), false, true, Duration.EndOfGame).setText("Target land becomes a 2/2 creature that's still a land"), new GenericManaCost(2)); ability2.addCost(new RemoveCountersSourceCost(CounterType.P1P1.createInstance())); ability2.addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance()).setText("Put a +1/+1 counter on it.")); ability2.addTarget(new TargetLandPermanent()); diff --git a/Mage.Sets/src/mage/cards/s/SpinEngine.java b/Mage.Sets/src/mage/cards/s/SpinEngine.java index 3eb073092b7..76075d21a00 100644 --- a/Mage.Sets/src/mage/cards/s/SpinEngine.java +++ b/Mage.Sets/src/mage/cards/s/SpinEngine.java @@ -3,16 +3,14 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.RestrictionEffect; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.effects.common.combat.CantBeBlockedByTargetSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -29,7 +27,10 @@ public final class SpinEngine extends CardImpl { this.toughness = new MageInt(1); // {R}: Target creature can't block Spin Engine this turn - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SpinEngineEffect(), new ManaCostsImpl("{R}")); + Ability ability = new SimpleActivatedAbility( + new CantBeBlockedByTargetSourceEffect(Duration.EndOfTurn), + new ColoredManaCost(ColoredManaSymbol.R) + ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } @@ -42,34 +43,4 @@ public final class SpinEngine extends CardImpl { public SpinEngine copy() { return new SpinEngine(this); } - -} - -class SpinEngineEffect extends RestrictionEffect { - - public SpinEngineEffect() { - super(Duration.EndOfTurn); - staticText = "Target creature can't block {this} this turn"; - } - - public SpinEngineEffect(final SpinEngineEffect effect) { - super(effect); - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - return permanent.getId().equals(source.getSourceId()); - } - - @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { - UUID targetId = source.getFirstTarget(); - return targetId == null || !blocker.getId().equals(targetId); - } - - @Override - public SpinEngineEffect copy() { - return new SpinEngineEffect(this); - } - } diff --git a/Mage.Sets/src/mage/cards/s/SpinedBasher.java b/Mage.Sets/src/mage/cards/s/SpinedBasher.java index 9d86aab6d03..084f3f21447 100644 --- a/Mage.Sets/src/mage/cards/s/SpinedBasher.java +++ b/Mage.Sets/src/mage/cards/s/SpinedBasher.java @@ -24,7 +24,7 @@ public final class SpinedBasher extends CardImpl { this.toughness = new MageInt(1); // Morph {2}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{B}"))); } private SpinedBasher(final SpinedBasher card) { diff --git a/Mage.Sets/src/mage/cards/s/SpinedSliver.java b/Mage.Sets/src/mage/cards/s/SpinedSliver.java index 5fa93ec12f1..3f45af3206c 100644 --- a/Mage.Sets/src/mage/cards/s/SpinedSliver.java +++ b/Mage.Sets/src/mage/cards/s/SpinedSliver.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BecomesBlockedAllTriggeredAbility; @@ -11,14 +9,15 @@ import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.combat.CombatGroup; +import java.util.UUID; + /** - * * @author KholdFuzion */ public final class SpinedSliver extends CardImpl { @@ -31,10 +30,11 @@ public final class SpinedSliver extends CardImpl { this.toughness = new MageInt(2); // Whenever a Sliver becomes blocked, that Sliver gets +1/+1 until end of turn for each creature blocking it. - BlockersCount value = new BlockersCount(); - Effect effect = new BoostTargetEffect(value, value, Duration.EndOfTurn, true); - effect.setText("it gets +1/+1 until end of turn for each creature blocking it"); - this.addAbility(new BecomesBlockedAllTriggeredAbility(effect, false, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, true)); + this.addAbility(new BecomesBlockedAllTriggeredAbility( + new BoostTargetEffect(BlockersCount.instance, BlockersCount.instance, Duration.EndOfTurn, true) + .setText("that Sliver gets +1/+1 until end of turn for each creature blocking it"), + false, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS, true + ).setTriggerPhrase("Whenever a Sliver becomes blocked, ")); } private SpinedSliver(final SpinedSliver card) { @@ -47,18 +47,8 @@ public final class SpinedSliver extends CardImpl { } } -class BlockersCount implements DynamicValue { - - private final String message; - - public BlockersCount() { - this.message = "each creature blocking it"; - } - - public BlockersCount(final BlockersCount blockersCount) { - super(); - this.message = blockersCount.message; - } +enum BlockersCount implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -73,12 +63,12 @@ class BlockersCount implements DynamicValue { @Override public BlockersCount copy() { - return new BlockersCount(this); + return this; } @Override public String getMessage() { - return message; + return "each creature blocking it"; } @Override diff --git a/Mage.Sets/src/mage/cards/s/SpinerockKnoll.java b/Mage.Sets/src/mage/cards/s/SpinerockKnoll.java index f2c0b8a2fde..0a82ef2e68f 100644 --- a/Mage.Sets/src/mage/cards/s/SpinerockKnoll.java +++ b/Mage.Sets/src/mage/cards/s/SpinerockKnoll.java @@ -1,6 +1,7 @@ package mage.cards.s; import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; @@ -31,7 +32,8 @@ public final class SpinerockKnoll extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // Hideaway - this.addAbility(new HideawayAbility()); + this.addAbility(new HideawayAbility(4)); + this.addAbility(new EntersBattlefieldTappedAbility()); // {tap}: Add {R}. this.addAbility(new RedManaAbility()); diff --git a/Mage.Sets/src/mage/cards/s/SpinningWheelKick.java b/Mage.Sets/src/mage/cards/s/SpinningWheelKick.java new file mode 100644 index 00000000000..c4dedd9b9db --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpinningWheelKick.java @@ -0,0 +1,88 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpinningWheelKick extends CardImpl { + + public SpinningWheelKick(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{X}{G}{G}"); + + // Target creature you control deals damage equal to its power to each of X target creatures and/or planeswalkers. + this.getSpellAbility().addEffect(new SpinningWheelKickEffect()); + this.getSpellAbility().setTargetAdjuster(SpinningWheelKickAdjuster.instance); + } + + private SpinningWheelKick(final SpinningWheelKick card) { + super(card); + } + + @Override + public SpinningWheelKick copy() { + return new SpinningWheelKick(this); + } +} + +enum SpinningWheelKickAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetControlledCreaturePermanent()); + ability.addTarget(new TargetPermanent( + ability.getManaCostsToPay().getX(), + StaticFilters.FILTER_PERMANENT_CREATURE_OR_PLANESWALKER + )); + } +} + +class SpinningWheelKickEffect extends OneShotEffect { + + SpinningWheelKickEffect() { + super(Outcome.Benefit); + staticText = "target creature you control deals damage equal " + + "to its power to each of X target creatures and/or planeswalkers"; + this.setTargetPointer(new SecondTargetPointer()); + } + + private SpinningWheelKickEffect(final SpinningWheelKickEffect effect) { + super(effect); + } + + @Override + public SpinningWheelKickEffect copy() { + return new SpinningWheelKickEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent creature = game.getPermanent(source.getFirstTarget()); + if (creature == null) { + return false; + } + for (UUID targetId : getTargetPointer().getTargets(game, source)) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + permanent.damage(creature.getPower().getValue(), creature.getId(), source, game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpiritLink.java b/Mage.Sets/src/mage/cards/s/SpiritLink.java index 5c7ed70def0..422399d667d 100644 --- a/Mage.Sets/src/mage/cards/s/SpiritLink.java +++ b/Mage.Sets/src/mage/cards/s/SpiritLink.java @@ -1,10 +1,9 @@ - package mage.cards.s; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DealsDamageAttachedTriggeredAbility; -import mage.abilities.dynamicvalue.common.NumericSetToEffectValues; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.keyword.EnchantAbility; @@ -31,11 +30,10 @@ public final class SpiritLink extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Whenever enchanted creature deals damage, you gain that much life. - this.addAbility(new DealsDamageAttachedTriggeredAbility(Zone.BATTLEFIELD, new GainLifeEffect(new NumericSetToEffectValues("that much", "damage")), false)); + this.addAbility(new DealsDamageAttachedTriggeredAbility(Zone.BATTLEFIELD, new GainLifeEffect(SavedDamageValue.MUCH), false)); } private SpiritLink(final SpiritLink card) { diff --git a/Mage.Sets/src/mage/cards/s/SpiritLoop.java b/Mage.Sets/src/mage/cards/s/SpiritLoop.java index b7de9aa9f3b..c629ea21665 100644 --- a/Mage.Sets/src/mage/cards/s/SpiritLoop.java +++ b/Mage.Sets/src/mage/cards/s/SpiritLoop.java @@ -1,11 +1,9 @@ - package mage.cards.s; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.common.DealsDamageAttachedTriggeredAbility; import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; -import mage.abilities.dynamicvalue.common.NumericSetToEffectValues; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.ReturnToHandSourceEffect; @@ -32,15 +30,13 @@ public final class SpiritLoop extends CardImpl { TargetPermanent auraTarget = new TargetControlledCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); - + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // Whenever enchanted creature deals damage, you gain that much life. - this.addAbility(new DealsDamageAttachedTriggeredAbility(Zone.BATTLEFIELD, new GainLifeEffect(new NumericSetToEffectValues("that much", "damage")), false)); - + this.addAbility(new DealsDamageAttachedTriggeredAbility(Zone.BATTLEFIELD, new GainLifeEffect(SavedDamageValue.MUCH), false)); + // When Spirit Loop is put into a graveyard from the battlefield, return Spirit Loop to its owner's hand. this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new ReturnToHandSourceEffect())); - } private SpiritLoop(final SpiritLoop card) { @@ -51,4 +47,4 @@ public final class SpiritLoop extends CardImpl { public SpiritLoop copy() { return new SpiritLoop(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/Spiritualize.java b/Mage.Sets/src/mage/cards/s/Spiritualize.java index a45d98d71a5..21cd9dcc71b 100644 --- a/Mage.Sets/src/mage/cards/s/Spiritualize.java +++ b/Mage.Sets/src/mage/cards/s/Spiritualize.java @@ -1,23 +1,21 @@ - package mage.cards.s; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; 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.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetCreaturePermanent; /** @@ -50,7 +48,7 @@ public final class Spiritualize extends CardImpl { class SpiritualizeTriggeredAbility extends DelayedTriggeredAbility { public SpiritualizeTriggeredAbility() { - super(new SpiritualizeEffect(), Duration.EndOfTurn, false); + super(new GainLifeEffect(SavedDamageValue.MUCH), Duration.EndOfTurn, false); } public SpiritualizeTriggeredAbility(final SpiritualizeTriggeredAbility ability) { @@ -85,33 +83,3 @@ class SpiritualizeTriggeredAbility extends DelayedTriggeredAbility { return "Whenever target creature deals damage, " ; } } - -class SpiritualizeEffect extends OneShotEffect { - - public SpiritualizeEffect() { - super(Outcome.GainLife); - this.staticText = "you gain that much life"; - } - - public SpiritualizeEffect(final SpiritualizeEffect effect) { - super(effect); - } - - @Override - public SpiritualizeEffect copy() { - return new SpiritualizeEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int amount = (Integer) getValue("damage"); - if (amount > 0) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - controller.gainLife(amount, game, source); - return true; - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SpitefulRepossession.java b/Mage.Sets/src/mage/cards/s/SpitefulRepossession.java new file mode 100644 index 00000000000..6876ddaee6e --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpitefulRepossession.java @@ -0,0 +1,75 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.token.TreasureToken; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpitefulRepossession extends CardImpl { + + public SpitefulRepossession(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}"); + + // Spiteful Repossession deals damage to each opponent who controls more lands than you equal to the difference. Then create a number of Treasure tokens equal to the damage dealt this way. + this.getSpellAbility().addEffect(new SpitefulRepossessionEffect()); + } + + private SpitefulRepossession(final SpitefulRepossession card) { + super(card); + } + + @Override + public SpitefulRepossession copy() { + return new SpitefulRepossession(this); + } +} + +class SpitefulRepossessionEffect extends OneShotEffect { + + SpitefulRepossessionEffect() { + super(Outcome.Benefit); + staticText = "{this} deals damage to each opponent who controls more lands than you equal to the difference. " + + "Then create a number of Treasure tokens equal to the damage dealt this way"; + } + + private SpitefulRepossessionEffect(final SpitefulRepossessionEffect effect) { + super(effect); + } + + @Override + public SpitefulRepossessionEffect copy() { + return new SpitefulRepossessionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int controlledLands = game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, source.getControllerId(), source, game); + int damageDealt = 0; + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + int lands = game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, opponentId, source, game); + if (lands <= controlledLands) { + continue; + } + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + damageDealt += opponent.damage(lands - controlledLands, source, game); + } + } + if (damageDealt > 0) { + new TreasureToken().putOntoBattlefield(damageDealt, game, source); + } + return true; + + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpitefulSliver.java b/Mage.Sets/src/mage/cards/s/SpitefulSliver.java index 9ea011fbb4e..9d371990462 100644 --- a/Mage.Sets/src/mage/cards/s/SpitefulSliver.java +++ b/Mage.Sets/src/mage/cards/s/SpitefulSliver.java @@ -4,15 +4,14 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealtDamageToSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.target.TargetPlayer; +import mage.target.common.TargetPlayerOrPlaneswalker; import java.util.UUID; @@ -29,13 +28,11 @@ public final class SpitefulSliver extends CardImpl { this.toughness = new MageInt(2); // Sliver creatures you control have "Whenever this creature is dealt damage, it deals that much damage to target player or planeswalker." - Ability ability = new DealtDamageToSourceTriggeredAbility( - new SpitefulSliverEffect(), - false, false - ); - ability.addTarget(new TargetPlayer()); + Ability ability = new DealtDamageToSourceTriggeredAbility(new DamageTargetEffect(SavedDamageValue.MUCH, "it"), false); + ability.addTarget(new TargetPlayerOrPlaneswalker()); + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( - ability, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS + ability, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_SLIVERS ).setText("Sliver creatures you control have \"Whenever this creature is dealt damage, " + "it deals that much damage to target player or planeswalker.\"") )); @@ -50,26 +47,3 @@ public final class SpitefulSliver extends CardImpl { return new SpitefulSliver(this); } } - -class SpitefulSliverEffect extends OneShotEffect { - - SpitefulSliverEffect() { - super(Outcome.Damage); - this.staticText = "it deals that much damage to target player or planeswalker"; - } - - private SpitefulSliverEffect(final SpitefulSliverEffect effect) { - super(effect); - } - - @Override - public SpitefulSliverEffect copy() { - return new SpitefulSliverEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int amount = (Integer) getValue("damage"); - return new DamageTargetEffect(amount).apply(game, source); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SpitefulVisions.java b/Mage.Sets/src/mage/cards/s/SpitefulVisions.java index 2f6b7c5a5a0..7ab15780d01 100644 --- a/Mage.Sets/src/mage/cards/s/SpitefulVisions.java +++ b/Mage.Sets/src/mage/cards/s/SpitefulVisions.java @@ -29,7 +29,7 @@ public final class SpitefulVisions extends CardImpl { // At the beginning of each player's draw step, that player draws an additional card. - this.addAbility(new BeginningOfDrawTriggeredAbility(new DrawCardTargetEffect(1), TargetController.ANY, false)); + this.addAbility(new BeginningOfDrawTriggeredAbility(new DrawCardTargetEffect(1).setText("that player draws an additional card"), TargetController.ANY, false)); // Whenever a player draws a card, Spiteful Visions deals 1 damage to that player. TriggeredAbility triggeredAbility = new SpitefulVisionsTriggeredAbility(new DamageTargetEffect(1), false); @@ -74,7 +74,7 @@ class SpitefulVisionsTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever a player draws a card, Spiteful Visions deals 1 damage to that player."; + return "Whenever a player draws a card, {this} deals 1 damage to that player."; } @Override diff --git a/Mage.Sets/src/mage/cards/s/SpittingGourna.java b/Mage.Sets/src/mage/cards/s/SpittingGourna.java index e6986190bcd..6c3821fc99e 100644 --- a/Mage.Sets/src/mage/cards/s/SpittingGourna.java +++ b/Mage.Sets/src/mage/cards/s/SpittingGourna.java @@ -26,7 +26,7 @@ public final class SpittingGourna extends CardImpl { // Reach this.addAbility(ReachAbility.getInstance()); // Morph {4}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{G}"))); } private SpittingGourna(final SpittingGourna card) { diff --git a/Mage.Sets/src/mage/cards/s/SplendidReclamation.java b/Mage.Sets/src/mage/cards/s/SplendidReclamation.java index f798b78526c..a023a451d2b 100644 --- a/Mage.Sets/src/mage/cards/s/SplendidReclamation.java +++ b/Mage.Sets/src/mage/cards/s/SplendidReclamation.java @@ -56,8 +56,8 @@ class ReplenishEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - return controller.moveCards(controller.getGraveyard().getCards(new FilterLandCard(), source.getSourceId(), - source.getControllerId(), game), Zone.BATTLEFIELD, source, game, true, false, false, null); + return controller.moveCards(controller.getGraveyard().getCards(new FilterLandCard(), + source.getControllerId(), source, game), Zone.BATTLEFIELD, source, game, true, false, false, null); } return false; } diff --git a/Mage.Sets/src/mage/cards/s/SplinterTwin.java b/Mage.Sets/src/mage/cards/s/SplinterTwin.java index 584ff927417..0871fffdbc5 100644 --- a/Mage.Sets/src/mage/cards/s/SplinterTwin.java +++ b/Mage.Sets/src/mage/cards/s/SplinterTwin.java @@ -62,7 +62,7 @@ class SplinterTwinEffect extends OneShotEffect { public SplinterTwinEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "Create a token that's a copy of this creature, except it has haste. Exile it at the beginning of the next end step"; + this.staticText = "Create a token that's a copy of this creature, except it has haste. Exile that token at the beginning of the next end step"; } public SplinterTwinEffect(final SplinterTwinEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/SplittingHeadache.java b/Mage.Sets/src/mage/cards/s/SplittingHeadache.java index fff7ab904a3..0337ec3f741 100644 --- a/Mage.Sets/src/mage/cards/s/SplittingHeadache.java +++ b/Mage.Sets/src/mage/cards/s/SplittingHeadache.java @@ -26,8 +26,7 @@ public final class SplittingHeadache extends CardImpl { this.getSpellAbility().addEffect(new DiscardTargetEffect(2)); // • Target player reveals their hand. You choose a card from it. That player discards that card. - Mode mode = new Mode(); - mode.addEffect(new DiscardCardYouChooseTargetEffect(TargetController.ANY)); + Mode mode = new Mode(new DiscardCardYouChooseTargetEffect(TargetController.ANY)); mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SpoilsOfTheVault.java b/Mage.Sets/src/mage/cards/s/SpoilsOfTheVault.java index b230904b04c..9c48dda85ff 100644 --- a/Mage.Sets/src/mage/cards/s/SpoilsOfTheVault.java +++ b/Mage.Sets/src/mage/cards/s/SpoilsOfTheVault.java @@ -56,7 +56,7 @@ class SpoilsOfTheVaultEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Player controller = game.getPlayer(source.getControllerId()); String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); if (sourceObject == null || controller == null || cardName == null || cardName.isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/s/SporeBurst.java b/Mage.Sets/src/mage/cards/s/SporeBurst.java index 90153777def..1765f547269 100644 --- a/Mage.Sets/src/mage/cards/s/SporeBurst.java +++ b/Mage.Sets/src/mage/cards/s/SporeBurst.java @@ -7,6 +7,7 @@ import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.common.DomainHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.game.permanent.token.SaprolingToken; @@ -21,8 +22,9 @@ public final class SporeBurst extends CardImpl { // Domain - Create a 1/1 green Saproling creature token for each basic land type among lands you control. - this.getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), new DomainValue())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), DomainValue.REGULAR)); this.getSpellAbility().addHint(DomainHint.instance); + this.getSpellAbility().setAbilityWord(AbilityWord.DOMAIN); } private SporeBurst(final SporeBurst card) { diff --git a/Mage.Sets/src/mage/cards/s/SporeCloud.java b/Mage.Sets/src/mage/cards/s/SporeCloud.java index a79d04cad4a..8bce663ef36 100644 --- a/Mage.Sets/src/mage/cards/s/SporeCloud.java +++ b/Mage.Sets/src/mage/cards/s/SporeCloud.java @@ -77,7 +77,7 @@ class SporeCloudEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { List doNotUntapNextUntapStep = new ArrayList<>(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { doNotUntapNextUntapStep.add(permanent); } if (!doNotUntapNextUntapStep.isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/s/SpringLeafAvenger.java b/Mage.Sets/src/mage/cards/s/SpringLeafAvenger.java index 1a02e5dccc4..d53f32e91e0 100644 --- a/Mage.Sets/src/mage/cards/s/SpringLeafAvenger.java +++ b/Mage.Sets/src/mage/cards/s/SpringLeafAvenger.java @@ -9,7 +9,8 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.StaticFilters; +import mage.filter.FilterCard; +import mage.filter.common.FilterPermanentCard; import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; @@ -19,6 +20,8 @@ import java.util.UUID; */ public final class SpringLeafAvenger extends CardImpl { + private static final FilterCard filter = new FilterPermanentCard("permanent card from your graveyard"); + public SpringLeafAvenger(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); @@ -34,7 +37,7 @@ public final class SpringLeafAvenger extends CardImpl { Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility( new ReturnFromGraveyardToHandTargetEffect(), false ); - ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_PERMANENT)); + ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SpringjackShepherd.java b/Mage.Sets/src/mage/cards/s/SpringjackShepherd.java index 0c1fe8cbdd2..50632461e16 100644 --- a/Mage.Sets/src/mage/cards/s/SpringjackShepherd.java +++ b/Mage.Sets/src/mage/cards/s/SpringjackShepherd.java @@ -9,6 +9,7 @@ import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.ValueHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.ManaType; import mage.constants.SubType; @@ -35,7 +36,7 @@ public final class SpringjackShepherd extends CardImpl { effect.setText("create a 0/1 white Goat creature token for each white mana symbol in the mana costs of permanents you control."); this.addAbility(new EntersBattlefieldTriggeredAbility( effect, false) - .withFlavorWord("Chroma") + .setAbilityWord(AbilityWord.CHROMA) .addHint(new ValueHint("White mana symbols in your permanents", xValue)) ); } diff --git a/Mage.Sets/src/mage/cards/s/SprintingWarbrute.java b/Mage.Sets/src/mage/cards/s/SprintingWarbrute.java index de2e1e8f32a..fc912f8e747 100644 --- a/Mage.Sets/src/mage/cards/s/SprintingWarbrute.java +++ b/Mage.Sets/src/mage/cards/s/SprintingWarbrute.java @@ -26,7 +26,7 @@ public final class SprintingWarbrute extends CardImpl { // Sprinting Warbrute attacks each turn if able. this.addAbility(new AttacksEachCombatStaticAbility()); // Dash {3}{R} - this.addAbility(new DashAbility(this, "{3}{R}")); + this.addAbility(new DashAbility("{3}{R}")); } private SprintingWarbrute(final SprintingWarbrute card) { diff --git a/Mage.Sets/src/mage/cards/s/SpriteNoble.java b/Mage.Sets/src/mage/cards/s/SpriteNoble.java index eb527b73de0..5baa3d98b83 100644 --- a/Mage.Sets/src/mage/cards/s/SpriteNoble.java +++ b/Mage.Sets/src/mage/cards/s/SpriteNoble.java @@ -4,14 +4,14 @@ import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; @@ -22,9 +22,11 @@ import java.util.UUID; */ public final class SpriteNoble extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures you control with flying"); + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creatures you control with flying"); static { + filter.add(TargetController.YOU.getControllerPredicate()); filter.add(new AbilityPredicate(FlyingAbility.class)); } @@ -36,11 +38,16 @@ public final class SpriteNoble extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); + // Other creatures you control with flying get +0/+1. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(0, 1, Duration.WhileOnBattlefield, filter, true))); + this.addAbility(new SimpleStaticAbility(new BoostAllEffect( + 0, 1, Duration.WhileOnBattlefield, filter, true + ))); + // {tap}: Other creatures you control with flying get +1/+0 until end of turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 0, Duration.EndOfTurn, filter, true), - new TapSourceCost())); + this.addAbility(new SimpleActivatedAbility(new BoostAllEffect( + 1, 0, Duration.EndOfTurn, filter, true + ), new TapSourceCost())); } private SpriteNoble(final SpriteNoble card) { diff --git a/Mage.Sets/src/mage/cards/s/SpyNetwork.java b/Mage.Sets/src/mage/cards/s/SpyNetwork.java index abb405b5e97..4be5d8353fd 100644 --- a/Mage.Sets/src/mage/cards/s/SpyNetwork.java +++ b/Mage.Sets/src/mage/cards/s/SpyNetwork.java @@ -35,7 +35,7 @@ public final class SpyNetwork extends CardImpl { this.getSpellAbility().addEffect(new SpyNetworkLookAtTargetPlayerHandEffect()); this.getSpellAbility().addEffect(new LookLibraryTopCardTargetPlayerEffect().setText(" the top card of that player's library")); this.getSpellAbility().addEffect(new SpyNetworkFaceDownEffect()); - this.getSpellAbility().addEffect(new LookLibraryControllerEffect(4, false, true)); + this.getSpellAbility().addEffect(new LookLibraryControllerEffect(4)); this.getSpellAbility().addTarget(new TargetPlayer()); } @@ -70,7 +70,7 @@ class SpyNetworkLookAtTargetPlayerHandEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player you = game.getPlayer(source.getControllerId()); Player targetPlayer = game.getPlayer(source.getFirstTarget()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (you != null && targetPlayer != null) { you.lookAtCards("Hand of " + targetPlayer.getName() + " (" + (sourceObject != null ? sourceObject.getIdName() : null) + ')', targetPlayer.getHand(), game); return true; @@ -100,16 +100,16 @@ class SpyNetworkFaceDownEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(this.getTargetPointer().getFirst(game, source)); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (controller != null && player != null && mageObject != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent("face down creature controlled by " + player.getLogName()); filter.add(FaceDownPredicate.instance); filter.add(new ControllerIdPredicate(player.getId())); TargetCreaturePermanent target = new TargetCreaturePermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { + if (target.canChoose(controller.getId(), source, game)) { while (controller.chooseUse(outcome, "Look at a face down creature controlled by " + player.getLogName() + "?", source, game)) { target.clearChosen(); - while (!target.isChosen() && target.canChoose(source.getSourceId(), controller.getId(), game) && controller.canRespond()) { + while (!target.isChosen() && target.canChoose(controller.getId(), source, game) && controller.canRespond()) { controller.chooseTarget(outcome, target, source, game); } Permanent faceDownCreature = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/s/SqueakingPieSneak.java b/Mage.Sets/src/mage/cards/s/SqueakingPieSneak.java index 33528deeb4d..853ef52fd21 100644 --- a/Mage.Sets/src/mage/cards/s/SqueakingPieSneak.java +++ b/Mage.Sets/src/mage/cards/s/SqueakingPieSneak.java @@ -35,9 +35,9 @@ public final class SqueakingPieSneak extends CardImpl { // As an additional cost to cast Squeaking Pie Sneak, reveal a Goblin card from your hand or pay {3}. this.getSpellAbility().addCost(new OrCost( - new RevealTargetFromHandCost(new TargetCardInHand(filter)), - new GenericManaCost(3), - "reveal a Goblin card from your hand or pay {3}")); + "reveal a Goblin card from your hand or pay {3}", new RevealTargetFromHandCost(new TargetCardInHand(filter)), + new GenericManaCost(3) + )); // Fear this.addAbility(FearAbility.getInstance()); } diff --git a/Mage.Sets/src/mage/cards/s/SquirrelMob.java b/Mage.Sets/src/mage/cards/s/SquirrelMob.java index ecca5201dee..a0db1770d85 100644 --- a/Mage.Sets/src/mage/cards/s/SquirrelMob.java +++ b/Mage.Sets/src/mage/cards/s/SquirrelMob.java @@ -1,44 +1,44 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class SquirrelMob extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent(SubType.SQUIRREL, ""); + + static { + filter.add(AnotherPredicate.instance); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + public SquirrelMob(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{G}"); this.subtype.add(SubType.SQUIRREL); this.power = new MageInt(2); this.toughness = new MageInt(2); // Squirrel Mob gets +1/+1 for each other Squirrel on the battlefield. - FilterCreaturePermanent filter = new FilterCreaturePermanent("other Squirrel"); - filter.add(SubType.SQUIRREL.getPredicate()); - filter.add(Predicates.not(new PermanentIdPredicate(this.getId()))); - DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); - Effect effect = new BoostSourceEffect(xValue, xValue, Duration.WhileOnBattlefield, false); - effect.setText("{this} gets +1/+1 for each other Squirrel on the battlefield"); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + this.addAbility(new SimpleStaticAbility(new BoostSourceEffect( + xValue, xValue, Duration.WhileOnBattlefield, false + ).setText("{this} gets +1/+1 for each other Squirrel on the battlefield"))); } private SquirrelMob(final SquirrelMob card) { diff --git a/Mage.Sets/src/mage/cards/s/SramsExpertise.java b/Mage.Sets/src/mage/cards/s/SramsExpertise.java index 6334c3bf86e..32332a5628a 100644 --- a/Mage.Sets/src/mage/cards/s/SramsExpertise.java +++ b/Mage.Sets/src/mage/cards/s/SramsExpertise.java @@ -1,29 +1,36 @@ - - package mage.cards.s; -import java.util.UUID; import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect; +import mage.abilities.effects.common.cost.CastFromHandForFreeEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.permanent.token.ServoToken; +import java.util.UUID; + /** * @author fireshoes */ public final class SramsExpertise extends CardImpl { + private static final FilterCard filter = new FilterCard("a spell with mana value 3 or less"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); + } + public SramsExpertise(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}{W}"); - // Create three 1/1 colorless Servo artifact creature tokens. this.getSpellAbility().addEffect(new CreateTokenEffect(new ServoToken(), 3)); // You may cast a card with converted mana cost 3 or less from your hand without paying its mana cost. - this.getSpellAbility().addEffect(new CastWithoutPayingManaCostEffect(3).concatBy("
")); + this.getSpellAbility().addEffect(new CastFromHandForFreeEffect(filter).concatBy("
")); } private SramsExpertise(final SramsExpertise card) { diff --git a/Mage.Sets/src/mage/cards/s/Stabilizer.java b/Mage.Sets/src/mage/cards/s/Stabilizer.java index bd70c9553e1..d305216451a 100644 --- a/Mage.Sets/src/mage/cards/s/Stabilizer.java +++ b/Mage.Sets/src/mage/cards/s/Stabilizer.java @@ -60,7 +60,7 @@ class StabilizerEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject == null) { return null; } diff --git a/Mage.Sets/src/mage/cards/s/StadiumVendors.java b/Mage.Sets/src/mage/cards/s/StadiumVendors.java index 9faae0932cf..e31d4992e0c 100644 --- a/Mage.Sets/src/mage/cards/s/StadiumVendors.java +++ b/Mage.Sets/src/mage/cards/s/StadiumVendors.java @@ -69,7 +69,7 @@ class StadiumVendorsEffect extends OneShotEffect { return false; } TargetPlayer target = new TargetPlayer(1, 1, true); - if (controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.Benefit, target, source, game)) { Player player = game.getPlayer(target.getFirstTarget()); ChoiceColor colorChoice = new ChoiceColor(true); if (player == null diff --git a/Mage.Sets/src/mage/cards/s/StaffOfTheLetterMagus.java b/Mage.Sets/src/mage/cards/s/StaffOfTheLetterMagus.java index 806541bd5b2..4cb9d8ad7d7 100644 --- a/Mage.Sets/src/mage/cards/s/StaffOfTheLetterMagus.java +++ b/Mage.Sets/src/mage/cards/s/StaffOfTheLetterMagus.java @@ -65,7 +65,7 @@ class StaffOfTheLetterMagusChooseLetterEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } ChoiceImpl choice = new ChoiceImpl(true); @@ -122,7 +122,7 @@ class StaffOfTheLetterMagusEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Spell spell = game.getStack().getSpell(this.getTargetPointer().getFirst(game, source)); if (controller != null && spell != null) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject instanceof Permanent) { Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (permanent != null && game.getState().getValue(mageObject.getId() + "_letter") != null) { diff --git a/Mage.Sets/src/mage/cards/s/StalwartShieldBearers.java b/Mage.Sets/src/mage/cards/s/StalwartShieldBearers.java index 1245387b2e0..565f3f85ad8 100644 --- a/Mage.Sets/src/mage/cards/s/StalwartShieldBearers.java +++ b/Mage.Sets/src/mage/cards/s/StalwartShieldBearers.java @@ -1,34 +1,34 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.keyword.DefenderAbility; 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.constants.SubType; +import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; +import java.util.UUID; + /** - * * @author North */ public final class StalwartShieldBearers extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with defender"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control with defender"); static { + filter.add(TargetController.YOU.getControllerPredicate()); filter.add(new AbilityPredicate(DefenderAbility.class)); } public StalwartShieldBearers(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); @@ -36,7 +36,9 @@ public final class StalwartShieldBearers extends CardImpl { this.toughness = new MageInt(3); this.addAbility(DefenderAbility.getInstance()); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(0, 2, Duration.WhileOnBattlefield, filter, true))); + this.addAbility(new SimpleStaticAbility(new BoostAllEffect( + 0, 2, Duration.WhileOnBattlefield, filter, true + ))); } private StalwartShieldBearers(final StalwartShieldBearers card) { diff --git a/Mage.Sets/src/mage/cards/s/StandOrFall.java b/Mage.Sets/src/mage/cards/s/StandOrFall.java index b074b3345bc..a34a01e9620 100644 --- a/Mage.Sets/src/mage/cards/s/StandOrFall.java +++ b/Mage.Sets/src/mage/cards/s/StandOrFall.java @@ -94,7 +94,7 @@ class StandOrFallEffect extends OneShotEffect { TargetCreaturePermanent creatures = new TargetCreaturePermanent(0, count, new FilterCreaturePermanent("creatures to put in the first pile"), true); List pile1 = new ArrayList<>(); creatures.setRequired(false); - if (player.choose(Outcome.Neutral, creatures, source.getSourceId(), game)) { + if (player.choose(Outcome.Neutral, creatures, source, game)) { List targets = creatures.getTargets(); for (UUID targetId : targets) { Permanent p = game.getPermanent(targetId); diff --git a/Mage.Sets/src/mage/cards/s/Standardize.java b/Mage.Sets/src/mage/cards/s/Standardize.java index 8879005abe6..d5befc3562a 100644 --- a/Mage.Sets/src/mage/cards/s/Standardize.java +++ b/Mage.Sets/src/mage/cards/s/Standardize.java @@ -57,7 +57,7 @@ class StandardizeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); String chosenType = ""; if (player != null && sourceObject != null) { Choice typeChoice = new ChoiceCreatureType(sourceObject); diff --git a/Mage.Sets/src/mage/cards/s/StarfieldOfNyx.java b/Mage.Sets/src/mage/cards/s/StarfieldOfNyx.java index 9bf5979fb41..c8338a53746 100644 --- a/Mage.Sets/src/mage/cards/s/StarfieldOfNyx.java +++ b/Mage.Sets/src/mage/cards/s/StarfieldOfNyx.java @@ -112,7 +112,7 @@ public final class StarfieldOfNyx extends CardImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, - source.getControllerId(), source.getSourceId(), game)) { + source.getControllerId(), source, game)) { switch (layer) { case TypeChangingEffects_4: if (sublayer == SubLayer.NA) { diff --git a/Mage.Sets/src/mage/cards/s/Statecraft.java b/Mage.Sets/src/mage/cards/s/Statecraft.java index 8f9b5bf428f..bd29f19f62c 100644 --- a/Mage.Sets/src/mage/cards/s/Statecraft.java +++ b/Mage.Sets/src/mage/cards/s/Statecraft.java @@ -61,11 +61,11 @@ class StatecraftPreventionEffect extends PreventionEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (super.applies(event, source, game)) { Permanent sourcePermanent = game.getPermanent(event.getSourceId()); - if (sourcePermanent != null && filter.match(sourcePermanent, source.getSourceId(), source.getControllerId(), game)) { + if (sourcePermanent != null && filter.match(sourcePermanent, source.getControllerId(), source, game)) { return true; } Permanent targetPermanent = game.getPermanent(event.getTargetId()); - if (targetPermanent != null && filter.match(targetPermanent, source.getSourceId(), source.getControllerId(), game)) { + if (targetPermanent != null && filter.match(targetPermanent, source.getControllerId(), source, game)) { return true; } } diff --git a/Mage.Sets/src/mage/cards/s/SteadfastArmasaur.java b/Mage.Sets/src/mage/cards/s/SteadfastArmasaur.java index c1c6bd174d4..cbc2dab16ea 100644 --- a/Mage.Sets/src/mage/cards/s/SteadfastArmasaur.java +++ b/Mage.Sets/src/mage/cards/s/SteadfastArmasaur.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -14,19 +12,25 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.BlockedByIdPredicate; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class SteadfastArmasaur extends CardImpl { + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature blocking or blocked by it"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.EITHER); + } + public SteadfastArmasaur(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); @@ -38,12 +42,11 @@ public final class SteadfastArmasaur extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // {1}{W}, {T}: Steadfast Armasaur deals damage equal to its toughness to target creature blocking or blocked by it. - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking or blocked by it"); - filter.add(Predicates.or(new BlockedByIdPredicate(this.getId()), - new BlockingAttackerIdPredicate(this.getId()))); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(SourcePermanentToughnessValue.getInstance()), new ManaCostsImpl("{1}{W}")); + Ability ability = new SimpleActivatedAbility( + new DamageTargetEffect(SourcePermanentToughnessValue.getInstance()), new ManaCostsImpl<>("{1}{W}") + ); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SteamAugury.java b/Mage.Sets/src/mage/cards/s/SteamAugury.java index af6f005a577..0c7792c7edd 100644 --- a/Mage.Sets/src/mage/cards/s/SteamAugury.java +++ b/Mage.Sets/src/mage/cards/s/SteamAugury.java @@ -66,7 +66,7 @@ class SteamAuguryEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Set cardsToGraveyard = new LinkedHashSet<>(); Set cardsToHand = new LinkedHashSet<>(); if (controller == null || sourceObject == null) { diff --git a/Mage.Sets/src/mage/cards/s/SteamVines.java b/Mage.Sets/src/mage/cards/s/SteamVines.java index 8bfd128b2f4..4a3f7535671 100644 --- a/Mage.Sets/src/mage/cards/s/SteamVines.java +++ b/Mage.Sets/src/mage/cards/s/SteamVines.java @@ -92,7 +92,7 @@ class SteamVinesEffect extends OneShotEffect { target.setNotTarget(true); //not a target, it is chosen Card steamVinesCard = game.getCard(source.getSourceId()); if (steamVinesCard != null && landsController != null) { - if (landsController.choose(Outcome.DestroyPermanent, target, source.getId(), game)) { + if (landsController.choose(Outcome.DestroyPermanent, target, source, game)) { if (target.getFirstTarget() != null) { Permanent landChosen = game.getPermanent(target.getFirstTarget()); if (landChosen != null) { diff --git a/Mage.Sets/src/mage/cards/s/SteamfloggerBoss.java b/Mage.Sets/src/mage/cards/s/SteamfloggerBoss.java index 8659d72e0e4..c4467fa9c81 100644 --- a/Mage.Sets/src/mage/cards/s/SteamfloggerBoss.java +++ b/Mage.Sets/src/mage/cards/s/SteamfloggerBoss.java @@ -23,7 +23,7 @@ import mage.filter.common.FilterCreaturePermanent; public final class SteamfloggerBoss extends CardImpl { private static final FilterCreaturePermanent filter - = new FilterCreaturePermanent(SubType.RIGGER, "Rigger creatures"); + = new FilterCreaturePermanent(SubType.RIGGER, "Riggers"); public SteamfloggerBoss(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); @@ -53,7 +53,7 @@ public final class SteamfloggerBoss extends CardImpl { Zone.BATTLEFIELD, new InfoEffect( "If a Rigger you control would assemble a Contraption, " - + "it assembles two Contraptions instead. (NOT IMPLEMENTED)" + + "it assembles two Contraptions instead" ) )); diff --git a/Mage.Sets/src/mage/cards/s/SteelSabotage.java b/Mage.Sets/src/mage/cards/s/SteelSabotage.java index 9bb658f9e85..bafd92e25c0 100644 --- a/Mage.Sets/src/mage/cards/s/SteelSabotage.java +++ b/Mage.Sets/src/mage/cards/s/SteelSabotage.java @@ -23,8 +23,7 @@ public final class SteelSabotage extends CardImpl { // Choose one - Counter target artifact spell; or return target artifact to its owner's hand. this.getSpellAbility().addEffect(new CounterTargetEffect()); this.getSpellAbility().addTarget(new TargetSpell(new FilterArtifactSpell())); - Mode mode = new Mode(); - mode.addEffect(new ReturnToHandTargetEffect()); + Mode mode = new Mode(new ReturnToHandTargetEffect()); mode.addTarget(new TargetArtifactPermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SteelcladSerpent.java b/Mage.Sets/src/mage/cards/s/SteelcladSerpent.java index 00e88ddd5a1..45fa63baa0a 100644 --- a/Mage.Sets/src/mage/cards/s/SteelcladSerpent.java +++ b/Mage.Sets/src/mage/cards/s/SteelcladSerpent.java @@ -74,7 +74,7 @@ class SteelcladSerpentEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(source.getSourceId())) { - return game.getBattlefield().getActivePermanents(filter, source.getControllerId(), permanent.getId(), game).isEmpty(); + return game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game).isEmpty(); } return false; } diff --git a/Mage.Sets/src/mage/cards/s/SteelformSliver.java b/Mage.Sets/src/mage/cards/s/SteelformSliver.java index 1f7c1206a89..8e639460ab5 100644 --- a/Mage.Sets/src/mage/cards/s/SteelformSliver.java +++ b/Mage.Sets/src/mage/cards/s/SteelformSliver.java @@ -29,7 +29,7 @@ public final class SteelformSliver extends CardImpl { // Sliver creatures you control get +0/+1. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(0, 1, Duration.WhileOnBattlefield, - StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, false))); + StaticFilters.FILTER_PERMANENT_SLIVERS, false))); } private SteelformSliver(final SteelformSliver card) { diff --git a/Mage.Sets/src/mage/cards/s/SteelyResolve.java b/Mage.Sets/src/mage/cards/s/SteelyResolve.java index b0659ecec4c..497104c058d 100644 --- a/Mage.Sets/src/mage/cards/s/SteelyResolve.java +++ b/Mage.Sets/src/mage/cards/s/SteelyResolve.java @@ -2,6 +2,8 @@ package mage.cards.s; import java.util.UUID; + +import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.ChooseCreatureTypeEffect; @@ -55,9 +57,9 @@ class FilterSteelyResolve extends FilterCreaturePermanent { } @Override - public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { - if (super.match(permanent, sourceId, playerId, game)) { - SubType subType = ChooseCreatureTypeEffect.getChosenCreatureType(sourceId, game); + public boolean match(Permanent permanent, UUID playerId, Ability source, Game game) { + if (super.match(permanent, playerId, source, game)) { + SubType subType = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game); if (subType != null && permanent.hasSubtype(subType, game)) { return true; } diff --git a/Mage.Sets/src/mage/cards/s/Stenchskipper.java b/Mage.Sets/src/mage/cards/s/Stenchskipper.java index 882c78f60ec..2dd8118e19e 100644 --- a/Mage.Sets/src/mage/cards/s/Stenchskipper.java +++ b/Mage.Sets/src/mage/cards/s/Stenchskipper.java @@ -1,9 +1,8 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.keyword.FlyingAbility; @@ -12,14 +11,21 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author emerald000 */ public final class Stenchskipper extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterControlledCreaturePermanent( + SubType.GOBLIN, "if you control no Goblins" + ), ComparisonType.FEWER_THAN, 1 + ); + public Stenchskipper(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.ELEMENTAL); this.power = new MageInt(6); this.toughness = new MageInt(5); @@ -29,14 +35,9 @@ public final class Stenchskipper extends CardImpl { // At the beginning of the end step, if you control no Goblins, sacrifice Stenchskipper. this.addAbility(new BeginningOfEndStepTriggeredAbility( - Zone.BATTLEFIELD, - new SacrificeSourceEffect(), - TargetController.ANY, - new PermanentsOnTheBattlefieldCondition( - new FilterControlledCreaturePermanent(SubType.GOBLIN, "if you control no Goblins"), - ComparisonType.FEWER_THAN, - 1), - false)); + Zone.BATTLEFIELD, new SacrificeSourceEffect(), + TargetController.NEXT, condition, false + )); } private Stenchskipper(final Stenchskipper card) { diff --git a/Mage.Sets/src/mage/cards/s/StensiaMasquerade.java b/Mage.Sets/src/mage/cards/s/StensiaMasquerade.java index df953fc8902..b7d5b5869fe 100644 --- a/Mage.Sets/src/mage/cards/s/StensiaMasquerade.java +++ b/Mage.Sets/src/mage/cards/s/StensiaMasquerade.java @@ -22,7 +22,6 @@ import mage.filter.predicate.permanent.AttackingPredicate; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; @@ -50,7 +49,7 @@ public final class StensiaMasquerade extends CardImpl { this.addAbility(new StensiaMasqueradeTriggeredAbility()); // Madness {2}{R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{2}{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{2}{R}"))); } private StensiaMasquerade(final StensiaMasquerade card) { diff --git a/Mage.Sets/src/mage/cards/s/SternJudge.java b/Mage.Sets/src/mage/cards/s/SternJudge.java index 234bbef5740..21c7faea98a 100644 --- a/Mage.Sets/src/mage/cards/s/SternJudge.java +++ b/Mage.Sets/src/mage/cards/s/SternJudge.java @@ -70,7 +70,7 @@ class SternJudgeEffect extends OneShotEffect { continue; } player.loseLife(game.getBattlefield().count( - filter, playerId, source.getSourceId(), game + filter, source.getSourceId(), source, game ), game, source, false); } return true; diff --git a/Mage.Sets/src/mage/cards/s/StickyFingers.java b/Mage.Sets/src/mage/cards/s/StickyFingers.java new file mode 100644 index 00000000000..557fbf2e54f --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StickyFingers.java @@ -0,0 +1,60 @@ +package mage.cards.s; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.DiesAttachedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.constants.AttachmentType; +import mage.constants.SubType; +import mage.game.permanent.token.TreasureToken; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.effects.common.AttachEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author weirddan455 + */ +public final class StickyFingers extends CardImpl { + + public StickyFingers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // Enchanted creature has menace and "Whenever this creature deals combat damage to a player, create a Treasure token. + Ability ability = new SimpleStaticAbility(new GainAbilityAttachedEffect(new MenaceAbility(false), AttachmentType.AURA)); + ability.addEffect(new GainAbilityAttachedEffect(new DealsCombatDamageToAPlayerTriggeredAbility(new CreateTokenEffect(new TreasureToken()), false), AttachmentType.AURA) + .setText("and \"Whenever this creature deals combat damage to a player, create a Treasure token.\" (It can't be blocked except by two or more creatures. The token is an artifact with \"{T}, Sacrifice this artifact: Add one mana of any color.\")")); + this.addAbility(ability); + + // When enchanted creature dies, draw a card. + this.addAbility(new DiesAttachedTriggeredAbility(new DrawCardSourceControllerEffect(1), "enchanted creature")); + } + + private StickyFingers(final StickyFingers card) { + super(card); + } + + @Override + public StickyFingers copy() { + return new StickyFingers(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StimulusPackage.java b/Mage.Sets/src/mage/cards/s/StimulusPackage.java new file mode 100644 index 00000000000..19fa50bac64 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StimulusPackage.java @@ -0,0 +1,44 @@ +package mage.cards.s; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.game.permanent.token.CitizenGreenWhiteToken; +import mage.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StimulusPackage extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.TREASURE, "a Treasure"); + + public StimulusPackage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}{G}"); + + // When Stimulus Package enters the battlefield, create two Treasure tokens. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new TreasureToken(), 2))); + + // Sacrifice a Treasure: Create a 1/1 green and white Citizen creature token. + this.addAbility(new SimpleActivatedAbility( + new CreateTokenEffect(new CitizenGreenWhiteToken()), new SacrificeTargetCost(filter) + )); + } + + private StimulusPackage(final StimulusPackage card) { + super(card); + } + + @Override + public StimulusPackage copy() { + return new StimulusPackage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StirThePride.java b/Mage.Sets/src/mage/cards/s/StirThePride.java index 8d055f273a1..949e0afb140 100644 --- a/Mage.Sets/src/mage/cards/s/StirThePride.java +++ b/Mage.Sets/src/mage/cards/s/StirThePride.java @@ -29,10 +29,9 @@ public final class StirThePride extends CardImpl { // Creatures you control get +2/+2 until end of turn; this.getSpellAbility().addEffect(new BoostControlledEffect(2,2, Duration.EndOfTurn)); // or until end of turn, creatures you control gain "Whenever this creature deals damage, you gain that much life." - Mode mode = new Mode(); Effect effect = new GainAbilityControlledEffect(new DealsDamageGainLifeSourceTriggeredAbility(), Duration.EndOfTurn); effect.setText("until end of turn, creatures you control gain \"Whenever this creature deals damage, you gain that much life.\""); - mode.addEffect(effect); + Mode mode = new Mode(effect); this.getSpellAbility().getModes().addMode(mode); // Entwine {1}{W} diff --git a/Mage.Sets/src/mage/cards/s/StitchersApprentice.java b/Mage.Sets/src/mage/cards/s/StitchersApprentice.java index 1e8081da097..100868f5eaa 100644 --- a/Mage.Sets/src/mage/cards/s/StitchersApprentice.java +++ b/Mage.Sets/src/mage/cards/s/StitchersApprentice.java @@ -75,7 +75,7 @@ class StitchersApprenticeEffect extends OneShotEffect { if (player != null) { Target target = new TargetControlledPermanent(new FilterControlledCreaturePermanent()); - if (target.canChoose(source.getSourceId(), player.getId(), game) && player.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) { + if (target.canChoose(player.getId(), source, game) && player.choose(Outcome.Sacrifice, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { return permanent.sacrifice(source, game); diff --git a/Mage.Sets/src/mage/cards/s/StitchwingSkaab.java b/Mage.Sets/src/mage/cards/s/StitchwingSkaab.java index 5dd8e57f62c..ed2016f8481 100644 --- a/Mage.Sets/src/mage/cards/s/StitchwingSkaab.java +++ b/Mage.Sets/src/mage/cards/s/StitchwingSkaab.java @@ -34,7 +34,7 @@ public final class StitchwingSkaab extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // {1}{U}, Discard two cards: Return Stitchwing Skaab from your graveyard to the battlefield tapped. - Ability ability = new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(true), new ManaCostsImpl("{1}{U}")); + Ability ability = new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(true, false), new ManaCostsImpl("{1}{U}")); ability.addCost(new DiscardTargetCost(new TargetCardInHand(2, new FilterCard("two cards")))); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StoicEphemera.java b/Mage.Sets/src/mage/cards/s/StoicEphemera.java index 21191738956..a0f1b1a5d4e 100644 --- a/Mage.Sets/src/mage/cards/s/StoicEphemera.java +++ b/Mage.Sets/src/mage/cards/s/StoicEphemera.java @@ -31,11 +31,13 @@ public final class StoicEphemera extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // When Stoic Ephemera blocks, sacrifice it at end of combat. - this.addAbility(new BlocksSourceTriggeredAbility( - new CreateDelayedTriggeredAbilityEffect( - new AtTheEndOfCombatDelayedTriggeredAbility(new SacrificeSourceEffect()) - ), false, false, true - )); + this.addAbility( + new BlocksSourceTriggeredAbility( + new CreateDelayedTriggeredAbilityEffect( + new AtTheEndOfCombatDelayedTriggeredAbility(new SacrificeSourceEffect()) + ).setText("sacrifice it at end of combat") + ).setTriggerPhrase("When {this} blocks, ") + ); } private StoicEphemera(final StoicEphemera card) { diff --git a/Mage.Sets/src/mage/cards/s/StolenStrategy.java b/Mage.Sets/src/mage/cards/s/StolenStrategy.java index 797c7b6892b..4925ba0620c 100644 --- a/Mage.Sets/src/mage/cards/s/StolenStrategy.java +++ b/Mage.Sets/src/mage/cards/s/StolenStrategy.java @@ -68,7 +68,7 @@ class StolenStrategyEffect extends OneShotEffect { if (damagedPlayer == null) { continue; } - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); UUID exileId = CardUtil.getCardExileZoneId(game, source); Card card = damagedPlayer.getLibrary().getFromTop(game); if (card != null && sourceObject != null) { diff --git a/Mage.Sets/src/mage/cards/s/StoneIdolTrap.java b/Mage.Sets/src/mage/cards/s/StoneIdolTrap.java index 8d46cad040e..c716115b9fd 100644 --- a/Mage.Sets/src/mage/cards/s/StoneIdolTrap.java +++ b/Mage.Sets/src/mage/cards/s/StoneIdolTrap.java @@ -65,7 +65,7 @@ class StoneIdolTrapCostReductionEffect extends CostModificationEffectImpl { @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { - int reductionAmount = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int reductionAmount = game.getBattlefield().count(filter, source.getControllerId(), source, game); CardUtil.reduceCost(abilityToModify, reductionAmount); return true; } diff --git a/Mage.Sets/src/mage/cards/s/StonebrowKrosanHero.java b/Mage.Sets/src/mage/cards/s/StonebrowKrosanHero.java index 9743ebadd66..8d82b172122 100644 --- a/Mage.Sets/src/mage/cards/s/StonebrowKrosanHero.java +++ b/Mage.Sets/src/mage/cards/s/StonebrowKrosanHero.java @@ -23,7 +23,7 @@ import java.util.UUID; */ public final class StonebrowKrosanHero extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(" creature you control with trample"); + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature you control with trample"); static { filter.add(new AbilityPredicate(TrampleAbility.class)); } diff --git a/Mage.Sets/src/mage/cards/s/StoneforgeAcolyte.java b/Mage.Sets/src/mage/cards/s/StoneforgeAcolyte.java index 3b5ae227335..01aa39b17ca 100644 --- a/Mage.Sets/src/mage/cards/s/StoneforgeAcolyte.java +++ b/Mage.Sets/src/mage/cards/s/StoneforgeAcolyte.java @@ -7,14 +7,13 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapTargetCost; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.permanent.TappedPredicate; @@ -45,8 +44,8 @@ public final class StoneforgeAcolyte extends CardImpl { // Cohort — {T}, Tap an untapped Ally you control: Look at the top four cards of your library. // You may reveal an Equipment card from among them and put it into your hand. Put the rest on the bottom of your library in any order. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new LookLibraryAndPickControllerEffect(StaticValue.get(4), false, StaticValue.get(1), filterEquipment, false), + Ability ability = new SimpleActivatedAbility( + new LookLibraryAndPickControllerEffect(4, 1, filterEquipment, PutCards.HAND, PutCards.BOTTOM_ANY), new TapSourceCost()); ability.addCost(new TapTargetCost(new TargetControlledPermanent(filterAlly))); ability.setAbilityWord(AbilityWord.COHORT); diff --git a/Mage.Sets/src/mage/cards/s/StonehewerGiant.java b/Mage.Sets/src/mage/cards/s/StonehewerGiant.java index 47cf1c89c32..32c6fb962fa 100644 --- a/Mage.Sets/src/mage/cards/s/StonehewerGiant.java +++ b/Mage.Sets/src/mage/cards/s/StonehewerGiant.java @@ -94,7 +94,7 @@ class StonehewerGiantEffect extends OneShotEffect { Permanent equipment = game.getPermanent(card.getId()); Target targetCreature = new TargetControlledCreaturePermanent(); targetCreature.setNotTarget(true); - if (equipment != null && controller.choose(Outcome.BoostCreature, targetCreature, source.getSourceId(), game)) { + if (equipment != null && controller.choose(Outcome.BoostCreature, targetCreature, source, game)) { Permanent permanent = game.getPermanent(targetCreature.getFirstTarget()); permanent.addAttachment(equipment.getId(), source, game); } diff --git a/Mage.Sets/src/mage/cards/s/StonewiseFortifier.java b/Mage.Sets/src/mage/cards/s/StonewiseFortifier.java index abf069ca2c2..d21065c47cb 100644 --- a/Mage.Sets/src/mage/cards/s/StonewiseFortifier.java +++ b/Mage.Sets/src/mage/cards/s/StonewiseFortifier.java @@ -77,7 +77,7 @@ class StonewiseFortifierPreventAllDamageToEffect extends PreventionEffectImpl { if (!game.replaceEvent(preventEvent)) { int preventedDamage = event.getAmount(); MageObject damageSource = game.getObject(event.getSourceId()); - MageObject preventionSource = game.getObject(source.getSourceId()); + MageObject preventionSource = game.getObject(source); if (damageSource != null && preventionSource != null) { String message = " damage from " + damageSource.getName() + " prevented " + diff --git a/Mage.Sets/src/mage/cards/s/StormElemental.java b/Mage.Sets/src/mage/cards/s/StormElemental.java index d3c21dae544..f9ac6e9ba96 100644 --- a/Mage.Sets/src/mage/cards/s/StormElemental.java +++ b/Mage.Sets/src/mage/cards/s/StormElemental.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -15,12 +13,7 @@ import mage.abilities.keyword.FlyingAbility; 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.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterLandCard; import mage.filter.predicate.mageobject.AbilityPredicate; @@ -28,23 +21,28 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 & L_J */ public final class StormElemental extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying"); + static { filter.add(new AbilityPredicate(FlyingAbility.class)); } public StormElemental(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.ELEMENTAL); this.power = new MageInt(3); this.toughness = new MageInt(4); + // Flying + this.addAbility(FlyingAbility.getInstance()); + // {U}, Exile the top card of your library: Tap target creature with flying. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new ManaCostsImpl("{U}")); ability.addCost(new ExileTopCardLibraryCost()); @@ -70,6 +68,7 @@ public final class StormElemental extends CardImpl { class StormElementalEffect extends OneShotEffect { private static final FilterLandCard filter = new FilterLandCard("snow land"); + static { filter.add(SuperType.SNOW.getPredicate()); } diff --git a/Mage.Sets/src/mage/cards/s/StormFleetArsonist.java b/Mage.Sets/src/mage/cards/s/StormFleetArsonist.java index fd6a52446ea..8120ce3c9de 100644 --- a/Mage.Sets/src/mage/cards/s/StormFleetArsonist.java +++ b/Mage.Sets/src/mage/cards/s/StormFleetArsonist.java @@ -35,7 +35,7 @@ public final class StormFleetArsonist extends CardImpl { Ability ability = new ConditionalInterveningIfTriggeredAbility( new EntersBattlefieldTriggeredAbility(new SacrificeEffect(new FilterPermanent(), 1, "Target opponent")), RaidCondition.instance, - "Raid — When {this} enters the battlefield, if you attacked this turn, target opponent sacrifices a permanent."); + "When {this} enters the battlefield, if you attacked this turn, target opponent sacrifices a permanent."); ability.addTarget(new TargetOpponent()); ability.setAbilityWord(AbilityWord.RAID); ability.addHint(RaidHint.instance); diff --git a/Mage.Sets/src/mage/cards/s/StormFleetPyromancer.java b/Mage.Sets/src/mage/cards/s/StormFleetPyromancer.java index 5b2c4b58c05..e297e9433f1 100644 --- a/Mage.Sets/src/mage/cards/s/StormFleetPyromancer.java +++ b/Mage.Sets/src/mage/cards/s/StormFleetPyromancer.java @@ -35,7 +35,7 @@ public final class StormFleetPyromancer extends CardImpl { Ability ability = new ConditionalInterveningIfTriggeredAbility( new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2)), RaidCondition.instance, - "Raid — When {this} enters the battlefield, if you attacked this turn, {this} deals 2 damage to any target."); + "When {this} enters the battlefield, if you attacked this turn, {this} deals 2 damage to any target."); ability.addTarget(new TargetAnyTarget()); ability.setAbilityWord(AbilityWord.RAID); ability.addHint(RaidHint.instance); diff --git a/Mage.Sets/src/mage/cards/s/StormFleetSpy.java b/Mage.Sets/src/mage/cards/s/StormFleetSpy.java index f8a92c52534..ae68a6bd1ce 100644 --- a/Mage.Sets/src/mage/cards/s/StormFleetSpy.java +++ b/Mage.Sets/src/mage/cards/s/StormFleetSpy.java @@ -33,7 +33,7 @@ public final class StormFleetSpy extends CardImpl { Ability ability = new ConditionalInterveningIfTriggeredAbility( new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)), RaidCondition.instance, - "Raid — When {this} enters the battlefield, if you attacked this turn, draw a card."); + "When {this} enters the battlefield, if you attacked this turn, draw a card."); ability.setAbilityWord(AbilityWord.RAID); ability.addHint(RaidHint.instance); this.addAbility(ability, new PlayerAttackedWatcher()); diff --git a/Mage.Sets/src/mage/cards/s/StormHerald.java b/Mage.Sets/src/mage/cards/s/StormHerald.java index 6a13a096f30..2e01d82fa1e 100644 --- a/Mage.Sets/src/mage/cards/s/StormHerald.java +++ b/Mage.Sets/src/mage/cards/s/StormHerald.java @@ -92,7 +92,7 @@ class StormHeraldEffect extends OneShotEffect { FilterCard filter = new FilterCard("aura cards to attach to creatures you control"); filter.add(SubType.AURA.getPredicate()); filter.add(new StormHeraldAttachablePredicate(controller.getId())); - Set possibleTargets = controller.getGraveyard().getCards(filter, source.getSourceId(), controller.getId(), game); + Set possibleTargets = controller.getGraveyard().getCards(filter, controller.getId(), source, game); if (!possibleTargets.isEmpty()) { TargetCard targetAuras = new TargetCard(0, Integer.MAX_VALUE, Zone.GRAVEYARD, filter); targetAuras.setNotTarget(true); @@ -107,7 +107,7 @@ class StormHeraldEffect extends OneShotEffect { filterAttachTo.add(new StormHeraldAttachableToPredicate(auraCard)); TargetPermanent targetCreature = new TargetPermanent(filterAttachTo); targetCreature.setNotTarget(true); - if (controller.choose(Outcome.PutCardInPlay, targetCreature, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCardInPlay, targetCreature, source, game)) { Permanent targetPermanent = game.getPermanent(targetCreature.getFirstTarget()); if (!targetPermanent.cantBeAttachedBy(auraCard, source, game, true)) { game.getState().setValue("attachTo:" + auraCard.getId(), targetPermanent); diff --git a/Mage.Sets/src/mage/cards/s/StormOfForms.java b/Mage.Sets/src/mage/cards/s/StormOfForms.java new file mode 100644 index 00000000000..9a5ca915325 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StormOfForms.java @@ -0,0 +1,89 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CastSourceTriggeredAbility; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.common.TargetNonlandPermanent; + +import java.util.Collection; +import java.util.HashMap; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StormOfForms extends CardImpl { + + public StormOfForms(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}"); + + // When you cast this spell, copy it for each kind of counter among permanents you control. You may choose new targets for the copies. + this.addAbility(new CastSourceTriggeredAbility(new StormOfFormsEffect())); + + // Return target nonland permanent to its owner's hand. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetNonlandPermanent()); + } + + private StormOfForms(final StormOfForms card) { + super(card); + } + + @Override + public StormOfForms copy() { + return new StormOfForms(this); + } +} + +class StormOfFormsEffect extends OneShotEffect { + + StormOfFormsEffect() { + super(Outcome.Benefit); + staticText = "copy it for each kind of counter among permanents you control. " + + "You may choose new targets for the copies"; + } + + private StormOfFormsEffect(final StormOfFormsEffect effect) { + super(effect); + } + + @Override + public StormOfFormsEffect copy() { + return new StormOfFormsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Spell spell = (Spell) getValue("spellCast"); + if (controller == null || spell == null) { + return false; + } + int amount = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_PERMANENT, + source.getControllerId(), source, game + ).stream() + .map(p -> p.getCounters(game)) + .map(HashMap::keySet) + .flatMap(Collection::stream) + .distinct() + .mapToInt(x -> 1) + .sum(); + if (amount > 0) { + spell.createCopyOnStack(game, source, source.getControllerId(), true, amount); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/StormOfSouls.java b/Mage.Sets/src/mage/cards/s/StormOfSouls.java index a33a47df307..d73bc1d2df9 100644 --- a/Mage.Sets/src/mage/cards/s/StormOfSouls.java +++ b/Mage.Sets/src/mage/cards/s/StormOfSouls.java @@ -5,9 +5,10 @@ import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileSpellEffect; import mage.abilities.keyword.FlyingAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; @@ -15,8 +16,6 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.targetpointer.FixedTargets; -import java.util.LinkedHashSet; -import java.util.Set; import java.util.UUID; /** @@ -34,10 +33,14 @@ public class StormOfSouls extends CardImpl { this.getSpellAbility().addEffect(new ExileSpellEffect()); } - private StormOfSouls(final StormOfSouls card) { super(card); } + private StormOfSouls(final StormOfSouls card) { + super(card); + } @Override - public StormOfSouls copy() { return new StormOfSouls(this); } + public StormOfSouls copy() { + return new StormOfSouls(this); + } } class StormOfSoulsReturnEffect extends OneShotEffect { @@ -47,39 +50,34 @@ class StormOfSoulsReturnEffect extends OneShotEffect { "Each of them is a 1/1 Spirit with flying in addition to its other types."; } - private StormOfSoulsReturnEffect(final StormOfSoulsReturnEffect effect) { super(effect); } + private StormOfSoulsReturnEffect(final StormOfSoulsReturnEffect effect) { + super(effect); + } @Override - public StormOfSoulsReturnEffect copy() { return new StormOfSoulsReturnEffect(this); } + public StormOfSoulsReturnEffect copy() { + return new StormOfSoulsReturnEffect(this); + } @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - - if (player == null) { return false; } - - Set creatureCardsToBeMovedFromGraveyard = player.getGraveyard().getCards(StaticFilters.FILTER_CARD_CREATURE, game); - if (creatureCardsToBeMovedFromGraveyard == null) { return false; } - - if (creatureCardsToBeMovedFromGraveyard.isEmpty()) { return false; } - - boolean anyCardsMoved = player.moveCards(creatureCardsToBeMovedFromGraveyard, Zone.BATTLEFIELD, source, game); - if (!anyCardsMoved) { return false; } - - // Figure out which cards were successfuly moved so that they can be turned into 1/1 Spirits - Set creatureCardsMovedFromGraveyard = new LinkedHashSet<>(); - - for (Card card : creatureCardsToBeMovedFromGraveyard) { - if (game.getState().getZone(card.getId()) == Zone.BATTLEFIELD) { - creatureCardsMovedFromGraveyard.add(card); - } + if (player == null) { + return false; } - // Change the creatures - ContinuousEffectImpl effect = new StormOfSoulsChangeCreatureEffect(); - effect.setTargetPointer(new FixedTargets(creatureCardsMovedFromGraveyard, game)); - game.addEffect(effect, source); + Cards cards = new CardsImpl(player.getGraveyard().getCards(StaticFilters.FILTER_CARD_CREATURE, game)); + if (cards.isEmpty()) { + return false; + } + player.moveCards(cards, Zone.BATTLEFIELD, source, game); + + // Figure out which cards were successfuly moved so that they can be turned into 1/1 Spirits + cards.retainZone(Zone.BATTLEFIELD, game); + + // Change the creatures + game.addEffect(new StormOfSoulsChangeCreatureEffect().setTargetPointer(new FixedTargets(cards, game)), source); return true; } } @@ -87,7 +85,7 @@ class StormOfSoulsReturnEffect extends OneShotEffect { class StormOfSoulsChangeCreatureEffect extends ContinuousEffectImpl { public StormOfSoulsChangeCreatureEffect() { - super(Duration.WhileOnBattlefield, Outcome.Benefit); + super(Duration.Custom, Outcome.Benefit); } private StormOfSoulsChangeCreatureEffect(final StormOfSoulsChangeCreatureEffect effect) { @@ -97,26 +95,26 @@ class StormOfSoulsChangeCreatureEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { Player player = game.getPlayer(source.getControllerId()); - if (player == null) { return false; } + if (player == null) { + return false; + } // Each of them is a 1/1 Spirit with flying in addition to its other types for (UUID cardID : targetPointer.getTargets(game, source)) { Permanent permanent = game.getPermanent(cardID); - if (permanent == null) { continue; } + if (permanent == null) { + continue; + } switch (layer) { case TypeChangingEffects_4: - permanent.getSubtype().add(SubType.SPIRIT); + permanent.addSubType(game, SubType.SPIRIT); break; case AbilityAddingRemovingEffects_6: - // Don't double add flying - if (!permanent.getAbilities().contains(FlyingAbility.getInstance())) { - // Add it index 0 so that it shows up at the top of the card's text. - permanent.getAbilities().add(0, FlyingAbility.getInstance()); - } + permanent.addAbility(FlyingAbility.getInstance(), source.getSourceId(), game); break; case PTChangingEffects_7: - if (sublayer == SubLayer.ModifyPT_7c) { + if (sublayer == SubLayer.SetPT_7b) { permanent.getPower().setValue(1); permanent.getToughness().setValue(1); } @@ -127,7 +125,9 @@ class StormOfSoulsChangeCreatureEffect extends ContinuousEffectImpl { } @Override - public boolean apply(Game game, Ability source) { return false; } + public boolean apply(Game game, Ability source) { + return false; + } @Override public StormOfSoulsChangeCreatureEffect copy() { diff --git a/Mage.Sets/src/mage/cards/s/StormTheFestival.java b/Mage.Sets/src/mage/cards/s/StormTheFestival.java index 185b64c24a7..921184cec88 100644 --- a/Mage.Sets/src/mage/cards/s/StormTheFestival.java +++ b/Mage.Sets/src/mage/cards/s/StormTheFestival.java @@ -2,12 +2,12 @@ package mage.cards.s; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.FlashbackAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterPermanentCard; import mage.filter.predicate.mageobject.ManaValuePredicate; @@ -20,7 +20,7 @@ import java.util.UUID; public final class StormTheFestival extends CardImpl { private static final FilterCard filter = new FilterPermanentCard( - "up to two permanent cards with mana value 5 or less" + "permanent cards with mana value 5 or less" ); static { @@ -30,10 +30,10 @@ public final class StormTheFestival extends CardImpl { public StormTheFestival(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}{G}{G}"); - // Look at the top five cards of your library. Put up to two permanent cards with mana value 5 or less from among them onto the battlefield. Put the rest on the bottom of your library in a random order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - 5, 2, filter, false, true, Zone.BATTLEFIELD, true - ).setBackInRandomOrder(true)); + // Look at the top five cards of your library. + // You may put up to two permanent cards with mana value 5 or less from among them onto the battlefield. + // Put the rest on the bottom of your library in a random order. + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(5, 2, filter, PutCards.BATTLEFIELD, PutCards.BOTTOM_RANDOM)); // Flashback {7}{G}{G}{G} this.addAbility(new FlashbackAbility(this, new ManaCostsImpl<>("{7}{G}{G}{G}"))); diff --git a/Mage.Sets/src/mage/cards/s/StormTheVault.java b/Mage.Sets/src/mage/cards/s/StormTheVault.java index 7e40fbc0493..00bf218daaa 100644 --- a/Mage.Sets/src/mage/cards/s/StormTheVault.java +++ b/Mage.Sets/src/mage/cards/s/StormTheVault.java @@ -4,7 +4,7 @@ package mage.cards.s; import java.util.UUID; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; -import mage.abilities.common.ControlledCreaturesDealCombatDamagePlayerTriggeredAbility; +import mage.abilities.common.DealCombatDamageControlledTriggeredAbility; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; @@ -32,7 +32,7 @@ public final class StormTheVault extends CardImpl { this.secondSideCardClazz = mage.cards.v.VaultOfCatlacan.class; // 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." - this.addAbility(new ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(new CreateTokenEffect(new TreasureToken()))); + this.addAbility(new DealCombatDamageControlledTriggeredAbility(new CreateTokenEffect(new TreasureToken()))); // At the beginning of your end step, if you control five or more artifacts, transform Storm the Vault. this.addAbility(new TransformAbility()); diff --git a/Mage.Sets/src/mage/cards/s/StormcragElemental.java b/Mage.Sets/src/mage/cards/s/StormcragElemental.java index 248d146de40..d2d26275aeb 100644 --- a/Mage.Sets/src/mage/cards/s/StormcragElemental.java +++ b/Mage.Sets/src/mage/cards/s/StormcragElemental.java @@ -27,7 +27,7 @@ public final class StormcragElemental extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Megamorph {4}{R}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{R}{R}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{R}{R}"), true)); } private StormcragElemental(final StormcragElemental card) { diff --git a/Mage.Sets/src/mage/cards/s/StormwingDragon.java b/Mage.Sets/src/mage/cards/s/StormwingDragon.java index 2ab90cea19f..0a1b7d52d96 100644 --- a/Mage.Sets/src/mage/cards/s/StormwingDragon.java +++ b/Mage.Sets/src/mage/cards/s/StormwingDragon.java @@ -43,7 +43,7 @@ public final class StormwingDragon extends CardImpl { this.addAbility(FirstStrikeAbility.getInstance()); // Megamorph {5}{R}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{5}{R}{R}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{5}{R}{R}"), true)); // When Stormwing Dragon is turned face up, put a +1/+1 counter on each other Dragon creature you control. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter), false, false)); diff --git a/Mage.Sets/src/mage/cards/s/Storyweave.java b/Mage.Sets/src/mage/cards/s/Storyweave.java new file mode 100644 index 00000000000..ac9cf594864 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Storyweave.java @@ -0,0 +1,164 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Storyweave extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SAGA); + + public Storyweave(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); + + // Choose one — + // • Put two +1/+1 counters on target creature you control. + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2))); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + + // • Put two lore counters on target Saga you control. The next time one or more enchantment creatures enter the battlefield under your control this turn, each enters with two additional +1/+1 counters on it. + Mode mode = new Mode(new AddCountersTargetEffect(CounterType.LORE.createInstance(2))); + mode.addEffect(new StoryweaveReplacementEffect()); + mode.addTarget(new TargetPermanent(filter)); + this.getSpellAbility().addMode(mode); + this.getSpellAbility().addWatcher(new StoryweaveWatcher()); + } + + private Storyweave(final Storyweave card) { + super(card); + } + + @Override + public Storyweave copy() { + return new Storyweave(this); + } + + public static Ability makeAbility() { + // for testing purposes + Ability ability = new SimpleActivatedAbility(new StoryweaveReplacementEffect(), new GenericManaCost(0)); + ability.addWatcher(new StoryweaveWatcher()); + return ability; + } +} + +class StoryweaveReplacementEffect extends ReplacementEffectImpl { + + private int counter = 0; + + StoryweaveReplacementEffect() { + super(Duration.EndOfTurn, Outcome.BoostCreature); + staticText = "The next time one or more enchantment creatures enter the battlefield " + + "under your control this turn, each enters with two additional +1/+1 counters on it"; + } + + StoryweaveReplacementEffect(StoryweaveReplacementEffect effect) { + super(effect); + this.counter = effect.counter; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + this.counter = StoryweaveWatcher.getCounter(game, source); + } + + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (StoryweaveWatcher.getCounter(game, source) > counter) { + discard(); + return false; + } + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + return permanent != null + && permanent.isControlledBy(source.getControllerId()) + && permanent.isEnchantment(game) + && permanent.isCreature(game); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + if (creature != null) { + creature.addCounters( + CounterType.P1P1.createInstance(2), + source.getControllerId(), source, + game, event.getAppliedEffects() + ); + } + return false; + } + + @Override + public StoryweaveReplacementEffect copy() { + return new StoryweaveReplacementEffect(this); + } +} + +class StoryweaveWatcher extends Watcher { + + private final Map playerMap = new HashMap<>(); + + StoryweaveWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.ENTERS_THE_BATTLEFIELD) { + return; + } + EntersTheBattlefieldEvent zEvent = ((EntersTheBattlefieldEvent) event); + if (zEvent.getTarget().isEnchantment(game) && zEvent.getTarget().isCreature(game)) { + playerMap.compute(zEvent.getPlayerId(), CardUtil::setOrIncrementValue); + } + } + + @Override + public void reset() { + super.reset(); + this.playerMap.clear(); + } + + static int getCounter(Game game, Ability source) { + return game + .getState() + .getWatcher(StoryweaveWatcher.class) + .playerMap + .getOrDefault(source.getControllerId(), 0); + } +} diff --git a/Mage.Sets/src/mage/cards/s/Strangle.java b/Mage.Sets/src/mage/cards/s/Strangle.java new file mode 100644 index 00000000000..b9334b863fc --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Strangle.java @@ -0,0 +1,32 @@ +package mage.cards.s; + +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Strangle extends CardImpl { + + public Strangle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R}"); + + // Strangle deals 3 damage to target creature or planeswalker. + this.getSpellAbility().addEffect(new DamageTargetEffect(3)); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + } + + private Strangle(final Strangle card) { + super(card); + } + + @Override + public Strangle copy() { + return new Strangle(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/Stranglehold.java b/Mage.Sets/src/mage/cards/s/Stranglehold.java index c7043b163dd..a5cc95c0ae7 100644 --- a/Mage.Sets/src/mage/cards/s/Stranglehold.java +++ b/Mage.Sets/src/mage/cards/s/Stranglehold.java @@ -67,7 +67,7 @@ class OpponentsCantSearchLibarariesEffect extends ContinuousRuleModifyingEffectI @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't search libraries (" + mageObject.getLogName() + " in play)."; } @@ -110,7 +110,7 @@ class StrangleholdSkipExtraTurnsEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player player = game.getPlayer(event.getPlayerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (player != null && sourceObject != null) { game.informPlayers(sourceObject.getLogName() + ": Extra turn of " + player.getLogName() + " skipped"); } diff --git a/Mage.Sets/src/mage/cards/s/StranglingGrasp.java b/Mage.Sets/src/mage/cards/s/StranglingGrasp.java index 2c78cb5ff18..0cd028601f4 100644 --- a/Mage.Sets/src/mage/cards/s/StranglingGrasp.java +++ b/Mage.Sets/src/mage/cards/s/StranglingGrasp.java @@ -101,8 +101,8 @@ class StranglingGraspEffect extends OneShotEffect { } TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { - player.choose(outcome, target, source.getSourceId(), game); + if (target.canChoose(player.getId(), source, game)) { + player.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.sacrifice(source, game); diff --git a/Mage.Sets/src/mage/cards/s/StrataScythe.java b/Mage.Sets/src/mage/cards/s/StrataScythe.java index 1ce482bd5d2..704c81ae2e3 100644 --- a/Mage.Sets/src/mage/cards/s/StrataScythe.java +++ b/Mage.Sets/src/mage/cards/s/StrataScythe.java @@ -114,7 +114,7 @@ class SameNameAsExiledCountValue implements DynamicValue { if (permanent != null && !permanent.getImprinted().isEmpty()) { FilterPermanent filterPermanent = new FilterPermanent(); filterPermanent.add(new NamePredicate(game.getCard(permanent.getImprinted().get(0)).getName())); - value = game.getBattlefield().count(filterPermanent, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + value = game.getBattlefield().count(filterPermanent, sourceAbility.getControllerId(), sourceAbility, game); } return value; } diff --git a/Mage.Sets/src/mage/cards/s/Stratadon.java b/Mage.Sets/src/mage/cards/s/Stratadon.java index c786703af29..8a49cb4b56a 100644 --- a/Mage.Sets/src/mage/cards/s/Stratadon.java +++ b/Mage.Sets/src/mage/cards/s/Stratadon.java @@ -61,7 +61,7 @@ class StratadonCostReductionEffect extends CostModificationEffectImpl { @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { - CardUtil.reduceCost(abilityToModify, new DomainValue().calculate(game, source, this)); + CardUtil.reduceCost(abilityToModify, DomainValue.REGULAR.calculate(game, source, this)); return true; } diff --git a/Mage.Sets/src/mage/cards/s/StrategicPlanning.java b/Mage.Sets/src/mage/cards/s/StrategicPlanning.java index 6e25ff17394..1a20bb62d75 100644 --- a/Mage.Sets/src/mage/cards/s/StrategicPlanning.java +++ b/Mage.Sets/src/mage/cards/s/StrategicPlanning.java @@ -1,14 +1,11 @@ - package mage.cards.s; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.StaticFilters; /** * @@ -20,8 +17,7 @@ public final class StrategicPlanning extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}"); // Look at the top three cards of your library. Put one of them into your hand and the rest into your graveyard. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(3), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.GRAVEYARD, false, false, false, Zone.HAND, false)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.GRAVEYARD)); } private StrategicPlanning(final StrategicPlanning card) { diff --git a/Mage.Sets/src/mage/cards/s/StrategySchmategy.java b/Mage.Sets/src/mage/cards/s/StrategySchmategy.java index 25e9156cd87..2413e0fd99f 100644 --- a/Mage.Sets/src/mage/cards/s/StrategySchmategy.java +++ b/Mage.Sets/src/mage/cards/s/StrategySchmategy.java @@ -46,7 +46,13 @@ class StrategySchmategyffect extends OneShotEffect { public StrategySchmategyffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "Roll a six-sided die. {this} has the indicated effect. 1 - Do nothing. 2 - Destroy all artifacts. 3 - Destroy all lands. 4 - {this} deals 3 damage to each creature and each player. 5 - Each player discards their hand and draws seven cards. 6 - Repeat this process two more times"; + this.staticText = "Roll a six-sided die. {this} has the indicated effect." + + "
1 - Do nothing." + + "
2 - Destroy all artifacts." + + "
3 - Destroy all lands." + + "
4 - {this} deals 3 damage to each creature and each player." + + "
5 - Each player discards their hand and draws seven cards." + + "
6 - Repeat this process two more times"; } public StrategySchmategyffect(final StrategySchmategyffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/StratusDancer.java b/Mage.Sets/src/mage/cards/s/StratusDancer.java index bd0c35adf03..6e579014595 100644 --- a/Mage.Sets/src/mage/cards/s/StratusDancer.java +++ b/Mage.Sets/src/mage/cards/s/StratusDancer.java @@ -34,7 +34,7 @@ public final class StratusDancer extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Megamorph {1}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{U}"), true)); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{U}"), true)); // When Stratus Dancer is turned face up, counter target instant or sorcery spell Effect effect = new CounterTargetEffect(); diff --git a/Mage.Sets/src/mage/cards/s/StreamOfThought.java b/Mage.Sets/src/mage/cards/s/StreamOfThought.java index c2772831fdc..4a0f2cc2b6a 100644 --- a/Mage.Sets/src/mage/cards/s/StreamOfThought.java +++ b/Mage.Sets/src/mage/cards/s/StreamOfThought.java @@ -32,7 +32,7 @@ public final class StreamOfThought extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayer()); // Replicate {2}{U}{U} - this.addAbility(new ReplicateAbility(this, "{2}{U}{U}")); + this.addAbility(new ReplicateAbility("{2}{U}{U}")); } private StreamOfThought(final StreamOfThought card) { diff --git a/Mage.Sets/src/mage/cards/s/StreambedAquitects.java b/Mage.Sets/src/mage/cards/s/StreambedAquitects.java index 2d7f81b84d0..32ba35910ea 100644 --- a/Mage.Sets/src/mage/cards/s/StreambedAquitects.java +++ b/Mage.Sets/src/mage/cards/s/StreambedAquitects.java @@ -1,4 +1,3 @@ - package mage.cards.s; import mage.MageInt; @@ -14,27 +13,21 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; -import mage.target.Target; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetLandPermanent; import java.util.UUID; /** - * * @author LevelX2 */ public final class StreambedAquitects extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Merfolk creature"); - static { - filter.add(SubType.MERFOLK.getPredicate()); - } + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.MERFOLK, "Merfolk creature"); public StreambedAquitects(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.MERFOLK); this.subtype.add(SubType.SCOUT); @@ -42,16 +35,18 @@ public final class StreambedAquitects extends CardImpl { this.toughness = new MageInt(3); // {tap}: Target Merfolk creature gets +1/+1 and gains islandwalk until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(1,1, Duration.EndOfTurn), new TapSourceCost()); - ability.addEffect(new GainAbilityTargetEffect(new IslandwalkAbility(false), Duration.EndOfTurn)); - Target target = new TargetCreaturePermanent(filter); - ability.addTarget(target); + Ability ability = new SimpleActivatedAbility(new BoostTargetEffect( + 1, 1, Duration.EndOfTurn + ).setText("target Merfolk creature gets +1/+1"), new TapSourceCost()); + ability.addEffect(new GainAbilityTargetEffect( + new IslandwalkAbility(false), Duration.EndOfTurn + ).setText("and gains islandwalk until end of turn")); + ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); // {tap}: Target land becomes an Island until end of turn. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesBasicLandTargetEffect(Duration.EndOfTurn, SubType.ISLAND), new TapSourceCost()); - target = new TargetLandPermanent(); - ability.addTarget(target); + ability = new SimpleActivatedAbility(new BecomesBasicLandTargetEffect(Duration.EndOfTurn, SubType.ISLAND), new TapSourceCost()); + ability.addTarget(new TargetLandPermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StrengthOfIsolation.java b/Mage.Sets/src/mage/cards/s/StrengthOfIsolation.java index b8eef436c77..7382dda0dd7 100644 --- a/Mage.Sets/src/mage/cards/s/StrengthOfIsolation.java +++ b/Mage.Sets/src/mage/cards/s/StrengthOfIsolation.java @@ -47,7 +47,7 @@ public final class StrengthOfIsolation extends CardImpl { ability.addEffect(effect); this.addAbility(ability); // Madness {W} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{W}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{W}"))); } private StrengthOfIsolation(final StrengthOfIsolation card) { diff --git a/Mage.Sets/src/mage/cards/s/StrengthOfLunacy.java b/Mage.Sets/src/mage/cards/s/StrengthOfLunacy.java index 879bf4adb12..a2d2fea2cec 100644 --- a/Mage.Sets/src/mage/cards/s/StrengthOfLunacy.java +++ b/Mage.Sets/src/mage/cards/s/StrengthOfLunacy.java @@ -47,7 +47,7 @@ public final class StrengthOfLunacy extends CardImpl { ability.addEffect(effect); this.addAbility(ability); // Madness {B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{B}"))); } private StrengthOfLunacy(final StrengthOfLunacy card) { diff --git a/Mage.Sets/src/mage/cards/s/StrengthOfUnity.java b/Mage.Sets/src/mage/cards/s/StrengthOfUnity.java index 324c9db9375..fbd5f118e8b 100644 --- a/Mage.Sets/src/mage/cards/s/StrengthOfUnity.java +++ b/Mage.Sets/src/mage/cards/s/StrengthOfUnity.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.DomainValue; @@ -13,21 +11,21 @@ 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.Zone; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; -/** - * - * @author LoneFox +import java.util.UUID; +/** + * @author LoneFox */ public final class StrengthOfUnity extends CardImpl { public StrengthOfUnity(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -37,8 +35,7 @@ public final class StrengthOfUnity extends CardImpl { Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); // Domain - Enchanted creature gets +1/+1 for each basic land type among lands you control. - DomainValue dv = new DomainValue(); - Effect effect = new BoostEnchantedEffect(dv, dv); + Effect effect = new BoostEnchantedEffect(DomainValue.REGULAR, DomainValue.REGULAR); effect.setText("Domain — Enchanted creature gets +1/+1 for each basic land type among lands you control."); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect).addHint(DomainHint.instance)); } diff --git a/Mage.Sets/src/mage/cards/s/StrictProctor.java b/Mage.Sets/src/mage/cards/s/StrictProctor.java index b6b6034074a..e94df1af1f2 100644 --- a/Mage.Sets/src/mage/cards/s/StrictProctor.java +++ b/Mage.Sets/src/mage/cards/s/StrictProctor.java @@ -15,6 +15,7 @@ import mage.game.events.GameEvent; import mage.target.targetpointer.FixedTarget; import java.util.UUID; +import mage.game.stack.StackAbility; /** * @author TheElk801 @@ -58,16 +59,25 @@ class StrictProctorTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ABILITY_TRIGGERED; + return event.getType() == GameEvent.EventType.TRIGGERED_ABILITY; } @Override public boolean checkTrigger(GameEvent event, Game game) { - GameEvent triggeringEvent = (GameEvent) game.getState().getValue(event.getId().toString()); - if (triggeringEvent == null || triggeringEvent.getType() != GameEvent.EventType.ENTERS_THE_BATTLEFIELD) { + // retrieve the event that led to the trigger triggering + // verify that it is a ETB event + StackAbility stackAbilityOfTriggeredAbility = (StackAbility) game.getObject(event.getTargetId()); + if (stackAbilityOfTriggeredAbility == null + || stackAbilityOfTriggeredAbility.getSourceId() == null) { return false; } - getEffects().setTargetPointer(new FixedTarget(triggeringEvent.getTargetId(), game)); + GameEvent triggeringEvent = (GameEvent) game.getState().getValue("triggeringEvent" + stackAbilityOfTriggeredAbility.getSourceId()); + if (triggeringEvent == null + || triggeringEvent.getType() != GameEvent.EventType.ENTERS_THE_BATTLEFIELD) { + return false; + } + // set the target to the ability that gets triggered from the enter the battlefield trigger + getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); return true; } @@ -78,7 +88,7 @@ class StrictProctorTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever a permanent entering the battlefield causes a triggered ability to trigger, " + - "counter that ability unless its controller pays {2}."; + return "Whenever a permanent entering the battlefield causes a triggered ability to trigger, " + + "counter that ability unless its controller pays {2}."; } } diff --git a/Mage.Sets/src/mage/cards/s/StrikingSliver.java b/Mage.Sets/src/mage/cards/s/StrikingSliver.java index 00de19b7e60..083e5e51fa5 100644 --- a/Mage.Sets/src/mage/cards/s/StrikingSliver.java +++ b/Mage.Sets/src/mage/cards/s/StrikingSliver.java @@ -30,7 +30,7 @@ public final class StrikingSliver extends CardImpl { // Sliver creatures you control have first strike. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(FirstStrikeAbility.getInstance(), - Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS))); + Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_SLIVERS))); } private StrikingSliver(final StrikingSliver card) { diff --git a/Mage.Sets/src/mage/cards/s/StromkirkOccultist.java b/Mage.Sets/src/mage/cards/s/StromkirkOccultist.java index a33db53e385..275548de47d 100644 --- a/Mage.Sets/src/mage/cards/s/StromkirkOccultist.java +++ b/Mage.Sets/src/mage/cards/s/StromkirkOccultist.java @@ -33,7 +33,7 @@ public final class StromkirkOccultist extends CardImpl { this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new ExileTopXMayPlayUntilEndOfTurnEffect(1), false)); // Madness {1}{R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{1}{R}"))); } private StromkirkOccultist(final StromkirkOccultist card) { diff --git a/Mage.Sets/src/mage/cards/s/StrongarmThug.java b/Mage.Sets/src/mage/cards/s/StrongarmThug.java index c20c1a67a9c..453895ddef8 100644 --- a/Mage.Sets/src/mage/cards/s/StrongarmThug.java +++ b/Mage.Sets/src/mage/cards/s/StrongarmThug.java @@ -1,12 +1,9 @@ - - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -14,20 +11,21 @@ import mage.constants.SubType; import mage.filter.common.FilterCreatureCard; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Backfir3 */ public final class StrongarmThug extends CardImpl { - private static final FilterCreatureCard filter = new FilterCreatureCard("Mercenary card"); + private static final FilterCreatureCard filter = new FilterCreatureCard("Mercenary card from your graveyard"); static { filter.add(SubType.MERCENARY.getPredicate()); } public StrongarmThug(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.MERCENARY); @@ -35,7 +33,7 @@ public final class StrongarmThug extends CardImpl { this.toughness = new MageInt(1); // When Strongarm Thug enters the battlefield, you may return target Mercenary card from your graveyard to your hand. - Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), true); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StrongholdGambit.java b/Mage.Sets/src/mage/cards/s/StrongholdGambit.java index e5acf21277a..044d7825961 100644 --- a/Mage.Sets/src/mage/cards/s/StrongholdGambit.java +++ b/Mage.Sets/src/mage/cards/s/StrongholdGambit.java @@ -61,14 +61,14 @@ class StrongholdGambitEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { Map choosenCard = new LinkedHashMap<>(); for (UUID playerId : game.getState().getPlayerList(controller.getId())) { Player player = game.getPlayer(playerId); if (player != null && !player.getHand().isEmpty()) { TargetCardInHand target = new TargetCardInHand(); - if (player.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + if (player.choose(Outcome.Benefit, target, source, game)) { choosenCard.put(playerId, target.getFirstTarget()); } } diff --git a/Mage.Sets/src/mage/cards/s/StructuralAssault.java b/Mage.Sets/src/mage/cards/s/StructuralAssault.java new file mode 100644 index 00000000000..70f8f6a3ee9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StructuralAssault.java @@ -0,0 +1,105 @@ +package mage.cards.s; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.WatcherScope; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.watchers.Watcher; + +/** + * + * @author weirddan455 + */ +public final class StructuralAssault extends CardImpl { + + public StructuralAssault(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}{R}"); + + // Destroy all artifacts, then Structural Assault deals damage to each creature equal to the number of artifacts that were put into graveyards from the battlefield this turn. + this.getSpellAbility().addEffect(new DestroyAllEffect(StaticFilters.FILTER_PERMANENT_ARTIFACTS)); + this.getSpellAbility().addEffect(new StructuralAssaultEffect()); + this.getSpellAbility().addWatcher(new StructuralAssaultWatcher()); + } + + private StructuralAssault(final StructuralAssault card) { + super(card); + } + + @Override + public StructuralAssault copy() { + return new StructuralAssault(this); + } +} + +// CardsPutIntoGraveyardWatcher does not count tokens so custom watcher is needed. +class StructuralAssaultWatcher extends Watcher { + + private int artifactsDied = 0; + + public StructuralAssaultWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.isDiesEvent() && zEvent.getTarget().isArtifact(game)) { + artifactsDied++; + } + } + } + + @Override + public void reset() { + super.reset(); + artifactsDied = 0; + } + + public int getArtifactsDied() { + return artifactsDied; + } +} + +class StructuralAssaultEffect extends OneShotEffect { + + public StructuralAssaultEffect() { + super(Outcome.Damage); + this.staticText = ", then {this} deals damage to each creature equal to the number of artifacts that were put into graveyards from the battlefield this turn"; + } + + private StructuralAssaultEffect(final StructuralAssaultEffect effect) { + super(effect); + } + + @Override + public StructuralAssaultEffect copy() { + return new StructuralAssaultEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + StructuralAssaultWatcher watcher = game.getState().getWatcher(StructuralAssaultWatcher.class); + if (watcher != null) { + int artifacts = watcher.getArtifactsDied(); + if (artifacts > 0) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURES, source.getControllerId(), source, game)) { + permanent.damage(artifacts, source, game); + } + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/StumpsquallHydra.java b/Mage.Sets/src/mage/cards/s/StumpsquallHydra.java index e59c1c4e8b1..118ce63f227 100644 --- a/Mage.Sets/src/mage/cards/s/StumpsquallHydra.java +++ b/Mage.Sets/src/mage/cards/s/StumpsquallHydra.java @@ -97,7 +97,7 @@ class StumpsquallHydraEffect extends OneShotEffect { } TargetAmount targetAmount = new TargetCreatureOrPlaneswalkerAmount(xValue, filter); targetAmount.setNotTarget(true); - player.choose(outcome, targetAmount, source.getSourceId(), game); + player.choose(outcome, targetAmount, source, game); for (UUID targetId : targetAmount.getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent == null) { diff --git a/Mage.Sets/src/mage/cards/s/StunSniper.java b/Mage.Sets/src/mage/cards/s/StunSniper.java index 47e187bb53c..47f46a6df14 100644 --- a/Mage.Sets/src/mage/cards/s/StunSniper.java +++ b/Mage.Sets/src/mage/cards/s/StunSniper.java @@ -33,7 +33,7 @@ public final class StunSniper extends CardImpl { this.toughness = new MageInt(1); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); - ability.addEffect(new TapTargetEffect()); + ability.addEffect(new TapTargetEffect().setText("tap that creature")); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StuntedGrowth.java b/Mage.Sets/src/mage/cards/s/StuntedGrowth.java index d6250d70e7e..b8f4b61f813 100644 --- a/Mage.Sets/src/mage/cards/s/StuntedGrowth.java +++ b/Mage.Sets/src/mage/cards/s/StuntedGrowth.java @@ -66,7 +66,7 @@ class StuntedGrowthEffect extends OneShotEffect { int possibleNumber = Math.min(3, targetPlayer.getHand().size()); if (possibleNumber > 0) { Target target = new TargetCardInHand(possibleNumber, new FilterCard("cards from your hand")); - targetPlayer.choose(outcome, target, source.getSourceId(), game); + targetPlayer.choose(outcome, target, source, game); Cards cards = new CardsImpl(); for (UUID cardId: target.getTargets()) { Card card = game.getCard(cardId); diff --git a/Mage.Sets/src/mage/cards/s/SubjugatorAngel.java b/Mage.Sets/src/mage/cards/s/SubjugatorAngel.java index bd8a9e69990..41b0f2ef202 100644 --- a/Mage.Sets/src/mage/cards/s/SubjugatorAngel.java +++ b/Mage.Sets/src/mage/cards/s/SubjugatorAngel.java @@ -1,4 +1,3 @@ - package mage.cards.s; import java.util.UUID; @@ -10,8 +9,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; /** * @@ -19,12 +17,6 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class SubjugatorAngel extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public SubjugatorAngel(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{W}{W}"); this.subtype.add(SubType.ANGEL); @@ -35,7 +27,7 @@ public final class SubjugatorAngel extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Subjugator Angel enters the battlefield, tap all creatures your opponents control. - this.addAbility(new EntersBattlefieldTriggeredAbility(new TapAllEffect(filter))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new TapAllEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES))); } private SubjugatorAngel(final SubjugatorAngel card) { diff --git a/Mage.Sets/src/mage/cards/s/SubterraneanTremors.java b/Mage.Sets/src/mage/cards/s/SubterraneanTremors.java index 88faa3308e9..fe346fcbb86 100644 --- a/Mage.Sets/src/mage/cards/s/SubterraneanTremors.java +++ b/Mage.Sets/src/mage/cards/s/SubterraneanTremors.java @@ -69,7 +69,7 @@ class SubterraneanTremorsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int damage = source.getManaCostsToPay().getX(); - UUID sourceId = source.getSourceId(); + UUID sourceId = source != null ? source.getSourceId() : null; UUID controllerId = source.getControllerId(); // X damage to each creature without flying diff --git a/Mage.Sets/src/mage/cards/s/SubtleStrike.java b/Mage.Sets/src/mage/cards/s/SubtleStrike.java index 5fe03e42287..d3a015cfdc7 100644 --- a/Mage.Sets/src/mage/cards/s/SubtleStrike.java +++ b/Mage.Sets/src/mage/cards/s/SubtleStrike.java @@ -29,10 +29,9 @@ public final class SubtleStrike extends CardImpl { this.getSpellAbility().addEffect(minusOneMinusOne); this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("gets -1/-1 until end of turn")); // • Put a +1/+1 counter on target creature. - Mode mode1 = new Mode(); AddCountersTargetEffect plusOnePlusOneCounter = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); plusOnePlusOneCounter.setText("Put a +1/+1 counter on target creature"); - mode1.addEffect(plusOnePlusOneCounter); + Mode mode1 = new Mode(plusOnePlusOneCounter); mode1.addTarget(new TargetCreaturePermanent().withChooseHint("gets +1/+1 counter")); this.getSpellAbility().addMode(mode1); } diff --git a/Mage.Sets/src/mage/cards/s/Subtlety.java b/Mage.Sets/src/mage/cards/s/Subtlety.java index 85d7e326253..bdb8052ea8d 100644 --- a/Mage.Sets/src/mage/cards/s/Subtlety.java +++ b/Mage.Sets/src/mage/cards/s/Subtlety.java @@ -5,22 +5,18 @@ import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.costs.common.ExileFromHandCost; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; import mage.abilities.keyword.EvokeAbility; import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.FilterSpell; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; -import mage.game.Game; -import mage.players.Player; import mage.target.TargetSpell; import mage.target.common.TargetCardInHand; @@ -57,7 +53,10 @@ public final class Subtlety extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Subtlety enters the battlefield, choose up to one target creature spell or planeswalker spell. Its owner puts it on the top or bottom of their library. - Ability ability = new EntersBattlefieldTriggeredAbility(new SubtletyEffect()); + Ability ability = new EntersBattlefieldTriggeredAbility(new PutOnTopOrBottomLibraryTargetEffect( + "choose up to one target creature spell or planeswalker spell. " + + "Its owner puts it on the top or bottom of their library" + )); ability.addTarget(new TargetSpell(0, 1, filter)); this.addAbility(ability); @@ -74,34 +73,3 @@ public final class Subtlety extends CardImpl { return new Subtlety(this); } } - -class SubtletyEffect extends OneShotEffect { - - SubtletyEffect() { - super(Outcome.Removal); - staticText = "choose up to one target creature spell or planeswalker spell. " + - "Its owner puts it on the top or bottom of their library"; - } - - private SubtletyEffect(final SubtletyEffect effect) { - super(effect); - } - - @Override - public SubtletyEffect copy() { - return new SubtletyEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget())); - if (player == null) { - return false; - } - if (player.chooseUse(Outcome.Detriment, "Put the targeted spell on the top or bottom of your library?", - "", "Top", "Bottom", source, game)) { - return new PutOnLibraryTargetEffect(true).apply(game, source); - } - return new PutOnLibraryTargetEffect(false).apply(game, source); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SuddenDemise.java b/Mage.Sets/src/mage/cards/s/SuddenDemise.java index 2b0cc7769f5..a83832b93eb 100644 --- a/Mage.Sets/src/mage/cards/s/SuddenDemise.java +++ b/Mage.Sets/src/mage/cards/s/SuddenDemise.java @@ -64,7 +64,7 @@ class SuddenDemiseDamageEffect extends OneShotEffect { final int damage = source.getManaCostsToPay().getX(); FilterPermanent filter = new FilterCreaturePermanent(); filter.add(new ColorPredicate(choice.getColor())); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanent.damage(damage, source.getSourceId(), source, game, false, true); } return true; diff --git a/Mage.Sets/src/mage/cards/s/SuddenReclamation.java b/Mage.Sets/src/mage/cards/s/SuddenReclamation.java index 1614e991dff..1531121d612 100644 --- a/Mage.Sets/src/mage/cards/s/SuddenReclamation.java +++ b/Mage.Sets/src/mage/cards/s/SuddenReclamation.java @@ -67,7 +67,7 @@ class SuddenReclamationEffect extends OneShotEffect { Cards cardsToHand = new CardsImpl(); Target target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), controller.getId(), game) + if (target.canChoose(controller.getId(), source, game) && controller.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { @@ -76,7 +76,7 @@ class SuddenReclamationEffect extends OneShotEffect { } target = new TargetCardInYourGraveyard(new FilterLandCard("land card from your graveyard")); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), controller.getId(), game) + if (target.canChoose(controller.getId(), source, game) && controller.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/s/SufferThePast.java b/Mage.Sets/src/mage/cards/s/SufferThePast.java index 2ff2c16feef..e570a2dfaaa 100644 --- a/Mage.Sets/src/mage/cards/s/SufferThePast.java +++ b/Mage.Sets/src/mage/cards/s/SufferThePast.java @@ -67,7 +67,7 @@ class SufferThePastEffect extends OneShotEffect { int numberToTarget = Math.min(targetPlayer.getGraveyard().size(), source.getManaCostsToPay().getX()); TargetCardInOpponentsGraveyard target = new TargetCardInOpponentsGraveyard(numberToTarget, numberToTarget, filter); if (you != null) { - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) && target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), game)) { + if (target.canChoose(source.getControllerId(), source, game) && target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), source, game)) { if (!target.getTargets().isEmpty()) { List targets = target.getTargets(); for (UUID targetId : targets) { diff --git a/Mage.Sets/src/mage/cards/s/SuffocatingFumes.java b/Mage.Sets/src/mage/cards/s/SuffocatingFumes.java index b3821fba0de..47433c982a1 100644 --- a/Mage.Sets/src/mage/cards/s/SuffocatingFumes.java +++ b/Mage.Sets/src/mage/cards/s/SuffocatingFumes.java @@ -1,14 +1,13 @@ package mage.cards.s; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.keyword.CyclingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.common.FilterOpponentsCreaturePermanent; +import mage.filter.StaticFilters; import java.util.UUID; @@ -17,19 +16,16 @@ import java.util.UUID; */ public final class SuffocatingFumes extends CardImpl { - private static final FilterCreaturePermanent filter - = new FilterOpponentsCreaturePermanent("creatures your opponents control"); - public SuffocatingFumes(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); // Creatures your opponents control get -1/-1 until end of turn. this.getSpellAbility().addEffect(new BoostAllEffect( - -1, -1, Duration.EndOfTurn, filter, false + -1, -1, Duration.EndOfTurn, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, false )); // Cycling {2} - this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); + this.addAbility(new CyclingAbility(new GenericManaCost(2))); } private SuffocatingFumes(final SuffocatingFumes card) { diff --git a/Mage.Sets/src/mage/cards/s/SuitUp.java b/Mage.Sets/src/mage/cards/s/SuitUp.java new file mode 100644 index 00000000000..d2f3b31bd42 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SuitUp.java @@ -0,0 +1,55 @@ +package mage.cards.s; + +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.AddCardTypeTargetEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SuitUp extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("creature or Vehicle"); + + static { + filter.add(Predicates.or( + CardType.CREATURE.getPredicate(), + SubType.VEHICLE.getPredicate() + )); + } + + public SuitUp(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}"); + + // Until end of turn, target creature or Vehicle becomes an artifact creature with base power and toughness 4/5. + this.getSpellAbility().addEffect(new AddCardTypeTargetEffect( + Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE + ).setText("until end of turn, target creature or Vehicle becomes an artifact creature")); + this.getSpellAbility().addEffect(new SetPowerToughnessTargetEffect( + 4, 5, Duration.EndOfTurn + ).setText("with base power and toughness 4/5")); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); + } + + private SuitUp(final SuitUp card) { + super(card); + } + + @Override + public SuitUp copy() { + return new SuitUp(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SultaiAscendancy.java b/Mage.Sets/src/mage/cards/s/SultaiAscendancy.java index 7fbcaaddab9..abacba8a0e9 100644 --- a/Mage.Sets/src/mage/cards/s/SultaiAscendancy.java +++ b/Mage.Sets/src/mage/cards/s/SultaiAscendancy.java @@ -1,17 +1,13 @@ - package mage.cards.s; import java.util.UUID; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TargetController; -import mage.constants.Zone; -import mage.filter.FilterCard; /** * @@ -22,11 +18,11 @@ public final class SultaiAscendancy extends CardImpl { public SultaiAscendancy(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}{G}{U}"); - // At the beginning of your upkeep, look at the top two cards of your library. Put any number of them into your graveyard and the rest on top of your library in any order. - Effect effect = new LookLibraryAndPickControllerEffect( - StaticValue.get(2), false, StaticValue.get(2), new FilterCard(), Zone.LIBRARY, true, false, true, Zone.GRAVEYARD, false); - effect.setText("look at the top two cards of your library. Put any number of them into your graveyard and the rest on top of your library in any order"); - this.addAbility(new BeginningOfUpkeepTriggeredAbility(effect, TargetController.YOU, false)); + // At the beginning of your upkeep, look at the top two cards of your library. + // Put any number of them into your graveyard and the rest back on top of your library in any order. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new LookLibraryAndPickControllerEffect(2, Integer.MAX_VALUE, PutCards.GRAVEYARD, PutCards.TOP_ANY), + TargetController.YOU, false)); } private SultaiAscendancy(final SultaiAscendancy card) { diff --git a/Mage.Sets/src/mage/cards/s/SultaiCharm.java b/Mage.Sets/src/mage/cards/s/SultaiCharm.java index 396660d480f..e3857574757 100644 --- a/Mage.Sets/src/mage/cards/s/SultaiCharm.java +++ b/Mage.Sets/src/mage/cards/s/SultaiCharm.java @@ -37,14 +37,12 @@ public final class SultaiCharm extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); // * Destroy target artifact or enchantment. - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); this.getSpellAbility().addMode(mode); // * Draw two cards, then discard a card. - mode = new Mode(); - mode.addEffect(new DrawDiscardControllerEffect(2,1)); + mode = new Mode(new DrawDiscardControllerEffect(2,1)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SultaiSoothsayer.java b/Mage.Sets/src/mage/cards/s/SultaiSoothsayer.java index c962951bbd4..1bf2e150147 100644 --- a/Mage.Sets/src/mage/cards/s/SultaiSoothsayer.java +++ b/Mage.Sets/src/mage/cards/s/SultaiSoothsayer.java @@ -1,17 +1,14 @@ - package mage.cards.s; import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.StaticFilters; /** * @@ -27,9 +24,10 @@ public final class SultaiSoothsayer extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(5); - // When Sultai Soothsayer enters the battlefield, look at the top four cards of your library. Put one of them into your hand and the rest into your graveyard. - this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect(StaticValue.get(4), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.GRAVEYARD, false, false, false, Zone.HAND, false), false)); + // When Sultai Soothsayer enters the battlefield, look at the top four cards of your library. + // Put one of them into your hand and the rest into your graveyard. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new LookLibraryAndPickControllerEffect(4, 1, PutCards.HAND, PutCards.GRAVEYARD))); } private SultaiSoothsayer(final SultaiSoothsayer card) { diff --git a/Mage.Sets/src/mage/cards/s/SumalaWoodshaper.java b/Mage.Sets/src/mage/cards/s/SumalaWoodshaper.java index 4c6ad7aa68d..aac25d74ece 100644 --- a/Mage.Sets/src/mage/cards/s/SumalaWoodshaper.java +++ b/Mage.Sets/src/mage/cards/s/SumalaWoodshaper.java @@ -2,13 +2,12 @@ package mage.cards.s; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; @@ -37,11 +36,11 @@ public final class SumalaWoodshaper extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(1); - // When Sumala Woodshaper enters the battlefield, look at the top four cards of your library. You may reveal a creature or enchantment card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. - this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(1), filter, Zone.LIBRARY, false, - true, false, Zone.HAND, false, false, false - ).setBackInRandomOrder(true), false)); + // When Sumala Woodshaper enters the battlefield, look at the top four cards of your library. + // You may reveal a creature or enchantment card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new LookLibraryAndPickControllerEffect(4, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM))); } private SumalaWoodshaper(final SumalaWoodshaper card) { diff --git a/Mage.Sets/src/mage/cards/s/SummonTheSchool.java b/Mage.Sets/src/mage/cards/s/SummonTheSchool.java index 274ff5d580f..95a55524098 100644 --- a/Mage.Sets/src/mage/cards/s/SummonTheSchool.java +++ b/Mage.Sets/src/mage/cards/s/SummonTheSchool.java @@ -1,11 +1,9 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapTargetCost; import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -16,27 +14,32 @@ import mage.filter.predicate.permanent.TappedPredicate; import mage.game.permanent.token.MerfolkWizardToken; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class SummonTheSchool extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Merfolk you control"); + private static final FilterControlledPermanent filter + = new FilterControlledPermanent(SubType.MERFOLK, "untapped Merfolk you control"); static { filter.add(TappedPredicate.UNTAPPED); - filter.add(SubType.MERFOLK.getPredicate()); } public SummonTheSchool(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.TRIBAL,CardType.SORCERY},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.TRIBAL, CardType.SORCERY}, "{3}{W}"); this.subtype.add(SubType.MERFOLK); - + // Create two 1/1 blue Merfolk Wizard creature tokens. this.getSpellAbility().addEffect(new CreateTokenEffect(new MerfolkWizardToken(), 2)); + // Tap four untapped Merfolk you control: Return Summon the School from your graveyard to your hand. - this.addAbility(new SimpleActivatedAbility(Zone.GRAVEYARD, new ReturnToHandSourceEffect(), new TapTargetCost(new TargetControlledPermanent(4, 4, filter, false)))); + this.addAbility(new SimpleActivatedAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), + new TapTargetCost(new TargetControlledPermanent(4, filter)) + )); } private SummonTheSchool(final SummonTheSchool card) { diff --git a/Mage.Sets/src/mage/cards/s/SummonersEgg.java b/Mage.Sets/src/mage/cards/s/SummonersEgg.java index af57aa40e20..2c665151089 100644 --- a/Mage.Sets/src/mage/cards/s/SummonersEgg.java +++ b/Mage.Sets/src/mage/cards/s/SummonersEgg.java @@ -10,10 +10,7 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; @@ -36,7 +33,7 @@ public final class SummonersEgg extends CardImpl { // Imprint - When Summoner's Egg enters the battlefield, you may exile a card from your hand face down. this.addAbility(new EntersBattlefieldTriggeredAbility( new SummonersEggImprintEffect(), true) - .withFlavorWord("Imprint") + .setAbilityWord(AbilityWord.IMPRINT) ); // When Summoner's Egg dies, turn the exiled card face up. If it's a creature card, put it onto the battlefield under your control. @@ -71,7 +68,7 @@ class SummonersEggImprintEffect extends OneShotEffect { if (controller != null && sourcePermanent != null) { if (!controller.getHand().isEmpty()) { TargetCard target = new TargetCard(Zone.HAND, StaticFilters.FILTER_CARD); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + if (target.canChoose(source.getControllerId(), source, game) && controller.choose(Outcome.Benefit, controller.getHand(), target, game)) { Card card = controller.getHand().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/s/SummoningTrap.java b/Mage.Sets/src/mage/cards/s/SummoningTrap.java index dadc579e069..4339ce56bae 100644 --- a/Mage.Sets/src/mage/cards/s/SummoningTrap.java +++ b/Mage.Sets/src/mage/cards/s/SummoningTrap.java @@ -5,10 +5,12 @@ import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.costs.AlternativeCostSourceAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +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.events.GameEvent; import mage.game.stack.Spell; @@ -34,8 +36,10 @@ public final class SummoningTrap extends CardImpl { // If a creature spell you cast this turn was countered by a spell or ability an opponent controlled, you may pay {0} rather than pay Summoning Trap's mana cost. this.addAbility(new AlternativeCostSourceAbility(new ManaCostsImpl("{0}"), SummoningTrapCondition.instance), new SummoningTrapWatcher()); - // Look at the top seven cards of your library. You may put a creature card from among them onto the battlefield. Put the rest on the bottom of your library in any order. - this.getSpellAbility().addEffect(new SummoningTrapEffect()); + // Look at the top seven cards of your library. You may put a creature card from among them onto the battlefield. + // Put the rest on the bottom of your library in any order. + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + 7, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.BATTLEFIELD, PutCards.BOTTOM_ANY)); } private SummoningTrap(final SummoningTrap card) { @@ -104,45 +108,3 @@ class SummoningTrapWatcher extends Watcher { players.clear(); } } - -class SummoningTrapEffect extends OneShotEffect { - - public SummoningTrapEffect(final SummoningTrapEffect effect) { - super(effect); - } - - public SummoningTrapEffect() { - super(Outcome.PutCreatureInPlay); - this.staticText = "Look at the top seven cards of your library. You may put a creature card from among them onto the battlefield. Put the rest on the bottom of your library in any order"; - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 7)); - if (!cards.isEmpty()) { - TargetCard target = new TargetCard(Zone.LIBRARY, - new FilterCreatureCard( - "creature card to put on the battlefield")); - if (controller.choose(Outcome.PutCreatureInPlay, cards, target, game)) { - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - controller.moveCards(card, Zone.BATTLEFIELD, source, game); - } - } - if (!cards.isEmpty()) { - controller.putCardsOnBottomOfLibrary(cards, game, source, true); - } - } - return true; - } - - @Override - public SummoningTrapEffect copy() { - return new SummoningTrapEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java b/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java index 83d6e0e0321..64bafb1026a 100644 --- a/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java +++ b/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java @@ -1,13 +1,9 @@ package mage.cards.s; -import java.util.UUID; -import mage.ApprovingObject; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.Cards; @@ -17,17 +13,17 @@ import mage.constants.ComparisonType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.common.FilterNonlandCard; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.players.Player; -import mage.target.TargetCard; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author spjspj */ public final class SunbirdsInvocation extends CardImpl { @@ -54,11 +50,11 @@ public final class SunbirdsInvocation extends CardImpl { class SunbirdsInvocationTriggeredAbility extends SpellCastControllerTriggeredAbility { - public SunbirdsInvocationTriggeredAbility() { + SunbirdsInvocationTriggeredAbility() { super(new SunbirdsInvocationEffect(), false); } - public SunbirdsInvocationTriggeredAbility(SunbirdsInvocationTriggeredAbility ability) { + private SunbirdsInvocationTriggeredAbility(SunbirdsInvocationTriggeredAbility ability) { super(ability); } @@ -87,12 +83,10 @@ class SunbirdsInvocationTriggeredAbility extends SpellCastControllerTriggeredAbi @Override public String getRule() { - return "Whenever you cast a spell from your hand, " - + "reveal the top X cards of your library, " - + "where X is that spell's mana value. " - + "You may cast a card revealed this way with " - + "mana value X or less without paying its mana cost." - + " Put the rest on the bottom of your library in a random order."; + return "Whenever you cast a spell from your hand, reveal the top X cards of your library, " + + "where X is that spell's mana value. You may cast a spell with mana value X or less " + + "from among cards revealed this way without paying its mana cost. " + + "Put the rest on the bottom of your library in a random order."; } } @@ -100,10 +94,6 @@ class SunbirdsInvocationEffect extends OneShotEffect { public SunbirdsInvocationEffect() { super(Outcome.PutCardInPlay); - staticText = "reveal the top X cards of your library, where X is that " - + "spell's mana value. You may cast a card revealed this " - + "way with mana value X or less without paying its mana cost. " - + "Put the rest on the bottom of your library in a random order"; } public SunbirdsInvocationEffect(final SunbirdsInvocationEffect effect) { @@ -113,9 +103,7 @@ class SunbirdsInvocationEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller == null - || sourceObject == null) { + if (controller == null) { return false; } Spell spell = game.getSpellOrLKIStack(this.getTargetPointer().getFirst(game, source)); @@ -124,29 +112,15 @@ class SunbirdsInvocationEffect extends OneShotEffect { } int xValue = spell.getManaValue(); Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, xValue)); - if (!cards.isEmpty()) { - controller.revealCards(sourceObject.getIdName(), cards, game); - - FilterCard filter = new FilterNonlandCard("card revealed this way with mana value " + xValue + " or less"); - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, xValue + 1)); - TargetCard target = new TargetCard(1, Zone.LIBRARY, filter); - - if (controller.chooseTarget(Outcome.PlayForFree, cards, target, source, game)) { - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - if (controller.chooseUse(Outcome.Benefit, "Cast " + card.getLogName() + " without paying its mana cost?", source, game)) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - if (cardWasCast) { - cards.remove(card); - } - } - } - } - controller.putCardsOnBottomOfLibrary(cards, game, source, false); + if (cards.isEmpty()) { + return true; } + controller.revealCards(source, cards, game); + FilterCard filter = new FilterCard(); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, xValue + 1)); + CardUtil.castSpellWithAttributesForFree(controller, source, game, cards, filter); + cards.retainZone(Zone.LIBRARY, game); + controller.putCardsOnBottomOfLibrary(cards, game, source, false); return true; } diff --git a/Mage.Sets/src/mage/cards/s/Suncleanser.java b/Mage.Sets/src/mage/cards/s/Suncleanser.java index ede7ec7aa80..105fd78d0f5 100644 --- a/Mage.Sets/src/mage/cards/s/Suncleanser.java +++ b/Mage.Sets/src/mage/cards/s/Suncleanser.java @@ -44,8 +44,7 @@ public final class Suncleanser extends CardImpl { ability.addTarget(new TargetCreaturePermanent()); // • Target opponent loses all counters. That player can't get counters for as long as Suncleanser remains on the battlefield. - Mode mode = new Mode(); - mode.addEffect(new SuncleanserRemoveCountersEffect(true)); + Mode mode = new Mode(new SuncleanserRemoveCountersEffect(true)); mode.addEffect(new SuncleanserPreventCountersEffect(true)); mode.addTarget(new TargetOpponent()); ability.addMode(mode); diff --git a/Mage.Sets/src/mage/cards/s/SunderingTitan.java b/Mage.Sets/src/mage/cards/s/SunderingTitan.java index 398e59c62f1..049f9295bee 100644 --- a/Mage.Sets/src/mage/cards/s/SunderingTitan.java +++ b/Mage.Sets/src/mage/cards/s/SunderingTitan.java @@ -72,7 +72,7 @@ class SunderingTitanDestroyLandEffect extends OneShotEffect { FilterLandPermanent filter = new FilterLandPermanent(landName + " to destroy"); filter.add(landName.getPredicate()); Target target = new TargetLandPermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (target.canChoose(source.getControllerId(), source, game)) { controller.chooseTarget(outcome, target, source, game); lands.add(target.getFirstTarget()); } diff --git a/Mage.Sets/src/mage/cards/s/Sunforger.java b/Mage.Sets/src/mage/cards/s/Sunforger.java index 937b4913fc9..85e47c4ec46 100644 --- a/Mage.Sets/src/mage/cards/s/Sunforger.java +++ b/Mage.Sets/src/mage/cards/s/Sunforger.java @@ -178,7 +178,7 @@ class CardCanBeCastPredicate implements Predicate { public boolean apply(Card input, Game game) { SpellAbility ability = input.getSpellAbility().copy(); ability.setControllerId(controllerId); - input.adjustTargets(ability, game); + ability.adjustTargets(game); return ability.canChooseTarget(game, controllerId); } diff --git a/Mage.Sets/src/mage/cards/s/SunkenHope.java b/Mage.Sets/src/mage/cards/s/SunkenHope.java index 52d5b2b6224..4f910df13ee 100644 --- a/Mage.Sets/src/mage/cards/s/SunkenHope.java +++ b/Mage.Sets/src/mage/cards/s/SunkenHope.java @@ -66,9 +66,9 @@ class SunkenHopeReturnToHandEffect extends OneShotEffect { } Target target = new TargetControlledPermanent(1, 1, new FilterControlledCreaturePermanent(), true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { while (player.canRespond() && !target.isChosen() - && target.canChoose(source.getSourceId(), player.getId(), game)) { + && target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.ReturnToHand, target, source, game); } diff --git a/Mage.Sets/src/mage/cards/s/SunriseSovereign.java b/Mage.Sets/src/mage/cards/s/SunriseSovereign.java index 19297404286..d2865fc977b 100644 --- a/Mage.Sets/src/mage/cards/s/SunriseSovereign.java +++ b/Mage.Sets/src/mage/cards/s/SunriseSovereign.java @@ -1,8 +1,7 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -12,31 +11,37 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class SunriseSovereign extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Giant"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Giant creatures"); static { filter.add(SubType.GIANT.getPredicate()); } public SunriseSovereign(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}"); this.subtype.add(SubType.GIANT); this.subtype.add(SubType.WARRIOR); this.power = new MageInt(5); this.toughness = new MageInt(5); + // Other Giant creatures you control get +2/+2 and have trample. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, filter, true))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.WhileOnBattlefield, filter, true))); + Ability ability = new SimpleStaticAbility(new BoostControlledEffect( + 2, 2, Duration.WhileOnBattlefield, filter, true + )); + ability.addEffect(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.WhileOnBattlefield, filter, true + ).setText("and have trample")); + this.addAbility(ability); } private SunriseSovereign(final SunriseSovereign card) { diff --git a/Mage.Sets/src/mage/cards/s/SunscourgeChampion.java b/Mage.Sets/src/mage/cards/s/SunscourgeChampion.java index d29838f9f16..072c76860f8 100644 --- a/Mage.Sets/src/mage/cards/s/SunscourgeChampion.java +++ b/Mage.Sets/src/mage/cards/s/SunscourgeChampion.java @@ -1,9 +1,6 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.costs.common.DiscardCardCost; @@ -13,19 +10,20 @@ import mage.abilities.keyword.EternalizeAbility; 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.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author spjspj */ public final class SunscourgeChampion extends CardImpl { - - private static String rule = "Eternalize - {2}{W}{W}, Discard a card ({2}{W}{W}, Discard a card, Exile this card from your graveyard: Create a token that's a copy of it, except it's a 4/4 black Zombie"; + + private static final String rule = "Eternalize — {2}{W}{W}, Discard a card. ({2}{W}{W}, Discard a card, Exile this card from your graveyard: Create a token that's a copy of it, except it's a 4/4 black Zombie)"; public SunscourgeChampion(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); @@ -39,7 +37,7 @@ public final class SunscourgeChampion extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new SunscourgeChampionEffect(), false)); // Eternalize - {2}{W}{W}, Discard a card. - EternalizeAbility ability = new EternalizeAbility(new ManaCostsImpl("{2}{W}{W}"), this, rule); + Ability ability = new EternalizeAbility(new ManaCostsImpl<>("{2}{W}{W}"), this, rule); ability.addCost(new DiscardCardCost()); this.addAbility(ability); } @@ -67,10 +65,9 @@ class SunscourgeChampionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + Permanent permanent = source.getSourcePermanentIfItStillExists(game); Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller != null && permanent != null && sourceObject != null) { + if (controller != null && permanent != null) { controller.gainLife(permanent.getPower().getValue(), game, source); return true; } diff --git a/Mage.Sets/src/mage/cards/s/SuntailSquadron.java b/Mage.Sets/src/mage/cards/s/SuntailSquadron.java new file mode 100644 index 00000000000..c40183e4ab5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SuntailSquadron.java @@ -0,0 +1,67 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ConjureCardEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SuntailSquadron extends CardImpl { + + public SuntailSquadron(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}{W}"); + + // Conjure a card named Suntail Hawk into your hand. If you have fewer than 7 cards in hand, repeat this process. + this.getSpellAbility().addEffect(new SuntailSquadronEffect()); + } + + private SuntailSquadron(final SuntailSquadron card) { + super(card); + } + + @Override + public SuntailSquadron copy() { + return new SuntailSquadron(this); + } +} + +class SuntailSquadronEffect extends OneShotEffect { + + SuntailSquadronEffect() { + super(Outcome.Benefit); + staticText = "conjure a card named Suntail Hawk into your hand. " + + "If you have fewer than 7 cards in hand, repeat this process"; + } + + private SuntailSquadronEffect(final SuntailSquadronEffect effect) { + super(effect); + } + + @Override + public SuntailSquadronEffect copy() { + return new SuntailSquadronEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Effect effect = new ConjureCardEffect("Suntail Hawk"); + do { + effect.apply(game, source); + } while (player.getHand().size() < 7); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SupremeExemplar.java b/Mage.Sets/src/mage/cards/s/SupremeExemplar.java index e4d6e38058c..698bfdd351c 100644 --- a/Mage.Sets/src/mage/cards/s/SupremeExemplar.java +++ b/Mage.Sets/src/mage/cards/s/SupremeExemplar.java @@ -33,7 +33,7 @@ public final class SupremeExemplar extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Champion an Elemental - this.addAbility(new ChampionAbility(this, SubType.ELEMENTAL, false)); + this.addAbility(new ChampionAbility(this, SubType.ELEMENTAL)); } private SupremeExemplar(final SupremeExemplar card) { diff --git a/Mage.Sets/src/mage/cards/s/SupremeInquisitor.java b/Mage.Sets/src/mage/cards/s/SupremeInquisitor.java index dfc0ff0b2bf..2b88ce48624 100644 --- a/Mage.Sets/src/mage/cards/s/SupremeInquisitor.java +++ b/Mage.Sets/src/mage/cards/s/SupremeInquisitor.java @@ -1,31 +1,22 @@ - package mage.cards.s; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapTargetCost; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.search.SearchLibraryAndExileTargetEffect; 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.common.FilterControlledPermanent; import mage.filter.predicate.permanent.TappedPredicate; -import mage.game.Game; -import mage.players.Player; import mage.target.TargetPlayer; -import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class SupremeInquisitor extends CardImpl { @@ -38,7 +29,7 @@ public final class SupremeInquisitor extends CardImpl { } public SupremeInquisitor(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.HUMAN); this.subtype.add(SubType.WIZARD); @@ -46,7 +37,10 @@ public final class SupremeInquisitor extends CardImpl { this.toughness = new MageInt(3); // Tap five untapped Wizards you control: Search target player's library for up to five cards and exile them. Then that player shuffles their library. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SupremeInquisitorEffect(), new TapTargetCost(new TargetControlledPermanent(5, 5, filter, true))); + Ability ability = new SimpleActivatedAbility( + new SearchLibraryAndExileTargetEffect(5, true), + new TapTargetCost(new TargetControlledPermanent(5, filter)) + ); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } @@ -60,43 +54,3 @@ public final class SupremeInquisitor extends CardImpl { return new SupremeInquisitor(this); } } - -class SupremeInquisitorEffect extends OneShotEffect { - - private static final FilterCard filter = new FilterCard(); - - public SupremeInquisitorEffect() { - super(Outcome.Exile); - staticText = "Search target player's library for up to five cards and exile them. Then that player shuffles"; - } - - public SupremeInquisitorEffect(final SupremeInquisitorEffect effect) { - super(effect); - } - - @Override - public SupremeInquisitorEffect copy() { - return new SupremeInquisitorEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player targetPlayer = game.getPlayer(source.getFirstTarget()); - Player player = game.getPlayer(source.getControllerId()); - if (player != null && targetPlayer != null) { - TargetCardInLibrary target = new TargetCardInLibrary(0, 5, filter); - if (player.searchLibrary(target, source, game, targetPlayer.getId())) { - List targetId = target.getTargets(); - for (UUID targetCard : targetId) { - Card card = targetPlayer.getLibrary().remove(targetCard, game); - if (card != null) { - player.moveCardToExileWithInfo(card, null, null, source, game, Zone.LIBRARY, true); - } - } - } - targetPlayer.shuffleLibrary(source, game); - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SupremeLeaderSnoke.java b/Mage.Sets/src/mage/cards/s/SupremeLeaderSnoke.java index 4959cd037f2..17c764b6f08 100644 --- a/Mage.Sets/src/mage/cards/s/SupremeLeaderSnoke.java +++ b/Mage.Sets/src/mage/cards/s/SupremeLeaderSnoke.java @@ -2,7 +2,6 @@ package mage.cards.s; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.common.PayVariableLoyaltyCost; @@ -42,7 +41,7 @@ public final class SupremeLeaderSnoke extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SNOKE); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Put a loyalty counter on Supreme Leader Snoke for each life lost by all opponents from noncombat sources this turn. Ability ability1 = new LoyaltyAbility(new SupremeLeaderSnokeCounterEffect(CounterType.LOYALTY.createInstance()), 1); diff --git a/Mage.Sets/src/mage/cards/s/SupremeWill.java b/Mage.Sets/src/mage/cards/s/SupremeWill.java index 4ae4f567d70..d7c70baa919 100644 --- a/Mage.Sets/src/mage/cards/s/SupremeWill.java +++ b/Mage.Sets/src/mage/cards/s/SupremeWill.java @@ -1,17 +1,14 @@ - package mage.cards.s; import java.util.UUID; import mage.abilities.Mode; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.CounterUnlessPaysEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import mage.target.TargetSpell; /** @@ -28,8 +25,7 @@ public final class SupremeWill extends CardImpl { this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(new GenericManaCost(3))); // or Look at the top four cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order. - Mode mode = new Mode(); - mode.addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(4), false, StaticValue.get(1), StaticFilters.FILTER_CARD, Zone.LIBRARY, false, false)); + Mode mode = new Mode(new LookLibraryAndPickControllerEffect(4, 1, PutCards.HAND, PutCards.BOTTOM_ANY)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SurgeOfZeal.java b/Mage.Sets/src/mage/cards/s/SurgeOfZeal.java index fd0dd855f73..0af9198901f 100644 --- a/Mage.Sets/src/mage/cards/s/SurgeOfZeal.java +++ b/Mage.Sets/src/mage/cards/s/SurgeOfZeal.java @@ -69,7 +69,7 @@ class SurgeOfZealEffect extends OneShotEffect { Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source)); if (target != null) { ObjectColor color = target.getColor(game); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { if (permanent.getColor(game).shares(color)) { ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); effect.setTargetPointer(new FixedTarget(permanent, game)); diff --git a/Mage.Sets/src/mage/cards/s/SurgehackerMech.java b/Mage.Sets/src/mage/cards/s/SurgehackerMech.java index 20fa0306238..276bd969787 100644 --- a/Mage.Sets/src/mage/cards/s/SurgehackerMech.java +++ b/Mage.Sets/src/mage/cards/s/SurgehackerMech.java @@ -28,7 +28,7 @@ import java.util.UUID; public final class SurgehackerMech extends CardImpl { private static final FilterPermanent filter - = new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker and opponent controls"); + = new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker an opponent controls"); private static final FilterPermanent filter2 = new FilterControlledPermanent(SubType.VEHICLE); @@ -52,7 +52,7 @@ public final class SurgehackerMech extends CardImpl { this.addAbility(new MenaceAbility(false)); // When Surgehacker Mech enters the battlefield, it deals damage equal to twice the number of Vehicles you control to target creature or planeswalker an opponent controls. - Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(xValue)); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(xValue).setText("it deals damage equal to twice the number of Vehicles you control to target creature or planeswalker an opponent controls")); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability.addHint(hint)); diff --git a/Mage.Sets/src/mage/cards/s/SurpriseDeployment.java b/Mage.Sets/src/mage/cards/s/SurpriseDeployment.java index 28c0cf00f46..b1e8ef05572 100644 --- a/Mage.Sets/src/mage/cards/s/SurpriseDeployment.java +++ b/Mage.Sets/src/mage/cards/s/SurpriseDeployment.java @@ -81,7 +81,7 @@ class SurpriseDeploymentEffect extends OneShotEffect { if (controller != null) { if (controller.chooseUse(Outcome.PutCreatureInPlay, choiceText, source, game)) { TargetCardInHand target = new TargetCardInHand(filter); - if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCreatureInPlay, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { diff --git a/Mage.Sets/src/mage/cards/s/SurrakarMarauder.java b/Mage.Sets/src/mage/cards/s/SurrakarMarauder.java index 8bacd91aad3..da2d0712ea8 100644 --- a/Mage.Sets/src/mage/cards/s/SurrakarMarauder.java +++ b/Mage.Sets/src/mage/cards/s/SurrakarMarauder.java @@ -1,9 +1,9 @@ - package mage.cards.s; import java.util.UUID; import mage.MageInt; import mage.abilities.common.LandfallAbility; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.IntimidateAbility; import mage.cards.CardImpl; @@ -27,7 +27,9 @@ public final class SurrakarMarauder extends CardImpl { // Landfall - Whenever a land enters the battlefield under your control, Surrakar Marauder gains intimidate until end of turn. // (It can't be blocked except by artifact creatures and/or creatures that share a color with it.) - this.addAbility(new LandfallAbility(new GainAbilitySourceEffect(IntimidateAbility.getInstance(), Duration.EndOfTurn), false)); + Effect effect = new GainAbilitySourceEffect(IntimidateAbility.getInstance(), Duration.EndOfTurn); + effect.setText("{this} gains intimidate until end of turn. (It can't be blocked except by artifact creatures and/or creatures that share a color with it.)"); + this.addAbility(new LandfallAbility(effect)); } private SurrakarMarauder(final SurrakarMarauder card) { diff --git a/Mage.Sets/src/mage/cards/s/SurrakarSpellblade.java b/Mage.Sets/src/mage/cards/s/SurrakarSpellblade.java index 7d5321e5804..dcc56ab0ba4 100644 --- a/Mage.Sets/src/mage/cards/s/SurrakarSpellblade.java +++ b/Mage.Sets/src/mage/cards/s/SurrakarSpellblade.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; @@ -13,35 +11,32 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; -import mage.filter.FilterSpell; -import mage.filter.predicate.Predicates; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class SurrakarSpellblade extends CardImpl { - private static final FilterSpell filter = new FilterSpell("instant or sorcery card"); - - static { - filter.add(Predicates.or( - CardType.INSTANT.getPredicate(), - CardType.SORCERY.getPredicate())); - } - public SurrakarSpellblade(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.SURRAKAR); this.power = new MageInt(2); this.toughness = new MageInt(1); // Whenever you cast an instant or sorcery spell, you may put a charge counter on Surrakar Spellblade. - this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), filter, true)); + this.addAbility(new SpellCastControllerTriggeredAbility( + new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, true + )); // Whenever Surrakar Spellblade deals combat damage to a player, you may draw X cards, where X is the number of charge counters on it. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DrawCardSourceControllerEffect(new CountersSourceCount(CounterType.CHARGE)), true)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DrawCardSourceControllerEffect( + new CountersSourceCount(CounterType.CHARGE) + ).setText("draw X cards, where X is the number of charge counters on it"), true)); } private SurrakarSpellblade(final SurrakarSpellblade card) { diff --git a/Mage.Sets/src/mage/cards/s/SurtlandElementalist.java b/Mage.Sets/src/mage/cards/s/SurtlandElementalist.java index 5d8d9d2b309..d2c6d613456 100644 --- a/Mage.Sets/src/mage/cards/s/SurtlandElementalist.java +++ b/Mage.Sets/src/mage/cards/s/SurtlandElementalist.java @@ -1,34 +1,29 @@ package mage.cards.s; -import java.util.UUID; - -import mage.ApprovingObject; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.costs.OrCost; import mage.abilities.costs.common.RevealTargetFromHandCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.constants.Outcome; -import mage.constants.SubType; +import mage.abilities.effects.common.cost.CastFromHandForFreeEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.FilterCard; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; +import mage.filter.common.FilterInstantOrSorceryCard; import mage.target.common.TargetCardInHand; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class SurtlandElementalist extends CardImpl { private static final FilterCard filter = new FilterCard("a Giant card from your hand"); + private static final FilterCard filter2 = new FilterInstantOrSorceryCard("an instant or sorcery spell"); + static { filter.add(SubType.GIANT.getPredicate()); } @@ -43,12 +38,12 @@ public final class SurtlandElementalist extends CardImpl { // As an additional cost to cast this spell, reveal a Giant card from your hand or pay {2}. this.getSpellAbility().addCost(new OrCost( - new RevealTargetFromHandCost(new TargetCardInHand(filter)), - new GenericManaCost(2), - "reveal a Giant card from your hand or pay {2}")); + "reveal a Giant card from your hand or pay {2}", new RevealTargetFromHandCost(new TargetCardInHand(filter)), + new GenericManaCost(2) + )); // Whenever Surtland Elementalist attacks, you may cast an instant or sorcery spell from your hand without paying its mana cost. - this.addAbility(new AttacksTriggeredAbility(new SurtlandElementalistEffect(), true)); + this.addAbility(new AttacksTriggeredAbility(new CastFromHandForFreeEffect(filter2), true)); } private SurtlandElementalist(final SurtlandElementalist card) { @@ -60,39 +55,3 @@ public final class SurtlandElementalist extends CardImpl { return new SurtlandElementalist(this); } } - -class SurtlandElementalistEffect extends OneShotEffect { - - public SurtlandElementalistEffect () { - super(Outcome.PlayForFree); - this.staticText = "cast an instant or sorcery spell from your hand without paying its mana cost"; - } - - private SurtlandElementalistEffect(final SurtlandElementalistEffect effect) { - super(effect); - } - - @Override - public SurtlandElementalistEffect copy() { - return new SurtlandElementalistEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - TargetCardInHand target = new TargetCardInHand(0, 1, StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY); - if (player.chooseTarget(Outcome.PlayForFree, target, source, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - boolean cardWasCast = player.cast(player.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - return cardWasCast; - } - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SurtlandFlinger.java b/Mage.Sets/src/mage/cards/s/SurtlandFlinger.java index 644ffecf644..285d0f5e803 100644 --- a/Mage.Sets/src/mage/cards/s/SurtlandFlinger.java +++ b/Mage.Sets/src/mage/cards/s/SurtlandFlinger.java @@ -76,7 +76,7 @@ class SurtlandFlingerEffect extends OneShotEffect { TargetPermanent target = new TargetPermanent( 0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, true ); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent == null) { return false; diff --git a/Mage.Sets/src/mage/cards/s/SurvivorOfTheUnseen.java b/Mage.Sets/src/mage/cards/s/SurvivorOfTheUnseen.java index d773ec1842d..f7e7ca917e1 100644 --- a/Mage.Sets/src/mage/cards/s/SurvivorOfTheUnseen.java +++ b/Mage.Sets/src/mage/cards/s/SurvivorOfTheUnseen.java @@ -80,7 +80,7 @@ class SurvivorOfTheUnseenEffect extends OneShotEffect { private boolean putOnLibrary(Player player, Ability source, Game game) { TargetCardInHand target = new TargetCardInHand(); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.ReturnToHand, target, source, game); Card card = player.getHand().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/s/SustainerOfTheRealm.java b/Mage.Sets/src/mage/cards/s/SustainerOfTheRealm.java index 9fa32c744de..6c591f7ea1b 100644 --- a/Mage.Sets/src/mage/cards/s/SustainerOfTheRealm.java +++ b/Mage.Sets/src/mage/cards/s/SustainerOfTheRealm.java @@ -1,4 +1,3 @@ - package mage.cards.s; import java.util.UUID; @@ -9,8 +8,8 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; /** * @@ -28,7 +27,7 @@ public final class SustainerOfTheRealm extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Whenever Sustainer of the Realm blocks, it gets +0/+2 until end of turn. - this.addAbility(new BlocksSourceTriggeredAbility(new BoostSourceEffect(0, 2, Duration.EndOfTurn), false)); + this.addAbility(new BlocksSourceTriggeredAbility(new BoostSourceEffect(0, 2, Duration.EndOfTurn, "it"))); } private SustainerOfTheRealm(final SustainerOfTheRealm card) { diff --git a/Mage.Sets/src/mage/cards/s/SvellaIceShaper.java b/Mage.Sets/src/mage/cards/s/SvellaIceShaper.java index 8b7437056d1..703f974f971 100644 --- a/Mage.Sets/src/mage/cards/s/SvellaIceShaper.java +++ b/Mage.Sets/src/mage/cards/s/SvellaIceShaper.java @@ -1,6 +1,5 @@ package mage.cards.s; -import mage.ApprovingObject; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -9,19 +8,17 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; -import mage.cards.*; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.filter.common.FilterNonlandCard; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.*; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.token.IcyManalithToken; import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; -import java.util.Set; import java.util.UUID; /** @@ -47,7 +44,7 @@ public final class SvellaIceShaper extends CardImpl { this.addAbility(ability); // {6}{R}{G}, {T}: Look at the top four cards of your library. You may cast a spell from among them without paying its mana cost. Put the rest on the bottom of your library in a random order. - ability = new SimpleActivatedAbility(new SvellaIceShaperEffect(), new ManaCostsImpl("{6}{R}{G}")); + ability = new SimpleActivatedAbility(new SvellaIceShaperEffect(), new ManaCostsImpl<>("{6}{R}{G}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); } @@ -86,23 +83,9 @@ class SvellaIceShaperEffect extends OneShotEffect { if (controller == null) { return false; } - Set cardsSet = controller.getLibrary().getTopCards(game, 4); - Cards cards = new CardsImpl(cardsSet); - TargetCard target = new TargetCardInLibrary(0, 1, - new FilterNonlandCard("card to cast without paying its mana cost")); - controller.choose(Outcome.PlayForFree, cards, target, game); - Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); - if (card == null) { - controller.putCardsOnBottomOfLibrary(cards, game, source, false); - return true; - } - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - if (cardWasCast) { - cards.remove(card); - } + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 4)); + CardUtil.castSpellWithAttributesForFree(controller, source, game, cards, StaticFilters.FILTER_CARD); + cards.retainZone(Zone.LIBRARY, game); controller.putCardsOnBottomOfLibrary(cards, game, source, false); return true; } diff --git a/Mage.Sets/src/mage/cards/s/SvyelunOfSeaAndSky.java b/Mage.Sets/src/mage/cards/s/SvyelunOfSeaAndSky.java index c52dc802825..39736d64df8 100644 --- a/Mage.Sets/src/mage/cards/s/SvyelunOfSeaAndSky.java +++ b/Mage.Sets/src/mage/cards/s/SvyelunOfSeaAndSky.java @@ -29,7 +29,7 @@ import java.util.UUID; */ public final class SvyelunOfSeaAndSky extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(SubType.MERFOLK, "other Merfolk"); + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.MERFOLK); static { filter.add(AnotherPredicate.instance); diff --git a/Mage.Sets/src/mage/cards/s/SwarmShambler.java b/Mage.Sets/src/mage/cards/s/SwarmShambler.java index e82020013b1..d54acb9165d 100644 --- a/Mage.Sets/src/mage/cards/s/SwarmShambler.java +++ b/Mage.Sets/src/mage/cards/s/SwarmShambler.java @@ -90,8 +90,8 @@ class SwarmShamblerTriggeredAbility extends TriggeredAbilityImpl { Permanent permanent = game.getPermanent(event.getTargetId()); return sourceObject != null && permanent != null - && StaticFilters.FILTER_CONTROLLED_CREATURE_P1P1.match(permanent, getSourceId(), getControllerId(), game) - && StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS.match(sourceObject, getSourceId(), getControllerId(), game); + && StaticFilters.FILTER_CONTROLLED_CREATURE_P1P1.match(permanent, getControllerId(), this, game) + && StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS.match(sourceObject, getControllerId(), this, game); } @Override diff --git a/Mage.Sets/src/mage/cards/s/SwayOfTheStars.java b/Mage.Sets/src/mage/cards/s/SwayOfTheStars.java index cc908553689..e1bc3e05df1 100644 --- a/Mage.Sets/src/mage/cards/s/SwayOfTheStars.java +++ b/Mage.Sets/src/mage/cards/s/SwayOfTheStars.java @@ -69,7 +69,7 @@ class SwayOfTheStarsEffect extends OneShotEffect { FilterPermanent filter = new FilterPermanent(); filter.add(new OwnerIdPredicate(playerId)); Cards toLib = new CardsImpl(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, controller.getId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, controller.getId(), source, game)) { toLib.add(permanent); } player.shuffleCardsToLibrary(toLib, game, source); diff --git a/Mage.Sets/src/mage/cards/s/SwiftReckoning.java b/Mage.Sets/src/mage/cards/s/SwiftReckoning.java index c02acce70e5..58980f6a871 100644 --- a/Mage.Sets/src/mage/cards/s/SwiftReckoning.java +++ b/Mage.Sets/src/mage/cards/s/SwiftReckoning.java @@ -1,15 +1,13 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.SpellMasteryCondition; import mage.abilities.decorator.ConditionalAsThoughEffect; -import mage.abilities.effects.AsThoughEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Zone; @@ -17,8 +15,9 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SwiftReckoning extends CardImpl { @@ -30,13 +29,17 @@ public final class SwiftReckoning extends CardImpl { } public SwiftReckoning(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{W}"); // Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, you may cast Swift Reckoning as though it had flash. - AsThoughEffect effect = new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame); - effect.setText("Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, you may cast {this} as though it had flash"); - this.addAbility(new SimpleStaticAbility(Zone.ALL, new ConditionalAsThoughEffect(effect, - SpellMasteryCondition.instance))); + this.addAbility(new SimpleStaticAbility( + Zone.ALL, + new ConditionalAsThoughEffect( + new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame), SpellMasteryCondition.instance + ).setText("If there are two or more instant and/or sorcery cards in your graveyard, " + + "you may cast {this} as though it had flash") + ).setAbilityWord(AbilityWord.SPELL_MASTERY)); + // Destroy target tapped creature. this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); diff --git a/Mage.Sets/src/mage/cards/s/SwiftReconfiguration.java b/Mage.Sets/src/mage/cards/s/SwiftReconfiguration.java new file mode 100644 index 00000000000..d8a774f2802 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SwiftReconfiguration.java @@ -0,0 +1,112 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SwiftReconfiguration extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("creature or Vehicle"); + + static { + filter.add(Predicates.or( + CardType.CREATURE.getPredicate(), + SubType.VEHICLE.getPredicate() + )); + } + + public SwiftReconfiguration(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); + + this.subtype.add(SubType.AURA); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Enchant creature or Vehicle + TargetPermanent auraTarget = new TargetPermanent(filter); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // Enchanted permanent is a Vehicle artifact with crew 5 and it loses all other card types. + this.addAbility(new SimpleStaticAbility(new SwiftReconfigurationEffect())); + } + + private SwiftReconfiguration(final SwiftReconfiguration card) { + super(card); + } + + @Override + public SwiftReconfiguration copy() { + return new SwiftReconfiguration(this); + } +} + +class SwiftReconfigurationEffect extends ContinuousEffectImpl { + + SwiftReconfigurationEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + staticText = "enchanted permanent is a Vehicle artifact with crew 5 and it loses all other card types"; + } + + private SwiftReconfigurationEffect(final SwiftReconfigurationEffect effect) { + super(effect); + } + + @Override + public SwiftReconfigurationEffect copy() { + return new SwiftReconfigurationEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent aura = source.getSourcePermanentIfItStillExists(game); + if (aura == null) { + return false; + } + Permanent permanent = game.getPermanent(aura.getAttachedTo()); + if (permanent == null) { + return false; + } + switch (layer) { + case TypeChangingEffects_4: + permanent.removeAllCardTypes(game); + permanent.addCardType(game, CardType.ARTIFACT); + permanent.addSubType(game, SubType.VEHICLE); + return true; + case AbilityAddingRemovingEffects_6: + permanent.addAbility(new CrewAbility(5), source.getSourceId(), game); + return true; + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.TypeChangingEffects_4 + || layer == Layer.AbilityAddingRemovingEffects_6; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SwiftWarkite.java b/Mage.Sets/src/mage/cards/s/SwiftWarkite.java index cf410941e49..a57c3f60887 100644 --- a/Mage.Sets/src/mage/cards/s/SwiftWarkite.java +++ b/Mage.Sets/src/mage/cards/s/SwiftWarkite.java @@ -92,7 +92,7 @@ class SwiftWarkiteEffect extends OneShotEffect { if (controller != null) { if (controller.chooseUse(Outcome.PutCardInPlay, "Put a creature card from your hand? (No = from your graveyard)", source, game)) { Target target = new TargetCardInHand(0, 1, filter); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); Card card = controller.getHand().get(target.getFirstTarget(), game); if (card != null) { if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { @@ -110,7 +110,7 @@ class SwiftWarkiteEffect extends OneShotEffect { } } else { Target target = new TargetCardInYourGraveyard(0, 1, filter); - target.choose(Outcome.PutCardInPlay, source.getControllerId(), source.getSourceId(), game); + target.choose(Outcome.PutCardInPlay, source.getControllerId(), source.getSourceId(), source, game); Card card = controller.getGraveyard().get(target.getFirstTarget(), game); if (card != null) { controller.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/s/SwirlingSpriggan.java b/Mage.Sets/src/mage/cards/s/SwirlingSpriggan.java index eceb04d798a..15b5ee2d62e 100644 --- a/Mage.Sets/src/mage/cards/s/SwirlingSpriggan.java +++ b/Mage.Sets/src/mage/cards/s/SwirlingSpriggan.java @@ -20,7 +20,7 @@ import mage.target.common.TargetControlledCreaturePermanent; * @author LevelX2 */ public final class SwirlingSpriggan extends CardImpl { - + public SwirlingSpriggan(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}{G}"); this.subtype.add(SubType.GOBLIN); @@ -30,7 +30,7 @@ public final class SwirlingSpriggan extends CardImpl { this.toughness = new MageInt(3); // {GU}{GU}: Target creature you control becomes the color or colors of your choice until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesColorOrColorsTargetEffect(Duration.EndOfTurn), new ManaCostsImpl("G/U}{G/U}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesColorOrColorsTargetEffect(Duration.EndOfTurn), new ManaCostsImpl("{G/U}{G/U}")); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SwoopingProtector.java b/Mage.Sets/src/mage/cards/s/SwoopingProtector.java new file mode 100644 index 00000000000..b0c2b554087 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SwoopingProtector.java @@ -0,0 +1,51 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SwoopingProtector extends CardImpl { + + public SwoopingProtector(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Swooping Protector enters the battlefield with a shield counter on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.SHIELD.createInstance(1)), + "with a shield counter on it. (If it would be dealt damage " + + "or destroyed, remove a shield counter from it instead.)" + )); + } + + private SwoopingProtector(final SwoopingProtector card) { + super(card); + } + + @Override + public SwoopingProtector copy() { + return new SwoopingProtector(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SwordOfTruthAndJustice.java b/Mage.Sets/src/mage/cards/s/SwordOfTruthAndJustice.java index 10eb177ad8d..4108d854aed 100644 --- a/Mage.Sets/src/mage/cards/s/SwordOfTruthAndJustice.java +++ b/Mage.Sets/src/mage/cards/s/SwordOfTruthAndJustice.java @@ -86,7 +86,7 @@ class SwordOfTruthAndJusticeEffect extends OneShotEffect { } Target target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (player.choose(outcome, target, source.getSourceId(), game)) { + if (player.choose(outcome, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game); diff --git a/Mage.Sets/src/mage/cards/s/SwordPointDiplomacy.java b/Mage.Sets/src/mage/cards/s/SwordPointDiplomacy.java index 2118d5885aa..7fc28f57770 100644 --- a/Mage.Sets/src/mage/cards/s/SwordPointDiplomacy.java +++ b/Mage.Sets/src/mage/cards/s/SwordPointDiplomacy.java @@ -61,7 +61,7 @@ class SwordPointDiplomacyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/s/SwornDefender.java b/Mage.Sets/src/mage/cards/s/SwornDefender.java index ae30d0a4afe..c54524244c9 100644 --- a/Mage.Sets/src/mage/cards/s/SwornDefender.java +++ b/Mage.Sets/src/mage/cards/s/SwornDefender.java @@ -9,14 +9,13 @@ import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.BlockedByIdPredicate; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; import mage.util.CardUtil; import java.util.UUID; @@ -26,6 +25,13 @@ import java.util.UUID; */ public final class SwornDefender extends CardImpl { + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature blocking or blocked by {this}"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.EITHER); + } + public SwornDefender(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); this.subtype.add(SubType.HUMAN); @@ -33,14 +39,10 @@ public final class SwornDefender extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(3); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking or blocked by SwornDefender"); - filter.add(Predicates.or(new BlockedByIdPredicate(this.getId()), - new BlockingAttackerIdPredicate(this.getId()))); // {1}: Sworn Defender’s power becomes the toughness of target creature blocking or being blocked by Sworn Defender minus 1 until end of turn, and Sworn Defender’s toughness becomes 1 plus the power of that creature until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SwornDefenderEffect(), new GenericManaCost(1)); - ability.addTarget(new TargetCreaturePermanent(filter)); + Ability ability = new SimpleActivatedAbility(new SwornDefenderEffect(), new GenericManaCost(1)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); - } private SwornDefender(final SwornDefender card) { diff --git a/Mage.Sets/src/mage/cards/s/SydriGalvanicGenius.java b/Mage.Sets/src/mage/cards/s/SydriGalvanicGenius.java index 9b8b07c61d8..a07f21e6e79 100644 --- a/Mage.Sets/src/mage/cards/s/SydriGalvanicGenius.java +++ b/Mage.Sets/src/mage/cards/s/SydriGalvanicGenius.java @@ -46,7 +46,7 @@ public final class SydriGalvanicGenius extends CardImpl { this.toughness = new MageInt(2); // {U}: Target noncreature artifact becomes an artifact creature with power and toughness each equal to its converted mana cost until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SydriGalvanicGeniusEffect(), new ManaCostsImpl("{U")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SydriGalvanicGeniusEffect(), new ManaCostsImpl("{U}")); ability.addTarget(new TargetPermanent(filterNonCreature)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/SylvanEchoes.java b/Mage.Sets/src/mage/cards/s/SylvanEchoes.java index f181a731563..47b86af15e4 100644 --- a/Mage.Sets/src/mage/cards/s/SylvanEchoes.java +++ b/Mage.Sets/src/mage/cards/s/SylvanEchoes.java @@ -60,6 +60,6 @@ class SylvanEchoesTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever you clash and win, you may draw a card"; + return "Whenever you clash and win, you may draw a card."; } } diff --git a/Mage.Sets/src/mage/cards/s/SylvanHierophant.java b/Mage.Sets/src/mage/cards/s/SylvanHierophant.java index d385bc69c2b..93740e1102d 100644 --- a/Mage.Sets/src/mage/cards/s/SylvanHierophant.java +++ b/Mage.Sets/src/mage/cards/s/SylvanHierophant.java @@ -11,7 +11,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; @@ -27,7 +27,7 @@ public final class SylvanHierophant extends CardImpl { private static final FilterCreatureCard filter = new FilterCreatureCard("another target creature card from your graveyard"); static { - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); } public SylvanHierophant(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SylvanLibrary.java b/Mage.Sets/src/mage/cards/s/SylvanLibrary.java index 345b3b00191..2dec3dfdc65 100644 --- a/Mage.Sets/src/mage/cards/s/SylvanLibrary.java +++ b/Mage.Sets/src/mage/cards/s/SylvanLibrary.java @@ -89,7 +89,7 @@ class SylvanLibraryEffect extends OneShotEffect { FilterCard filter = new FilterCard(numberOfTargets + " cards of cards drawn this turn"); filter.add(new CardIdPredicate(cards)); TargetCardInHand target = new TargetCardInHand(numberOfTargets, filter); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); Cards cardsPutBack = new CardsImpl(); for (UUID cardId : target.getTargets()) { diff --git a/Mage.Sets/src/mage/cards/s/SylvanOffering.java b/Mage.Sets/src/mage/cards/s/SylvanOffering.java index c5789a19848..f6a615026e0 100644 --- a/Mage.Sets/src/mage/cards/s/SylvanOffering.java +++ b/Mage.Sets/src/mage/cards/s/SylvanOffering.java @@ -63,7 +63,7 @@ class SylvanOfferingEffect1 extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Target target = new TargetOpponent(true); - target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), game); + target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), source, game); Player opponent = game.getPlayer(target.getFirstTarget()); if (opponent != null) { int xValue = source.getManaCostsToPay().getX(); @@ -100,7 +100,7 @@ class SylvanOfferingEffect2 extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Target target = new TargetOpponent(true); - target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), game); + target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), source, game); Player opponent = game.getPlayer(target.getFirstTarget()); if (opponent != null) { int xValue = source.getManaCostsToPay().getX(); diff --git a/Mage.Sets/src/mage/cards/s/SynapseSliver.java b/Mage.Sets/src/mage/cards/s/SynapseSliver.java index aa91c233829..094db229dad 100644 --- a/Mage.Sets/src/mage/cards/s/SynapseSliver.java +++ b/Mage.Sets/src/mage/cards/s/SynapseSliver.java @@ -1,37 +1,40 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.DrawCardTargetEffect; +import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SetTargetPointer; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; /** - * * @author cbt33 */ public final class SynapseSliver extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.SLIVER, "a Sliver"); + public SynapseSliver(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); this.subtype.add(SubType.SLIVER); this.power = new MageInt(3); this.toughness = new MageInt(3); // Whenever a Sliver deals combat damage to a player, its controller may draw a card. - Effect effect = new DrawCardTargetEffect(1); - effect.setText("its controller may draw a card"); - this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility(effect, - new FilterCreaturePermanent(SubType.SLIVER, "a Sliver"), - true, SetTargetPointer.PLAYER, true)); + this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility( + new SynapseSliverEffect(), filter, false, + SetTargetPointer.PLAYER, true + )); } private SynapseSliver(final SynapseSliver card) { @@ -43,3 +46,28 @@ public final class SynapseSliver extends CardImpl { return new SynapseSliver(this); } } + +class SynapseSliverEffect extends OneShotEffect { + + SynapseSliverEffect() { + super(Outcome.Benefit); + staticText = "its controller may draw a card"; + } + + private SynapseSliverEffect(final SynapseSliverEffect effect) { + super(effect); + } + + @Override + public SynapseSliverEffect copy() { + return new SynapseSliverEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + return player != null + && player.chooseUse(outcome, "Draw a card?", source, game) + && player.drawCards(1, source, game) > 0; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SyndicateInfiltrator.java b/Mage.Sets/src/mage/cards/s/SyndicateInfiltrator.java new file mode 100644 index 00000000000..335240bc447 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SyndicateInfiltrator.java @@ -0,0 +1,50 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.DifferentManaValuesInGraveCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.common.DifferentManaValuesInGraveHint; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SyndicateInfiltrator extends CardImpl { + + public SyndicateInfiltrator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // As long as there are five or more mana values among cards in your graveyard, Syndicate Infiltrator gets +2/+2. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), + DifferentManaValuesInGraveCondition.FIVE, "as long as there are five " + + "or more mana values among cards in your graveyard, {this} gets +2/+2" + )).addHint(DifferentManaValuesInGraveHint.instance)); + } + + private SyndicateInfiltrator(final SyndicateInfiltrator card) { + super(card); + } + + @Override + public SyndicateInfiltrator copy() { + return new SyndicateInfiltrator(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SyndicateTrafficker.java b/Mage.Sets/src/mage/cards/s/SyndicateTrafficker.java index 635823a0206..d83a217ea9e 100644 --- a/Mage.Sets/src/mage/cards/s/SyndicateTrafficker.java +++ b/Mage.Sets/src/mage/cards/s/SyndicateTrafficker.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -13,30 +11,34 @@ import mage.abilities.keyword.IndestructibleAbility; 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.constants.SubType; import mage.counters.CounterType; -import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.StaticFilters; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class SyndicateTrafficker extends CardImpl { public SyndicateTrafficker(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.AETHERBORN); this.subtype.add(SubType.ROGUE); this.power = new MageInt(3); this.toughness = new MageInt(1); // {1}, Sacrifice an artifact: Put a +1/+1 counter on Syndicate Trafficker. It gains indestructible until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new GenericManaCost(1)); - ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledArtifactPermanent("an artifact")))); - ability.addEffect(new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn)); + Ability ability = new SimpleActivatedAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new GenericManaCost(1) + ); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_AN))); + ability.addEffect(new GainAbilitySourceEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn + ).setText("It gains indestructible until end of turn")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SynodSanctum.java b/Mage.Sets/src/mage/cards/s/SynodSanctum.java index 9838e9d6ec5..77eb9f2cfe4 100644 --- a/Mage.Sets/src/mage/cards/s/SynodSanctum.java +++ b/Mage.Sets/src/mage/cards/s/SynodSanctum.java @@ -78,7 +78,7 @@ class SynodSanctumEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { if (getTargetPointer().getFirst(game, source) != null) { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); diff --git a/Mage.Sets/src/mage/cards/s/SyphonFlesh.java b/Mage.Sets/src/mage/cards/s/SyphonFlesh.java index 944e0d49ee3..88c09c5a6fc 100644 --- a/Mage.Sets/src/mage/cards/s/SyphonFlesh.java +++ b/Mage.Sets/src/mage/cards/s/SyphonFlesh.java @@ -65,7 +65,7 @@ class SyphonFleshEffect extends OneShotEffect { if (player != null && !playerId.equals(source.getControllerId())) { TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Sacrifice, target, source, game); perms.addAll(target.getTargets()); } diff --git a/Mage.Sets/src/mage/cards/s/SyphonLife.java b/Mage.Sets/src/mage/cards/s/SyphonLife.java index 29874a4a43b..8cfbb7a8563 100644 --- a/Mage.Sets/src/mage/cards/s/SyphonLife.java +++ b/Mage.Sets/src/mage/cards/s/SyphonLife.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.keyword.RetraceAbility; @@ -10,20 +8,21 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author Plopman */ public final class SyphonLife extends CardImpl { public SyphonLife(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{B}"); // Target player loses 2 life and you gain 2 life. this.getSpellAbility().addEffect(new LoseLifeTargetEffect(2)); this.getSpellAbility().addTarget(new TargetPlayer()); - this.getSpellAbility().addEffect(new GainLifeEffect(2)); + this.getSpellAbility().addEffect(new GainLifeEffect(2).concatBy("and")); + // Retrace this.addAbility(new RetraceAbility(this)); } diff --git a/Mage.Sets/src/mage/cards/s/SyphonMind.java b/Mage.Sets/src/mage/cards/s/SyphonMind.java index 4cff653a10d..7feddc0b5eb 100644 --- a/Mage.Sets/src/mage/cards/s/SyphonMind.java +++ b/Mage.Sets/src/mage/cards/s/SyphonMind.java @@ -63,7 +63,7 @@ class SyphonMindEffect extends OneShotEffect { Player otherPlayer = game.getPlayer(playerId); if (otherPlayer != null && !otherPlayer.getHand().isEmpty()) { TargetCardInHand target = new TargetCardInHand(); - if (otherPlayer.choose(Outcome.Discard, target, source.getSourceId(), game)) { + if (otherPlayer.choose(Outcome.Discard, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { if (otherPlayer.discard(card, false, source, game)) { diff --git a/Mage.Sets/src/mage/cards/s/SyphonSliver.java b/Mage.Sets/src/mage/cards/s/SyphonSliver.java index 88e993c08fc..d9dbe7e6d1e 100644 --- a/Mage.Sets/src/mage/cards/s/SyphonSliver.java +++ b/Mage.Sets/src/mage/cards/s/SyphonSliver.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -9,13 +7,13 @@ import mage.abilities.keyword.LifelinkAbility; 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.constants.SubType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SyphonSliver extends CardImpl { @@ -28,9 +26,10 @@ public final class SyphonSliver extends CardImpl { this.toughness = new MageInt(2); // Sliver creatures you control have lifelink. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new GainAbilityControlledEffect(LifelinkAbility.getInstance(), - Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS))); + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + LifelinkAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_SLIVERS + ))); } private SyphonSliver(final SyphonSliver card) { diff --git a/Mage.Sets/src/mage/cards/s/SyrKonradTheGrim.java b/Mage.Sets/src/mage/cards/s/SyrKonradTheGrim.java index 650293218b8..ad96561c219 100644 --- a/Mage.Sets/src/mage/cards/s/SyrKonradTheGrim.java +++ b/Mage.Sets/src/mage/cards/s/SyrKonradTheGrim.java @@ -91,7 +91,7 @@ class SyrKonradTheGrimTriggeredAbility extends TriggeredAbilityImpl { } // Or a creature card leaves your graveyard return zEvent.getFromZone() == Zone.GRAVEYARD - && zEvent.getPlayerId() == this.getControllerId(); + && card.isOwnedBy(this.getControllerId()); } @Override diff --git a/Mage.Sets/src/mage/cards/t/TahngarthFirstMate.java b/Mage.Sets/src/mage/cards/t/TahngarthFirstMate.java index a8c700033e5..ab89f75eb84 100644 --- a/Mage.Sets/src/mage/cards/t/TahngarthFirstMate.java +++ b/Mage.Sets/src/mage/cards/t/TahngarthFirstMate.java @@ -127,7 +127,7 @@ class TahngarthFirstMateEffect extends OneShotEffect { } TargetPlayerOrPlaneswalker target = new TargetPlayerOrPlaneswalker(filter); target.setNotTarget(true); - if (!controller.choose(outcome, target, source.getSourceId(), game)) { + if (!controller.choose(outcome, target, source, game)) { return false; } ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfCombat, player.getId()); diff --git a/Mage.Sets/src/mage/cards/t/TaigamSidisisHand.java b/Mage.Sets/src/mage/cards/t/TaigamSidisisHand.java index 945448bd291..b7a40e13288 100644 --- a/Mage.Sets/src/mage/cards/t/TaigamSidisisHand.java +++ b/Mage.Sets/src/mage/cards/t/TaigamSidisisHand.java @@ -6,39 +6,30 @@ import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.Cost; -import mage.abilities.costs.common.ExileFromGraveCost; +import mage.abilities.costs.common.ExileXFromYourGraveCost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.SkipDrawStepEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; 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.SuperType; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.FixedTarget; /** * - * @author spjspj + * @author awjackson */ public final class TaigamSidisisHand extends CardImpl { + private static final DynamicValue xValue = new SignInversionDynamicValue(GetXValue.instance); + public TaigamSidisisHand(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{B}"); @@ -49,16 +40,20 @@ public final class TaigamSidisisHand extends CardImpl { this.toughness = new MageInt(4); // Skip your draw step. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SkipDrawStepEffect())); + this.addAbility(new SimpleStaticAbility(new SkipDrawStepEffect())); - // At the beginning of your upkeep, look at the top three cards of your library. Put one of them into your hand and the rest into your graveyard. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new LookLibraryAndPickControllerEffect(StaticValue.get(3), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.GRAVEYARD, false, false, false, Zone.HAND, false), TargetController.YOU, false)); + // At the beginning of your upkeep, look at the top three cards of your library. + // Put one of them into your hand and the rest into your graveyard. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.GRAVEYARD), + TargetController.YOU, false)); // {B}, {T}, Exile X cards from your graveyard: Target creature gets -X/-X until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TaigamSidisisHandEffect(), new ManaCostsImpl("{B}")); + Ability ability = new SimpleActivatedAbility( + new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn), + new ColoredManaCost(ColoredManaSymbol.B)); ability.addCost(new TapSourceCost()); - ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(0, Integer.MAX_VALUE, StaticFilters.FILTER_CARDS_FROM_YOUR_GRAVEYARD))); + ability.addCost(new ExileXFromYourGraveCost(StaticFilters.FILTER_CARDS_FROM_YOUR_GRAVEYARD)); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } @@ -72,41 +67,3 @@ public final class TaigamSidisisHand extends CardImpl { return new TaigamSidisisHand(this); } } - -class TaigamSidisisHandEffect extends OneShotEffect { - - public TaigamSidisisHandEffect() { - super(Outcome.Benefit); - this.staticText = "creature gets -X/-X until end of turn"; - } - - public TaigamSidisisHandEffect(final TaigamSidisisHandEffect effect) { - super(effect); - } - - @Override - public TaigamSidisisHandEffect copy() { - return new TaigamSidisisHandEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); - - if (targetCreature != null) { - int amount = 0; - for (Cost cost : source.getCosts()) { - if (cost instanceof ExileFromGraveCost) { - amount = ((ExileFromGraveCost) cost).getExiledCards().size(); - ContinuousEffect effect = new BoostTargetEffect(-amount, -amount, Duration.EndOfTurn); - effect.setTargetPointer(new FixedTarget(source.getTargets().getFirstTarget(), game)); - game.addEffect(effect, source); - } - } - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/t/TaigamsScheming.java b/Mage.Sets/src/mage/cards/t/TaigamsScheming.java index 21646bd1a01..746d8cf2e05 100644 --- a/Mage.Sets/src/mage/cards/t/TaigamsScheming.java +++ b/Mage.Sets/src/mage/cards/t/TaigamsScheming.java @@ -1,14 +1,11 @@ - package mage.cards.t; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.FilterCard; /** * @@ -20,8 +17,7 @@ public final class TaigamsScheming extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{U}"); // Look at the top five cards of your library. Put any number of them into your graveyard and the rest back on top of your library in any order - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(5), false, StaticValue.get(5), - new FilterCard("cards"), Zone.LIBRARY, true, false, true, Zone.GRAVEYARD, false)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(5, Integer.MAX_VALUE, PutCards.GRAVEYARD, PutCards.TOP_ANY)); } private TaigamsScheming(final TaigamsScheming card) { diff --git a/Mage.Sets/src/mage/cards/t/TaintedIndulgence.java b/Mage.Sets/src/mage/cards/t/TaintedIndulgence.java new file mode 100644 index 00000000000..2f2efe90245 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TaintedIndulgence.java @@ -0,0 +1,43 @@ +package mage.cards.t; + +import mage.abilities.condition.Condition; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.DifferentManaValuesInGraveCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.abilities.hint.common.DifferentManaValuesInGraveHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TaintedIndulgence extends CardImpl { + + private static final Condition condition = new InvertCondition(DifferentManaValuesInGraveCondition.FIVE); + + public TaintedIndulgence(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}{B}"); + + // Draw two cards. Then discard a card unless there are five or more mana values among cards in your graveyard. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DiscardControllerEffect(1), condition, "Then discard a card " + + "unless there are five or more mana values among cards in your graveyard" + )); + this.getSpellAbility().addHint(DifferentManaValuesInGraveHint.instance); + } + + private TaintedIndulgence(final TaintedIndulgence card) { + super(card); + } + + @Override + public TaintedIndulgence copy() { + return new TaintedIndulgence(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TajuruArcher.java b/Mage.Sets/src/mage/cards/t/TajuruArcher.java index 513c5922915..ac1d5cffa70 100644 --- a/Mage.Sets/src/mage/cards/t/TajuruArcher.java +++ b/Mage.Sets/src/mage/cards/t/TajuruArcher.java @@ -42,7 +42,7 @@ public final class TajuruArcher extends CardImpl { this.toughness = new MageInt(2); Ability ability = new AllyEntersBattlefieldTriggeredAbility(new DamageTargetEffect(new PermanentsOnBattlefieldCount(filter)), true); ability.addTarget(new TargetCreaturePermanent(filterTarget)); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(null)); } private TajuruArcher(final TajuruArcher card) { diff --git a/Mage.Sets/src/mage/cards/t/TakeDown.java b/Mage.Sets/src/mage/cards/t/TakeDown.java index 275d9181dae..7cf0576ccc9 100644 --- a/Mage.Sets/src/mage/cards/t/TakeDown.java +++ b/Mage.Sets/src/mage/cards/t/TakeDown.java @@ -34,8 +34,7 @@ public final class TakeDown extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); // • Take Down deals 1 damage to each creature with flying - Mode mode = new Mode(); - mode.addEffect(new DamageAllEffect(1, filter)); + Mode mode = new Mode(new DamageAllEffect(1, filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/t/TakeToTheStreets.java b/Mage.Sets/src/mage/cards/t/TakeToTheStreets.java new file mode 100644 index 00000000000..8a9e3fca6bc --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TakeToTheStreets.java @@ -0,0 +1,45 @@ +package mage.cards.t; + +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TakeToTheStreets extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.CITIZEN, ""); + + public TakeToTheStreets(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}"); + + // Creatures you control get +2/+2 until end of turn. Citizens you control get an additional +1/+1 and gain vigilance until end of turn. + this.getSpellAbility().addEffect(new BoostControlledEffect( + 2, 2, Duration.EndOfTurn + )); + this.getSpellAbility().addEffect(new BoostControlledEffect( + 1, 1, Duration.EndOfTurn, filter + ).setText("Citizens you control get an additional +1/+1")); + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), Duration.EndOfTurn, filter + ).setText("and gain vigilance until end of turn")); + } + + private TakeToTheStreets(final TakeToTheStreets card) { + super(card); + } + + @Override + public TakeToTheStreets copy() { + return new TakeToTheStreets(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TakenumaAbandonedMire.java b/Mage.Sets/src/mage/cards/t/TakenumaAbandonedMire.java index 027398fc150..16933850fcf 100644 --- a/Mage.Sets/src/mage/cards/t/TakenumaAbandonedMire.java +++ b/Mage.Sets/src/mage/cards/t/TakenumaAbandonedMire.java @@ -36,7 +36,7 @@ public final class TakenumaAbandonedMire extends CardImpl { // Channel — {3}{B}, Discard Takenuma, Abandoned Mire: Mill three cards, then return a creature or planeswalker card from your graveyard to your hand. This ability costs {1} less to activate for each legendary creature you control. Ability ability = new ChannelAbility("{3}{B}", new TakenumaAbandonedMireEffect()); ability.setCostAdjuster(LegendaryCreatureCostAdjuster.instance); - this.addAbility(ability); + this.addAbility(ability.addHint(LegendaryCreatureCostAdjuster.getHint())); } private TakenumaAbandonedMire(final TakenumaAbandonedMire card) { diff --git a/Mage.Sets/src/mage/cards/t/TalarasBattalion.java b/Mage.Sets/src/mage/cards/t/TalarasBattalion.java index 6d11ea84c5f..08cff739af0 100644 --- a/Mage.Sets/src/mage/cards/t/TalarasBattalion.java +++ b/Mage.Sets/src/mage/cards/t/TalarasBattalion.java @@ -1,38 +1,31 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; -import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.Condition; -import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.common.CastOnlyIfConditionIsTrueAbility; import mage.abilities.keyword.TrampleAbility; 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.WatcherScope; -import mage.constants.Zone; -import mage.filter.FilterSpell; -import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.stack.Spell; import mage.watchers.Watcher; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * - * @author jeffwadsworth + * @author TheElk801 */ public final class TalarasBattalion extends CardImpl { public TalarasBattalion(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.WARRIOR); @@ -43,7 +36,10 @@ public final class TalarasBattalion extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Cast Talara's Battalion only if you've cast another green spell this turn. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new TalarasBattalionEffect()), new TalarasBattalionWatcher(this.getId())); + this.addAbility(new CastOnlyIfConditionIsTrueAbility( + TalarasBattalionWatcher::checkSpell, + "cast this spell only if you've cast another green spell this turn" + ), new TalarasBattalionWatcher()); } @@ -57,82 +53,32 @@ public final class TalarasBattalion extends CardImpl { } } -class TalarasBattalionEffect extends ContinuousRuleModifyingEffectImpl { - - TalarasBattalionEffect() { - super(Duration.EndOfGame, Outcome.Detriment); - staticText = "Cast this spell only if you've cast another green spell this turn"; - } - - TalarasBattalionEffect(final TalarasBattalionEffect effect) { - super(effect); - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.CAST_SPELL - && event.getSourceId().equals(source.getSourceId())) { - CastGreenSpellThisTurnCondition condition = new CastGreenSpellThisTurnCondition(); - return (!condition.apply(game, source)); - } - return false; - - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public TalarasBattalionEffect copy() { - return new TalarasBattalionEffect(this); - } -} - -class CastGreenSpellThisTurnCondition implements Condition { - - @Override - public boolean apply(Game game, Ability source) { - TalarasBattalionWatcher watcher = game.getState().getWatcher(TalarasBattalionWatcher.class, source.getControllerId()); - if (watcher != null) { - return watcher.conditionMet(); - } - return false; - } -} - class TalarasBattalionWatcher extends Watcher { - private static final FilterSpell filter = new FilterSpell(); + private final Set playerSet = new HashSet<>(); - static { - filter.add(new ColorPredicate(ObjectColor.GREEN)); - } - private final UUID cardId; - - public TalarasBattalionWatcher(UUID cardId) { - super(WatcherScope.PLAYER); - this.cardId = cardId; + TalarasBattalionWatcher() { + super(WatcherScope.GAME); } @Override public void watch(GameEvent event, Game game) { - if (condition == true) { //no need to check - condition has already occured + if (event.getType() != EventType.SPELL_CAST) { return; } - if (event.getType() == GameEvent.EventType.SPELL_CAST - && controllerId.equals(event.getPlayerId())) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (!spell.getSourceId().equals(cardId) && filter.match(spell, game)) { - condition = true; - } + Spell spell = game.getSpell(event.getSourceId()); + if (spell != null && spell.getColor(game).isGreen()) { + playerSet.add(spell.getControllerId()); } } @Override public void reset() { super.reset(); - condition = false; + playerSet.clear(); + } + + static boolean checkSpell(Game game, Ability source) { + return game.getState().getWatcher(TalarasBattalionWatcher.class).playerSet.contains(source.getControllerId()); } } diff --git a/Mage.Sets/src/mage/cards/t/TalentOfTheTelepath.java b/Mage.Sets/src/mage/cards/t/TalentOfTheTelepath.java index a8448d2ae13..94ede04f9e1 100644 --- a/Mage.Sets/src/mage/cards/t/TalentOfTheTelepath.java +++ b/Mage.Sets/src/mage/cards/t/TalentOfTheTelepath.java @@ -1,23 +1,24 @@ package mage.cards.t; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.condition.common.SpellMasteryCondition; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; +import mage.filter.StaticFilters; import mage.filter.common.FilterInstantOrSorceryCard; import mage.game.Game; import mage.players.Player; -import mage.target.TargetCard; import mage.target.common.TargetOpponent; +import mage.util.CardUtil; -import java.util.Set; import java.util.UUID; -import mage.ApprovingObject; /** * @author LevelX2 @@ -33,9 +34,8 @@ public final class TalentOfTheTelepath extends CardImpl { // Spell mastery — If there are two or more instant and/or // sorcery cards in your graveyard, you may cast up to two revealed instant // and/or sorcery cards instead of one. - getSpellAbility().addEffect(new TalentOfTheTelepathEffect()); - getSpellAbility().addTarget(new TargetOpponent()); - + this.getSpellAbility().addEffect(new TalentOfTheTelepathEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); } private TalentOfTheTelepath(final TalentOfTheTelepath card) { @@ -54,12 +54,12 @@ class TalentOfTheTelepathEffect extends OneShotEffect { public TalentOfTheTelepathEffect() { super(Outcome.PlayForFree); - this.staticText = "Target opponent reveals the top seven cards of their " - + "library. You may cast an instant or sorcery card from among them " - + "without paying its mana cost. Then that player puts the rest into their graveyard. " - + "
Spell mastery — If there are two or more instant " - + "and/or sorcery cards in your graveyard, you may cast up to two " - + "revealed instant and/or sorcery cards instead of one."; + this.staticText = "Target opponent reveals the top seven cards of their " + + "library. You may cast an instant or sorcery spell from among them " + + "without paying its mana cost. Then that player puts the rest into their graveyard. " + + "
Spell mastery — If there are two or more instant " + + "and/or sorcery cards in your graveyard, you may cast up to two " + + "instant and/or sorcery spells from among the revealed cards instead of one."; } public TalentOfTheTelepathEffect(final TalentOfTheTelepathEffect effect) { @@ -73,60 +73,19 @@ class TalentOfTheTelepathEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Cards cardsToCast = new CardsImpl(); - Player targetOpponent = game.getPlayer(targetPointer.getFirst(game, source)); - MageObject sourceObject = source.getSourceObject(game); - if (targetOpponent != null && sourceObject != null) { - Set allCards = targetOpponent.getLibrary().getTopCards(game, 7); - Cards cards = new CardsImpl(allCards); - targetOpponent.revealCards(sourceObject.getIdName() + " - " - + targetOpponent.getName() + "'s top library cards", cards, game); - for (Card card : allCards) { - if (filter.match(card, game)) { - cardsToCast.add(card); - } - } - // cast an instant or sorcery for free - if (!cardsToCast.isEmpty()) { - int numberOfSpells = 1; - if (SpellMasteryCondition.instance.apply(game, source)) { - numberOfSpells++; - } - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - TargetCard target = new TargetCard(Zone.LIBRARY, filter); // zone should be ignored here - target.setNotTarget(true); - while (controller.canRespond() - && numberOfSpells > 0 - && !cardsToCast.isEmpty() - && controller.chooseUse(outcome, "Cast an instant or sorcery card " - + "from among them for free?", source, game) - && controller.choose(Outcome.PlayForFree, cardsToCast, target, game)) { - Card card = cardsToCast.get(target.getFirstTarget(), game); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - cardsToCast.remove(card); - if (cardWasCast) { - numberOfSpells--; - allCards.remove(card); - } - } else { - break; - } - if (!controller.canRespond()) { - return false; - } - target.clearChosen(); - } - } - } - - targetOpponent.moveCards(allCards, Zone.GRAVEYARD, source, game); - return true; + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(targetPointer.getFirst(game, source)); + if (controller == null || opponent == null) { + return false; } - return false; + Cards cards = new CardsImpl(opponent.getLibrary().getTopCards(game, 7)); + opponent.revealCards(source, cards, game); + CardUtil.castMultipleWithAttributeForFree( + controller, source, game, cards, StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, + SpellMasteryCondition.instance.apply(game, source) ? 2 : 1 + ); + cards.retainZone(Zone.LIBRARY, game); + opponent.moveCards(cards, Zone.GRAVEYARD, source, game); + return true; } } diff --git a/Mage.Sets/src/mage/cards/t/Tamanoa.java b/Mage.Sets/src/mage/cards/t/Tamanoa.java index 03bf1e1d97b..cbd84866c28 100644 --- a/Mage.Sets/src/mage/cards/t/Tamanoa.java +++ b/Mage.Sets/src/mage/cards/t/Tamanoa.java @@ -1,4 +1,3 @@ - package mage.cards.t; import java.util.UUID; @@ -6,7 +5,7 @@ import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.dynamicvalue.common.NumericSetToEffectValues; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.GainLifeEffect; import mage.cards.CardImpl; @@ -31,7 +30,7 @@ public final class Tamanoa extends CardImpl { this.toughness = new MageInt(4); // Whenever a noncreature source you control deals damage, you gain that much life. - Ability ability = new TamanoaDealsDamageTriggeredAbility(Zone.BATTLEFIELD, new GainLifeEffect(new NumericSetToEffectValues("that much", "damage")), false); + Ability ability = new TamanoaDealsDamageTriggeredAbility(Zone.BATTLEFIELD, new GainLifeEffect(SavedDamageValue.MUCH), false); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TameshiRealityArchitect.java b/Mage.Sets/src/mage/cards/t/TameshiRealityArchitect.java new file mode 100644 index 00000000000..394c4b77c5d --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TameshiRealityArchitect.java @@ -0,0 +1,88 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.ZoneChangeAllTriggeredAbility; +import mage.abilities.costs.common.ReturnToHandChosenControlledPermanentCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterArtifactOrEnchantmentCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetControlledPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TameshiRealityArchitect extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("noncreature permanent"); + + static { + filter.add(Predicates.not(CardType.CREATURE.getPredicate())); + } + + public TameshiRealityArchitect(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.MOONFOLK); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Whenever one or more noncreature permanents are returned to hand, draw a card. This ability triggers only once each turn. + this.addAbility(new ZoneChangeAllTriggeredAbility(Zone.BATTLEFIELD, Zone.BATTLEFIELD, Zone.HAND, + new DrawCardSourceControllerEffect(1), filter, + "Whenever one or more noncreature permanents are returned to hand, ", false).setTriggersOnce(true)); + + // {X}{W}, Return a land you control to its owner's hand: Return target artifact or enchantment card with mana value X or less from your graveyard to the battlefield. Activate only as a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect() + .setText("return target artifact or enchantment card with " + + "mana value X or less from your graveyard to the battlefield"), + new ManaCostsImpl<>("{X}{W}") + ); + ability.addCost(new ReturnToHandChosenControlledPermanentCost( + new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND) + )); + this.addAbility(ability.setTargetAdjuster(TameshiRealityArchitectAdjuster.instance)); + } + + private TameshiRealityArchitect(final TameshiRealityArchitect card) { + super(card); + } + + @Override + public TameshiRealityArchitect copy() { + return new TameshiRealityArchitect(this); + } +} + +enum TameshiRealityArchitectAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int xValue = ability.getManaCostsToPay().getX(); + FilterCard filter = new FilterArtifactOrEnchantmentCard( + "artifact or enchantment card with mana value " + xValue + " or less from your graveyard" + ); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, xValue + 1)); + ability.getTargets().clear(); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TamiyoCollectorOfTales.java b/Mage.Sets/src/mage/cards/t/TamiyoCollectorOfTales.java index 11e4b8bff87..cd7a1539c82 100644 --- a/Mage.Sets/src/mage/cards/t/TamiyoCollectorOfTales.java +++ b/Mage.Sets/src/mage/cards/t/TamiyoCollectorOfTales.java @@ -2,12 +2,11 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseACardNameEffect; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.*; import mage.constants.*; import mage.game.Game; @@ -31,7 +30,7 @@ public final class TamiyoCollectorOfTales extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TAMIYO); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Spells and abilities your opponents control can't cause you to discard cards or sacrifice permanents. this.addAbility(new SimpleStaticAbility(new TamiyoCollectorOfTalesRuleEffect())); @@ -40,7 +39,7 @@ public final class TamiyoCollectorOfTales extends CardImpl { this.addAbility(new LoyaltyAbility(new TamiyoCollectorOfTalesEffect(), 1)); // -3: Return target card from your graveyard to your hand. - Ability ability = new LoyaltyAbility(new ReturnToHandTargetEffect(), -3); + Ability ability = new LoyaltyAbility(new ReturnFromGraveyardToHandTargetEffect(), -3); ability.addTarget(new TargetCardInYourGraveyard()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TamiyoCompleatedSage.java b/Mage.Sets/src/mage/cards/t/TamiyoCompleatedSage.java new file mode 100644 index 00000000000..36bc4cddf45 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TamiyoCompleatedSage.java @@ -0,0 +1,115 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.dynamicvalue.common.GetXLoyaltyValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.keyword.CompleatedAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.permanent.PermanentCard; +import mage.game.permanent.token.TamiyosNotebookToken; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TamiyoCompleatedSage extends CardImpl { + + public TamiyoCompleatedSage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{G}{G/U/P}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.TAMIYO); + this.setStartingLoyalty(5); + + // Compleated + this.addAbility(CompleatedAbility.getInstance()); + + // +1: Tap up to one target artifact or creature. It doesn't untap during its controller's next untap step. + Ability ability = new LoyaltyAbility(new TapTargetEffect(), 1); + ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("it")); + ability.addTarget(new TargetPermanent( + 0, 1, StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE + )); + this.addAbility(ability); + + // −X: Exile target nonland permanent card with mana value X from your graveyard. Create a token that's a copy of that card. + this.addAbility(new LoyaltyAbility(new TamiyoCompleatedSageEffect()).setTargetAdjuster(TamiyoCompleatedSageAdjuster.instance)); + + // −7: Create Tamiyo's Notebook, a legendary colorless artifact token with "Spells you cast cost {2} less to cast" and "{T}: Draw a card." + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new TamiyosNotebookToken()), -7)); + } + + private TamiyoCompleatedSage(final TamiyoCompleatedSage card) { + super(card); + } + + @Override + public TamiyoCompleatedSage copy() { + return new TamiyoCompleatedSage(this); + } +} + +enum TamiyoCompleatedSageAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int xValue = GetXLoyaltyValue.instance.calculate(game, ability, null); + FilterCard filter = new FilterPermanentCard("nonland permanent card with mana value " + xValue); + filter.add(Predicates.not(CardType.LAND.getPredicate())); + filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, xValue)); + ability.getTargets().clear(); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + } +} + +class TamiyoCompleatedSageEffect extends OneShotEffect { + + TamiyoCompleatedSageEffect() { + super(Outcome.Benefit); + staticText = "exile target nonland permanent card with mana value X " + + "from your graveyard. Create a token that's a copy of that card"; + } + + private TamiyoCompleatedSageEffect(final TamiyoCompleatedSageEffect effect) { + super(effect); + } + + @Override + public TamiyoCompleatedSageEffect copy() { + return new TamiyoCompleatedSageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(source.getFirstTarget()); + if (player == null || card == null) { + return false; + } + player.moveCards(card, Zone.EXILED, source, game); + return new CreateTokenCopyTargetEffect().setSavedPermanent( + new PermanentCard(card, source.getControllerId(), game) + ).apply(game, source); + } +} +// aqua got norted diff --git a/Mage.Sets/src/mage/cards/t/TamiyoFieldResearcher.java b/Mage.Sets/src/mage/cards/t/TamiyoFieldResearcher.java index 8c9b21198de..a3062ca82c3 100644 --- a/Mage.Sets/src/mage/cards/t/TamiyoFieldResearcher.java +++ b/Mage.Sets/src/mage/cards/t/TamiyoFieldResearcher.java @@ -5,7 +5,6 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -51,7 +50,7 @@ public final class TamiyoFieldResearcher extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TAMIYO); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Choose up to two target creatures. Until your next turn, whenever either of those creatures deals combat damage, you draw a card. Ability ability = new LoyaltyAbility(new TamiyoFieldResearcherEffect1(), 1); diff --git a/Mage.Sets/src/mage/cards/t/TamiyoTheMoonSage.java b/Mage.Sets/src/mage/cards/t/TamiyoTheMoonSage.java index 1b25f0ce93f..6b2f271d4fc 100644 --- a/Mage.Sets/src/mage/cards/t/TamiyoTheMoonSage.java +++ b/Mage.Sets/src/mage/cards/t/TamiyoTheMoonSage.java @@ -4,7 +4,6 @@ package mage.cards.t; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; @@ -35,11 +34,11 @@ public final class TamiyoTheMoonSage extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TAMIYO); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Tap target permanent. It doesn't untap during its controller's next untap step. LoyaltyAbility ability = new LoyaltyAbility(new TapTargetEffect(), 1); - ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect()); + ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("it")); Target target = new TargetPermanent(); ability.addTarget(target); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/t/TamiyosSafekeeping.java b/Mage.Sets/src/mage/cards/t/TamiyosSafekeeping.java new file mode 100644 index 00000000000..b3295b763b1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TamiyosSafekeeping.java @@ -0,0 +1,39 @@ +package mage.cards.t; + +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TamiyosSafekeeping extends CardImpl { + + public TamiyosSafekeeping(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}"); + + // Target permanent you control gains hexproof and indestructible until end of turn. You gain 2 life. + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HexproofAbility.getInstance()) + .setText("target permanent you control gains hexproof")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(IndestructibleAbility.getInstance()) + .setText("and indestructible until end of turn")); + this.getSpellAbility().addTarget(new TargetControlledPermanent()); + this.getSpellAbility().addEffect(new GainLifeEffect(2)); + } + + private TamiyosSafekeeping(final TamiyosSafekeeping card) { + super(card); + } + + @Override + public TamiyosSafekeeping copy() { + return new TamiyosSafekeeping(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TanaTheBloodsower.java b/Mage.Sets/src/mage/cards/t/TanaTheBloodsower.java index 4482c0080fc..f050d396019 100644 --- a/Mage.Sets/src/mage/cards/t/TanaTheBloodsower.java +++ b/Mage.Sets/src/mage/cards/t/TanaTheBloodsower.java @@ -1,11 +1,9 @@ - package mage.cards.t; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.keyword.PartnerAbility; import mage.abilities.keyword.TrampleAbility; @@ -13,11 +11,8 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Outcome; import mage.constants.SuperType; -import mage.game.Game; import mage.game.permanent.token.SaprolingToken; -import mage.players.Player; /** * @@ -36,8 +31,10 @@ public final class TanaTheBloodsower extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); + // Whenever Tana, the Bloodsower deals combat damage to a player, create that many 1/1 green Saproling creature tokens. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new TanaTheBloodsowerEffect(), false, true)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new CreateTokenEffect(new SaprolingToken(), SavedDamageValue.MANY), false, true)); // Partner this.addAbility(PartnerAbility.getInstance()); @@ -52,33 +49,3 @@ public final class TanaTheBloodsower extends CardImpl { return new TanaTheBloodsower(this); } } - -class TanaTheBloodsowerEffect extends OneShotEffect { - - public TanaTheBloodsowerEffect() { - super(Outcome.PutCreatureInPlay); - this.staticText = "create that many 1/1 green Saproling creature tokens"; - } - - public TanaTheBloodsowerEffect(final TanaTheBloodsowerEffect effect) { - super(effect); - } - - @Override - public TanaTheBloodsowerEffect copy() { - return new TanaTheBloodsowerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(targetPointer.getFirst(game, source)); - if (player != null) { - int amount = (Integer)getValue("damage"); - if (amount > 0) { - return new CreateTokenEffect(new SaprolingToken(), amount).apply(game, source); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/t/Tangle.java b/Mage.Sets/src/mage/cards/t/Tangle.java index cc3f4d24b86..fa7b1d27a59 100644 --- a/Mage.Sets/src/mage/cards/t/Tangle.java +++ b/Mage.Sets/src/mage/cards/t/Tangle.java @@ -74,7 +74,7 @@ class TangleEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { List doNotUntapNextUntapStep = new ArrayList<>(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { doNotUntapNextUntapStep.add(permanent); } if (!doNotUntapNextUntapStep.isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/t/TanukiTransplanter.java b/Mage.Sets/src/mage/cards/t/TanukiTransplanter.java new file mode 100644 index 00000000000..5b76967040e --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TanukiTransplanter.java @@ -0,0 +1,125 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.ReconfigureAbility; +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.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TanukiTransplanter extends CardImpl { + + public TanukiTransplanter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.EQUIPMENT); + this.subtype.add(SubType.DOG); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Whenever Tanuki Transplanter or equipped creature attacks, add an amount of {G} equal to its power. Until end of turn, you don't lose this mana as steps and phases end. + this.addAbility(new TanukiTransplanterTriggeredAbility()); + + // Reconfigure {3} + this.addAbility(new ReconfigureAbility("{3}")); + } + + private TanukiTransplanter(final TanukiTransplanter card) { + super(card); + } + + @Override + public TanukiTransplanter copy() { + return new TanukiTransplanter(this); + } +} + +class TanukiTransplanterTriggeredAbility extends TriggeredAbilityImpl { + + TanukiTransplanterTriggeredAbility() { + super(Zone.BATTLEFIELD, new TanukiTransplanterEffect()); + } + + private TanukiTransplanterTriggeredAbility(final TanukiTransplanterTriggeredAbility ability) { + super(ability); + } + + @Override + public TanukiTransplanterTriggeredAbility copy() { + return new TanukiTransplanterTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + UUID attacker; + if (!game.getCombat().getAttackers().contains(getSourceId())) { + Permanent permanent = getSourcePermanentOrLKI(game); + if (permanent != null && game.getCombat().getAttackers().contains(permanent.getAttachedTo())) { + attacker = permanent.getAttachedTo(); + } else { + attacker = null; + } + } else { + attacker = getSourceId(); + } + if (attacker == null) { + return false; + } + getEffects().setTargetPointer(new FixedTarget(attacker, game)); + return true; + } + + @Override + public String getRule() { + return "Whenever {this} or equipped creature attacks, add an amount of {G} equal to its power. " + + "Until end of turn, you don't lose this mana as steps and phases end."; + } +} + +class TanukiTransplanterEffect extends OneShotEffect { + + TanukiTransplanterEffect() { + super(Outcome.Benefit); + } + + private TanukiTransplanterEffect(final TanukiTransplanterEffect effect) { + super(effect); + } + + @Override + public TanukiTransplanterEffect copy() { + return new TanukiTransplanterEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (player == null || permanent == null || permanent.getPower().getValue() < 1) { + return false; + } + player.getManaPool().addMana(Mana.GreenMana(permanent.getPower().getValue()), game, source, true); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TappingAtTheWindow.java b/Mage.Sets/src/mage/cards/t/TappingAtTheWindow.java index 5b6fa979fbc..6e0604fc50e 100644 --- a/Mage.Sets/src/mage/cards/t/TappingAtTheWindow.java +++ b/Mage.Sets/src/mage/cards/t/TappingAtTheWindow.java @@ -1,18 +1,13 @@ package mage.cards.t; -import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.FlashbackAbility; -import mage.cards.*; +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.game.Game; -import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInLibrary; import java.util.UUID; @@ -24,8 +19,11 @@ public final class TappingAtTheWindow extends CardImpl { public TappingAtTheWindow(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); - // Look at the top three cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest into your graveyard. - this.getSpellAbility().addEffect(new TappingAtTheWindowEffect()); + // Look at the top three cards of your library. + // You may reveal a creature card from among them and put it into your hand. + // Put the rest into your graveyard. + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + 3, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.GRAVEYARD)); // Flashback {2}{G} this.addAbility(new FlashbackAbility(this, new ManaCostsImpl<>("{2}{G}"))); @@ -40,42 +38,3 @@ public final class TappingAtTheWindow extends CardImpl { return new TappingAtTheWindow(this); } } - -class TappingAtTheWindowEffect extends OneShotEffect { - - TappingAtTheWindowEffect() { - super(Outcome.Benefit); - staticText = "look at the top three cards of your library. You may reveal a creature card " + - "from among them and put it into your hand. Put the rest into your graveyard"; - } - - private TappingAtTheWindowEffect(final TappingAtTheWindowEffect effect) { - super(effect); - } - - @Override - public TappingAtTheWindowEffect copy() { - return new TappingAtTheWindowEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 3)); - TargetCard target = new TargetCardInLibrary( - 0, 1, StaticFilters.FILTER_CARD_CREATURE - ); - player.choose(outcome, cards, target, game); - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - player.revealCards(source, new CardsImpl(card), game); - player.moveCards(card, Zone.HAND, source, game); - } - cards.retainZone(Zone.LIBRARY, game); - player.moveCards(card, Zone.GRAVEYARD, source, game); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/t/Tariff.java b/Mage.Sets/src/mage/cards/t/Tariff.java index 205dab61c6a..4b1c7148fe7 100644 --- a/Mage.Sets/src/mage/cards/t/Tariff.java +++ b/Mage.Sets/src/mage/cards/t/Tariff.java @@ -77,7 +77,7 @@ class TariffEffect extends OneShotEffect { } private void processPlayer(Game game, Ability source, Player player) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); List creatures = getPermanentsWithTheHighestCMC(game, player.getId(), new FilterControlledCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/t/TaskMageAssembly.java b/Mage.Sets/src/mage/cards/t/TaskMageAssembly.java index 9b511cb7c94..416b91bc353 100644 --- a/Mage.Sets/src/mage/cards/t/TaskMageAssembly.java +++ b/Mage.Sets/src/mage/cards/t/TaskMageAssembly.java @@ -65,7 +65,7 @@ class TaskMageAssemblyStateTriggeredAbility extends StateTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - return game.getBattlefield().count(new FilterCreaturePermanent(), this.getSourceId(), this.getControllerId(), game) == 0; + return game.getBattlefield().count(new FilterCreaturePermanent(), this.getControllerId(), this, game) == 0; } @Override diff --git a/Mage.Sets/src/mage/cards/t/TatsumasaTheDragonsFang.java b/Mage.Sets/src/mage/cards/t/TatsumasaTheDragonsFang.java index 66a197a6776..b23f2e2bb43 100644 --- a/Mage.Sets/src/mage/cards/t/TatsumasaTheDragonsFang.java +++ b/Mage.Sets/src/mage/cards/t/TatsumasaTheDragonsFang.java @@ -1,14 +1,13 @@ package mage.cards.t; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.ExileSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.keyword.EquipAbility; @@ -17,12 +16,13 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.events.ZoneChangeEvent; -import mage.game.permanent.Permanent; import mage.game.permanent.token.TatsumaDragonToken; +import mage.game.permanent.token.Token; import mage.target.targetpointer.FixedTarget; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; /** @@ -36,11 +36,11 @@ public final class TatsumasaTheDragonsFang extends CardImpl { this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +5/+5. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(5, 5))); + this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(5, 5))); // {6}, Exile Tatsumasa, the Dragon's Fang: Create a 5/5 blue Dragon Spirit creature token with flying. Return Tatsumasa to the battlefield under its owner's control when that token dies. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TatsumaTheDragonsFangEffect(), new GenericManaCost(6)); - ability.addCost(new ExileSourceCost(true)); + Ability ability = new SimpleActivatedAbility(new TatsumaTheDragonsFangEffect(), new GenericManaCost(6)); + ability.addCost(new ExileSourceCost()); this.addAbility(ability); // Equip {3} @@ -61,7 +61,8 @@ class TatsumaTheDragonsFangEffect extends OneShotEffect { public TatsumaTheDragonsFangEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "Create a 5/5 blue Dragon Spirit creature token with flying. Return Tatsumasa to the battlefield under its owner's control when that token dies"; + this.staticText = "Create a 5/5 blue Dragon Spirit creature token with flying. " + + "Return {this} to the battlefield under its owner's control when that token dies"; } public TatsumaTheDragonsFangEffect(final TatsumaTheDragonsFangEffect effect) { @@ -75,35 +76,25 @@ class TatsumaTheDragonsFangEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - CreateTokenEffect effect = new CreateTokenEffect(new TatsumaDragonToken()); - effect.apply(game, source); - for (UUID tokenId : effect.getLastAddedTokenIds()) { // by cards like Doubling Season multiple tokens can be added to the battlefield - Permanent tokenPermanent = game.getPermanent(tokenId); - if (tokenPermanent != null) { - FixedTarget fixedTarget = new FixedTarget(tokenPermanent, game); - Effect returnEffect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false); - returnEffect.setTargetPointer(new FixedTarget(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId()))); - DelayedTriggeredAbility delayedAbility = new TatsumaTheDragonsFangTriggeredAbility(fixedTarget, returnEffect); - game.addDelayedTriggeredAbility(delayedAbility, source); - } - } - + Token token = new TatsumaDragonToken(); + token.putOntoBattlefield(1, game, source); + game.addDelayedTriggeredAbility(new TatsumaTheDragonsFangTriggeredAbility(token, source, game), source); return true; } } class TatsumaTheDragonsFangTriggeredAbility extends DelayedTriggeredAbility { - protected FixedTarget fixedTarget; + private final Set tokens = new HashSet<>(); - public TatsumaTheDragonsFangTriggeredAbility(FixedTarget fixedTarget, Effect effect) { - super(effect, Duration.OneUse); - this.fixedTarget = fixedTarget; + public TatsumaTheDragonsFangTriggeredAbility(Token token, Ability source, Game game) { + super(new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false).setTargetPointer(new FixedTarget(new MageObjectReference(source, 1))), Duration.Custom, false, false); + tokens.addAll(token.getLastAddedTokenIds()); } public TatsumaTheDragonsFangTriggeredAbility(final TatsumaTheDragonsFangTriggeredAbility ability) { super(ability); - this.fixedTarget = ability.fixedTarget; + tokens.addAll(ability.tokens); } @Override @@ -118,12 +109,7 @@ class TatsumaTheDragonsFangTriggeredAbility extends DelayedTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (((ZoneChangeEvent) event).isDiesEvent()) { - if (fixedTarget.getFirst(game, this).equals(event.getTargetId())) { - return true; - } - } - return false; + return ((ZoneChangeEvent) event).isDiesEvent() && tokens.contains(event.getTargetId()); } @Override diff --git a/Mage.Sets/src/mage/cards/t/TatsunariToadRider.java b/Mage.Sets/src/mage/cards/t/TatsunariToadRider.java new file mode 100644 index 00000000000..e536f6e3064 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TatsunariToadRider.java @@ -0,0 +1,90 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.combat.CantBeBlockedByAllTargetEffect; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.game.permanent.token.KeimiToken; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TatsunariToadRider extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent(); + private static final FilterPermanent filter3 = new FilterControlledPermanent(SubType.FROG); + + static { + filter.add(new NamePredicate("Keimi")); + filter2.add(Predicates.or( + new AbilityPredicate(FlyingAbility.class), + new AbilityPredicate(ReachAbility.class) + )); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.EQUAL_TO, 0); + + public TatsunariToadRider(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.NINJA); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever you cast an enchantment spell, if you don't control a creature named Keimi, create Keimi, a legendary 3/3 black and green Frog creature token with "Whenever you cast an enchantment spell, each opponent loses 1 life and you gain 1 life." + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new SpellCastControllerTriggeredAbility( + new CreateTokenEffect(new KeimiToken()), + StaticFilters.FILTER_SPELL_AN_ENCHANTMENT, false + ), condition, "Whenever you cast an enchantment spell, if you don't control " + + "a creature named Keimi, create Keimi, a legendary 3/3 black and green Frog creature token with " + + "\"Whenever you cast an enchantment spell, each opponent loses 1 life and you gain 1 life.\"" + )); + + // {1}{G/U}: Tatsunari, Toad Rider and target Frog you control can't be blocked this turn except by creatures with flying or reach. + Ability ability = new SimpleActivatedAbility( + new CantBeBlockedByCreaturesSourceEffect( + filter2, Duration.EndOfTurn + ).setText("{this}"), new ManaCostsImpl<>("{1}{G/U}") + ); + ability.addEffect(new CantBeBlockedByAllTargetEffect(filter2, Duration.EndOfTurn) + .setText("and target Frog you control can't be blocked this turn except by creatures with flying or reach")); + ability.addTarget(new TargetPermanent(filter3)); + this.addAbility(ability); + } + + private TatsunariToadRider(final TatsunariToadRider card) { + super(card); + } + + @Override + public TatsunariToadRider copy() { + return new TatsunariToadRider(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TattermungeWitch.java b/Mage.Sets/src/mage/cards/t/TattermungeWitch.java index f0ca061f3d2..e1521f1b758 100644 --- a/Mage.Sets/src/mage/cards/t/TattermungeWitch.java +++ b/Mage.Sets/src/mage/cards/t/TattermungeWitch.java @@ -38,7 +38,7 @@ public final class TattermungeWitch extends CardImpl { this.toughness = new MageInt(1); // {R}{G}: Each blocked creature gets +1/+0 and gains trample until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 0, Duration.EndOfTurn, filter, false), new ManaCostsImpl("{R}{G}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 0, Duration.EndOfTurn, filter, false).setText("each blocked creature gets +1/+0"), new ManaCostsImpl("{R}{G}")); ability.addEffect(new GainAbilityAllEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, filter, "and gains trample until end of turn")); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/t/TattooWard.java b/Mage.Sets/src/mage/cards/t/TattooWard.java index 657089d0303..bd2d801d4e1 100644 --- a/Mage.Sets/src/mage/cards/t/TattooWard.java +++ b/Mage.Sets/src/mage/cards/t/TattooWard.java @@ -1,9 +1,5 @@ - package mage.cards.t; -import java.util.UUID; -import mage.constants.SubType; -import mage.target.common.TargetCreaturePermanent; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -12,31 +8,22 @@ import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; -import mage.constants.Outcome; -import mage.target.TargetPermanent; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.ProtectionAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AttachmentType; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Zone; -import mage.filter.FilterCard; +import mage.constants.*; import mage.filter.StaticFilters; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class TattooWard extends CardImpl { - private static final FilterCard filter = new FilterCard("enchantments"); - - static { - filter.add(CardType.ENCHANTMENT.getPredicate()); - } - public TattooWard(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); @@ -46,20 +33,22 @@ public final class TattooWard extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Enchanted creature gets +1/+1 and has protection from enchantments. This effect doesn't remove Tattoo Ward. - Ability ability2 = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 1, Duration.WhileOnBattlefield)); - ProtectionAbility protectionAbility = new ProtectionAbility(filter); - protectionAbility.setAuraIdNotToBeRemoved(getId()); - ability2.addEffect(new GainAbilityAttachedEffect(protectionAbility, AttachmentType.AURA, Duration.WhileOnBattlefield)); - this.addAbility(ability2); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect( + 1, 1, Duration.WhileOnBattlefield + )); + ability.addEffect(new GainAbilityAttachedEffect( + new ProtectionAbility(StaticFilters.FILTER_PERMANENT_ENCHANTMENTS), + AttachmentType.AURA, Duration.WhileOnBattlefield + ).setDoesntRemoveItself(true)); + this.addAbility(ability); // Sacrifice Tattoo Ward: Destroy target enchantment. - Ability ability3 = new SimpleActivatedAbility(new DestroyTargetEffect(), new SacrificeSourceCost()); - ability3.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ENCHANTMENT)); - this.addAbility(ability3); + ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new SacrificeSourceCost()); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ENCHANTMENT)); + this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TayamLuminousEnigma.java b/Mage.Sets/src/mage/cards/t/TayamLuminousEnigma.java index fde6ef9fbed..b959e615da7 100644 --- a/Mage.Sets/src/mage/cards/t/TayamLuminousEnigma.java +++ b/Mage.Sets/src/mage/cards/t/TayamLuminousEnigma.java @@ -94,7 +94,7 @@ class TayamLuminousEnigmaCost extends RemoveCounterCost { int countersRemoved = 0; Player controller = game.getPlayer(controllerId); for (int i = 0; i < countersToRemove; i++) { - if (target.choose(Outcome.UnboostCreature, controllerId, source.getSourceId(), game)) { + if (target.choose(Outcome.UnboostCreature, controllerId, source.getSourceId(), source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { if (!permanent.getCounters(game).isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/t/TazeemRaptor.java b/Mage.Sets/src/mage/cards/t/TazeemRaptor.java index 0a150869ea6..329880d36c7 100644 --- a/Mage.Sets/src/mage/cards/t/TazeemRaptor.java +++ b/Mage.Sets/src/mage/cards/t/TazeemRaptor.java @@ -73,7 +73,7 @@ class TazeemRaptorEffect extends OneShotEffect { TargetPermanent target = new TargetControlledPermanent( 0, 1, StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, true ); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); return player.moveCards(game.getCard(target.getFirstTarget()), Zone.HAND, source, game); } } diff --git a/Mage.Sets/src/mage/cards/t/TazriBeaconOfUnity.java b/Mage.Sets/src/mage/cards/t/TazriBeaconOfUnity.java index 034ee4d1b4c..f38d11082a1 100644 --- a/Mage.Sets/src/mage/cards/t/TazriBeaconOfUnity.java +++ b/Mage.Sets/src/mage/cards/t/TazriBeaconOfUnity.java @@ -7,8 +7,8 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.common.PartyCount; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect; import mage.abilities.hint.common.PartyCountHint; import mage.constants.SubType; @@ -52,13 +52,9 @@ public final class TazriBeaconOfUnity extends CardImpl { ).addHint(PartyCountHint.instance)); // {2/U}{2/B}{2/R}{2/G}: Look at the top six cards of your library. You may reveal up to two Cleric, Rogue, Warrior, Wizard, and/or Ally cards from among them and put them into your hand. Put the rest on the bottom of your library in a random order. - this.addAbility(new SimpleActivatedAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(6), false, StaticValue.get(2), filter, Zone.LIBRARY, false, - true, true, Zone.HAND, true, false, false - ).setBackInRandomOrder(true).setText("Look at the top six cards of your library. You may reveal up to two " + - "Cleric, Rogue, Warrior, Wizard, and/or Ally cards from among them and put them into your hand. " + - "Put the rest on the bottom of your library in a random order." - ), new ManaCostsImpl<>("{2/U}{2/B}{2/R}{2/G}"))); + this.addAbility(new SimpleActivatedAbility( + new LookLibraryAndPickControllerEffect(6, 2, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM), + new ManaCostsImpl<>("{2/U}{2/B}{2/R}{2/G}"))); } private TazriBeaconOfUnity(final TazriBeaconOfUnity card) { diff --git a/Mage.Sets/src/mage/cards/t/TectonicHellion.java b/Mage.Sets/src/mage/cards/t/TectonicHellion.java index d6757793bb5..22caf023a7a 100644 --- a/Mage.Sets/src/mage/cards/t/TectonicHellion.java +++ b/Mage.Sets/src/mage/cards/t/TectonicHellion.java @@ -71,7 +71,7 @@ class TectonicHellionEffect extends OneShotEffect { game.getState() .getPlayersInRange(source.getControllerId(), game) .forEach(uuid -> landMap.put(uuid, game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, uuid, source.getSourceId(), game + StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, uuid, source, game ).size())); int max = landMap .values() diff --git a/Mage.Sets/src/mage/cards/t/TeferiHeroOfDominaria.java b/Mage.Sets/src/mage/cards/t/TeferiHeroOfDominaria.java index 76918d6299d..73116eaebf4 100644 --- a/Mage.Sets/src/mage/cards/t/TeferiHeroOfDominaria.java +++ b/Mage.Sets/src/mage/cards/t/TeferiHeroOfDominaria.java @@ -4,7 +4,6 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; @@ -36,7 +35,7 @@ public final class TeferiHeroOfDominaria extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TEFERI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Draw a card. At the beginning of the next end step, untap up to two lands. LoyaltyAbility ability = new LoyaltyAbility(new DrawCardSourceControllerEffect(1), 1); diff --git a/Mage.Sets/src/mage/cards/t/TeferiMageOfZhalfir.java b/Mage.Sets/src/mage/cards/t/TeferiMageOfZhalfir.java index f3e94a8b3eb..4fa8f4920da 100644 --- a/Mage.Sets/src/mage/cards/t/TeferiMageOfZhalfir.java +++ b/Mage.Sets/src/mage/cards/t/TeferiMageOfZhalfir.java @@ -123,7 +123,7 @@ class TeferiMageOfZhalfirReplacementEffect extends ContinuousRuleModifyingEffect @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can cast spells only any time you could cast a sorcery (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/t/TeferiMasterOfTime.java b/Mage.Sets/src/mage/cards/t/TeferiMasterOfTime.java index 8673079ba55..1cef3aac957 100644 --- a/Mage.Sets/src/mage/cards/t/TeferiMasterOfTime.java +++ b/Mage.Sets/src/mage/cards/t/TeferiMasterOfTime.java @@ -2,7 +2,6 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.OneShotEffect; @@ -28,7 +27,7 @@ public final class TeferiMasterOfTime extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TEFERI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // You may activate loyalty abilities of Teferi, Master of Time on any player's turn any time you could cast an instant. this.addAbility(new SimpleStaticAbility(new TeferiMasterOfTimeActivationEffect())); diff --git a/Mage.Sets/src/mage/cards/t/TeferiTemporalArchmage.java b/Mage.Sets/src/mage/cards/t/TeferiTemporalArchmage.java index bb40bd0acac..cf3a8b8610d 100644 --- a/Mage.Sets/src/mage/cards/t/TeferiTemporalArchmage.java +++ b/Mage.Sets/src/mage/cards/t/TeferiTemporalArchmage.java @@ -1,21 +1,17 @@ - package mage.cards.t; import java.util.UUID; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.UntapTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; -import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.game.command.emblems.TeferiTemporalArchmageEmblem; import mage.target.TargetPermanent; @@ -31,11 +27,10 @@ public final class TeferiTemporalArchmage extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TEFERI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Look at the top two cards of your library. Put one of them into your hand and the other on the bottom of your library. - this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(2), false, StaticValue.get(1), new FilterCard(), Zone.LIBRARY, false, false), 1)); + this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect(2, 1, PutCards.HAND, PutCards.BOTTOM_ANY), 1)); // -1: Untap up to four target permanents. LoyaltyAbility loyaltyAbility = new LoyaltyAbility(new UntapTargetEffect(), -1); diff --git a/Mage.Sets/src/mage/cards/t/TeferiTimeRaveler.java b/Mage.Sets/src/mage/cards/t/TeferiTimeRaveler.java index 3cfed14c3fd..edd1a58596a 100644 --- a/Mage.Sets/src/mage/cards/t/TeferiTimeRaveler.java +++ b/Mage.Sets/src/mage/cards/t/TeferiTimeRaveler.java @@ -3,7 +3,6 @@ package mage.cards.t; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -44,7 +43,7 @@ public final class TeferiTimeRaveler extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TEFERI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // Each opponent can cast spells only any time they could cast a sorcery. this.addAbility(new SimpleStaticAbility(new TeferiTimeRavelerReplacementEffect())); @@ -84,7 +83,7 @@ class TeferiTimeRavelerReplacementEffect extends ContinuousRuleModifyingEffectIm @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can cast spells only any time you could cast a sorcery (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/t/TeferiTimebender.java b/Mage.Sets/src/mage/cards/t/TeferiTimebender.java index be09d8f4cf8..542925bb874 100644 --- a/Mage.Sets/src/mage/cards/t/TeferiTimebender.java +++ b/Mage.Sets/src/mage/cards/t/TeferiTimebender.java @@ -3,7 +3,6 @@ package mage.cards.t; import java.util.UUID; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.UntapTargetEffect; @@ -28,7 +27,7 @@ public final class TeferiTimebender extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TEFERI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +2: Untap up to one target artifact or creature. FilterPermanent filter = new FilterPermanent("artifact or creature"); diff --git a/Mage.Sets/src/mage/cards/t/TeferiTimelessVoyager.java b/Mage.Sets/src/mage/cards/t/TeferiTimelessVoyager.java index ec3ab59fc17..3e6d1e2e98a 100644 --- a/Mage.Sets/src/mage/cards/t/TeferiTimelessVoyager.java +++ b/Mage.Sets/src/mage/cards/t/TeferiTimelessVoyager.java @@ -3,7 +3,6 @@ package mage.cards.t; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -30,7 +29,7 @@ public final class TeferiTimelessVoyager extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TEFERI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Draw a card. this.addAbility(new LoyaltyAbility(new DrawCardSourceControllerEffect(1), 1)); diff --git a/Mage.Sets/src/mage/cards/t/TeferiWhoSlowsTheSunset.java b/Mage.Sets/src/mage/cards/t/TeferiWhoSlowsTheSunset.java index 5a521f76f28..58a0e3f0603 100644 --- a/Mage.Sets/src/mage/cards/t/TeferiWhoSlowsTheSunset.java +++ b/Mage.Sets/src/mage/cards/t/TeferiWhoSlowsTheSunset.java @@ -2,19 +2,17 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.StaticFilters; import mage.game.Game; import mage.game.command.emblems.TeferiWhoSlowsTheSunsetEmblem; import mage.game.permanent.Permanent; @@ -35,7 +33,7 @@ public final class TeferiWhoSlowsTheSunset extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TEFERI); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Choose up to one target artifact, up to one target creature, and up to one target land. Untap the chosen permanents you control. Tap the chosen permanents you don't control. You gain 2 life. Ability ability = new LoyaltyAbility(new TeferiWhoSlowsTheSunsetEffect(), 1); @@ -46,10 +44,7 @@ public final class TeferiWhoSlowsTheSunset extends CardImpl { this.addAbility(ability); // −2: Look at the top three cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order. - this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(3), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, false, false - ), -2)); + this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.BOTTOM_ANY), -2)); // −7: You get an emblem with "Untap all permanents you control during each opponent's untap step" and "You draw a card during each opponent's draw step." this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new TeferiWhoSlowsTheSunsetEmblem()), -7)); diff --git a/Mage.Sets/src/mage/cards/t/TeferisPuzzleBox.java b/Mage.Sets/src/mage/cards/t/TeferisPuzzleBox.java index 0031ef90fdf..e22774bea9e 100644 --- a/Mage.Sets/src/mage/cards/t/TeferisPuzzleBox.java +++ b/Mage.Sets/src/mage/cards/t/TeferisPuzzleBox.java @@ -42,7 +42,7 @@ class TeferisPuzzleBoxEffect extends OneShotEffect { public TeferisPuzzleBoxEffect() { super(Outcome.Neutral); - staticText = "At the beginning of each player's draw step, that player puts the cards in their hand on the bottom of their library in any order, then draws that many cards"; + staticText = "that player puts the cards in their hand on the bottom of their library in any order, then draws that many cards"; } public TeferisPuzzleBoxEffect(final TeferisPuzzleBoxEffect effect) { diff --git a/Mage.Sets/src/mage/cards/t/TeferisVeil.java b/Mage.Sets/src/mage/cards/t/TeferisVeil.java index aee497270ba..48c1c7df24c 100644 --- a/Mage.Sets/src/mage/cards/t/TeferisVeil.java +++ b/Mage.Sets/src/mage/cards/t/TeferisVeil.java @@ -21,7 +21,7 @@ public final class TeferisVeil extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); // Whenever a creature you control attacks, it phases out at end of combat. - Effect effect = new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(new PhaseOutTargetEffect("it", false))); + Effect effect = new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(new PhaseOutTargetEffect("it"))); effect.setText("it phases out at end of combat"); this.addAbility(new AttacksCreatureYouControlTriggeredAbility(effect, false, true)); } diff --git a/Mage.Sets/src/mage/cards/t/Teleportal.java b/Mage.Sets/src/mage/cards/t/Teleportal.java index 1392bd60a63..8e30b1ea4d7 100644 --- a/Mage.Sets/src/mage/cards/t/Teleportal.java +++ b/Mage.Sets/src/mage/cards/t/Teleportal.java @@ -73,7 +73,7 @@ class TeleportalEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { CantBeBlockedTargetEffect effect = new CantBeBlockedTargetEffect(); effect.setTargetPointer(new FixedTarget(creature.getId(), game)); game.addEffect(effect, source); diff --git a/Mage.Sets/src/mage/cards/t/TemperedSliver.java b/Mage.Sets/src/mage/cards/t/TemperedSliver.java index 6de875e1a7f..e7a8f3e7ea1 100644 --- a/Mage.Sets/src/mage/cards/t/TemperedSliver.java +++ b/Mage.Sets/src/mage/cards/t/TemperedSliver.java @@ -31,7 +31,7 @@ public final class TemperedSliver extends CardImpl { this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( new DealsCombatDamageToAPlayerTriggeredAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), false,"Whenever this creature deals combat damage to a player, put a +1/+1 counter on it.",false - ), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS + ), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_SLIVERS ))); } diff --git a/Mage.Sets/src/mage/cards/t/TemporalCascade.java b/Mage.Sets/src/mage/cards/t/TemporalCascade.java index e181d46b044..13a806be210 100644 --- a/Mage.Sets/src/mage/cards/t/TemporalCascade.java +++ b/Mage.Sets/src/mage/cards/t/TemporalCascade.java @@ -27,8 +27,7 @@ public final class TemporalCascade extends CardImpl { this.getSpellAbility().addEffect(new ShuffleHandGraveyardAllEffect()); // or each player draws seven cards. - Mode mode = new Mode(); - mode.addEffect(new TemporalCascadeDrawEffect()); + Mode mode = new Mode(new TemporalCascadeDrawEffect()); this.getSpellAbility().getModes().addMode(mode); // Entwine {2} diff --git a/Mage.Sets/src/mage/cards/t/TemporaryInsanity.java b/Mage.Sets/src/mage/cards/t/TemporaryInsanity.java index 92f690cc284..054a282f4cb 100644 --- a/Mage.Sets/src/mage/cards/t/TemporaryInsanity.java +++ b/Mage.Sets/src/mage/cards/t/TemporaryInsanity.java @@ -76,10 +76,10 @@ class TargetCreatureWithPowerLessThanNumberOfCardsInYourGraveyard extends Target } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - MageObject targetSource = game.getObject(sourceId); + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + MageObject targetSource = game.getObject(source); if(targetSource != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { if (permanent.getPower().getValue() < game.getPlayer(sourceControllerId).getGraveyard().size()) { return true; diff --git a/Mage.Sets/src/mage/cards/t/TemptWithImmortality.java b/Mage.Sets/src/mage/cards/t/TemptWithImmortality.java index fb7dfcc85ec..2610ddad3f4 100644 --- a/Mage.Sets/src/mage/cards/t/TemptWithImmortality.java +++ b/Mage.Sets/src/mage/cards/t/TemptWithImmortality.java @@ -73,7 +73,7 @@ class TemptWithImmortalityEffect extends OneShotEffect { filter.add(new OwnerIdPredicate(opponent.getId())); Target targetCardOpponent = new TargetCardInGraveyard(filter); - if (targetCardOpponent.canChoose(source.getSourceId(), opponent.getId(), game)) { + if (targetCardOpponent.canChoose(opponent.getId(), source, game)) { if (opponent.chooseUse(outcome, "Return a creature card from your graveyard to the battlefield?", source, game)) { if (opponent.chooseTarget(outcome, targetCardOpponent, source, game)) { Card card = game.getCard(targetCardOpponent.getFirstTarget()); @@ -100,7 +100,7 @@ class TemptWithImmortalityEffect extends OneShotEffect { private boolean returnCreatureFromGraveToBattlefield(Player player, Ability source, Game game) { Target target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE); target.setNotTarget(false); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (target.canChoose(source.getControllerId(), source, game)) { if (player.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/t/TemptingWurm.java b/Mage.Sets/src/mage/cards/t/TemptingWurm.java index a82d7ce2bde..46e01a107ce 100644 --- a/Mage.Sets/src/mage/cards/t/TemptingWurm.java +++ b/Mage.Sets/src/mage/cards/t/TemptingWurm.java @@ -80,7 +80,7 @@ class TemptingWurmEffect extends OneShotEffect { if (opponent != null){ Target target = new TargetCardInHand(0, Integer.MAX_VALUE, filter); - if(target.canChoose(source.getSourceId(), opponent.getId(), game)) { + if(target.canChoose(opponent.getId(), source, game)) { if (opponent.chooseUse(Outcome.PutCardInPlay , "Put any artifact, creature, enchantment, and/or land cards cards from your hand onto the battlefield?", source, game)) { if (target.chooseTarget(Outcome.PutCardInPlay, opponent.getId(), source, game)) { for (UUID cardId: target.getTargets()){ diff --git a/Mage.Sets/src/mage/cards/t/TemurCharger.java b/Mage.Sets/src/mage/cards/t/TemurCharger.java index d0df7b38439..764118f0bd7 100644 --- a/Mage.Sets/src/mage/cards/t/TemurCharger.java +++ b/Mage.Sets/src/mage/cards/t/TemurCharger.java @@ -40,7 +40,7 @@ public final class TemurCharger extends CardImpl { this.toughness = new MageInt(1); // Morph - Reveal a green card in your hand. - this.addAbility(new MorphAbility(this, new RevealTargetFromHandCost(new TargetCardInHand(filter)))); + this.addAbility(new MorphAbility(new RevealTargetFromHandCost(new TargetCardInHand(filter)))); // When Temur Charger is turned face up, target creature gains trample until end of turn. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn)); diff --git a/Mage.Sets/src/mage/cards/t/TemurCharm.java b/Mage.Sets/src/mage/cards/t/TemurCharm.java index 2e10b9e76be..bc5ccdaf423 100644 --- a/Mage.Sets/src/mage/cards/t/TemurCharm.java +++ b/Mage.Sets/src/mage/cards/t/TemurCharm.java @@ -48,14 +48,12 @@ public final class TemurCharm extends CardImpl { this.getSpellAbility().addTarget(target); // Counter target spell unless its controller pays {3}. - Mode mode = new Mode(); - mode.addEffect(new CounterUnlessPaysEffect(new GenericManaCost(3))); + Mode mode = new Mode(new CounterUnlessPaysEffect(new GenericManaCost(3))); mode.addTarget(new TargetSpell()); this.getSpellAbility().addMode(mode); // Creatures with power 3 or less can't block this turn. - mode = new Mode(); - mode.addEffect(new CantBlockAllEffect(filterCantBlock, Duration.EndOfTurn)); + mode = new Mode(new CantBlockAllEffect(filterCantBlock, Duration.EndOfTurn)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/t/TemurSabertooth.java b/Mage.Sets/src/mage/cards/t/TemurSabertooth.java index 2f8058a3b60..d92e8faa54c 100644 --- a/Mage.Sets/src/mage/cards/t/TemurSabertooth.java +++ b/Mage.Sets/src/mage/cards/t/TemurSabertooth.java @@ -78,7 +78,7 @@ class TemurSabertoothEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Target target = new TargetPermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { + if (target.canChoose(controller.getId(), source, game)) { if (controller.chooseUse(outcome, "Return another creature to hand?", source, game) && controller.chooseTarget(outcome, target, source, game)) { Permanent toHand = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/t/TenaciousUnderdog.java b/Mage.Sets/src/mage/cards/t/TenaciousUnderdog.java new file mode 100644 index 00000000000..c0d8dbcf934 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TenaciousUnderdog.java @@ -0,0 +1,82 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.keyword.BlitzAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TenaciousUnderdog extends CardImpl { + + public TenaciousUnderdog(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Blitz—{2}{B}{B}, Pay 2 life. + Ability ability = new BlitzAbility(this, "{2}{B}{B}"); + ability.addCost(new PayLifeCost(2)); + this.addAbility(ability); + + // You may cast Tenacious Underdog from your graveyard using its blitz ability. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new TenaciousUnderdogEffect())); + } + + private TenaciousUnderdog(final TenaciousUnderdog card) { + super(card); + } + + @Override + public TenaciousUnderdog copy() { + return new TenaciousUnderdog(this); + } +} + +class TenaciousUnderdogEffect extends AsThoughEffectImpl { + + TenaciousUnderdogEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfGame, Outcome.PutCreatureInPlay); + staticText = "You may cast {this} from your graveyard using its blitz ability"; + } + + private TenaciousUnderdogEffect(final TenaciousUnderdogEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public TenaciousUnderdogEffect copy() { + return new TenaciousUnderdogEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game, UUID playerId) { + return objectId.equals(source.getSourceId()) + && source.isControlledBy(playerId) + && affectedAbility instanceof BlitzAbility + && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD + && game.getCard(source.getSourceId()) != null; + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/t/Tephraderm.java b/Mage.Sets/src/mage/cards/t/Tephraderm.java index f9b06856ca3..5c642c96b0a 100644 --- a/Mage.Sets/src/mage/cards/t/Tephraderm.java +++ b/Mage.Sets/src/mage/cards/t/Tephraderm.java @@ -74,7 +74,7 @@ class TephradermCreatureDamageTriggeredAbility extends TriggeredAbilityImpl { Permanent sourcePermanent = game.getPermanent(event.getSourceId()); if (sourcePermanent != null - && FILTER_CREATURE.match(sourcePermanent, getSourceId(), getControllerId(), game)) { + && FILTER_CREATURE.match(sourcePermanent, getControllerId(), this, game)) { for (Effect effect : getEffects()) { if (effect instanceof DamageTargetEffect) { effect.setTargetPointer(new FixedTarget(sourcePermanent.getId(), game)); @@ -120,7 +120,7 @@ class TephradermSpellDamageTriggeredAbility extends TriggeredAbilityImpl { } StackObject sourceSpell = game.getStack().getStackObject(event.getSourceId()); - if (sourceSpell != null && StaticFilters.FILTER_SPELL.match(sourceSpell, getSourceId(), getControllerId(), game)) { + if (sourceSpell != null && StaticFilters.FILTER_SPELL.match(sourceSpell, getControllerId(), this, game)) { for (Effect effect : getEffects()) { if (effect instanceof DamageTargetEffect) { effect.setTargetPointer(new FixedTarget(sourceSpell.getControllerId())); diff --git a/Mage.Sets/src/mage/cards/t/TergridGodOfFright.java b/Mage.Sets/src/mage/cards/t/TergridGodOfFright.java index c6f5de8ffc7..ce57cc7b75a 100644 --- a/Mage.Sets/src/mage/cards/t/TergridGodOfFright.java +++ b/Mage.Sets/src/mage/cards/t/TergridGodOfFright.java @@ -198,7 +198,7 @@ class TergridsLaternEffect extends OneShotEffect { Outcome aiOutcome = (targetedPlayer.getLife() <= 3 * 2) ? Outcome.Benefit : Outcome.Detriment; Set choiceSet = new HashSet<>(); - if (game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_PERMANENT_NON_LAND, source.getSourceId(), targetedPlayer.getId(), game) > 0) { + if (game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_PERMANENT_NON_LAND, targetedPlayer.getId(), source, game) > 0) { choiceSet.add(SACRIFICE_CHOICE); } if (targetedPlayer.getHand().size() > 0) { @@ -222,7 +222,7 @@ class TergridsLaternEffect extends OneShotEffect { case SACRIFICE_CHOICE: TargetPermanent target = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_NON_LAND); target.setNotTarget(true); - targetedPlayer.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + targetedPlayer.choose(Outcome.Sacrifice, target, source, game); Permanent chosenLand = game.getPermanent(target.getFirstTarget()); return chosenLand != null && chosenLand.sacrifice(source, game); case DISCARD_CHOICE: diff --git a/Mage.Sets/src/mage/cards/t/TerminalAgony.java b/Mage.Sets/src/mage/cards/t/TerminalAgony.java index f4200e43ee9..c77ed386646 100644 --- a/Mage.Sets/src/mage/cards/t/TerminalAgony.java +++ b/Mage.Sets/src/mage/cards/t/TerminalAgony.java @@ -23,7 +23,7 @@ public final class TerminalAgony extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Madness {B}{R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{B}{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{B}{R}"))); } private TerminalAgony(final TerminalAgony card) { diff --git a/Mage.Sets/src/mage/cards/t/Terminus.java b/Mage.Sets/src/mage/cards/t/Terminus.java index 1bd33f97f03..87a06e7b08b 100644 --- a/Mage.Sets/src/mage/cards/t/Terminus.java +++ b/Mage.Sets/src/mage/cards/t/Terminus.java @@ -67,7 +67,7 @@ class TerminusEffect extends OneShotEffect { filter.add(new OwnerIdPredicate(player.getId())); Cards toLib = new CardsImpl(); for (Permanent permanent : game.getBattlefield() - .getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + .getActivePermanents(filter, source.getControllerId(), source, game)) { toLib.add(permanent); } player.putCardsOnBottomOfLibrary(toLib, game, source, true); diff --git a/Mage.Sets/src/mage/cards/t/TerraEternal.java b/Mage.Sets/src/mage/cards/t/TerraEternal.java index c02a9020a32..f1b7d71afb2 100644 --- a/Mage.Sets/src/mage/cards/t/TerraEternal.java +++ b/Mage.Sets/src/mage/cards/t/TerraEternal.java @@ -1,33 +1,31 @@ - package mage.cards.t; -import java.util.UUID; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterLandPermanent; +import java.util.UUID; + /** - * * @author North */ public final class TerraEternal extends CardImpl { - public TerraEternal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}"); + private static final FilterPermanent filter = new FilterLandPermanent("all lands"); + public TerraEternal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); // All lands are indestructible. - FilterLandPermanent filter = new FilterLandPermanent("All lands"); - Effect effect = new GainAbilityAllEffect(IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield, filter, false); - effect.setText("All lands are indestructible"); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( + IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield, filter, false + ))); } private TerraEternal(final TerraEternal card) { diff --git a/Mage.Sets/src/mage/cards/t/Terraformer.java b/Mage.Sets/src/mage/cards/t/Terraformer.java index 40b751b1c9a..2857b042d39 100644 --- a/Mage.Sets/src/mage/cards/t/Terraformer.java +++ b/Mage.Sets/src/mage/cards/t/Terraformer.java @@ -119,7 +119,7 @@ class TerraformerContinuousEffect extends ContinuousEffectImpl { game.getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game ).stream() .map(permanent -> new MageObjectReference(permanent, game)) .forEach(affectedObjectList::add); diff --git a/Mage.Sets/src/mage/cards/t/TerritorialKavu.java b/Mage.Sets/src/mage/cards/t/TerritorialKavu.java index 4b5ef1fee77..d8972a7d88e 100644 --- a/Mage.Sets/src/mage/cards/t/TerritorialKavu.java +++ b/Mage.Sets/src/mage/cards/t/TerritorialKavu.java @@ -6,7 +6,6 @@ import mage.abilities.Mode; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.DiscardCardCost; -import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.DomainValue; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -25,8 +24,6 @@ import java.util.UUID; */ public final class TerritorialKavu extends CardImpl { - private static final DynamicValue xValue = new DomainValue(); - public TerritorialKavu(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{G}"); @@ -36,7 +33,7 @@ public final class TerritorialKavu extends CardImpl { // Domain — Territorial Kavu's power and toughness are each equal to the number of basic land types among lands you control. this.addAbility(new SimpleStaticAbility( - Zone.ALL, new SetPowerToughnessSourceEffect(xValue, Duration.EndOfGame) + Zone.ALL, new SetPowerToughnessSourceEffect(DomainValue.REGULAR, Duration.EndOfGame) ).addHint(DomainHint.instance).setAbilityWord(AbilityWord.DOMAIN)); // Whenever Territorial Kavu attacks, choose one — diff --git a/Mage.Sets/src/mage/cards/t/TeveshSzatDoomOfFools.java b/Mage.Sets/src/mage/cards/t/TeveshSzatDoomOfFools.java index 67a9ae5eb04..08c6f7675c3 100644 --- a/Mage.Sets/src/mage/cards/t/TeveshSzatDoomOfFools.java +++ b/Mage.Sets/src/mage/cards/t/TeveshSzatDoomOfFools.java @@ -3,7 +3,6 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; @@ -41,7 +40,7 @@ public final class TeveshSzatDoomOfFools extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SZAT); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +2: Create two 0/1 black Thrull creature tokens. this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new BreedingPitThrullToken(), 2), 2)); @@ -102,10 +101,10 @@ class TeveshSzatDoomOfFoolsSacrificeEffect extends OneShotEffect { } TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (!target.canChoose(source.getControllerId(), source, game)) { return false; } - target.choose(outcome, source.getControllerId(), source.getSourceId(), game); + target.choose(outcome, source.getControllerId(), source.getSourceId(), source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent == null) { return false; @@ -159,7 +158,7 @@ class TeveshSzatDoomOfFoolsCommanderEffect extends OneShotEffect { // gain control of all commanders for (Permanent permanent : game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game )) { game.addEffect(new GainControlTargetEffect( Duration.Custom, true diff --git a/Mage.Sets/src/mage/cards/t/TeyoTheShieldmage.java b/Mage.Sets/src/mage/cards/t/TeyoTheShieldmage.java index 6a862561612..88173d0b7f6 100644 --- a/Mage.Sets/src/mage/cards/t/TeyoTheShieldmage.java +++ b/Mage.Sets/src/mage/cards/t/TeyoTheShieldmage.java @@ -1,7 +1,6 @@ package mage.cards.t; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.GainAbilityControllerEffect; @@ -25,7 +24,7 @@ public final class TeyoTheShieldmage extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TEYO); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // You have hexproof. this.addAbility(new SimpleStaticAbility(new GainAbilityControllerEffect(HexproofAbility.getInstance()))); diff --git a/Mage.Sets/src/mage/cards/t/TezzeretAgentOfBolas.java b/Mage.Sets/src/mage/cards/t/TezzeretAgentOfBolas.java index 76c27ebc5e1..4a5b9295ce4 100644 --- a/Mage.Sets/src/mage/cards/t/TezzeretAgentOfBolas.java +++ b/Mage.Sets/src/mage/cards/t/TezzeretAgentOfBolas.java @@ -4,11 +4,11 @@ package mage.cards.t; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.continuous.AddCardTypeTargetEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessTargetEffect; import mage.cards.CardImpl; @@ -18,7 +18,6 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.SuperType; -import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; @@ -31,21 +30,17 @@ import mage.target.common.TargetArtifactPermanent; */ public final class TezzeretAgentOfBolas extends CardImpl { - private static final FilterCard filter = new FilterCard("an artifact card"); - - static { - filter.add(CardType.ARTIFACT.getPredicate()); - } - public TezzeretAgentOfBolas(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{U}{B}"); this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TEZZERET); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); - // +1: Look at the top five cards of your library. You may reveal an artifact card from among them and put it into your hand. Put the rest on the bottom of your library in any order. - this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect(5, 1, filter, true), 1)); + // +1: Look at the top five cards of your library. You may reveal an artifact card from among them and put it into your hand. + // Put the rest on the bottom of your library in any order. + this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect( + 5, 1, StaticFilters.FILTER_CARD_ARTIFACT_AN, PutCards.HAND, PutCards.BOTTOM_ANY), 1)); // -1: Target artifact becomes an artifact creature with base power and toughness 5/5. Effect effect = new AddCardTypeTargetEffect(Duration.EndOfGame, CardType.ARTIFACT, CardType.CREATURE); diff --git a/Mage.Sets/src/mage/cards/t/TezzeretArtificeMaster.java b/Mage.Sets/src/mage/cards/t/TezzeretArtificeMaster.java index 722a9103fd7..d84a8477d72 100644 --- a/Mage.Sets/src/mage/cards/t/TezzeretArtificeMaster.java +++ b/Mage.Sets/src/mage/cards/t/TezzeretArtificeMaster.java @@ -1,7 +1,6 @@ package mage.cards.t; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.condition.common.MetalcraftCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; @@ -29,7 +28,7 @@ public final class TezzeretArtificeMaster extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TEZZERET); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Create a colorless Thopter artifact creature token with flying. this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new ThopterColorlessToken()), 1)); diff --git a/Mage.Sets/src/mage/cards/t/TezzeretBetrayerOfFlesh.java b/Mage.Sets/src/mage/cards/t/TezzeretBetrayerOfFlesh.java new file mode 100644 index 00000000000..6279e949f5e --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TezzeretBetrayerOfFlesh.java @@ -0,0 +1,196 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.ActivatedAbility; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GetEmblemEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.command.emblems.TezzeretBetrayerOfFleshEmblem; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.common.TargetArtifactPermanent; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TezzeretBetrayerOfFlesh extends CardImpl { + + public TezzeretBetrayerOfFlesh(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{U}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.TEZZERET); + this.setStartingLoyalty(4); + + // The first activated ability of an artifact you activate each turn costs {2} less to activate. + this.addAbility(new SimpleStaticAbility( + new TezzeretBetrayerOfFleshReductionEffect() + ), new TezzeretBetrayerOfFleshWatcher()); + + // +1: Draw two cards. Then discard two cards unless you discard an artifact card. + Ability ability = new LoyaltyAbility(new DrawCardSourceControllerEffect(2), 1); + ability.addEffect(new DoIfCostPaid( + null, new DiscardControllerEffect(2), + new DiscardCardCost(StaticFilters.FILTER_CARD_ARTIFACT_AN) + .setText("discard an artifact card instead of discarding two cards") + ).setText("Then discard two cards unless you discard an artifact card")); + this.addAbility(ability); + + // −2: Target artifact becomes an artifact creature. If it isn't a Vehicle, it has base power and toughness 4/4. + ability = new LoyaltyAbility(new TezzeretBetrayerOfFleshTypeEffect(), -2); + ability.addTarget(new TargetArtifactPermanent()); + this.addAbility(ability); + + // −6: You get an emblem with "Whenever an artifact you control becomes tapped, draw a card." + this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new TezzeretBetrayerOfFleshEmblem()), -6)); + } + + private TezzeretBetrayerOfFlesh(final TezzeretBetrayerOfFlesh card) { + super(card); + } + + @Override + public TezzeretBetrayerOfFlesh copy() { + return new TezzeretBetrayerOfFlesh(this); + } +} + +class TezzeretBetrayerOfFleshReductionEffect extends CostModificationEffectImpl { + + TezzeretBetrayerOfFleshReductionEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "the first activated ability of an artifact you activate each turn costs {2} less to activate"; + } + + private TezzeretBetrayerOfFleshReductionEffect(final TezzeretBetrayerOfFleshReductionEffect effect) { + super(effect); + } + + @Override + public TezzeretBetrayerOfFleshReductionEffect copy() { + return new TezzeretBetrayerOfFleshReductionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + CardUtil.reduceCost(abilityToModify, 2); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + return abilityToModify.isControlledBy(source.getControllerId()) + && abilityToModify instanceof ActivatedAbility + && TezzeretBetrayerOfFleshWatcher.checkPlayer(game, abilityToModify); + } +} + +class TezzeretBetrayerOfFleshWatcher extends Watcher { + + private final Set playerSet = new HashSet<>(); + + TezzeretBetrayerOfFleshWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.ACTIVATED_ABILITY) { + return; + } + Permanent permanent = game.getPermanent(event.getSourceId()); + if (permanent != null && permanent.isArtifact(game)) { + playerSet.add(event.getPlayerId()); + } + } + + @Override + public void reset() { + super.reset(); + playerSet.clear(); + } + + public static boolean checkPlayer(Game game, Ability ability) { + if (game.getState() + .getWatcher(TezzeretBetrayerOfFleshWatcher.class) + .playerSet + .contains(ability.getControllerId())) { + return false; + } + Permanent permanent = ability.getSourcePermanentOrLKI(game); + return permanent != null && permanent.isArtifact(game); + } +} + +class TezzeretBetrayerOfFleshTypeEffect extends ContinuousEffectImpl { + + TezzeretBetrayerOfFleshTypeEffect() { + super(Duration.Custom, Outcome.BecomeCreature); + staticText = "target artifact becomes an artifact creature. " + + "If it isn't a Vehicle, it has base power and toughness 4/4"; + } + + private TezzeretBetrayerOfFleshTypeEffect(final TezzeretBetrayerOfFleshTypeEffect effect) { + super(effect); + } + + @Override + public TezzeretBetrayerOfFleshTypeEffect copy() { + return new TezzeretBetrayerOfFleshTypeEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + discard(); + return false; + } + switch (layer) { + case TypeChangingEffects_4: + permanent.addCardType(game, CardType.ARTIFACT, CardType.CREATURE); + return true; + case PTChangingEffects_7: + if (sublayer != SubLayer.SetPT_7b + || permanent.hasSubtype(SubType.VEHICLE, game)) { + return false; + } + permanent.getPower().setValue(4); + permanent.getToughness().setValue(4); + return true; + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + switch (layer) { + case TypeChangingEffects_4: + case PTChangingEffects_7: + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TezzeretCruelMachinist.java b/Mage.Sets/src/mage/cards/t/TezzeretCruelMachinist.java index a8ffc254347..e8a4d8b6531 100644 --- a/Mage.Sets/src/mage/cards/t/TezzeretCruelMachinist.java +++ b/Mage.Sets/src/mage/cards/t/TezzeretCruelMachinist.java @@ -3,7 +3,6 @@ package mage.cards.t; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -36,7 +35,7 @@ public final class TezzeretCruelMachinist extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TEZZERET); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Draw a card. this.addAbility(new LoyaltyAbility(new DrawCardSourceControllerEffect(1), 1)); @@ -88,7 +87,7 @@ class TezzeretCruelMachinistEffect extends OneShotEffect { return false; } Target target = new TargetCardInHand(0, Integer.MAX_VALUE, StaticFilters.FILTER_CARD); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Cards cardsToMove = new CardsImpl(target.getTargets()); if (cardsToMove.isEmpty()) { return false; diff --git a/Mage.Sets/src/mage/cards/t/TezzeretMasterOfMetal.java b/Mage.Sets/src/mage/cards/t/TezzeretMasterOfMetal.java index a08d1dfaaf6..c9a4fd6ecb8 100644 --- a/Mage.Sets/src/mage/cards/t/TezzeretMasterOfMetal.java +++ b/Mage.Sets/src/mage/cards/t/TezzeretMasterOfMetal.java @@ -2,21 +2,18 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.ArtifactYouControlCount; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.abilities.effects.common.RevealCardsFromLibraryUntilEffect; -import mage.abilities.hint.ValueHint; +import mage.abilities.hint.common.ArtifactYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterPermanent; -import mage.filter.common.FilterArtifactCard; -import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.StaticFilters; import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.permanent.Permanent; @@ -36,16 +33,15 @@ public final class TezzeretMasterOfMetal extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TEZZERET); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Reveal cards from the top of your library until you reveal an artifact card. Put that card into your hand and the rest on the bottom of your library in a random order. - this.addAbility(new LoyaltyAbility(new RevealCardsFromLibraryUntilEffect(new FilterArtifactCard(), Zone.HAND, Zone.LIBRARY), 1)); + this.addAbility(new LoyaltyAbility(new RevealCardsFromLibraryUntilEffect(StaticFilters.FILTER_CARD_ARTIFACT, Zone.HAND, Zone.LIBRARY), 1)); // -3: Target opponent loses life equal to the number of artifacts you control. - DynamicValue xValue = new PermanentsOnBattlefieldCount(new FilterControlledArtifactPermanent()); - Ability ability = new LoyaltyAbility(new LoseLifeTargetEffect(xValue), -3); + Ability ability = new LoyaltyAbility(new LoseLifeTargetEffect(ArtifactYouControlCount.instance).setText("target opponent loses life equal to the number of artifacts you control"), -3); ability.addTarget(new TargetOpponent()); - ability.addHint(new ValueHint("Artifacts you control", xValue)); + ability.addHint(ArtifactYouControlHint.instance); this.addAbility(ability); // -8: Gain control of all artifacts and creatures target opponent controls. diff --git a/Mage.Sets/src/mage/cards/t/TezzeretMasterOfTheBridge.java b/Mage.Sets/src/mage/cards/t/TezzeretMasterOfTheBridge.java index 90e4661e197..596f74f3aa9 100644 --- a/Mage.Sets/src/mage/cards/t/TezzeretMasterOfTheBridge.java +++ b/Mage.Sets/src/mage/cards/t/TezzeretMasterOfTheBridge.java @@ -2,19 +2,17 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamagePlayersEffect; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledSpellsEffect; import mage.abilities.keyword.AffinityForArtifactsAbility; import mage.cards.*; import mage.constants.*; import mage.filter.FilterCard; import mage.filter.StaticFilters; -import mage.filter.common.FilterArtifactCard; import mage.filter.predicate.Predicates; import mage.game.Game; import mage.players.Player; @@ -36,14 +34,12 @@ public final class TezzeretMasterOfTheBridge extends CardImpl { )); } - private static final FilterCard filter2 = new FilterArtifactCard("artifact card from your graveyard"); - public TezzeretMasterOfTheBridge(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{U}{B}"); this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TEZZERET); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Creature and planeswalker spells you cast have affinity for artifacts. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledSpellsEffect( @@ -54,8 +50,8 @@ public final class TezzeretMasterOfTheBridge extends CardImpl { this.addAbility(new LoyaltyAbility(new TezzeretMasterOfTheBridgeEffect(), 2)); // -3: Return target artifact card from your graveyard to your hand. - Ability ability = new LoyaltyAbility(new ReturnToHandTargetEffect(), -3); - ability.addTarget(new TargetCardInYourGraveyard(filter2)); + Ability ability = new LoyaltyAbility(new ReturnFromGraveyardToHandTargetEffect(), -3); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); // -8: Exile the top ten cards of your library. Put all artifact cards from among them onto the battlefield. @@ -137,4 +133,4 @@ class TezzeretMasterOfTheBridgeEffect2 extends OneShotEffect { } return player.moveCards(cards2, Zone.BATTLEFIELD, source, game); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/t/TezzeretTheSchemer.java b/Mage.Sets/src/mage/cards/t/TezzeretTheSchemer.java index 8244bb7318f..9aec7c26321 100644 --- a/Mage.Sets/src/mage/cards/t/TezzeretTheSchemer.java +++ b/Mage.Sets/src/mage/cards/t/TezzeretTheSchemer.java @@ -4,7 +4,6 @@ package mage.cards.t; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; @@ -33,7 +32,7 @@ public final class TezzeretTheSchemer extends CardImpl { this.subtype.add(SubType.TEZZERET); //Starting Loyalty - 5 - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Create a colorless artifact token named Etherium Cell which has "{T}, Sacrifice this artifact: Add one mana of any color." this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new EtheriumCellToken()), 1)); diff --git a/Mage.Sets/src/mage/cards/t/TezzeretTheSeeker.java b/Mage.Sets/src/mage/cards/t/TezzeretTheSeeker.java index 581046db955..852cc6630a5 100644 --- a/Mage.Sets/src/mage/cards/t/TezzeretTheSeeker.java +++ b/Mage.Sets/src/mage/cards/t/TezzeretTheSeeker.java @@ -5,7 +5,6 @@ import java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.common.PayVariableLoyaltyCost; import mage.abilities.effects.ContinuousEffectImpl; @@ -35,7 +34,7 @@ public final class TezzeretTheSeeker extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TEZZERET); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Untap up to two target artifacts. LoyaltyAbility ability = new LoyaltyAbility(new UntapTargetEffect(), 1); diff --git a/Mage.Sets/src/mage/cards/t/TezzeretsBetrayal.java b/Mage.Sets/src/mage/cards/t/TezzeretsBetrayal.java index 02aa259eb37..da6499ea4f2 100644 --- a/Mage.Sets/src/mage/cards/t/TezzeretsBetrayal.java +++ b/Mage.Sets/src/mage/cards/t/TezzeretsBetrayal.java @@ -1,7 +1,6 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.search.SearchLibraryGraveyardPutInHandEffect; import mage.cards.CardImpl; @@ -11,8 +10,9 @@ import mage.filter.FilterCard; import mage.filter.predicate.mageobject.NamePredicate; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class TezzeretsBetrayal extends CardImpl { @@ -32,7 +32,7 @@ public final class TezzeretsBetrayal extends CardImpl { // You may search your library and/or graveyard for a card named Tezzeret, Master of Metal, reveal it, and put it into your hand. // If you search your library this way, shuffle it. - getSpellAbility().addEffect(new SearchLibraryGraveyardPutInHandEffect(filter)); + getSpellAbility().addEffect(new SearchLibraryGraveyardPutInHandEffect(filter, false, true)); } private TezzeretsBetrayal(final TezzeretsBetrayal card) { diff --git a/Mage.Sets/src/mage/cards/t/TezzeretsGatebreaker.java b/Mage.Sets/src/mage/cards/t/TezzeretsGatebreaker.java index 8be6e01f08e..cc18ad958e4 100644 --- a/Mage.Sets/src/mage/cards/t/TezzeretsGatebreaker.java +++ b/Mage.Sets/src/mage/cards/t/TezzeretsGatebreaker.java @@ -8,14 +8,13 @@ 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.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.combat.CantBeBlockedAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.predicate.Predicates; @@ -41,13 +40,7 @@ public final class TezzeretsGatebreaker extends CardImpl { // When Tezzeret's Gatebreaker enters the battlefield, look at the top five cards of your library. You may reveal a blue or artifact card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. this.addAbility(new EntersBattlefieldTriggeredAbility( - new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), filter, - Zone.LIBRARY, false, true, false, Zone.HAND, true, false, false - ).setBackInRandomOrder(true).setText("look at the top five cards of your library. " - + "You may reveal a blue or artifact card from among them and put it into your hand. " - + "Put the rest on the bottom of your library in a random order.") - )); + new LookLibraryAndPickControllerEffect(5, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM))); // {5}{U}, {T}, Sacrifice Tezzeret's Gatebreaker: Creatures you control can't be blocked this turn. Ability ability = new SimpleActivatedAbility( diff --git a/Mage.Sets/src/mage/cards/t/ThadaAdelAcquisitor.java b/Mage.Sets/src/mage/cards/t/ThadaAdelAcquisitor.java index bf02e7fc12b..3a3603ebe46 100644 --- a/Mage.Sets/src/mage/cards/t/ThadaAdelAcquisitor.java +++ b/Mage.Sets/src/mage/cards/t/ThadaAdelAcquisitor.java @@ -1,33 +1,29 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; import mage.abilities.keyword.IslandwalkAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; -import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class ThadaAdelAcquisitor extends CardImpl { public ThadaAdelAcquisitor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.MERFOLK); this.subtype.add(SubType.ROGUE); @@ -39,7 +35,9 @@ public final class ThadaAdelAcquisitor extends CardImpl { this.addAbility(new IslandwalkAbility()); // Whenever Thada Adel, Acquisitor deals combat damage to a player, search that player's library for an artifact card and exile it. Then that player shuffles their library. Until end of turn, you may play that card. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new ThadaAdelAcquisitorEffect(), false, true)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new ThadaAdelAcquisitorEffect(), false, true + )); } private ThadaAdelAcquisitor(final ThadaAdelAcquisitor card) { @@ -67,22 +65,16 @@ class ThadaAdelAcquisitorEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Player damagedPlayer = game.getPlayer(targetPointer.getFirst(game, source)); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller == null || damagedPlayer == null || sourceObject == null) { + if (controller == null || damagedPlayer == null) { return false; } - TargetCardInLibrary target = new TargetCardInLibrary(new FilterArtifactCard()); - if (controller.searchLibrary(target, source, game, damagedPlayer.getId())) { - if (!target.getTargets().isEmpty()) { - Card card = damagedPlayer.getLibrary().remove(target.getFirstTarget(), game); - if (card != null) { - controller.moveCardToExileWithInfo(card, source.getSourceId(), sourceObject.getIdName(), source, game, Zone.LIBRARY, true); - ContinuousEffect effect = new ThadaAdelPlayFromExileEffect(); - effect.setTargetPointer(new FixedTarget(card.getId())); - game.addEffect(effect, source); - } - } - } + TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_ARTIFACT); + controller.searchLibrary(target, source, game, damagedPlayer.getId()); + Card card = damagedPlayer.getLibrary().getCard(target.getFirstTarget(), game); + PlayFromNotOwnHandZoneTargetEffect.exileAndPlayFromExile( + game, source, card, TargetController.YOU, Duration.EndOfTurn, + false, false, false + ); damagedPlayer.shuffleLibrary(source, game); return true; } @@ -92,31 +84,3 @@ class ThadaAdelAcquisitorEffect extends OneShotEffect { return new ThadaAdelAcquisitorEffect(this); } } - -class ThadaAdelPlayFromExileEffect extends AsThoughEffectImpl { - - public ThadaAdelPlayFromExileEffect() { - super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); - staticText = "You may play this card from exile"; - } - - public ThadaAdelPlayFromExileEffect(final ThadaAdelPlayFromExileEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public ThadaAdelPlayFromExileEffect copy() { - return new ThadaAdelPlayFromExileEffect(this); - } - - @Override - public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { - return source.isControlledBy(affectedControllerId) - && sourceId.equals(getTargetPointer().getFirst(game, source)); - } -} diff --git a/Mage.Sets/src/mage/cards/t/ThaliasLieutenant.java b/Mage.Sets/src/mage/cards/t/ThaliasLieutenant.java index a5329812e5a..1b82f206f33 100644 --- a/Mage.Sets/src/mage/cards/t/ThaliasLieutenant.java +++ b/Mage.Sets/src/mage/cards/t/ThaliasLieutenant.java @@ -1,9 +1,7 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; -import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersAllEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; @@ -15,13 +13,14 @@ import mage.counters.CounterType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AnotherPredicate; +import java.util.UUID; + /** - * * @author fireshoes */ public final class ThaliasLieutenant extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another Human you control"); + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another Human"); static { filter.add(AnotherPredicate.instance); @@ -29,17 +28,17 @@ public final class ThaliasLieutenant extends CardImpl { } public ThaliasLieutenant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); this.power = new MageInt(1); this.toughness = new MageInt(1); // When Thalia's Lieutenant enters the battlefield, put +1/+1 counter on each other Human you control. - this.addAbility(new EntersBattlefieldTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter), false)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter).setText("put +1/+1 counter on each other Human you control"), false)); // Whenever another Human enters the battlefield under you control, put a +1/+1 counter on Thalia's Lieutenant. - this.addAbility(new EntersBattlefieldAllTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter)); + this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter)); } private ThaliasLieutenant(final ThaliasLieutenant card) { diff --git a/Mage.Sets/src/mage/cards/t/ThantisTheWarweaver.java b/Mage.Sets/src/mage/cards/t/ThantisTheWarweaver.java index dc578625118..18417ac284f 100644 --- a/Mage.Sets/src/mage/cards/t/ThantisTheWarweaver.java +++ b/Mage.Sets/src/mage/cards/t/ThantisTheWarweaver.java @@ -14,7 +14,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.StaticFilters; @@ -39,13 +38,7 @@ public final class ThantisTheWarweaver extends CardImpl { this.addAbility(ReachAbility.getInstance()); // All creatures attack each combat if able. - this.addAbility(new SimpleStaticAbility( - Zone.BATTLEFIELD, - new AttacksIfAbleAllEffect( - StaticFilters.FILTER_PERMANENT_CREATURES, - Duration.WhileOnBattlefield, true - ).setText("All creatures attack each combat if able") - )); + this.addAbility(new SimpleStaticAbility(new AttacksIfAbleAllEffect(StaticFilters.FILTER_PERMANENT_ALL_CREATURES))); // Whenever a creature attacks you or a planeswalker you control, put a +1/+1 counter on Thantis the Warweaver. this.addAbility(new AttacksAllTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/t/ThassasIntervention.java b/Mage.Sets/src/mage/cards/t/ThassasIntervention.java index 1f9db130bc2..55a5ba1b9fe 100644 --- a/Mage.Sets/src/mage/cards/t/ThassasIntervention.java +++ b/Mage.Sets/src/mage/cards/t/ThassasIntervention.java @@ -4,14 +4,12 @@ import mage.abilities.Mode; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.MultipliedValue; import mage.abilities.dynamicvalue.common.ManacostVariableValue; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.CounterUnlessPaysEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import mage.target.TargetSpell; import java.util.UUID; @@ -29,14 +27,7 @@ public final class ThassasIntervention extends CardImpl { // Choose one- // • Look at the top X cards of your library. Put up to two of them into your hand and the rest on the bottom of your library in a random order. this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - ManacostVariableValue.REGULAR, false, StaticValue.get(2), - StaticFilters.FILTER_CARD, Zone.LIBRARY, false, false, - true, Zone.HAND, true, false, false - ).setBackInRandomOrder(true).setText( - "Look at the top X cards of your library. Put up to two of them into your hand " + - "and the rest on the bottom of your library in a random order." - ) - ); + ManacostVariableValue.REGULAR, 2, PutCards.HAND, PutCards.BOTTOM_RANDOM, true)); // • Counter target spell unless its controller pays twice {X}. Mode mode = new Mode(new CounterUnlessPaysEffect(xValue) diff --git a/Mage.Sets/src/mage/cards/t/TheAkroanWar.java b/Mage.Sets/src/mage/cards/t/TheAkroanWar.java index d96a3790842..64837eddb37 100644 --- a/Mage.Sets/src/mage/cards/t/TheAkroanWar.java +++ b/Mage.Sets/src/mage/cards/t/TheAkroanWar.java @@ -10,8 +10,8 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.common.FilterOpponentsCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; @@ -24,9 +24,6 @@ import mage.abilities.condition.common.SourceRemainsInZoneCondition; */ public final class TheAkroanWar extends CardImpl { - private static final FilterCreaturePermanent filter - = new FilterOpponentsCreaturePermanent("creatures your opponents control"); - public TheAkroanWar(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); @@ -51,9 +48,7 @@ public final class TheAkroanWar extends CardImpl { sagaAbility.addChapterEffect( this, SagaChapter.CHAPTER_II, - new AttacksIfAbleAllEffect( - filter, Duration.UntilYourNextTurn, true - ) + new AttacksIfAbleAllEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, Duration.UntilYourNextTurn) ); // III — Each tapped creature deals damage to itself equal to its power. @@ -101,4 +96,4 @@ class TheAkroanWarEffect extends OneShotEffect { .forEach(permanent -> permanent.damage(permanent.getPower().getValue(), permanent.getId(), source, game)); return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/t/TheAntiquitiesWar.java b/Mage.Sets/src/mage/cards/t/TheAntiquitiesWar.java index 77f6b4b972f..f5b79931e3c 100644 --- a/Mage.Sets/src/mage/cards/t/TheAntiquitiesWar.java +++ b/Mage.Sets/src/mage/cards/t/TheAntiquitiesWar.java @@ -1,13 +1,12 @@ - package mage.cards.t; import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SagaAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -17,7 +16,6 @@ import mage.constants.Outcome; import mage.constants.SagaChapter; import mage.constants.SubLayer; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; @@ -36,10 +34,10 @@ public final class TheAntiquitiesWar extends CardImpl { // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) SagaAbility sagaAbility = new SagaAbility(this); - // I, II — Look at the top five cards of your library. You may reveal an artifact card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. + // I, II — Look at the top five cards of your library. You may reveal an artifact card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, - new LookLibraryAndPickControllerEffect(StaticValue.get(5), false, StaticValue.get(1), - StaticFilters.FILTER_CARD_ARTIFACT_AN, Zone.LIBRARY, false, true, false, Zone.HAND, true, true, false).setBackInRandomOrder(true)); + new LookLibraryAndPickControllerEffect(5, 1, StaticFilters.FILTER_CARD_ARTIFACT_AN, PutCards.HAND, PutCards.BOTTOM_RANDOM)); // III — Artifacts you control become artifact creatures with base power and toughness 5/5 until end of turn. sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new TheAntiquitiesWarEffect()); @@ -77,7 +75,7 @@ class TheAntiquitiesWarEffect extends ContinuousEffectImpl { @Override public void init(Ability source, Game game) { super.init(source, game); - for (Permanent perm : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, source.getControllerId(), source, game)) { affectedObjectList.add(new MageObjectReference(perm, game)); } } diff --git a/Mage.Sets/src/mage/cards/t/TheBattleOfEndor.java b/Mage.Sets/src/mage/cards/t/TheBattleOfEndor.java index 672fb6e33c5..83da310e877 100644 --- a/Mage.Sets/src/mage/cards/t/TheBattleOfEndor.java +++ b/Mage.Sets/src/mage/cards/t/TheBattleOfEndor.java @@ -77,7 +77,7 @@ class TheBattleOfEndorEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), source.getControllerId(), source, game)) { permanent.addCounters(CounterType.P1P1.createInstance(source.getManaCostsToPay().getX()), source.getControllerId(), source, game); } return true; diff --git a/Mage.Sets/src/mage/cards/t/TheBearsOfLittjara.java b/Mage.Sets/src/mage/cards/t/TheBearsOfLittjara.java index 497dd590202..abe2a130862 100644 --- a/Mage.Sets/src/mage/cards/t/TheBearsOfLittjara.java +++ b/Mage.Sets/src/mage/cards/t/TheBearsOfLittjara.java @@ -93,7 +93,7 @@ class TheBearsOfLittjaraEffect extends OneShotEffect { } for (Permanent creature : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game )) { if (creature == null) { continue; diff --git a/Mage.Sets/src/mage/cards/t/TheBloodskyMassacre.java b/Mage.Sets/src/mage/cards/t/TheBloodskyMassacre.java index 78c4dc81945..0799e525516 100644 --- a/Mage.Sets/src/mage/cards/t/TheBloodskyMassacre.java +++ b/Mage.Sets/src/mage/cards/t/TheBloodskyMassacre.java @@ -115,7 +115,7 @@ class TheBloodskyMassacreEffect extends OneShotEffect { if (player == null) { return false; } - int berserkers = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int berserkers = game.getBattlefield().count(filter, source.getControllerId(), source, game); player.getManaPool().addMana(new Mana(ManaType.RED, berserkers), game, source, true); return true; } diff --git a/Mage.Sets/src/mage/cards/t/TheBookOfVileDarkness.java b/Mage.Sets/src/mage/cards/t/TheBookOfVileDarkness.java index dc39217f411..63d4c062d37 100644 --- a/Mage.Sets/src/mage/cards/t/TheBookOfVileDarkness.java +++ b/Mage.Sets/src/mage/cards/t/TheBookOfVileDarkness.java @@ -11,7 +11,6 @@ import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.CardsImpl; @@ -128,25 +127,25 @@ class TheBookOfVileDarknessCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { return source.getSourcePermanentIfItStillExists(game) != null - && game.getBattlefield().count(filter1, source.getSourceId(), source.getControllerId(), game) > 0 - && game.getBattlefield().count(filter2, source.getSourceId(), source.getControllerId(), game) > 0; + && game.getBattlefield().count(filter1, source.getControllerId(), source, game) > 0 + && game.getBattlefield().count(filter2, source.getControllerId(), source, game) > 0; } private static Permanent getPermanent(FilterPermanent filter, Player controller, Ability source, Game game) { - int count = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int count = game.getBattlefield().count(filter, source.getControllerId(), source, game); switch (count) { case 0: return null; case 1: return game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game ).stream().findFirst().orElse(null); default: break; } TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); - controller.choose(Outcome.Sacrifice, target, source.getControllerId(), game); + controller.choose(Outcome.Sacrifice, target, source, game); return game.getPermanent(target.getFirstTarget()); } diff --git a/Mage.Sets/src/mage/cards/t/TheDeckOfManyThings.java b/Mage.Sets/src/mage/cards/t/TheDeckOfManyThings.java index 9d65ea25439..016d2a4244b 100644 --- a/Mage.Sets/src/mage/cards/t/TheDeckOfManyThings.java +++ b/Mage.Sets/src/mage/cards/t/TheDeckOfManyThings.java @@ -146,10 +146,10 @@ class TheDeckOfManyThingsReturnEffect extends OneShotEffect { } TargetCardInGraveyard target = new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (!target.canChoose(source.getControllerId(), source, game)) { return false; } - player.choose(outcome, target, source.getControllerId(), game); + player.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card == null) { return false; diff --git a/Mage.Sets/src/mage/cards/t/TheDragonKamiReborn.java b/Mage.Sets/src/mage/cards/t/TheDragonKamiReborn.java new file mode 100644 index 00000000000..8dc210d3c6c --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheDragonKamiReborn.java @@ -0,0 +1,96 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.Effects; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.*; +import mage.constants.*; +import mage.counters.CounterType; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheDragonKamiReborn extends CardImpl { + + public TheDragonKamiReborn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); + + this.subtype.add(SubType.SAGA); + this.secondSideCardClazz = mage.cards.d.DragonKamisEgg.class; + + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I, II — You gain 2 life. Look at the top three cards of your library. Exile one of them face down with a hatching counter on it, then put the rest on the bottom of your library in any order. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, + new Effects(new GainLifeEffect(2), new TheDragonKamiRebornEffect()) + ); + + // III — Exile this Saga, then return it to the battlefield transformed under your control. + this.addAbility(new TransformAbility()); + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + + this.addAbility(sagaAbility); + } + + private TheDragonKamiReborn(final TheDragonKamiReborn card) { + super(card); + } + + @Override + public TheDragonKamiReborn copy() { + return new TheDragonKamiReborn(this); + } +} + +class TheDragonKamiRebornEffect extends OneShotEffect { + + TheDragonKamiRebornEffect() { + super(Outcome.Benefit); + staticText = "Look at the top three cards of your library. Exile one of them face down " + + "with a hatching counter on it, then put the rest on the bottom of your library in any order"; + } + + private TheDragonKamiRebornEffect(final TheDragonKamiRebornEffect effect) { + super(effect); + } + + @Override + public TheDragonKamiRebornEffect copy() { + return new TheDragonKamiRebornEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 3)); + if (cards.isEmpty()) { + return false; + } + TargetCard target = new TargetCardInLibrary(); + player.choose(outcome, cards, target, game); + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + player.moveCards(card, Zone.EXILED, source, game); + card.setFaceDown(true, game); + card.addCounters(CounterType.HATCHLING.createInstance(), source, game); + } + cards.retainZone(Zone.LIBRARY, game); + player.putCardsOnBottomOfLibrary(cards, game, source, true); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheElderspell.java b/Mage.Sets/src/mage/cards/t/TheElderspell.java index 8ea348358ca..0c3b4ebd570 100644 --- a/Mage.Sets/src/mage/cards/t/TheElderspell.java +++ b/Mage.Sets/src/mage/cards/t/TheElderspell.java @@ -75,7 +75,7 @@ class TheElderspellEffect extends OneShotEffect { } } TargetPermanent targetPermanent = new TargetPermanent(filter); - if (!player.choose(outcome, targetPermanent, source.getSourceId(), game)) { + if (!player.choose(outcome, targetPermanent, source, game)) { return false; } Permanent permanent = game.getPermanent(targetPermanent.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/t/TheFallenApart.java b/Mage.Sets/src/mage/cards/t/TheFallenApart.java index 3b311ead15f..b92acb08f8d 100644 --- a/Mage.Sets/src/mage/cards/t/TheFallenApart.java +++ b/Mage.Sets/src/mage/cards/t/TheFallenApart.java @@ -65,7 +65,7 @@ class TheFallenApartEntersEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } if (mageObject != null) { game.getState().setValue(mageObject.getId() + "_arms", 2); @@ -98,7 +98,7 @@ class TheFallenApartToggleEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (controller != null && mageObject != null) { if (game.getState().getValue(mageObject.getId() + "_arms") == null || game.getState().getValue(mageObject.getId() + "_legs") == null) { @@ -158,7 +158,7 @@ class TheFallenApartRestrictionEffect extends RestrictionEffect { @Override public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return (Integer) game.getState().getValue(mageObject.getId() + "_arms") > 0; } @@ -167,7 +167,7 @@ class TheFallenApartRestrictionEffect extends RestrictionEffect { @Override public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return (Integer) game.getState().getValue(mageObject.getId() + "_legs") > 0; } diff --git a/Mage.Sets/src/mage/cards/t/TheFirstEruption.java b/Mage.Sets/src/mage/cards/t/TheFirstEruption.java index 2af887c778a..c953045ccc1 100644 --- a/Mage.Sets/src/mage/cards/t/TheFirstEruption.java +++ b/Mage.Sets/src/mage/cards/t/TheFirstEruption.java @@ -99,8 +99,8 @@ class TheFirstEruptionEffect extends OneShotEffect { Target target = new TargetControlledPermanent(1, 1, filter, false); boolean sacrificed = false; - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - while (controller.canRespond() && !target.isChosen() && target.canChoose(source.getSourceId(), controller.getId(), game)) { + if (target.canChoose(controller.getId(), source, game)) { + while (controller.canRespond() && !target.isChosen() && target.canChoose(controller.getId(), source, game)) { controller.chooseTarget(Outcome.Sacrifice, target, source, game); } diff --git a/Mage.Sets/src/mage/cards/t/TheImmortalSun.java b/Mage.Sets/src/mage/cards/t/TheImmortalSun.java index cae359e0274..94efb82e2d8 100644 --- a/Mage.Sets/src/mage/cards/t/TheImmortalSun.java +++ b/Mage.Sets/src/mage/cards/t/TheImmortalSun.java @@ -77,7 +77,7 @@ class TheImmortalSunCantActivateEffect extends ContinuousRuleModifyingEffectImpl @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't activate loyalty abilities of planeswalkers (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/t/TheKamiWar.java b/Mage.Sets/src/mage/cards/t/TheKamiWar.java new file mode 100644 index 00000000000..62364fcf76d --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheKamiWar.java @@ -0,0 +1,78 @@ +package mage.cards.t; + +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.Effects; +import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; +import mage.abilities.keyword.TransformAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SagaChapter; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheKamiWar extends CardImpl { + + private static final FilterPermanent filter + = new FilterNonlandPermanent("nonland permanent an opponent controls"); + private static final FilterPermanent filter2 + = new FilterNonlandPermanent("other target nonland permanent"); + + static { + filter.add(TargetController.OPPONENT.getControllerPredicate()); + filter2.add(AnotherPredicate.instance); + } + + public TheKamiWar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{U}{B}{R}{G}"); + + this.subtype.add(SubType.SAGA); + this.secondSideCardClazz = mage.cards.o.OKagachiMadeManifest.class; + + // (As this Saga enters and after your draw step, add a lore counter.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I — Exile target nonland permanent an opponent controls. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I, + new ExileTargetEffect(), new TargetPermanent(filter) + ); + + // II — Return up to one other target nonland permanent to its owner's hand. Then each opponent discards a card. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, + new Effects( + new ReturnToHandTargetEffect(), + new DiscardEachPlayerEffect(TargetController.OPPONENT) + .concatBy("Then") + ), new TargetPermanent(0, 1, filter2) + ); + + // III — Exile this Saga, then return it to the battlefield transformed under your control. + this.addAbility(new TransformAbility()); + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect()); + + this.addAbility(sagaAbility); + } + + private TheKamiWar(final TheKamiWar card) { + super(card); + } + + @Override + public TheKamiWar copy() { + return new TheKamiWar(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheMendingOfDominaria.java b/Mage.Sets/src/mage/cards/t/TheMendingOfDominaria.java index 549b19c38d2..b6f1ae85b93 100644 --- a/Mage.Sets/src/mage/cards/t/TheMendingOfDominaria.java +++ b/Mage.Sets/src/mage/cards/t/TheMendingOfDominaria.java @@ -77,9 +77,9 @@ class TheMendingOfDominariaFirstEffect extends OneShotEffect { new MillCardsControllerEffect(2).apply(game, source); TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + if (target.canChoose(source.getControllerId(), source, game) && controller.chooseUse(outcome, "Return a creature card from your graveyard to hand?", source, game) - && controller.choose(Outcome.ReturnToHand, target, source.getSourceId(), game)) { + && controller.choose(Outcome.ReturnToHand, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { controller.moveCards(card, Zone.HAND, source, game); @@ -110,7 +110,7 @@ class TheMendingOfDominariaSecondEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { controller.moveCards( - controller.getGraveyard().getCards(new FilterLandCard(), source.getSourceId(), source.getControllerId(), game), + controller.getGraveyard().getCards(new FilterLandCard(), source.getControllerId(), source, game), Zone.BATTLEFIELD, source, game, false, false, false, null ); for (Card card : controller.getGraveyard().getCards(game)) { diff --git a/Mage.Sets/src/mage/cards/t/TheMimeoplasm.java b/Mage.Sets/src/mage/cards/t/TheMimeoplasm.java index ee3aa612e4e..9a296ee7bc2 100644 --- a/Mage.Sets/src/mage/cards/t/TheMimeoplasm.java +++ b/Mage.Sets/src/mage/cards/t/TheMimeoplasm.java @@ -71,14 +71,14 @@ class TheMimeoplasmEffect extends OneShotEffect { if (controller.chooseUse(Outcome.Benefit, "Do you want to exile two creature cards from graveyards?", source, game)) { TargetCardInGraveyard targetCopy = new TargetCardInGraveyard(new FilterCreatureCard("creature card to become a copy of")); targetCopy.setNotTarget(true); - if (controller.choose(Outcome.Copy, targetCopy, source.getSourceId(), game)) { + if (controller.choose(Outcome.Copy, targetCopy, source, game)) { Card cardToCopy = game.getCard(targetCopy.getFirstTarget()); if (cardToCopy != null) { FilterCreatureCard filter = new FilterCreatureCard("creature card to determine amount of additional +1/+1 counters"); filter.add(Predicates.not(new CardIdPredicate(cardToCopy.getId()))); TargetCardInGraveyard targetCounters = new TargetCardInGraveyard(filter); targetCounters.setNotTarget(true); - if (controller.choose(Outcome.Copy, targetCounters, source.getSourceId(), game)) { + if (controller.choose(Outcome.Copy, targetCounters, source, game)) { Card cardForCounters = game.getCard(targetCounters.getFirstTarget()); if (cardForCounters != null) { Cards cardsToExile = new CardsImpl(); diff --git a/Mage.Sets/src/mage/cards/t/ThePrismaticPiper.java b/Mage.Sets/src/mage/cards/t/ThePrismaticPiper.java new file mode 100644 index 00000000000..6401a2bb246 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThePrismaticPiper.java @@ -0,0 +1,42 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.CommanderChooseColorAbility; +import mage.abilities.keyword.PartnerAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ThePrismaticPiper extends CardImpl { + + public ThePrismaticPiper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SHAPESHIFTER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // If The Prismatic Piper is your commander, choose a color before the game begins. The Prismatic Piper is the chosen color. + this.addAbility(new CommanderChooseColorAbility()); + + // Partner + this.addAbility(PartnerAbility.getInstance()); + } + + private ThePrismaticPiper(final ThePrismaticPiper card) { + super(card); + } + + @Override + public ThePrismaticPiper copy() { + return new ThePrismaticPiper(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheRavensWarning.java b/Mage.Sets/src/mage/cards/t/TheRavensWarning.java index e977abfd22f..530ff7174a1 100644 --- a/Mage.Sets/src/mage/cards/t/TheRavensWarning.java +++ b/Mage.Sets/src/mage/cards/t/TheRavensWarning.java @@ -19,7 +19,7 @@ import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.game.permanent.token.OwlToken; +import mage.game.permanent.token.BlueBirdToken; import mage.target.targetpointer.FixedTarget; /** @@ -38,7 +38,7 @@ public final class TheRavensWarning extends CardImpl { // I — Create a 1/1 blue Bird creature token with flying. You gain 2 life. sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, - new CreateTokenEffect(new OwlToken()), new GainLifeEffect(2) + new CreateTokenEffect(new BlueBirdToken()), new GainLifeEffect(2) ); // II — Whenever one or more creatures you control with flying deal combat damage to a player this turn, diff --git a/Mage.Sets/src/mage/cards/t/TheRealityChip.java b/Mage.Sets/src/mage/cards/t/TheRealityChip.java new file mode 100644 index 00000000000..f84d9d13b69 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheRealityChip.java @@ -0,0 +1,55 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.AttachedToMatchesFilterCondition; +import mage.abilities.decorator.ConditionalAsThoughEffect; +import mage.abilities.effects.common.continuous.LookAtTopCardOfLibraryAnyTimeEffect; +import mage.abilities.effects.common.continuous.PlayTheTopCardEffect; +import mage.abilities.keyword.ReconfigureAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheRealityChip extends CardImpl { + + private static final Condition condition = new AttachedToMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_CREATURE); + + public TheRealityChip(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.EQUIPMENT); + this.subtype.add(SubType.JELLYFISH); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // You may look at the top card of your library any time. + this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect())); + + // As long as The Reality Chip is attached to a creature, you may play lands and cast spells from the top of your library. + this.addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect(new PlayTheTopCardEffect(), condition) + .setText("as long as {this} is attached to a creature, you may play lands and cast spells from the top of your library"))); + + // Reconfigure {2}{U} + this.addAbility(new ReconfigureAbility("{2}{U}")); + } + + private TheRealityChip(final TheRealityChip card) { + super(card); + } + + @Override + public TheRealityChip copy() { + return new TheRealityChip(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheRoyalScions.java b/Mage.Sets/src/mage/cards/t/TheRoyalScions.java index 291bbe9b25f..e5c59b1db9a 100644 --- a/Mage.Sets/src/mage/cards/t/TheRoyalScions.java +++ b/Mage.Sets/src/mage/cards/t/TheRoyalScions.java @@ -2,7 +2,6 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; import mage.abilities.effects.Effect; @@ -34,7 +33,7 @@ public final class TheRoyalScions extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.WILL); this.subtype.add(SubType.ROWAN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Draw a card, then discard a card. this.addAbility(new LoyaltyAbility(new DrawDiscardControllerEffect(1, 1), 1)); diff --git a/Mage.Sets/src/mage/cards/t/TheTricksterGodsHeist.java b/Mage.Sets/src/mage/cards/t/TheTricksterGodsHeist.java index 39a247322de..42f97c66e4a 100644 --- a/Mage.Sets/src/mage/cards/t/TheTricksterGodsHeist.java +++ b/Mage.Sets/src/mage/cards/t/TheTricksterGodsHeist.java @@ -108,13 +108,13 @@ class TheTricksterGodsHeistTarget extends TargetPermanent { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { Set cardTypes = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); if (targetSource == null) { return false; } - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (!permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { continue; } diff --git a/Mage.Sets/src/mage/cards/t/TheUnspeakable.java b/Mage.Sets/src/mage/cards/t/TheUnspeakable.java index 9eb45c2c5bb..c4640bc86f3 100644 --- a/Mage.Sets/src/mage/cards/t/TheUnspeakable.java +++ b/Mage.Sets/src/mage/cards/t/TheUnspeakable.java @@ -1,11 +1,10 @@ package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; @@ -16,8 +15,9 @@ import mage.constants.SuperType; import mage.filter.FilterCard; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Loki */ public final class TheUnspeakable extends CardImpl { @@ -29,7 +29,7 @@ public final class TheUnspeakable extends CardImpl { } public TheUnspeakable(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{6}{U}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{U}{U}{U}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SPIRIT); @@ -37,7 +37,7 @@ public final class TheUnspeakable extends CardImpl { this.toughness = new MageInt(7); this.addAbility(FlyingAbility.getInstance()); this.addAbility(TrampleAbility.getInstance()); - Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ReturnToHandTargetEffect(), true); + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), true); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TheWanderer.java b/Mage.Sets/src/mage/cards/t/TheWanderer.java index 1b4a1bc002a..7191a319d54 100644 --- a/Mage.Sets/src/mage/cards/t/TheWanderer.java +++ b/Mage.Sets/src/mage/cards/t/TheWanderer.java @@ -2,7 +2,6 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.PreventAllNonCombatDamageToAllEffect; @@ -40,7 +39,7 @@ public final class TheWanderer extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{W}"); this.addSuperType(SuperType.LEGENDARY); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Prevent all noncombat damage that would be dealt to you and other permanents you control. this.addAbility(new SimpleStaticAbility(new PreventAllNonCombatDamageToAllEffect( diff --git a/Mage.Sets/src/mage/cards/t/TheWanderingEmperor.java b/Mage.Sets/src/mage/cards/t/TheWanderingEmperor.java index 2d17a5bbd4c..5b8bfa900a3 100644 --- a/Mage.Sets/src/mage/cards/t/TheWanderingEmperor.java +++ b/Mage.Sets/src/mage/cards/t/TheWanderingEmperor.java @@ -2,11 +2,10 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; @@ -42,7 +41,7 @@ public final class TheWanderingEmperor extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{W}{W}"); this.addSuperType(SuperType.LEGENDARY); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // Flash this.addAbility(FlashAbility.getInstance()); @@ -64,7 +63,7 @@ public final class TheWanderingEmperor extends CardImpl { this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new SamuraiToken()), -1)); // −2: Exile target tapped creature. You gain 2 life. - ability = new LoyaltyAbility(new DestroyTargetEffect(), -2); + ability = new LoyaltyAbility(new ExileTargetEffect(), -2); ability.addEffect(new GainLifeEffect(2)); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/t/TheftOfDreams.java b/Mage.Sets/src/mage/cards/t/TheftOfDreams.java index 144436f83f7..b468d54acaa 100644 --- a/Mage.Sets/src/mage/cards/t/TheftOfDreams.java +++ b/Mage.Sets/src/mage/cards/t/TheftOfDreams.java @@ -63,7 +63,7 @@ class TheftOfDreamsEffect extends OneShotEffect { FilterCreaturePermanent filter = new FilterCreaturePermanent(); filter.add(TappedPredicate.TAPPED); filter.add(new ControllerIdPredicate(opponent.getId())); - return new DrawCardSourceControllerEffect(game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game)).apply(game, source); + return new DrawCardSourceControllerEffect(game.getBattlefield().count(filter, source.getControllerId(), source, game)).apply(game, source); } return false; } diff --git a/Mage.Sets/src/mage/cards/t/ThelonOfHavenwood.java b/Mage.Sets/src/mage/cards/t/ThelonOfHavenwood.java index b87598f205f..90d91fd7dd2 100644 --- a/Mage.Sets/src/mage/cards/t/ThelonOfHavenwood.java +++ b/Mage.Sets/src/mage/cards/t/ThelonOfHavenwood.java @@ -84,7 +84,7 @@ class ThelonOfHavenwoodBoostEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { int numCounters = creature.getCounters(game).getCount(CounterType.SPORE); if (numCounters > 0) { creature.addPower(numCounters); diff --git a/Mage.Sets/src/mage/cards/t/TheloniteHermit.java b/Mage.Sets/src/mage/cards/t/TheloniteHermit.java index 7f78ecf9f1b..1460dbc320e 100644 --- a/Mage.Sets/src/mage/cards/t/TheloniteHermit.java +++ b/Mage.Sets/src/mage/cards/t/TheloniteHermit.java @@ -42,7 +42,7 @@ public final class TheloniteHermit extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, false))); // Morph {3}{G}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{G}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{G}{G}"))); // When Thelonite Hermit is turned face up, create four 1/1 green Saproling creature tokens. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new CreateTokenEffect(new SaprolingToken(), 4))); diff --git a/Mage.Sets/src/mage/cards/t/ThelonsChant.java b/Mage.Sets/src/mage/cards/t/ThelonsChant.java index 06f25e38872..ea959e18381 100644 --- a/Mage.Sets/src/mage/cards/t/ThelonsChant.java +++ b/Mage.Sets/src/mage/cards/t/ThelonsChant.java @@ -75,7 +75,7 @@ class ThelonsChantEffect extends OneShotEffect { 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)) { + && player.choose(Outcome.UnboostCreature, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.addCounters(CounterType.M1M1.createInstance(), player.getId(), source, game); diff --git a/Mage.Sets/src/mage/cards/t/ThelonsCurse.java b/Mage.Sets/src/mage/cards/t/ThelonsCurse.java index efc5fcb36cc..a364d640928 100644 --- a/Mage.Sets/src/mage/cards/t/ThelonsCurse.java +++ b/Mage.Sets/src/mage/cards/t/ThelonsCurse.java @@ -91,8 +91,8 @@ class ThelonsCurseEffect extends OneShotEffect { int countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game).size(); while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.AIDontUseIt, "Pay {U} and untap a tapped blue creature under your control?", source, game)) { Target tappedCreatureTarget = new TargetControlledCreaturePermanent(1, 1, filter, true); - if (player.choose(Outcome.Detriment, tappedCreatureTarget, source.getSourceId(), game)) { - Cost cost = new ManaCostsImpl("U"); + if (player.choose(Outcome.Detriment, tappedCreatureTarget, source, game)) { + Cost cost = new ManaCostsImpl<>("{U}"); Permanent tappedCreature = game.getPermanent(tappedCreatureTarget.getFirstTarget()); if (cost.pay(source, game, source, player.getId(), false)) { diff --git a/Mage.Sets/src/mage/cards/t/ThermalFlux.java b/Mage.Sets/src/mage/cards/t/ThermalFlux.java index 2ca94f6bf8f..7dddc6a0fe2 100644 --- a/Mage.Sets/src/mage/cards/t/ThermalFlux.java +++ b/Mage.Sets/src/mage/cards/t/ThermalFlux.java @@ -48,11 +48,10 @@ public final class ThermalFlux extends CardImpl { new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false)); // Target snow permanent isn't snow until end of turn. // Draw a card at the beginning of the next turn's upkeep. - Mode mode = new Mode(); - mode.addTarget(new TargetPermanent(filterSnow)); - mode.addEffect(new ThermalFluxEffect(false)); + Mode mode = new Mode(new ThermalFluxEffect(false)); mode.addEffect(new CreateDelayedTriggeredAbilityEffect( new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false)); + mode.addTarget(new TargetPermanent(filterSnow)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/t/ThievesAuction.java b/Mage.Sets/src/mage/cards/t/ThievesAuction.java index 8d19d0f9689..32ef5468468 100644 --- a/Mage.Sets/src/mage/cards/t/ThievesAuction.java +++ b/Mage.Sets/src/mage/cards/t/ThievesAuction.java @@ -27,7 +27,9 @@ public final class ThievesAuction extends CardImpl { public ThievesAuction(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}{R}{R}"); - // Exile all nontoken permanents. Starting with you, each player chooses one of the exiled cards and puts it onto the battlefield tapped under their control. Repeat this process until all cards exiled this way have been chosen. + // Exile all nontoken permanents. + // Starting with you, each player chooses one of the exiled cards and puts it onto the battlefield tapped under their control. + // Repeat this process until all cards exiled this way have been chosen. this.getSpellAbility().addEffect(new ThievesAuctionEffect()); } @@ -54,7 +56,7 @@ class ThievesAuctionEffect extends OneShotEffect { this.staticText = "Exile all nontoken permanents. Starting with you, each player chooses one of the exiled cards and puts it onto the battlefield tapped under their control. Repeat this process until all cards exiled this way have been chosen"; } - ThievesAuctionEffect(final ThievesAuctionEffect effect) { + private ThievesAuctionEffect(final ThievesAuctionEffect effect) { super(effect); } @@ -66,36 +68,39 @@ class ThievesAuctionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - // Exile all nontoken permanents. - Cards exiledCards = new CardsImpl(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { - exiledCards.add(permanent); - controller.moveCardsToExile(permanent, source, game, true, CardUtil.getCardExileZoneId(game, source.getSourceId()), "Thieves' Auction"); - } - // Starting with you, each player - PlayerList playerList = game.getState().getPlayersInRange(controller.getId(), game); - Player player = playerList.getCurrent(game); - while (player != null && !exiledCards.isEmpty() && !game.hasEnded()) { - if (player.canRespond()) { - // chooses one of the exiled cards - TargetCard target = new TargetCardInExile(new FilterCard()); - if (player.choose(Outcome.PutCardInPlay, exiledCards, target, game)) { - // and puts it onto the battlefield tapped under their control. - Card chosenCard = exiledCards.get(target.getFirstTarget(), game); - if (chosenCard != null) { - player.moveCards(chosenCard, Zone.BATTLEFIELD, source, game, true, false, false, null); - } - exiledCards.remove(chosenCard); - } else { - break; - } - } - // Repeat this process until all cards exiled this way have been chosen. - player = playerList.getNext(game, false); - } - return true; + if (controller == null) { return false; } + + // Exile all nontoken permanents. + Cards exiledCards = new CardsImpl(); + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { + exiledCards.add(permanent); + controller.moveCardsToExile(permanent, source, game, true, CardUtil.getCardExileZoneId(game, source.getSourceId()), "Thieves' Auction"); } - return false; + + // Starting with you, each player + PlayerList playerList = game.getState().getPlayersInRange(controller.getId(), game); + Player player = playerList.getCurrent(game); + while (player != null && !exiledCards.isEmpty() && !game.hasEnded()) { + if (!player.canRespond()) { continue; } + + // chooses one of the exiled cards + TargetCard target = new TargetCardInExile(new FilterCard()); + if (player.choose(Outcome.PutCardInPlay, exiledCards, target, game)) { + // and puts it onto the battlefield tapped under their control. + Card chosenCard = exiledCards.get(target.getFirstTarget(), game); + if (chosenCard != null) { + player.moveCards(chosenCard, Zone.BATTLEFIELD, source, game, true, false, false, null); + } + exiledCards.remove(chosenCard); + } else { + // TODO Why does this break? + break; + } + + // Repeat this process until all cards exiled this way have been chosen. + player = playerList.getNext(game, false); + } + + return true; } } diff --git a/Mage.Sets/src/mage/cards/t/ThievesFortune.java b/Mage.Sets/src/mage/cards/t/ThievesFortune.java index 4730b51465c..27e9fdf5779 100644 --- a/Mage.Sets/src/mage/cards/t/ThievesFortune.java +++ b/Mage.Sets/src/mage/cards/t/ThievesFortune.java @@ -1,16 +1,13 @@ - package mage.cards.t; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.ProwlAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.StaticFilters; /** * @@ -26,7 +23,7 @@ public final class ThievesFortune extends CardImpl { this.addAbility(new ProwlAbility(this, "{U}")); // Look at the top four cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(4), false, StaticValue.get(1), StaticFilters.FILTER_CARD, Zone.LIBRARY, false, false)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(4, 1, PutCards.HAND, PutCards.BOTTOM_ANY)); } private ThievesFortune(final ThievesFortune card) { diff --git a/Mage.Sets/src/mage/cards/t/ThopterSpyNetwork.java b/Mage.Sets/src/mage/cards/t/ThopterSpyNetwork.java index 7f3f104d419..feb59d0f8e1 100644 --- a/Mage.Sets/src/mage/cards/t/ThopterSpyNetwork.java +++ b/Mage.Sets/src/mage/cards/t/ThopterSpyNetwork.java @@ -76,7 +76,7 @@ class ThopterSpyNetworkUpkeepTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "At the beginning of your upkeep, if you control an artifact, create a 1/1 colorless Thopter artifact creature token with flying"; + return "At the beginning of your upkeep, if you control an artifact, create a 1/1 colorless Thopter artifact creature token with flying."; } } @@ -123,6 +123,6 @@ class ThopterSpyNetworkDamageTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever one or more artifact creatures you control deal combat damage to a player, draw a card"; + return "Whenever one or more artifact creatures you control deal combat damage to a player, draw a card."; } } diff --git a/Mage.Sets/src/mage/cards/t/ThornbiteStaff.java b/Mage.Sets/src/mage/cards/t/ThornbiteStaff.java index 7a4fafb2d08..05b1d240ec6 100644 --- a/Mage.Sets/src/mage/cards/t/ThornbiteStaff.java +++ b/Mage.Sets/src/mage/cards/t/ThornbiteStaff.java @@ -1,4 +1,3 @@ - package mage.cards.t; import java.util.UUID; @@ -28,10 +27,7 @@ import mage.target.common.TargetAnyTarget; */ public final class ThornbiteStaff extends CardImpl { - private static final FilterPermanent filter = new FilterCreaturePermanent("a Shaman creature"); - static { - filter.add(SubType.SHAMAN.getPredicate()); - } + private static final FilterPermanent filter = new FilterCreaturePermanent(SubType.SHAMAN, "a Shaman creature"); public ThornbiteStaff(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.TRIBAL,CardType.ARTIFACT},"{2}"); diff --git a/Mage.Sets/src/mage/cards/t/ThorncasterSliver.java b/Mage.Sets/src/mage/cards/t/ThorncasterSliver.java index e3c75dd4a0e..569908848be 100644 --- a/Mage.Sets/src/mage/cards/t/ThorncasterSliver.java +++ b/Mage.Sets/src/mage/cards/t/ThorncasterSliver.java @@ -35,7 +35,7 @@ public final class ThorncasterSliver extends CardImpl { ability.addTarget(new TargetAnyTarget()); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(ability, - Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS) + Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS) .setText("Sliver creatures you control have \"Whenever this creature attacks, it deals 1 damage to any target.\""))); } diff --git a/Mage.Sets/src/mage/cards/t/ThorntoothWitch.java b/Mage.Sets/src/mage/cards/t/ThorntoothWitch.java index 4cb0681eb9b..33cd5cf5f11 100644 --- a/Mage.Sets/src/mage/cards/t/ThorntoothWitch.java +++ b/Mage.Sets/src/mage/cards/t/ThorntoothWitch.java @@ -20,7 +20,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class ThorntoothWitch extends CardImpl { - private static final FilterSpell filter = new FilterSpell("Treefolk"); + private static final FilterSpell filter = new FilterSpell("a Treefolk spell"); static { filter.add(SubType.TREEFOLK.getPredicate()); diff --git a/Mage.Sets/src/mage/cards/t/ThoughtHemorrhage.java b/Mage.Sets/src/mage/cards/t/ThoughtHemorrhage.java index 521204f7f73..607869c008f 100644 --- a/Mage.Sets/src/mage/cards/t/ThoughtHemorrhage.java +++ b/Mage.Sets/src/mage/cards/t/ThoughtHemorrhage.java @@ -73,7 +73,7 @@ class ThoughtHemorrhageEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); String cardName = (String) game.getState().getValue( source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); if (sourceObject != null diff --git a/Mage.Sets/src/mage/cards/t/ThoughtPrison.java b/Mage.Sets/src/mage/cards/t/ThoughtPrison.java index e626ad3396f..f5eec32e33b 100644 --- a/Mage.Sets/src/mage/cards/t/ThoughtPrison.java +++ b/Mage.Sets/src/mage/cards/t/ThoughtPrison.java @@ -9,6 +9,7 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -40,7 +41,7 @@ public final class ThoughtPrison extends CardImpl { // Imprint - When Thought Prison enters the battlefield, you may have target player reveal their hand. If you do, choose a nonland card from it and exile that card. EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new ThoughtPrisonImprintEffect(), true); ability.addTarget(new TargetPlayer()); - ability.withFlavorWord("Imprint"); + ability.setAbilityWord(AbilityWord.IMPRINT); this.addAbility(ability); // Whenever a player casts a spell that shares a color or converted mana cost with the exiled card, Thought Prison deals 2 damage to that player. diff --git a/Mage.Sets/src/mage/cards/t/ThoughtsOfRuin.java b/Mage.Sets/src/mage/cards/t/ThoughtsOfRuin.java index c4ca1b7a9c0..700fda38510 100644 --- a/Mage.Sets/src/mage/cards/t/ThoughtsOfRuin.java +++ b/Mage.Sets/src/mage/cards/t/ThoughtsOfRuin.java @@ -79,7 +79,7 @@ class ThoughtsOfRuinEffect extends OneShotEffect { FilterLandPermanent playerFilter = filter.copy(); playerFilter.add(new ControllerIdPredicate(playerId)); Target target = new TargetLandPermanent(amount, amount, playerFilter, true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); for (UUID landId : target.getTargets()) { Permanent permanent = game.getPermanent(landId); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/t/ThoughtweftTrio.java b/Mage.Sets/src/mage/cards/t/ThoughtweftTrio.java index 610a79d651c..4ba212246e3 100644 --- a/Mage.Sets/src/mage/cards/t/ThoughtweftTrio.java +++ b/Mage.Sets/src/mage/cards/t/ThoughtweftTrio.java @@ -34,7 +34,7 @@ public final class ThoughtweftTrio extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // Champion a Kithkin - this.addAbility(new ChampionAbility(this, SubType.KITHKIN, false)); + this.addAbility(new ChampionAbility(this, SubType.KITHKIN)); // Thoughtweft Trio can block any number of creatures. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CanBlockAdditionalCreatureEffect(0))); diff --git a/Mage.Sets/src/mage/cards/t/ThousandFacedShadow.java b/Mage.Sets/src/mage/cards/t/ThousandFacedShadow.java index 9187d0844db..0a1d59b6f67 100644 --- a/Mage.Sets/src/mage/cards/t/ThousandFacedShadow.java +++ b/Mage.Sets/src/mage/cards/t/ThousandFacedShadow.java @@ -87,10 +87,16 @@ class ThousandFacedShadowTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanent(event.getTargetId()); return permanent != null - && ((EntersTheBattlefieldEvent) event).getFromZone() == Zone.GRAVEYARD + && ((EntersTheBattlefieldEvent) event).getFromZone() == Zone.HAND && permanent.getId().equals(getSourceId()); } + @Override + public boolean checkInterveningIfClause(Game game) { + Permanent permanent = getSourcePermanentIfItStillExists(game); + return permanent != null && permanent.isAttacking(); + } + @Override public String getRule() { return "When {this} enters the battlefield from your hand, if it's attacking, " + diff --git a/Mage.Sets/src/mage/cards/t/ThousandWinds.java b/Mage.Sets/src/mage/cards/t/ThousandWinds.java index 38ec8ab347c..d47f6976619 100644 --- a/Mage.Sets/src/mage/cards/t/ThousandWinds.java +++ b/Mage.Sets/src/mage/cards/t/ThousandWinds.java @@ -39,7 +39,7 @@ public final class ThousandWinds extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Morph {5}{U}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{5}{U}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{5}{U}{U}"))); // When Thousand Winds is turned face up, return all other tapped creatures to their owners' hands. this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new ReturnToHandFromBattlefieldAllEffect(filter))); } diff --git a/Mage.Sets/src/mage/cards/t/ThranTome.java b/Mage.Sets/src/mage/cards/t/ThranTome.java index 43304db5bed..14525488549 100644 --- a/Mage.Sets/src/mage/cards/t/ThranTome.java +++ b/Mage.Sets/src/mage/cards/t/ThranTome.java @@ -64,7 +64,7 @@ class ThranTomeEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { // validate source and controller exist Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject == null || controller == null) { return false; diff --git a/Mage.Sets/src/mage/cards/t/ThrasherBrute.java b/Mage.Sets/src/mage/cards/t/ThrasherBrute.java index c047b79a1fb..d2b04012262 100644 --- a/Mage.Sets/src/mage/cards/t/ThrasherBrute.java +++ b/Mage.Sets/src/mage/cards/t/ThrasherBrute.java @@ -70,9 +70,9 @@ class ThrasherBruteFilter extends FilterTeamPermanent { } @Override - public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { - return super.match(permanent, sourceId, playerId, game) - && (sourceId.equals(permanent.getId()) + public boolean match(Permanent permanent, UUID playerId, Ability source, Game game) { + return super.match(permanent, playerId, source, game) + && (source.getSourceId().equals(permanent.getId()) || permanent.hasSubtype(SubType.WARRIOR, game)); } } diff --git a/Mage.Sets/src/mage/cards/t/ThrashingMudspawn.java b/Mage.Sets/src/mage/cards/t/ThrashingMudspawn.java index 3f614b1a97e..2eef3920f0c 100644 --- a/Mage.Sets/src/mage/cards/t/ThrashingMudspawn.java +++ b/Mage.Sets/src/mage/cards/t/ThrashingMudspawn.java @@ -35,7 +35,7 @@ public final class ThrashingMudspawn extends CardImpl { this.addAbility(ability); // Morph {1}{B}{B} - this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{1}{B}{B}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl<>("{1}{B}{B}"))); } diff --git a/Mage.Sets/src/mage/cards/t/ThreeDreams.java b/Mage.Sets/src/mage/cards/t/ThreeDreams.java index d9ff246f885..164f99cb7f4 100644 --- a/Mage.Sets/src/mage/cards/t/ThreeDreams.java +++ b/Mage.Sets/src/mage/cards/t/ThreeDreams.java @@ -1,16 +1,12 @@ package mage.cards.t; -import mage.abilities.Ability; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.FilterCard; -import mage.game.Game; -import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCardWithDifferentNameInLibrary; import java.util.UUID; @@ -19,12 +15,20 @@ import java.util.UUID; */ public final class ThreeDreams extends CardImpl { + private static final FilterCard aurafilter = new FilterCard("Aura cards with different names"); + + static { + aurafilter.add(SubType.AURA.getPredicate()); + } + public ThreeDreams(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}"); - // Search your library for up to three Aura cards with different names, reveal them, and put them into your hand. Then shuffle your library. - this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new ThreeDreamsTarget(), true, true)); + this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect( + new TargetCardWithDifferentNameInLibrary(0, 3, aurafilter), + true, true + )); } private ThreeDreams(final ThreeDreams card) { @@ -36,41 +40,3 @@ public final class ThreeDreams extends CardImpl { return new ThreeDreams(this); } } - -class ThreeDreamsTarget extends TargetCardInLibrary { - - private static final FilterCard aurafilter = new FilterCard("Aura cards with different names"); - - static { - aurafilter.add(SubType.AURA.getPredicate()); - } - - public ThreeDreamsTarget() { - super(0, 3, aurafilter.copy()); - } - - public ThreeDreamsTarget(final ThreeDreamsTarget target) { - super(target); - } - - @Override - public ThreeDreamsTarget copy() { - return new ThreeDreamsTarget(this); - } - - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Cards cards, Game game) { - Card card = cards.get(id, game); - if (card != null) { - // check if card with that name was selected before - for (UUID targetId : this.getTargets()) { - Card iCard = game.getCard(targetId); - if (iCard != null && iCard.getName().equals(card.getName())) { - return false; - } - } - return filter.match(card, playerId, game); - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/t/ThreeWishes.java b/Mage.Sets/src/mage/cards/t/ThreeWishes.java index 78e06814acb..26ade1cb6c6 100644 --- a/Mage.Sets/src/mage/cards/t/ThreeWishes.java +++ b/Mage.Sets/src/mage/cards/t/ThreeWishes.java @@ -145,7 +145,7 @@ class ThreeWishesLookAtCardEffect extends AsThoughEffectImpl { if (affectedControllerId.equals(source.getControllerId())) { Card card = game.getCard(objectId); if (card != null) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/t/ThrillingEncore.java b/Mage.Sets/src/mage/cards/t/ThrillingEncore.java index 865b21b9ea5..81e837ea137 100644 --- a/Mage.Sets/src/mage/cards/t/ThrillingEncore.java +++ b/Mage.Sets/src/mage/cards/t/ThrillingEncore.java @@ -67,17 +67,12 @@ class ThrillingEncoreEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - Cards cards = new CardsImpl(); - for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { - Player player = game.getPlayer(playerId); - if (player == null) { - continue; - } - cards.addAll(player.getGraveyard().getCards(filter, source.getSourceId(), playerId, game)); - } + CardsPutIntoGraveyardWatcher watcher = game.getState().getWatcher(CardsPutIntoGraveyardWatcher.class); + if (controller == null || watcher == null) { return false; } + + Cards cards = new CardsImpl(watcher.getCardsPutIntoGraveyardFromBattlefield(game)); + cards.removeIf(uuid -> !game.getCard(uuid).isCreature(game)); + return controller.moveCards(cards, Zone.BATTLEFIELD, source, game); } } diff --git a/Mage.Sets/src/mage/cards/t/ThrivingGrubs.java b/Mage.Sets/src/mage/cards/t/ThrivingGrubs.java index 4c8bc6f4044..d77d4dcc4a8 100644 --- a/Mage.Sets/src/mage/cards/t/ThrivingGrubs.java +++ b/Mage.Sets/src/mage/cards/t/ThrivingGrubs.java @@ -1,7 +1,6 @@ package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -15,24 +14,30 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ThrivingGrubs extends CardImpl { public ThrivingGrubs(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); this.subtype.add(SubType.GREMLIN); this.power = new MageInt(2); this.toughness = new MageInt(1); // When Thriving Grubs enters the battlefield, you get {E}{E}. - this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(2), false)); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new GetEnergyCountersControllerEffect(2), false + )); // Whenever Thriving Grubs attacks, you may pay {E}{E}. If you do, put a +1/+1 counter on it. - this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new PayEnergyCost(2)), false, - "Whenever {this} attacks you may pay {E}{E}. If you do, put a +1/+1 counter on it.")); + this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on it"), + new PayEnergyCost(2) + ), false)); } private ThrivingGrubs(final ThrivingGrubs card) { diff --git a/Mage.Sets/src/mage/cards/t/ThrivingIbex.java b/Mage.Sets/src/mage/cards/t/ThrivingIbex.java index 253f91b0409..e8c11693f86 100644 --- a/Mage.Sets/src/mage/cards/t/ThrivingIbex.java +++ b/Mage.Sets/src/mage/cards/t/ThrivingIbex.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -15,14 +13,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; +import java.util.UUID; + /** - * * @author fireshoes */ public final class ThrivingIbex extends CardImpl { public ThrivingIbex(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.subtype.add(SubType.GOAT); this.power = new MageInt(2); this.toughness = new MageInt(4); @@ -31,8 +30,11 @@ public final class ThrivingIbex extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(2))); // Whenever Thriving Ibex attacks, you may pay {E}{E}. If you do, put a +1/+1 counter on it. - this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new PayEnergyCost(2)), false, - "Whenever {this} attacks you may pay {E}{E}. If you do, put a +1/+1 counter on it.")); + this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on it"), + new PayEnergyCost(2) + ), false)); } private ThrivingIbex(final ThrivingIbex card) { diff --git a/Mage.Sets/src/mage/cards/t/ThrivingRats.java b/Mage.Sets/src/mage/cards/t/ThrivingRats.java index eb93516f88a..ad91484a1c5 100644 --- a/Mage.Sets/src/mage/cards/t/ThrivingRats.java +++ b/Mage.Sets/src/mage/cards/t/ThrivingRats.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -15,14 +13,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; +import java.util.UUID; + /** - * * @author fireshoes */ public final class ThrivingRats extends CardImpl { public ThrivingRats(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.RAT); this.power = new MageInt(1); this.toughness = new MageInt(2); @@ -31,8 +30,11 @@ public final class ThrivingRats extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(2))); // Whenever Thriving Rats attacks, you may pay {E}{E}. If you do, put a +1/+1 counter on it. - this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new PayEnergyCost(2)), false, - "Whenever {this} attacks you may pay {E}{E}. If you do, put a +1/+1 counter on it.")); + this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on it"), + new PayEnergyCost(2) + ), false)); } private ThrivingRats(final ThrivingRats card) { diff --git a/Mage.Sets/src/mage/cards/t/ThrivingRhino.java b/Mage.Sets/src/mage/cards/t/ThrivingRhino.java index 07497f26d93..bde7b650ed1 100644 --- a/Mage.Sets/src/mage/cards/t/ThrivingRhino.java +++ b/Mage.Sets/src/mage/cards/t/ThrivingRhino.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -15,14 +13,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ThrivingRhino extends CardImpl { public ThrivingRhino(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.RHINO); this.power = new MageInt(2); this.toughness = new MageInt(3); @@ -31,8 +30,11 @@ public final class ThrivingRhino extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(2))); // Whenever Thriving Rhino attacks, you may pay {E}{E}. If you do, put a +1/+1 counter on it. - this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new PayEnergyCost(2)), false)); - + this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on it"), + new PayEnergyCost(2) + ), false)); } private ThrivingRhino(final ThrivingRhino card) { diff --git a/Mage.Sets/src/mage/cards/t/ThrivingTurtle.java b/Mage.Sets/src/mage/cards/t/ThrivingTurtle.java index d523b374754..654d8ce82cd 100644 --- a/Mage.Sets/src/mage/cards/t/ThrivingTurtle.java +++ b/Mage.Sets/src/mage/cards/t/ThrivingTurtle.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -15,14 +13,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; +import java.util.UUID; + /** - * * @author fireshoes */ public final class ThrivingTurtle extends CardImpl { public ThrivingTurtle(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); this.subtype.add(SubType.TURTLE); this.power = new MageInt(0); this.toughness = new MageInt(3); @@ -31,7 +30,11 @@ public final class ThrivingTurtle extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(2))); // Whenever Thriving Turtle attacks, you may pay {E}{E}. If you do, put a +1/+1 counter on it. - this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new PayEnergyCost(2)), false)); + this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on it"), + new PayEnergyCost(2) + ), false)); } private ThrivingTurtle(final ThrivingTurtle card) { diff --git a/Mage.Sets/src/mage/cards/t/ThroughTheBreach.java b/Mage.Sets/src/mage/cards/t/ThroughTheBreach.java index 460a2ec5ed2..f23160de056 100644 --- a/Mage.Sets/src/mage/cards/t/ThroughTheBreach.java +++ b/Mage.Sets/src/mage/cards/t/ThroughTheBreach.java @@ -76,7 +76,7 @@ class ThroughTheBreachEffect extends OneShotEffect { if (controller != null) { if (controller.chooseUse(Outcome.PutCreatureInPlay, choiceText, source, game)) { TargetCardInHand target = new TargetCardInHand(StaticFilters.FILTER_CARD_CREATURE); - if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCreatureInPlay, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { diff --git a/Mage.Sets/src/mage/cards/t/ThrullWizard.java b/Mage.Sets/src/mage/cards/t/ThrullWizard.java index ea6d1d49ba9..72a67231701 100644 --- a/Mage.Sets/src/mage/cards/t/ThrullWizard.java +++ b/Mage.Sets/src/mage/cards/t/ThrullWizard.java @@ -40,7 +40,7 @@ public final class ThrullWizard extends CardImpl { this.toughness = new MageInt(1); // {1}{B}: Counter target black spell unless that spell's controller pays {B} or {3}. - Cost cost = new OrCost(new ColoredManaCost(ColoredManaSymbol.B), new GenericManaCost(3), "pay {B} or pay {3}"); + Cost cost = new OrCost("pay {B} or pay {3}", new ColoredManaCost(ColoredManaSymbol.B), new GenericManaCost(3)); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterUnlessPaysEffect(cost), new ManaCostsImpl("{1}{B}")); ability.addTarget(new TargetSpell(filter)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java b/Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java index 8c29f015be7..46efa1a3ef8 100644 --- a/Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java +++ b/Mage.Sets/src/mage/cards/t/ThunderbladeCharge.java @@ -3,7 +3,7 @@ package mage.cards.t; import java.util.UUID; import mage.ApprovingObject; import mage.abilities.Ability; -import mage.abilities.common.ControlledCreaturesDealCombatDamagePlayerTriggeredAbility; +import mage.abilities.common.DealCombatDamageControlledTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; @@ -34,7 +34,7 @@ public final class ThunderbladeCharge extends CardImpl { // Whenever one or more creatures you control deal combat damage to a player, // if Thunderblade Charge is in your graveyard, you may pay {2}{R}{R}{R}. // If you do, you may cast it without paying its mana cost. - this.addAbility(new ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Zone.GRAVEYARD, + this.addAbility(new DealCombatDamageControlledTriggeredAbility(Zone.GRAVEYARD, new DoIfCostPaid(new ThunderbladeChargeCastEffect(), new ManaCostsImpl("{2}{R}{R}{R}")) .setText("if {this} is in your graveyard, you may pay {2}{R}{R}{R}. " + "If you do, you may cast it without paying its mana cost"))); diff --git a/Mage.Sets/src/mage/cards/t/Thunderbolt.java b/Mage.Sets/src/mage/cards/t/Thunderbolt.java index 28b0ad0c89c..3f82a044ce4 100644 --- a/Mage.Sets/src/mage/cards/t/Thunderbolt.java +++ b/Mage.Sets/src/mage/cards/t/Thunderbolt.java @@ -31,8 +31,7 @@ public final class Thunderbolt extends CardImpl { // Choose one - Thunderbolt deals 3 damage to target player; or Thunderbolt deals 4 damage to target creature with flying. this.getSpellAbility().addEffect(new DamageTargetEffect(3)); this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); - Mode mode = new Mode(); - mode.addEffect(new DamageTargetEffect(4)); + Mode mode = new Mode(new DamageTargetEffect(4)); mode.addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/t/ThunderbreakRegent.java b/Mage.Sets/src/mage/cards/t/ThunderbreakRegent.java index e8c31c28bca..cd5d03d3242 100644 --- a/Mage.Sets/src/mage/cards/t/ThunderbreakRegent.java +++ b/Mage.Sets/src/mage/cards/t/ThunderbreakRegent.java @@ -15,7 +15,6 @@ import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; @@ -78,7 +77,7 @@ class ThunderbreakRegentTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (game.getOpponents(this.controllerId).contains(event.getPlayerId())) { Permanent creature = game.getPermanent(event.getTargetId()); - if (creature != null && filter.match(creature, getSourceId(), getControllerId(), game)) { + if (creature != null && filter.match(creature, getControllerId(), this, game)) { for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(event.getPlayerId())); } diff --git a/Mage.Sets/src/mage/cards/t/Thunderheads.java b/Mage.Sets/src/mage/cards/t/Thunderheads.java index ca78bae9119..d7235eb0532 100644 --- a/Mage.Sets/src/mage/cards/t/Thunderheads.java +++ b/Mage.Sets/src/mage/cards/t/Thunderheads.java @@ -23,7 +23,7 @@ public final class Thunderheads extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}"); // Replicate {2}{U} - this.addAbility(new ReplicateAbility(this, "{2}{U}")); + this.addAbility(new ReplicateAbility("{2}{U}")); // Create a 3/3 blue Weird creature token with defender and flying. Exile it at the beginning of the next end step. this.getSpellAbility().addEffect(new ThunderheadsEffect()); } diff --git a/Mage.Sets/src/mage/cards/t/ThunderherdMigration.java b/Mage.Sets/src/mage/cards/t/ThunderherdMigration.java index 966f02a773c..e4ab1f076fb 100644 --- a/Mage.Sets/src/mage/cards/t/ThunderherdMigration.java +++ b/Mage.Sets/src/mage/cards/t/ThunderherdMigration.java @@ -32,9 +32,9 @@ public final class ThunderherdMigration extends CardImpl { // As an additional cost to cast Thunderherd Migration, reveal a Dinosaur card from your hand or pay {1}. this.getSpellAbility().addCost(new OrCost( - new RevealTargetFromHandCost(new TargetCardInHand(filter)), - new GenericManaCost(1), - "reveal a Dinosaur card from your hand or pay {1}")); + "reveal a Dinosaur card from your hand or pay {1}", new RevealTargetFromHandCost(new TargetCardInHand(filter)), + new GenericManaCost(1) + )); // Search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library. this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true, true)); diff --git a/Mage.Sets/src/mage/cards/t/ThunderingRaiju.java b/Mage.Sets/src/mage/cards/t/ThunderingRaiju.java new file mode 100644 index 00000000000..688e79149d0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThunderingRaiju.java @@ -0,0 +1,74 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.permanent.ModifiedPredicate; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ThunderingRaiju extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(ModifiedPredicate.instance); + filter.add(AnotherPredicate.instance); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + private static final Hint hint = new ValueHint("Other modified creatures you control", xValue); + + public ThunderingRaiju(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Whenever Thundering Raiju attacks, put a +1/+1 counter on target creature you control. Then Thundering Raiju deals X damage to each opponent, where X is the number of modified creatures you control other than Thundering Raiju. + Ability ability = new AttacksTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()) + ); + ability.addTarget(new TargetControlledCreaturePermanent()); + ability.addEffect(new DamagePlayersEffect( + Outcome.Damage, xValue, TargetController.OPPONENT + ).setText("Then {this} deals X damage to each opponent, " + + "where X is the number of modified creatures you control other than {this}")); + this.addAbility(ability.addHint(hint)); + } + + private ThunderingRaiju(final ThunderingRaiju card) { + super(card); + } + + @Override + public ThunderingRaiju copy() { + return new ThunderingRaiju(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/ThunderkinAwakener.java b/Mage.Sets/src/mage/cards/t/ThunderkinAwakener.java index e8d3a109fee..72ab07be622 100644 --- a/Mage.Sets/src/mage/cards/t/ThunderkinAwakener.java +++ b/Mage.Sets/src/mage/cards/t/ThunderkinAwakener.java @@ -75,7 +75,7 @@ enum ThunderkinAwakenerPredicate implements ObjectSourcePlayerPredicate { @Override public boolean apply(ObjectSourcePlayer input, Game game) { - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(input.getSourceId()); + Permanent sourcePermanent = input.getSource().getSourcePermanentOrLKI(game); return sourcePermanent != null && input.getObject().getToughness().getValue() < sourcePermanent.getToughness().getValue(); } diff --git a/Mage.Sets/src/mage/cards/t/ThundermawHellkite.java b/Mage.Sets/src/mage/cards/t/ThundermawHellkite.java index 59305a501f8..2f2c43df000 100644 --- a/Mage.Sets/src/mage/cards/t/ThundermawHellkite.java +++ b/Mage.Sets/src/mage/cards/t/ThundermawHellkite.java @@ -84,7 +84,7 @@ class TapAllEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanent.tap(source, game); } return true; diff --git a/Mage.Sets/src/mage/cards/t/ThunderousOrator.java b/Mage.Sets/src/mage/cards/t/ThunderousOrator.java index ca16ff18ed7..637fda50b20 100644 --- a/Mage.Sets/src/mage/cards/t/ThunderousOrator.java +++ b/Mage.Sets/src/mage/cards/t/ThunderousOrator.java @@ -87,13 +87,13 @@ class ThunderousOratorEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { List abilities = new ArrayList<>(); - if (game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0) { + if (game.getBattlefield().count(filter, source.getControllerId(), source, game) > 0) { abilities.add(new MenaceAbility()); } game.getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game ).stream() .filter(Objects::nonNull) .map(p -> p.getAbilities(game)) diff --git a/Mage.Sets/src/mage/cards/t/ThwartTheEnemy.java b/Mage.Sets/src/mage/cards/t/ThwartTheEnemy.java index b3678828617..533fe434b34 100644 --- a/Mage.Sets/src/mage/cards/t/ThwartTheEnemy.java +++ b/Mage.Sets/src/mage/cards/t/ThwartTheEnemy.java @@ -5,8 +5,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.FilterObject; -import mage.filter.common.FilterOpponentsCreaturePermanent; +import mage.filter.StaticFilters; import java.util.UUID; @@ -15,15 +14,12 @@ import java.util.UUID; */ public final class ThwartTheEnemy extends CardImpl { - private static final FilterObject filter - = new FilterOpponentsCreaturePermanent("creatures your opponents control"); - public ThwartTheEnemy(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); // Prevent all damage that would be dealt this turn by creatures your opponents control. this.getSpellAbility().addEffect(new PreventAllDamageByAllObjectsEffect( - filter, Duration.EndOfTurn, false + StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, Duration.EndOfTurn, false )); } diff --git a/Mage.Sets/src/mage/cards/t/ThwartTheGrave.java b/Mage.Sets/src/mage/cards/t/ThwartTheGrave.java index f3e0221f613..8ab12900e2f 100644 --- a/Mage.Sets/src/mage/cards/t/ThwartTheGrave.java +++ b/Mage.Sets/src/mage/cards/t/ThwartTheGrave.java @@ -1,5 +1,6 @@ package mage.cards.t; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.PartyCount; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; @@ -67,8 +68,8 @@ class ThwartTheGraveTarget extends TargetCardInYourGraveyard { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set possibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); if (!this.getTargets().isEmpty()) { possibleTargets.removeIf(uuid -> { Card card = game.getCard(uuid); diff --git a/Mage.Sets/src/mage/cards/t/Tiamat.java b/Mage.Sets/src/mage/cards/t/Tiamat.java index 278136195b2..8174dcc904e 100644 --- a/Mage.Sets/src/mage/cards/t/Tiamat.java +++ b/Mage.Sets/src/mage/cards/t/Tiamat.java @@ -1,16 +1,13 @@ package mage.cards.t; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.CastFromEverywhereSourceCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.keyword.FlyingAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; @@ -18,11 +15,8 @@ import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.NamePredicate; -import mage.game.Game; -import mage.target.common.TargetCardInLibrary; -import mage.util.CardUtil; +import mage.target.common.TargetCardWithDifferentNameInLibrary; -import java.util.Objects; import java.util.UUID; /** @@ -30,6 +24,14 @@ import java.util.UUID; */ public final class Tiamat extends CardImpl { + private static final FilterCard filter + = new FilterCreatureCard("Dragon cards not named Tiamat that each have different names"); + + static { + filter.add(SubType.DRAGON.getPredicate()); + filter.add(Predicates.not(new NamePredicate("Tiamat"))); + } + public Tiamat(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}{B}{R}{G}"); @@ -44,8 +46,9 @@ public final class Tiamat extends CardImpl { // When Tiamat enters the battlefield, if you cast it, search your library for up to five Dragon cards named Tiama that each have different names, reveal them, put them into your hand, then shuffle. this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( - new SearchLibraryPutInHandEffect(new TiamatTarget(), true, true)), - CastFromEverywhereSourceCondition.instance, "When {this} enters the battlefield, " + + new SearchLibraryPutInHandEffect( + new TargetCardWithDifferentNameInLibrary(0, 5, filter), true, true + )), CastFromEverywhereSourceCondition.instance, "When {this} enters the battlefield, " + "if you cast it, search your library for up to five Dragon cards not named Tiamat " + "that each have different names, reveal them, put them into your hand, then shuffle." )); @@ -60,41 +63,3 @@ public final class Tiamat extends CardImpl { return new Tiamat(this); } } - -class TiamatTarget extends TargetCardInLibrary { - - private static final FilterCard filter - = new FilterCreatureCard("Dragon cards not named Tiamat that each have different names"); - - static { - filter.add(SubType.DRAGON.getPredicate()); - filter.add(Predicates.not(new NamePredicate("Tiamat"))); - } - - TiamatTarget() { - super(0, 5, filter); - } - - private TiamatTarget(final TiamatTarget target) { - super(target); - } - - @Override - public TiamatTarget copy() { - return new TiamatTarget(this); - } - - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Cards cards, Game game) { - Card card = cards.get(id, game); - return card != null - && filter.match(card, playerId, game) - && this - .getTargets() - .stream() - .map(game::getCard) - .filter(Objects::nonNull) - .map(Card::getName) - .noneMatch(n -> CardUtil.haveSameNames(card, n, game)); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TibaltRakishInstigator.java b/Mage.Sets/src/mage/cards/t/TibaltRakishInstigator.java index a7b685b0daa..4eefa1ffa80 100644 --- a/Mage.Sets/src/mage/cards/t/TibaltRakishInstigator.java +++ b/Mage.Sets/src/mage/cards/t/TibaltRakishInstigator.java @@ -1,7 +1,6 @@ package mage.cards.t; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.CantGainLifeAllEffect; @@ -22,7 +21,7 @@ public final class TibaltRakishInstigator extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TIBALT); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Your opponents can't gain life. this.addAbility(new SimpleStaticAbility( diff --git a/Mage.Sets/src/mage/cards/t/TibaltTheFiendBlooded.java b/Mage.Sets/src/mage/cards/t/TibaltTheFiendBlooded.java index 75c95923b0f..f1d8f37d7f0 100644 --- a/Mage.Sets/src/mage/cards/t/TibaltTheFiendBlooded.java +++ b/Mage.Sets/src/mage/cards/t/TibaltTheFiendBlooded.java @@ -3,7 +3,6 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.CardsInTargetHandCount; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffectImpl; @@ -38,7 +37,7 @@ public final class TibaltTheFiendBlooded extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TIBALT); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(2)); + this.setStartingLoyalty(2); // +1: Draw a card, then discard a card at random. LoyaltyAbility ability = new LoyaltyAbility(new DrawCardSourceControllerEffect(1), 1); @@ -113,7 +112,7 @@ class TibaltTheFiendBloodedThirdEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - List permanents = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game); for (Permanent permanent : permanents) { permanent.untap(game); diff --git a/Mage.Sets/src/mage/cards/t/TidalControl.java b/Mage.Sets/src/mage/cards/t/TidalControl.java index 795cdb1bc5b..34278e0fc74 100644 --- a/Mage.Sets/src/mage/cards/t/TidalControl.java +++ b/Mage.Sets/src/mage/cards/t/TidalControl.java @@ -37,7 +37,7 @@ public final class TidalControl extends CardImpl { this.addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl("{2}"))); // Pay 2 life or {2}: Counter target red or green spell. Any player may activate this ability. - SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new OrCost(new PayLifeCost(2), new ManaCostsImpl("{2}"), "pay 2 life or pay {2}")); + SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), new OrCost("pay 2 life or pay {2}", new PayLifeCost(2), new ManaCostsImpl("{2}"))); ability.addTarget(new TargetSpell(filter)); ability.setMayActivate(TargetController.ANY); ability.addEffect(new InfoEffect("Any player may activate this ability")); diff --git a/Mage.Sets/src/mage/cards/t/TideforceElemental.java b/Mage.Sets/src/mage/cards/t/TideforceElemental.java index bf19b55ea2b..68331bf88de 100644 --- a/Mage.Sets/src/mage/cards/t/TideforceElemental.java +++ b/Mage.Sets/src/mage/cards/t/TideforceElemental.java @@ -26,7 +26,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class TideforceElemental extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { filter.add(AnotherPredicate.instance); diff --git a/Mage.Sets/src/mage/cards/t/TigerTribeHunter.java b/Mage.Sets/src/mage/cards/t/TigerTribeHunter.java index 02c24474774..fe3a57548fd 100644 --- a/Mage.Sets/src/mage/cards/t/TigerTribeHunter.java +++ b/Mage.Sets/src/mage/cards/t/TigerTribeHunter.java @@ -77,7 +77,7 @@ class TigerTribeHunterEffect extends OneShotEffect { TargetPermanent target = new TargetPermanent( 0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, true ); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent == null) { return false; diff --git a/Mage.Sets/src/mage/cards/t/TilonallisCrown.java b/Mage.Sets/src/mage/cards/t/TilonallisCrown.java index f06ddc65be9..4edccc2590a 100644 --- a/Mage.Sets/src/mage/cards/t/TilonallisCrown.java +++ b/Mage.Sets/src/mage/cards/t/TilonallisCrown.java @@ -41,8 +41,7 @@ public final class TilonallisCrown extends CardImpl { this.addAbility(ability); // When Tilonalli's Crown enters the battlefield, it deals 1 damage to enchanted creature. - this.addAbility(new EntersBattlefieldTriggeredAbility(new DamageAttachedEffect(1, "it") - .setText("it deals 1 damage to enchanted creature"))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DamageAttachedEffect(1, "it"))); // Enchanted creature gets +3/+0 and has trample. ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(3, 0)); diff --git a/Mage.Sets/src/mage/cards/t/TilonallisSummoner.java b/Mage.Sets/src/mage/cards/t/TilonallisSummoner.java index ac0e317720e..2818ad31a84 100644 --- a/Mage.Sets/src/mage/cards/t/TilonallisSummoner.java +++ b/Mage.Sets/src/mage/cards/t/TilonallisSummoner.java @@ -20,7 +20,7 @@ import mage.cards.CardSetInfo; import mage.cards.CardsImpl; import mage.constants.*; import mage.game.Game; -import mage.game.permanent.token.TilonallisSummonerElementalToken; +import mage.game.permanent.token.RedElementalToken; import mage.players.Player; import mage.target.targetpointer.FixedTargets; @@ -82,13 +82,13 @@ class TilonallisSummonerEffect extends OneShotEffect { cost.add(new GenericManaCost(costX)); if (cost.pay(source, game, source, source.getControllerId(), false, null)) { controller.resetStoredBookmark(game); // otherwise you can undo the payment - CreateTokenEffect effect = new CreateTokenEffect(new TilonallisSummonerElementalToken(), costX, true, true); + CreateTokenEffect effect = new CreateTokenEffect(new RedElementalToken(), costX, true, true); effect.apply(game, source); Effect exileEffect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD) .setText("exile those tokens unless you have the city's blessing"); exileEffect.setTargetPointer(new FixedTargets(new CardsImpl(effect.getLastAddedTokenIds()), game)); game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( - Zone.ALL, exileEffect, TargetController.ANY, new InvertCondition(CitysBlessingCondition.instance)), source); + exileEffect, TargetController.ANY, new InvertCondition(CitysBlessingCondition.instance)), source); } } return true; diff --git a/Mage.Sets/src/mage/cards/t/TimberProtector.java b/Mage.Sets/src/mage/cards/t/TimberProtector.java index 35ab5f860e8..fb608938189 100644 --- a/Mage.Sets/src/mage/cards/t/TimberProtector.java +++ b/Mage.Sets/src/mage/cards/t/TimberProtector.java @@ -1,10 +1,8 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.keyword.IndestructibleAbility; @@ -13,31 +11,32 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; /** - * * @author Loki */ public final class TimberProtector extends CardImpl { - private static final FilterCreaturePermanent filterTreefolk = new FilterCreaturePermanent("Treefolk creatures"); - private static final FilterControlledPermanent filterBoth = new FilterControlledPermanent("Other Treefolk and Forests you control"); + private static final FilterCreaturePermanent filterTreefolk + = new FilterCreaturePermanent("Treefolk creatures"); + private static final FilterControlledPermanent filterBoth + = new FilterControlledPermanent("other Treefolk and Forests you control"); static { filterTreefolk.add(SubType.TREEFOLK.getPredicate()); - filterBoth.add(Predicates.or( - SubType.TREEFOLK.getPredicate(), - SubType.FOREST.getPredicate())); - filterBoth.add(AnotherPredicate.instance); + filterBoth.add(TimberProtectorPredicate.instance); } public TimberProtector(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.TREEFOLK); this.subtype.add(SubType.WARRIOR); @@ -45,11 +44,14 @@ public final class TimberProtector extends CardImpl { this.toughness = new MageInt(6); // Other Treefolk creatures you control get +1/+1. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filterTreefolk, true))); + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 1, Duration.WhileOnBattlefield, filterTreefolk, true + ))); + // Other Treefolk and Forests you control are indestructible. - Effect effect = new GainAbilityAllEffect(IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield, filterBoth, true); - effect.setText("Other Treefolk and Forests you control are indestructible"); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( + IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield, filterBoth + ))); } private TimberProtector(final TimberProtector card) { @@ -61,3 +63,17 @@ public final class TimberProtector extends CardImpl { return new TimberProtector(this); } } + +enum TimberProtectorPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + MageObject obj = input.getObject(); + if (obj.getId().equals(input.getSourceId())) { + return obj.hasSubtype(SubType.FOREST, game); + } + return obj.hasSubtype(SubType.FOREST, game) + || obj.hasSubtype(SubType.TREEFOLK, game); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TimbermawLarva.java b/Mage.Sets/src/mage/cards/t/TimbermawLarva.java index 4fe5da1980c..a84e15e87fb 100644 --- a/Mage.Sets/src/mage/cards/t/TimbermawLarva.java +++ b/Mage.Sets/src/mage/cards/t/TimbermawLarva.java @@ -1,9 +1,8 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; @@ -14,8 +13,9 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.common.FilterLandPermanent; +import java.util.UUID; + /** - * * @author North */ public final class TimbermawLarva extends CardImpl { @@ -28,15 +28,18 @@ public final class TimbermawLarva extends CardImpl { } + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + public TimbermawLarva(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.BEAST); this.power = new MageInt(2); this.toughness = new MageInt(2); - PermanentsOnBattlefieldCount value = new PermanentsOnBattlefieldCount(filter); - this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect(value, value, Duration.EndOfTurn), false)); + this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect( + xValue, xValue, Duration.EndOfTurn, true, "it" + ), false)); } private TimbermawLarva(final TimbermawLarva card) { diff --git a/Mage.Sets/src/mage/cards/t/TimberpackWolf.java b/Mage.Sets/src/mage/cards/t/TimberpackWolf.java index 12fbc4c2772..cd8f3bb5418 100644 --- a/Mage.Sets/src/mage/cards/t/TimberpackWolf.java +++ b/Mage.Sets/src/mage/cards/t/TimberpackWolf.java @@ -66,7 +66,7 @@ public final class TimberpackWolf extends CardImpl { @Override public boolean apply(Game game, Ability source) { - int count = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) - 1; + int count = game.getBattlefield().count(filter, source.getControllerId(), source, game) - 1; if (count > 0) { Permanent target = game.getPermanent(source.getSourceId()); if (target != null) { diff --git a/Mage.Sets/src/mage/cards/t/TimeOfHeroes.java b/Mage.Sets/src/mage/cards/t/TimeOfHeroes.java index 133b92453d3..c6e9cf89415 100644 --- a/Mage.Sets/src/mage/cards/t/TimeOfHeroes.java +++ b/Mage.Sets/src/mage/cards/t/TimeOfHeroes.java @@ -17,7 +17,7 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class TimeOfHeroes extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Each creature you control with a level counter"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Each creature you control with a level counter on it"); static { filter.add(TargetController.YOU.getControllerPredicate()); diff --git a/Mage.Sets/src/mage/cards/t/TimeSieve.java b/Mage.Sets/src/mage/cards/t/TimeSieve.java index 387bb67667c..13a1ca613e7 100644 --- a/Mage.Sets/src/mage/cards/t/TimeSieve.java +++ b/Mage.Sets/src/mage/cards/t/TimeSieve.java @@ -11,7 +11,9 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.target.common.TargetControlledPermanent; /** @@ -20,14 +22,14 @@ import mage.target.common.TargetControlledPermanent; */ public final class TimeSieve extends CardImpl { + private static final FilterControlledPermanent filter=new FilterControlledArtifactPermanent("artifacts"); public TimeSieve(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{U}{B}"); // {tap}, Sacrifice five artifacts: Take an extra turn after this one. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddExtraTurnControllerEffect(), new TapSourceCost()); - ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(5, 5, new FilterControlledArtifactPermanent("five artifacts"), true))); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(5, filter))); this.addAbility(ability); - } private TimeSieve(final TimeSieve card) { diff --git a/Mage.Sets/src/mage/cards/t/TimeWipe.java b/Mage.Sets/src/mage/cards/t/TimeWipe.java index 3f339ac7f74..4776badd776 100644 --- a/Mage.Sets/src/mage/cards/t/TimeWipe.java +++ b/Mage.Sets/src/mage/cards/t/TimeWipe.java @@ -63,7 +63,7 @@ class TimeWipeEffect extends OneShotEffect { } Target target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (player.choose(outcome, target, source.getSourceId(), game)) { + if (player.choose(outcome, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { player.moveCards(permanent, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/t/Timebender.java b/Mage.Sets/src/mage/cards/t/Timebender.java index 6fba549bd17..e8ad5090cdb 100644 --- a/Mage.Sets/src/mage/cards/t/Timebender.java +++ b/Mage.Sets/src/mage/cards/t/Timebender.java @@ -41,7 +41,7 @@ public final class Timebender extends CardImpl { this.toughness = new MageInt(1); // Morph {U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{U}"))); // When Timebender is turned face up, choose one — // Remove two time counters from target permanent or suspended card. diff --git a/Mage.Sets/src/mage/cards/t/Timecrafting.java b/Mage.Sets/src/mage/cards/t/Timecrafting.java index 5fcc757101c..4b6f0b7d05a 100644 --- a/Mage.Sets/src/mage/cards/t/Timecrafting.java +++ b/Mage.Sets/src/mage/cards/t/Timecrafting.java @@ -36,8 +36,7 @@ public final class Timecrafting extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanentOrSuspendedCard()); // or put X time counters on target permanent with a time counter on it or suspended card. - Mode mode = new Mode(); - mode.addEffect(new TimecraftingAddEffect()); + Mode mode = new Mode(new TimecraftingAddEffect()); mode.addTarget(new TargetPermanentOrSuspendedCard(filter, false)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/t/TimelyHordemate.java b/Mage.Sets/src/mage/cards/t/TimelyHordemate.java index b34056c5a54..a2ad67255bb 100644 --- a/Mage.Sets/src/mage/cards/t/TimelyHordemate.java +++ b/Mage.Sets/src/mage/cards/t/TimelyHordemate.java @@ -41,7 +41,7 @@ public final class TimelyHordemate extends CardImpl { // Raid — When Timely Hordemate enters the battlefield, if you attacked this turn, return target creature card with converted mana cost 2 or less from your graveyard to the battlefield. Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()), RaidCondition.instance, - "Raid — When {this} enters the battlefield, if you attacked this turn, return target creature card with mana value 2 or less from your graveyard to the battlefield."); + "When {this} enters the battlefield, if you attacked this turn, return target creature card with mana value 2 or less from your graveyard to the battlefield."); ability.addTarget(new TargetCardInYourGraveyard(filter)); ability.setAbilityWord(AbilityWord.RAID); ability.addHint(RaidHint.instance); diff --git a/Mage.Sets/src/mage/cards/t/TinderWall.java b/Mage.Sets/src/mage/cards/t/TinderWall.java index 4f1cede0ea5..cdac2cb8828 100644 --- a/Mage.Sets/src/mage/cards/t/TinderWall.java +++ b/Mage.Sets/src/mage/cards/t/TinderWall.java @@ -1,6 +1,5 @@ package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.Mana; import mage.abilities.Ability; @@ -15,16 +14,24 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterAttackingCreature; -import mage.filter.predicate.permanent.BlockedByIdPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author Plopman */ public final class TinderWall extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("creature it's blocking"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.BLOCKED_BY); + } + public TinderWall(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); this.subtype.add(SubType.PLANT); @@ -35,14 +42,14 @@ public final class TinderWall extends CardImpl { // Defender this.addAbility(DefenderAbility.getInstance()); + // Sacrifice Tinder Wall: Add {R}{R}. this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.RedMana(2), new SacrificeSourceCost())); + // {R}, Sacrifice Tinder Wall: Tinder Wall deals 2 damage to target creature it's blocking. - FilterAttackingCreature filter = new FilterAttackingCreature("creature it's blocking"); - filter.add(new BlockedByIdPredicate(this.getId())); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new ManaCostsImpl("{R}")); - ability.addTarget(new TargetCreaturePermanent(filter)); + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new ManaCostsImpl<>("{R}")); ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TirelessAngler.java b/Mage.Sets/src/mage/cards/t/TirelessAngler.java new file mode 100644 index 00000000000..efa0a2bb708 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TirelessAngler.java @@ -0,0 +1,72 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.effects.common.DraftFromSpellbookEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TirelessAngler extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("an Island or Swamp"); + + static { + filter.add(Predicates.or( + SubType.ISLAND.getPredicate(), + SubType.SWAMP.getPredicate() + )); + } + + private static final List spellbook = Collections.unmodifiableList(Arrays.asList( + // "Archipelagore", mutate card + "Fleet Swallower", + "Moat Piranhas", + "Mystic Skyfish", + "Nadir Kraken", + // "Pouncing Shoreshark", mutate card + "Riptide Turtle", + "Ruin Crab", + // "Sea-Dasher Octopus", mutate card + "Serpent of Yawning Depths", + "Sigiled Starfish", + "Spined Megalodon", + "Stinging Lionfish", + "Voracious Greatshark", + "Wormhole Serpent" + )); + + public TirelessAngler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // Whenever an Island or Swamp enters the battlefield under your control, draft a card from Tireless Angler's spellbook. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + new DraftFromSpellbookEffect(spellbook), filter + )); + } + + private TirelessAngler(final TirelessAngler card) { + super(card); + } + + @Override + public TirelessAngler copy() { + return new TirelessAngler(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TitanOfIndustry.java b/Mage.Sets/src/mage/cards/t/TitanOfIndustry.java new file mode 100644 index 00000000000..7b51f141f34 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TitanOfIndustry.java @@ -0,0 +1,107 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.GainLifeTargetEffect; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.RhinoWarriorToken; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.TargetPlayer; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TitanOfIndustry extends CardImpl { + + public TitanOfIndustry(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}{G}"); + + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(7); + this.toughness = new MageInt(7); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When Titan of Industry enters the battlefield, choose two — + // • Destroy target artifact or enchantment. + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); + ability.getModes().setMinModes(2); + ability.getModes().setMaxModes(2); + + // • Target player gains 5 life. + ability.addMode(new Mode(new GainLifeTargetEffect(5)).addTarget(new TargetPlayer())); + + // • Create a 4/4 green Rhino Warrior creature token. + ability.addMode(new Mode(new CreateTokenEffect(new RhinoWarriorToken()))); + + // • Put a shield counter on a creature you control. + ability.addMode(new Mode(new TitanOfIndustryEffect())); + this.addAbility(ability); + } + + private TitanOfIndustry(final TitanOfIndustry card) { + super(card); + } + + @Override + public TitanOfIndustry copy() { + return new TitanOfIndustry(this); + } +} + +class TitanOfIndustryEffect extends OneShotEffect { + + TitanOfIndustryEffect() { + super(Outcome.Benefit); + staticText = "put a shield counter on a creature you control"; + } + + private TitanOfIndustryEffect(final TitanOfIndustryEffect effect) { + super(effect); + } + + @Override + public TitanOfIndustryEffect copy() { + return new TitanOfIndustryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null || game.getBattlefield().count( + StaticFilters.FILTER_CONTROLLED_CREATURE, + source.getControllerId(), source, game + ) < 1) { + return false; + } + TargetPermanent target = new TargetControlledCreaturePermanent(); + target.setNotTarget(true); + player.choose(outcome, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + return permanent != null && permanent.addCounters(CounterType.SHIELD.createInstance(), source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TitanicBulvox.java b/Mage.Sets/src/mage/cards/t/TitanicBulvox.java index 7ddd62088ce..a5d328987b4 100644 --- a/Mage.Sets/src/mage/cards/t/TitanicBulvox.java +++ b/Mage.Sets/src/mage/cards/t/TitanicBulvox.java @@ -26,7 +26,7 @@ public final class TitanicBulvox extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); // Morph {4}{G}{G}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{G}{G}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{G}{G}{G}"))); } private TitanicBulvox(final TitanicBulvox card) { diff --git a/Mage.Sets/src/mage/cards/t/TitansNest.java b/Mage.Sets/src/mage/cards/t/TitansNest.java index 1b6e3a2c292..4155b986873 100644 --- a/Mage.Sets/src/mage/cards/t/TitansNest.java +++ b/Mage.Sets/src/mage/cards/t/TitansNest.java @@ -92,7 +92,7 @@ class TitansNestManaAbility extends ActivatedManaAbilityImpl { TitansNestManaAbility() { super(Zone.BATTLEFIELD, (BasicManaEffect) new BasicManaEffect( new TitansNestConditionalMana(), new CardsInControllerGraveyardCount()) - .setText("Add {C}. Spend this mana only to cast a colored spell without {X} in its mana cost."), + .setText("Add {C}. Spend this mana only to cast a spell that's one or more colors without {X} in its mana cost."), new ExileFromGraveCost(new TargetCardInYourGraveyard())); this.netMana.add(Mana.ColorlessMana(1)); } @@ -111,7 +111,7 @@ class TitansNestConditionalMana extends ConditionalMana { TitansNestConditionalMana() { super(Mana.ColorlessMana(1)); - staticText = "Spend this mana only to cast a colored spell without {X} in its mana cost."; + staticText = "Spend this mana only to cast a spell that's one or more colors without {X} in its mana cost."; addCondition(new TitansNestManaCondition()); } } @@ -123,7 +123,7 @@ class TitansNestManaCondition extends ManaCondition { if (!(source instanceof SpellAbility)) { return false; } - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object == null || object.getColor(game).isColorless()) { return false; } diff --git a/Mage.Sets/src/mage/cards/t/TivitSellerOfSecrets.java b/Mage.Sets/src/mage/cards/t/TivitSellerOfSecrets.java new file mode 100644 index 00000000000..f97962ab731 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TivitSellerOfSecrets.java @@ -0,0 +1,134 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.keyword.InvestigateEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.WardAbility; +import mage.abilities.meta.OrTriggeredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.TwoChoiceVote; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.VoteEvent; +import mage.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TivitSellerOfSecrets extends CardImpl { + + public TivitSellerOfSecrets(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{U}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SPHINX); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Ward {3} + this.addAbility(new WardAbility(new ManaCostsImpl<>("{3}"))); + + // Council's dilemma — Whenever Tivit enters the battlefield or deals combat damage to a player, starting with you, each player votes for evidence or bribery. For each evidence vote, investigate. For each bribery vote, create a Treasure token. + this.addAbility(new OrTriggeredAbility( + Zone.BATTLEFIELD, new TivitSellerOfSecretsEffect(), false, + "Whenever {this} enters the battlefield or deals combat damage to a player, ", + new EntersBattlefieldTriggeredAbility(null, false), + new DealsCombatDamageToAPlayerTriggeredAbility(null, false) + ).setAbilityWord(AbilityWord.COUNCILS_DILEMMA)); + + // While voting, you may vote an additional time. + this.addAbility(new SimpleStaticAbility(new TivitSellerOfSecretsReplacementEffect())); + } + + private TivitSellerOfSecrets(final TivitSellerOfSecrets card) { + super(card); + } + + @Override + public TivitSellerOfSecrets copy() { + return new TivitSellerOfSecrets(this); + } +} + +class TivitSellerOfSecretsEffect extends OneShotEffect { + + TivitSellerOfSecretsEffect() { + super(Outcome.Benefit); + staticText = "starting with you, each player votes for evidence or bribery. For each evidence vote, " + + "investigate. For each bribery vote, create a Treasure token"; + } + + private TivitSellerOfSecretsEffect(final TivitSellerOfSecretsEffect effect) { + super(effect); + } + + @Override + public TivitSellerOfSecretsEffect copy() { + return new TivitSellerOfSecretsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + TwoChoiceVote vote = new TwoChoiceVote( + "Evidence (investigate)", "Bribery (treasure)", Outcome.Detriment + ); + vote.doVotes(source, game); + int evidenceCounter = vote.getVoteCount(true); + int briberyCounter = vote.getVoteCount(false); + if (evidenceCounter > 0) { + new InvestigateEffect(evidenceCounter).apply(game, source); + } + if (briberyCounter > 0) { + new TreasureToken().putOntoBattlefield(briberyCounter, game, source); + } + return evidenceCounter + briberyCounter > 0; + } +} + +class TivitSellerOfSecretsReplacementEffect extends ReplacementEffectImpl { + + TivitSellerOfSecretsReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "while voting, you may vote an additional time"; + } + + private TivitSellerOfSecretsReplacementEffect(final TivitSellerOfSecretsReplacementEffect effect) { + super(effect); + } + + @Override + public TivitSellerOfSecretsReplacementEffect copy() { + return new TivitSellerOfSecretsReplacementEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.VOTE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return source.isControlledBy(event.getTargetId()); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + ((VoteEvent) event).incrementOptionalExtraVotes(); + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TobiasBeckett.java b/Mage.Sets/src/mage/cards/t/TobiasBeckett.java index 14871165450..c3b1b841d20 100644 --- a/Mage.Sets/src/mage/cards/t/TobiasBeckett.java +++ b/Mage.Sets/src/mage/cards/t/TobiasBeckett.java @@ -73,7 +73,7 @@ class TobiasBeckettEffect extends OneShotEffect { if (bountyTriggered != null) { Player opponent = game.getPlayer(bountyTriggered.getControllerId()); if (opponent != null) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); UUID exileId = CardUtil.getCardExileZoneId(game, source); Card card = opponent.getLibrary().getFromTop(game); if (card != null && sourceObject != null) { diff --git a/Mage.Sets/src/mage/cards/t/Togglodyte.java b/Mage.Sets/src/mage/cards/t/Togglodyte.java index 2352132c9ae..6c7d613d805 100644 --- a/Mage.Sets/src/mage/cards/t/Togglodyte.java +++ b/Mage.Sets/src/mage/cards/t/Togglodyte.java @@ -71,7 +71,7 @@ class TogglodyteEntersEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } if (mageObject != null) { boolean toggled = true; @@ -103,7 +103,7 @@ class TogglodyteToggleEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { if (game.getState().getValue(mageObject.getId() + "_toggle") == null) { return false; @@ -183,7 +183,7 @@ class TogglodyteCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return !Boolean.TRUE.equals(game.getState().getValue(mageObject.getId() + "_toggle")); } diff --git a/Mage.Sets/src/mage/cards/t/ToluzCleverConductor.java b/Mage.Sets/src/mage/cards/t/ToluzCleverConductor.java new file mode 100644 index 00000000000..a20d953f47d --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ToluzCleverConductor.java @@ -0,0 +1,123 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetForSourceEffect; +import mage.abilities.effects.keyword.ConniveSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.*; +import mage.game.ExileZone; +import mage.game.Game; +import mage.game.events.DiscardedCardsEvent; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.target.targetpointer.FixedTargets; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ToluzCleverConductor extends CardImpl { + + public ToluzCleverConductor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W/U}{U}{U/B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // When Toluz, Clever Conductor enters the battlefield, it connives. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ConniveSourceEffect())); + + // Whenever you discard one or more cards, exile them from your graveyard. + this.addAbility(new ToluzCleverConductorTriggeredAbility()); + + // When Toluz, Clever Conductor dies, put the cards exiled with it into their owner's hand. + this.addAbility(new DiesSourceTriggeredAbility(new ToluzCleverConductorEffect())); + } + + private ToluzCleverConductor(final ToluzCleverConductor card) { + super(card); + } + + @Override + public ToluzCleverConductor copy() { + return new ToluzCleverConductor(this); + } +} + +class ToluzCleverConductorTriggeredAbility extends TriggeredAbilityImpl { + + ToluzCleverConductorTriggeredAbility() { + super(Zone.BATTLEFIELD, new ExileTargetForSourceEffect()); + } + + private ToluzCleverConductorTriggeredAbility(final ToluzCleverConductorTriggeredAbility ability) { + super(ability); + } + + @Override + public ToluzCleverConductorTriggeredAbility copy() { + return new ToluzCleverConductorTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DISCARDED_CARDS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!isControlledBy(event.getPlayerId())) { + return false; + } + DiscardedCardsEvent dEvent = (DiscardedCardsEvent) event; + Cards cards = new CardsImpl(dEvent.getDiscardedCards()); + cards.retainZone(Zone.GRAVEYARD, game); + this.getEffects().setTargetPointer(new FixedTargets(cards, game)); + return true; + } + + @Override + public String getRule() { + return "Whenever you discard one or more cards, exile them from your graveyard."; + } +} + +class ToluzCleverConductorEffect extends OneShotEffect { + + ToluzCleverConductorEffect() { + super(Outcome.Benefit); + staticText = "put the cards exiled with it into their owner's hand"; + } + + private ToluzCleverConductorEffect(final ToluzCleverConductorEffect effect) { + super(effect); + } + + @Override + public ToluzCleverConductorEffect copy() { + return new ToluzCleverConductorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter() - 1)); + return player != null + && exileZone != null + && !exileZone.isEmpty() + && player.moveCards(exileZone, Zone.HAND, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TombstoneStairwell.java b/Mage.Sets/src/mage/cards/t/TombstoneStairwell.java index 5f70fdb1803..a4ebffdc6b9 100644 --- a/Mage.Sets/src/mage/cards/t/TombstoneStairwell.java +++ b/Mage.Sets/src/mage/cards/t/TombstoneStairwell.java @@ -20,7 +20,6 @@ import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; @@ -92,7 +91,7 @@ class TombstoneStairwellCreateTokenEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); - int creatureCardsInGraveyard = player.getGraveyard().count(StaticFilters.FILTER_CARD_CREATURE, source.getControllerId(), source.getSourceId(), game); + int creatureCardsInGraveyard = player.getGraveyard().count(StaticFilters.FILTER_CARD_CREATURE, source.getSourceId(), source, game); token.putOntoBattlefield(creatureCardsInGraveyard, game, source, playerId); for (UUID tokenId : token.getLastAddedTokenIds()) { tokensCreated.add(tokenId); diff --git a/Mage.Sets/src/mage/cards/t/TomikDistinguishedAdvokist.java b/Mage.Sets/src/mage/cards/t/TomikDistinguishedAdvokist.java index 2250dea4f3d..6fa4f7d41f1 100644 --- a/Mage.Sets/src/mage/cards/t/TomikDistinguishedAdvokist.java +++ b/Mage.Sets/src/mage/cards/t/TomikDistinguishedAdvokist.java @@ -11,10 +11,10 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.FilterObject; import mage.filter.FilterStackObject; import mage.filter.StaticFilters; -import mage.filter.predicate.Predicate; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -28,6 +28,12 @@ import java.util.UUID; */ public final class TomikDistinguishedAdvokist extends CardImpl { + private static final FilterStackObject filter = new FilterStackObject(); + + static { + filter.add(TargetedByOpponentsPredicate.instance); + } + public TomikDistinguishedAdvokist(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}"); @@ -41,8 +47,6 @@ public final class TomikDistinguishedAdvokist extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Lands on the battlefield and land cards in graveyards can't be the targets of spells or abilities your opponents control. - FilterObject filter = new FilterStackObject(); - filter.add(new TargetedByOpponentsPredicate(this.getId())); Ability ability = new SimpleStaticAbility(new CantBeTargetedAllEffect( StaticFilters.FILTER_LANDS, filter, Duration.WhileOnBattlefield ).setText("lands on the battlefield")); @@ -63,18 +67,13 @@ public final class TomikDistinguishedAdvokist extends CardImpl { } } -class TargetedByOpponentsPredicate implements Predicate { - - private final UUID sourceId; - - public TargetedByOpponentsPredicate(UUID sourceId) { - this.sourceId = sourceId; - } +enum TargetedByOpponentsPredicate implements ObjectSourcePlayerPredicate { + instance; @Override - public boolean apply(MageObject input, Game game) { - StackObject stackObject = game.getStack().getStackObject(input.getId()); - Permanent source = game.getPermanentOrLKIBattlefield(this.sourceId); + public boolean apply(ObjectSourcePlayer input, Game game) { + StackObject stackObject = game.getStack().getStackObject(input.getObject().getId()); + Permanent source = input.getSource().getSourcePermanentOrLKI(game); if (stackObject != null && source != null) { Player controller = game.getPlayer(source.getControllerId()); return controller != null && game.isOpponent(controller, stackObject.getControllerId()); diff --git a/Mage.Sets/src/mage/cards/t/TomorrowAzamisFamiliar.java b/Mage.Sets/src/mage/cards/t/TomorrowAzamisFamiliar.java index 97c9c3284ce..a054f43c034 100644 --- a/Mage.Sets/src/mage/cards/t/TomorrowAzamisFamiliar.java +++ b/Mage.Sets/src/mage/cards/t/TomorrowAzamisFamiliar.java @@ -1,17 +1,15 @@ - package mage.cards.t; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.FilterCard; import mage.game.Game; import mage.game.events.GameEvent; @@ -30,7 +28,7 @@ public final class TomorrowAzamisFamiliar extends CardImpl { this.toughness = new MageInt(5); // If you would draw a card, look at the top three cards of your library instead. Put one of those cards into your hand and the rest on the bottom of your library in any order. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TomorrowAzamisFamiliarReplacementEffect())); + this.addAbility(new SimpleStaticAbility(new TomorrowAzamisFamiliarReplacementEffect())); } private TomorrowAzamisFamiliar(final TomorrowAzamisFamiliar card) { @@ -66,8 +64,7 @@ class TomorrowAzamisFamiliarReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - new LookLibraryAndPickControllerEffect(StaticValue.get(3), false, StaticValue.get(1), new FilterCard(), Zone.LIBRARY, false, false) - .apply(game, source); + new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.BOTTOM_ANY).apply(game, source); return true; } diff --git a/Mage.Sets/src/mage/cards/t/ToothAndNail.java b/Mage.Sets/src/mage/cards/t/ToothAndNail.java index cd1ef626fe6..bb44783db2b 100644 --- a/Mage.Sets/src/mage/cards/t/ToothAndNail.java +++ b/Mage.Sets/src/mage/cards/t/ToothAndNail.java @@ -32,8 +32,7 @@ public final class ToothAndNail extends CardImpl { // Search your library for up to two creature cards, reveal them, put them into your hand, then shuffle your library; this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0, 2, StaticFilters.FILTER_CARD_CREATURES), true)); // or put up to two creature cards from your hand onto the battlefield. - Mode mode = new Mode(); - mode.addEffect(new ToothAndNailPutCreatureOnBattlefieldEffect()); + Mode mode = new Mode(new ToothAndNailPutCreatureOnBattlefieldEffect()); this.getSpellAbility().getModes().addMode(mode); // Entwine {2} @@ -74,7 +73,7 @@ class ToothAndNailPutCreatureOnBattlefieldEffect extends OneShotEffect { } TargetCardInHand target = new TargetCardInHand(0, 2, new FilterCreatureCard("creature cards")); - if (controller.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCreatureInPlay, target, source, game)) { return controller.moveCards(new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, source, game, false, false, false, null); } diff --git a/Mage.Sets/src/mage/cards/t/TopiaryStomper.java b/Mage.Sets/src/mage/cards/t/TopiaryStomper.java new file mode 100644 index 00000000000..ee29daeb826 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TopiaryStomper.java @@ -0,0 +1,64 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.effects.common.combat.CantAttackBlockUnlessConditionSourceEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.hint.common.LandsYouControlHint; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledLandPermanent; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TopiaryStomper extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledLandPermanent("you control seven or more lands"); + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 6); + + public TopiaryStomper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{G}"); + + this.subtype.add(SubType.PLANT); + this.subtype.add(SubType.DINOSAUR); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // When Topiary Stomper enters the battlefield, search your library for a basic land card, put it onto the battlefield tapped, then shuffle. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInPlayEffect( + new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true + ))); + + // Topiary Stomper can't attack or block unless you control seven or more lands. + this.addAbility(new SimpleStaticAbility( + new CantAttackBlockUnlessConditionSourceEffect(condition) + ).addHint(LandsYouControlHint.instance)); + } + + private TopiaryStomper(final TopiaryStomper card) { + super(card); + } + + @Override + public TopiaryStomper copy() { + return new TopiaryStomper(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/Topple.java b/Mage.Sets/src/mage/cards/t/Topple.java index e7e7afef9ef..752823f9b33 100644 --- a/Mage.Sets/src/mage/cards/t/Topple.java +++ b/Mage.Sets/src/mage/cards/t/Topple.java @@ -53,7 +53,7 @@ class ToppleTargetCreature extends TargetCreaturePermanent { public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { if (super.canTarget(controllerId, id, source, game)) { int maxPower = 0; - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (permanent.getPower().getValue() > maxPower) { maxPower = permanent.getPower().getValue(); } @@ -67,11 +67,11 @@ class ToppleTargetCreature extends TargetCreaturePermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { int maxPower = 0; - List activePermanents = game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game); + List activePermanents = game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game); Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); if(targetSource == null){ return possibleTargets; } @@ -91,8 +91,8 @@ class ToppleTargetCreature extends TargetCreaturePermanent { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - return !possibleTargets(sourceId, sourceControllerId, game).isEmpty(); + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + return !possibleTargets(sourceControllerId, source, game).isEmpty(); } @Override diff --git a/Mage.Sets/src/mage/cards/t/TorchBreath.java b/Mage.Sets/src/mage/cards/t/TorchBreath.java new file mode 100644 index 00000000000..e3ec989f658 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TorchBreath.java @@ -0,0 +1,59 @@ +package mage.cards.t; + +import mage.ObjectColor; +import mage.abilities.common.CantBeCounteredSourceAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceTargetsPermanentCondition; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TorchBreath extends CardImpl { + + private static final FilterPermanent filter + = new FilterPermanent("a blue permanent"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLUE)); + } + + private static final Condition condition = new SourceTargetsPermanentCondition(filter); + + public TorchBreath(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{R}"); + + // This spell costs {2} less to cast if it targets a blue permanent. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SpellCostReductionSourceEffect(2, condition).setCanWorksOnStackOnly(true) + ).setRuleAtTheTop(true)); + + // This spell can't be countered. + this.addAbility(new CantBeCounteredSourceAbility().setRuleAtTheTop(true)); + + // Torch Breath deals X damage to target creature or planeswalker. + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.REGULAR)); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + } + + private TorchBreath(final TorchBreath card) { + super(card); + } + + @Override + public TorchBreath copy() { + return new TorchBreath(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TormentOfHailfire.java b/Mage.Sets/src/mage/cards/t/TormentOfHailfire.java index 84242364d72..0b74d497d6f 100644 --- a/Mage.Sets/src/mage/cards/t/TormentOfHailfire.java +++ b/Mage.Sets/src/mage/cards/t/TormentOfHailfire.java @@ -69,7 +69,7 @@ class TormentOfHailfireEffect extends OneShotEffect { "Otherwise you have to discard a card or lose 3 life.", "Sacrifice", "Discard or life loss", source, game)) { Target target = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_NON_LAND); target.setNotTarget(true); - if (opponent.choose(outcome, target, source.getSourceId(), game)) { + if (opponent.choose(outcome, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { if (permanent.sacrifice(source, game)) { diff --git a/Mage.Sets/src/mage/cards/t/TormentOfScarabs.java b/Mage.Sets/src/mage/cards/t/TormentOfScarabs.java index 78f81a776b3..5884bfe634d 100644 --- a/Mage.Sets/src/mage/cards/t/TormentOfScarabs.java +++ b/Mage.Sets/src/mage/cards/t/TormentOfScarabs.java @@ -80,7 +80,7 @@ class TormentOfScarabsEffect extends OneShotEffect { if (permanents > 0 && enchantedPlayer.chooseUse(outcome, "Sacrifice a nonland permanent?", "Otherwise you have to discard a card or lose 3 life.", "Sacrifice", "Discard or life loss", source, game)) { Target target = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_NON_LAND); - if (enchantedPlayer.choose(outcome, target, source.getSourceId(), game)) { + if (enchantedPlayer.choose(outcome, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.sacrifice(source, game); diff --git a/Mage.Sets/src/mage/cards/t/TormentOfVenom.java b/Mage.Sets/src/mage/cards/t/TormentOfVenom.java index 797b13f2f85..8a6e2bab259 100644 --- a/Mage.Sets/src/mage/cards/t/TormentOfVenom.java +++ b/Mage.Sets/src/mage/cards/t/TormentOfVenom.java @@ -76,7 +76,7 @@ class TormentOfVenomEffect extends OneShotEffect { filter.add(Predicates.not(CardType.LAND.getPredicate())); filter.add(Predicates.not(new PermanentIdPredicate(targetCreature.getId()))); Target target = new TargetPermanent(filter); - if (controllingPlayer.choose(outcome, target, source.getSourceId(), game)) { + if (controllingPlayer.choose(outcome, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.sacrifice(source, game); diff --git a/Mage.Sets/src/mage/cards/t/TormentorExarch.java b/Mage.Sets/src/mage/cards/t/TormentorExarch.java index e005ad9d6d8..d3f8a398deb 100644 --- a/Mage.Sets/src/mage/cards/t/TormentorExarch.java +++ b/Mage.Sets/src/mage/cards/t/TormentorExarch.java @@ -30,8 +30,7 @@ public final class TormentorExarch extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(2, 0, Duration.EndOfTurn), false); ability.addTarget(new TargetCreaturePermanent()); - Mode mode = new Mode(); - mode.addEffect(new BoostTargetEffect(0, -2, Duration.EndOfTurn)); + Mode mode = new Mode(new BoostTargetEffect(0, -2, Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/t/TormentorsHelm.java b/Mage.Sets/src/mage/cards/t/TormentorsHelm.java index f29690f44bd..a5d37895ecf 100644 --- a/Mage.Sets/src/mage/cards/t/TormentorsHelm.java +++ b/Mage.Sets/src/mage/cards/t/TormentorsHelm.java @@ -68,7 +68,7 @@ class TormentorsHelmTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.BLOCKER_DECLARED; + return event.getType() == GameEvent.EventType.CREATURE_BLOCKED; } @Override @@ -79,7 +79,7 @@ class TormentorsHelmTriggeredAbility extends TriggeredAbilityImpl { if (creature != null && creature.getId().equals(event.getTargetId())) { this.getEffects().clear(); TormentorsHelmEffect effect = new TormentorsHelmEffect(creature.getId()); - effect.setTargetPointer(new FixedTarget(event.getPlayerId(), game)); + effect.setTargetPointer(new FixedTarget(game.getCombat().getDefendingPlayerId(creature.getId(), game))); this.addEffect(effect); return true; } diff --git a/Mage.Sets/src/mage/cards/t/TorporOrb.java b/Mage.Sets/src/mage/cards/t/TorporOrb.java index 0307fa147ab..3b046deaf19 100644 --- a/Mage.Sets/src/mage/cards/t/TorporOrb.java +++ b/Mage.Sets/src/mage/cards/t/TorporOrb.java @@ -73,7 +73,7 @@ class TorporOrbEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { MageObject enteringObject = game.getObject(event.getSourceId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Ability ability = (Ability) getValue("targetAbility"); if (enteringObject != null && sourceObject != null && ability != null) { MageObject abilitObject = game.getObject(ability.getSourceId()); diff --git a/Mage.Sets/src/mage/cards/t/TorrentOfSouls.java b/Mage.Sets/src/mage/cards/t/TorrentOfSouls.java index 066a935d58b..28dd0af542d 100644 --- a/Mage.Sets/src/mage/cards/t/TorrentOfSouls.java +++ b/Mage.Sets/src/mage/cards/t/TorrentOfSouls.java @@ -44,7 +44,7 @@ public final class TorrentOfSouls extends CardImpl { new ManaWasSpentCondition(ColoredManaSymbol.B), "Return up to one target creature card from your graveyard to the battlefield if {B} was spent to cast this spell")); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new TorrentOfSoulsEffect(), - new ManaWasSpentCondition(ColoredManaSymbol.R), " Creatures target player controls get +2/+0 and gain haste until end of turn if {R} was spent to cast this spell")); + new ManaWasSpentCondition(ColoredManaSymbol.R), "Creatures target player controls get +2/+0 and gain haste until end of turn if {R} was spent to cast this spell")); this.getSpellAbility().addTarget(targetCreature); this.getSpellAbility().addTarget(targetPlayer); diff --git a/Mage.Sets/src/mage/cards/t/TorrentSculptor.java b/Mage.Sets/src/mage/cards/t/TorrentSculptor.java index fa325a67759..17aaa98cc16 100644 --- a/Mage.Sets/src/mage/cards/t/TorrentSculptor.java +++ b/Mage.Sets/src/mage/cards/t/TorrentSculptor.java @@ -89,7 +89,7 @@ class TorrentSculptorEffect extends OneShotEffect { } TargetCard targetCard = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY); targetCard.setNotTarget(true); - player.choose(Outcome.Exile, targetCard, source.getSourceId(), game); + player.choose(Outcome.Exile, targetCard, source, game); Card card = game.getCard(targetCard.getFirstTarget()); if (card == null) { return false; diff --git a/Mage.Sets/src/mage/cards/t/TortoiseFormation.java b/Mage.Sets/src/mage/cards/t/TortoiseFormation.java index 06be216742a..e8a527ac1a9 100644 --- a/Mage.Sets/src/mage/cards/t/TortoiseFormation.java +++ b/Mage.Sets/src/mage/cards/t/TortoiseFormation.java @@ -21,7 +21,7 @@ public final class TortoiseFormation extends CardImpl { // Creatures you control gain shroud until end of turn. this.getSpellAbility().addEffect(new GainAbilityControlledEffect( ShroudAbility.getInstance(), Duration.EndOfTurn, - StaticFilters.FILTER_CONTROLLED_CREATURES + StaticFilters.FILTER_PERMANENT_CREATURES )); } diff --git a/Mage.Sets/src/mage/cards/t/Torture.java b/Mage.Sets/src/mage/cards/t/Torture.java index fb213678f0b..da01c582efa 100644 --- a/Mage.Sets/src/mage/cards/t/Torture.java +++ b/Mage.Sets/src/mage/cards/t/Torture.java @@ -40,7 +40,7 @@ public final class Torture extends CardImpl { this.addAbility(ability); // {1}{B}: Put a -1/-1 counter on enchanted creature. - //this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersAttachedEffect(CounterType.M1M1.createInstance(), rule), new ManaCostsImpl("[1}{B}"))); + //this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersAttachedEffect(CounterType.M1M1.createInstance(), rule), new ManaCostsImpl<>("{[1}{B}}"))); this.addAbility(new SimpleActivatedAbility( Zone.BATTLEFIELD, new AddCountersAttachedEffect(CounterType.M1M1.createInstance(),"enchanted creature"), diff --git a/Mage.Sets/src/mage/cards/t/TotemGuideHartebeest.java b/Mage.Sets/src/mage/cards/t/TotemGuideHartebeest.java index fbb597854c1..7a3883cdf01 100644 --- a/Mage.Sets/src/mage/cards/t/TotemGuideHartebeest.java +++ b/Mage.Sets/src/mage/cards/t/TotemGuideHartebeest.java @@ -33,7 +33,7 @@ public final class TotemGuideHartebeest extends CardImpl { this.toughness = new MageInt(5); // When Totem-Guide Hartebeest enters the battlefield, you may search your library for an Aura card, reveal it, put it into your hand, then shuffle your library. - this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true, false), true)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true, true), true)); } private TotemGuideHartebeest(final TotemGuideHartebeest card) { diff --git a/Mage.Sets/src/mage/cards/t/TourachsChant.java b/Mage.Sets/src/mage/cards/t/TourachsChant.java index a5319bf86f6..0dc26eb98e7 100644 --- a/Mage.Sets/src/mage/cards/t/TourachsChant.java +++ b/Mage.Sets/src/mage/cards/t/TourachsChant.java @@ -75,7 +75,7 @@ class TourachsChantEffect extends OneShotEffect { 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)) { + && player.choose(Outcome.UnboostCreature, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanent.addCounters(CounterType.M1M1.createInstance(), player.getId(), source, game); diff --git a/Mage.Sets/src/mage/cards/t/TovolarDireOverlord.java b/Mage.Sets/src/mage/cards/t/TovolarDireOverlord.java index 6ec93b9729e..4af27bafbf5 100644 --- a/Mage.Sets/src/mage/cards/t/TovolarDireOverlord.java +++ b/Mage.Sets/src/mage/cards/t/TovolarDireOverlord.java @@ -111,7 +111,7 @@ class TovolarDireOverlordEffect extends OneShotEffect { return true; } TargetPermanent target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); - player.choose(outcome, target, source.getControllerId(), game); + player.choose(outcome, target, source, game); for (UUID permanentId : target.getTargets()) { Permanent permanent = game.getPermanent(permanentId); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/t/TovolarsPackleader.java b/Mage.Sets/src/mage/cards/t/TovolarsPackleader.java index 22f9b010bf5..de4fc98fa8e 100644 --- a/Mage.Sets/src/mage/cards/t/TovolarsPackleader.java +++ b/Mage.Sets/src/mage/cards/t/TovolarsPackleader.java @@ -58,6 +58,7 @@ public final class TovolarsPackleader extends CardImpl { ), new ManaCostsImpl<>("{2}{G}{G}")); ability.addTarget(new TargetPermanent(filter)); ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL)); + this.addAbility(ability); // Nightbound this.addAbility(new NightboundAbility()); diff --git a/Mage.Sets/src/mage/cards/t/TowashiGuideBot.java b/Mage.Sets/src/mage/cards/t/TowashiGuideBot.java index 27ddb16b728..051da5a6ccc 100644 --- a/Mage.Sets/src/mage/cards/t/TowashiGuideBot.java +++ b/Mage.Sets/src/mage/cards/t/TowashiGuideBot.java @@ -83,7 +83,7 @@ enum TowashiGuideBotAdjuster implements CostAdjuster { @Override public void adjustCosts(Ability ability, Game game) { CardUtil.reduceCost(ability, game.getBattlefield().count( - filter, ability.getSourceId(), ability.getControllerId(), game + filter, ability.getControllerId(), ability, game )); } } diff --git a/Mage.Sets/src/mage/cards/t/TowerAbove.java b/Mage.Sets/src/mage/cards/t/TowerAbove.java index 835602e56f7..3a3af4b74c7 100644 --- a/Mage.Sets/src/mage/cards/t/TowerAbove.java +++ b/Mage.Sets/src/mage/cards/t/TowerAbove.java @@ -52,7 +52,7 @@ class TowerAboveEffect extends OneShotEffect { public TowerAboveEffect() { super(Outcome.BoostCreature); - staticText = "Until end of turn, target creature gets +4/+4 and gains trample, wither, and \"When this creature attacks, target creature blocks it this turn if able."; + staticText = "Until end of turn, target creature gets +4/+4 and gains trample, wither, and \"When this creature attacks, target creature blocks it this turn if able.\""; } public TowerAboveEffect(final TowerAboveEffect effect) { diff --git a/Mage.Sets/src/mage/cards/t/TowerGeist.java b/Mage.Sets/src/mage/cards/t/TowerGeist.java index 05a0d666c27..1e6b89582e6 100644 --- a/Mage.Sets/src/mage/cards/t/TowerGeist.java +++ b/Mage.Sets/src/mage/cards/t/TowerGeist.java @@ -32,15 +32,13 @@ package mage.cards.t; import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.FilterCard; /** * @@ -58,9 +56,10 @@ public final class TowerGeist extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - // When Tower Geist enters the battlefield, look at the top two cards of your library. Put one of them into your hand and the other into your graveyard. + // When Tower Geist enters the battlefield, look at the top two cards of your library. + // Put one of them into your hand and the other into your graveyard. this.addAbility(new EntersBattlefieldTriggeredAbility( - new LookLibraryAndPickControllerEffect(StaticValue.get(2), false, StaticValue.get(1), new FilterCard(), Zone.GRAVEYARD, false, false))); + new LookLibraryAndPickControllerEffect(2, 1, PutCards.HAND, PutCards.GRAVEYARD))); } private TowerGeist(final TowerGeist card) { diff --git a/Mage.Sets/src/mage/cards/t/ToweringBaloth.java b/Mage.Sets/src/mage/cards/t/ToweringBaloth.java index a11b5876eb1..115a8bf9d35 100644 --- a/Mage.Sets/src/mage/cards/t/ToweringBaloth.java +++ b/Mage.Sets/src/mage/cards/t/ToweringBaloth.java @@ -23,7 +23,7 @@ public final class ToweringBaloth extends CardImpl { this.toughness = new MageInt(6); // Morph {6}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{6}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{6}{G}"))); } private ToweringBaloth(final ToweringBaloth card) { diff --git a/Mage.Sets/src/mage/cards/t/ToweringTitan.java b/Mage.Sets/src/mage/cards/t/ToweringTitan.java index 777e7118a34..4b1549af15d 100644 --- a/Mage.Sets/src/mage/cards/t/ToweringTitan.java +++ b/Mage.Sets/src/mage/cards/t/ToweringTitan.java @@ -80,7 +80,7 @@ enum ToweringTitanCount implements DynamicValue { return game.getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, - sourceAbility.getControllerId(), sourceAbility.getSourceId(), game + sourceAbility.getControllerId(), sourceAbility, game ).stream() .filter(Objects::nonNull) .map(MageObject::getToughness) diff --git a/Mage.Sets/src/mage/cards/t/TownSentry.java b/Mage.Sets/src/mage/cards/t/TownSentry.java index 3bd3e75d021..1e9d4c239fb 100644 --- a/Mage.Sets/src/mage/cards/t/TownSentry.java +++ b/Mage.Sets/src/mage/cards/t/TownSentry.java @@ -1,4 +1,3 @@ - package mage.cards.t; import java.util.UUID; @@ -8,8 +7,8 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; /** * @@ -25,7 +24,7 @@ public final class TownSentry extends CardImpl { this.toughness = new MageInt(2); // Whenever Town Sentry blocks, it gets +0/+2 until end of turn. - this.addAbility(new BlocksSourceTriggeredAbility(new BoostSourceEffect(0, 2, Duration.EndOfTurn), false)); + this.addAbility(new BlocksSourceTriggeredAbility(new BoostSourceEffect(0, 2, Duration.EndOfTurn, "it"))); } private TownSentry(final TownSentry card) { diff --git a/Mage.Sets/src/mage/cards/t/ToxrillTheCorrosive.java b/Mage.Sets/src/mage/cards/t/ToxrillTheCorrosive.java index 18b469e1022..cb6ad9ee7b6 100644 --- a/Mage.Sets/src/mage/cards/t/ToxrillTheCorrosive.java +++ b/Mage.Sets/src/mage/cards/t/ToxrillTheCorrosive.java @@ -102,7 +102,7 @@ class ToxrillTheCorrosiveEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { for (Permanent permanent : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game )) { int counter = permanent.getCounters(game).getCount(CounterType.SLIME); permanent.getPower().boostValue(-counter); diff --git a/Mage.Sets/src/mage/cards/t/TrackDown.java b/Mage.Sets/src/mage/cards/t/TrackDown.java index 9b0ac81b092..5010afc1013 100644 --- a/Mage.Sets/src/mage/cards/t/TrackDown.java +++ b/Mage.Sets/src/mage/cards/t/TrackDown.java @@ -57,7 +57,7 @@ class TrackDownEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject == null || controller == null) { return false; diff --git a/Mage.Sets/src/mage/cards/t/TrackersInstincts.java b/Mage.Sets/src/mage/cards/t/TrackersInstincts.java index a224dec3fec..55591bf01dd 100644 --- a/Mage.Sets/src/mage/cards/t/TrackersInstincts.java +++ b/Mage.Sets/src/mage/cards/t/TrackersInstincts.java @@ -1,29 +1,18 @@ - package mage.cards.t; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.effects.common.RevealLibraryPickControllerEffect; import mage.abilities.keyword.FlashbackAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.TimingRule; -import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreatureCard; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; /** * - * @author North + * @author awjackson */ public final class TrackersInstincts extends CardImpl { @@ -31,7 +20,9 @@ public final class TrackersInstincts extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); // Reveal the top four cards of your library. Put a creature card from among them into your hand and the rest into your graveyard. - this.getSpellAbility().addEffect(new TrackersInstinctsEffect()); + this.getSpellAbility().addEffect(new RevealLibraryPickControllerEffect( + 4, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.GRAVEYARD, false)); + // Flashback {2}{U} this.addAbility(new FlashbackAbility(this, new ManaCostsImpl("{2}{U}"))); } @@ -45,43 +36,3 @@ public final class TrackersInstincts extends CardImpl { return new TrackersInstincts(this); } } - -class TrackersInstinctsEffect extends OneShotEffect { - - public TrackersInstinctsEffect() { - super(Outcome.DrawCard); - this.staticText = "Reveal the top four cards of your library. Put a creature card from among them into your hand and the rest into your graveyard"; - } - - public TrackersInstinctsEffect(final TrackersInstinctsEffect effect) { - super(effect); - } - - @Override - public TrackersInstinctsEffect copy() { - return new TrackersInstinctsEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 4)); - boolean creaturesFound = cards.count(StaticFilters.FILTER_CARD_CREATURE, game) > 0; - if (!cards.isEmpty()) { - controller.revealCards(source, cards, game); - TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCreatureCard("creature card to put in hand")); - if (creaturesFound && controller.choose(Outcome.DrawCard, cards, target, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - controller.moveCards(card, Zone.HAND, source, game); - cards.remove(card); - } - } - controller.moveCards(cards, Zone.GRAVEYARD, source, game); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/t/TragicArrogance.java b/Mage.Sets/src/mage/cards/t/TragicArrogance.java index 23b9dab4b99..f9d6b720a61 100644 --- a/Mage.Sets/src/mage/cards/t/TragicArrogance.java +++ b/Mage.Sets/src/mage/cards/t/TragicArrogance.java @@ -85,7 +85,7 @@ class TragicArroganceffect extends OneShotEffect { filterPlaneswalkerPermanent.add(new ControllerIdPredicate(playerId)); Target target4 = new TargetPermanent(1, 1, filterPlaneswalkerPermanent, true); - if (target1.canChoose(source.getSourceId(), controller.getId(), game)) { + if (target1.canChoose(controller.getId(), source, game)) { controller.chooseTarget(Outcome.Benefit, target1, source, game); Permanent artifact = game.getPermanent(target1.getFirstTarget()); if (artifact != null) { @@ -94,7 +94,7 @@ class TragicArroganceffect extends OneShotEffect { target1.clearChosen(); } - if (target2.canChoose(source.getSourceId(), controller.getId(), game)) { + if (target2.canChoose(controller.getId(), source, game)) { controller.chooseTarget(Outcome.Benefit, target2, source, game); Permanent creature = game.getPermanent(target2.getFirstTarget()); if (creature != null) { @@ -103,7 +103,7 @@ class TragicArroganceffect extends OneShotEffect { target2.clearChosen(); } - if (target3.canChoose(source.getSourceId(), controller.getId(), game)) { + if (target3.canChoose(controller.getId(), source, game)) { controller.chooseTarget(Outcome.Benefit, target3, source, game); Permanent enchantment = game.getPermanent(target3.getFirstTarget()); if (enchantment != null) { @@ -112,7 +112,7 @@ class TragicArroganceffect extends OneShotEffect { target3.clearChosen(); } - if (target4.canChoose(source.getSourceId(), controller.getId(), game)) { + if (target4.canChoose(controller.getId(), source, game)) { controller.chooseTarget(Outcome.Benefit, target4, source, game); Permanent planeswalker = game.getPermanent(target4.getFirstTarget()); if (planeswalker != null) { diff --git a/Mage.Sets/src/mage/cards/t/TrailOfCrumbs.java b/Mage.Sets/src/mage/cards/t/TrailOfCrumbs.java index 707eaa50630..7639faa551e 100644 --- a/Mage.Sets/src/mage/cards/t/TrailOfCrumbs.java +++ b/Mage.Sets/src/mage/cards/t/TrailOfCrumbs.java @@ -6,13 +6,13 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.common.FilterPermanentCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -31,7 +31,9 @@ public final class TrailOfCrumbs extends CardImpl { // When Trail of Crumbs enters the battlefield, create a Food token. this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new FoodToken()))); - // Whenever you sacrifice a Food, you may pay {1}. If you do, look at the top two cards of your library. You may reveal a permanent card from among them and put it into your hand. Put the rest on the bottom of your library in any order. + // Whenever you sacrifice a Food, you may pay {1}. If you do, look at the top two cards of your library. + // You may reveal a permanent card from among them and put it into your hand. + // Put the rest on the bottom of your library in any order. this.addAbility(new TrailOfCrumbsTriggeredAbility()); } @@ -47,11 +49,9 @@ public final class TrailOfCrumbs extends CardImpl { class TrailOfCrumbsTriggeredAbility extends TriggeredAbilityImpl { - private static final FilterCard filter = new FilterPermanentCard(); - TrailOfCrumbsTriggeredAbility() { super(Zone.BATTLEFIELD, new DoIfCostPaid(new LookLibraryAndPickControllerEffect( - 2, 1, filter, true, true, Zone.HAND, true + 2, 1, StaticFilters.FILTER_CARD_PERMANENT, PutCards.HAND, PutCards.BOTTOM_ANY ), new GenericManaCost(1))); } @@ -78,9 +78,7 @@ class TrailOfCrumbsTriggeredAbility extends TriggeredAbilityImpl { } @Override - public String getRule() { - return "Whenever you sacrifice a Food, you may pay {1}. If you do, " + - "look at the top two cards of your library. You may reveal a permanent card from among them " + - "and put it into your hand. Put the rest on the bottom of your library in any order."; + public String getTriggerPhrase() { + return "Whenever you sacrifice a Food, "; } } diff --git a/Mage.Sets/src/mage/cards/t/TrainOfThought.java b/Mage.Sets/src/mage/cards/t/TrainOfThought.java index 59e39d6f44e..e4722438cb0 100644 --- a/Mage.Sets/src/mage/cards/t/TrainOfThought.java +++ b/Mage.Sets/src/mage/cards/t/TrainOfThought.java @@ -19,7 +19,7 @@ public final class TrainOfThought extends CardImpl { // Replicate {1}{U} - this.addAbility(new ReplicateAbility(this, "{1}{U}")); + this.addAbility(new ReplicateAbility("{1}{U}")); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); diff --git a/Mage.Sets/src/mage/cards/t/TraitorsClutch.java b/Mage.Sets/src/mage/cards/t/TraitorsClutch.java index 50b5d830ef7..28e7f437960 100644 --- a/Mage.Sets/src/mage/cards/t/TraitorsClutch.java +++ b/Mage.Sets/src/mage/cards/t/TraitorsClutch.java @@ -1,10 +1,7 @@ - package mage.cards.t; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BecomesColorTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; @@ -14,31 +11,32 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.TimingRule; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class TraitorsClutch extends CardImpl { public TraitorsClutch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{4}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{B}"); // Target creature gets +1/+0, becomes black, and gains shadow until end of turn. - this.getSpellAbility().addEffect(new BoostTargetEffect(1,0, Duration.EndOfTurn)); - Effect effect = new BecomesColorTargetEffect(ObjectColor.BLACK, Duration.EndOfTurn); - effect.setText(", becomes black"); - this.getSpellAbility().addEffect(effect); - effect = new GainAbilityTargetEffect(ShadowAbility.getInstance(), Duration.EndOfTurn); - effect.setText(", and gains shadow until end of turn"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new BoostTargetEffect( + 1, 0, Duration.EndOfTurn + ).setText("target creature gets +1/+0")); + this.getSpellAbility().addEffect(new BecomesColorTargetEffect( + ObjectColor.BLACK, Duration.EndOfTurn + ).setText(", becomes black")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + ShadowAbility.getInstance(), Duration.EndOfTurn + ).setText(", and gains shadow until end of turn")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Flashback {1}{B} - this.addAbility(new FlashbackAbility(this, new ManaCostsImpl("{1}{B}"))); + this.addAbility(new FlashbackAbility(this, new ManaCostsImpl<>("{1}{B}"))); } private TraitorsClutch(final TraitorsClutch card) { diff --git a/Mage.Sets/src/mage/cards/t/TraitorsRoar.java b/Mage.Sets/src/mage/cards/t/TraitorsRoar.java index 387646e7765..d789661e71b 100644 --- a/Mage.Sets/src/mage/cards/t/TraitorsRoar.java +++ b/Mage.Sets/src/mage/cards/t/TraitorsRoar.java @@ -35,7 +35,7 @@ public final class TraitorsRoar extends CardImpl { this.getSpellAbility().addEffect(new TraitorsRoarEffect()); // Conspire - this.addAbility(new ConspireAbility(getId(), ConspireAbility.ConspireTargets.ONE)); + this.addAbility(new ConspireAbility(ConspireAbility.ConspireTargets.ONE)); } diff --git a/Mage.Sets/src/mage/cards/t/TramwayStation.java b/Mage.Sets/src/mage/cards/t/TramwayStation.java new file mode 100644 index 00000000000..2a5f212edf6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TramwayStation.java @@ -0,0 +1,50 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; +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.DrawCardSourceControllerEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TramwayStation extends CardImpl { + + public TramwayStation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Tramway Station enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {B} or {R}. + this.addAbility(new BlackManaAbility()); + this.addAbility(new RedManaAbility()); + + // {2}{B}{R}, {T}, Sacrifice Tramway Station: Draw a card. + Ability ability = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{2}{B}{R}") + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private TramwayStation(final TramwayStation card) { + super(card); + } + + @Override + public TramwayStation copy() { + return new TramwayStation(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/Traumatize.java b/Mage.Sets/src/mage/cards/t/Traumatize.java index 9424480ae73..775d1ddd724 100644 --- a/Mage.Sets/src/mage/cards/t/Traumatize.java +++ b/Mage.Sets/src/mage/cards/t/Traumatize.java @@ -1,18 +1,14 @@ package mage.cards.t; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.MillHalfLibraryTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.game.Game; -import mage.players.Player; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public final class Traumatize extends CardImpl { @@ -21,7 +17,7 @@ public final class Traumatize extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}{U}"); this.getSpellAbility().addTarget(new TargetPlayer()); - this.getSpellAbility().addEffect(new TraumatizeEffect()); + this.getSpellAbility().addEffect(new MillHalfLibraryTargetEffect(false)); } private Traumatize(final Traumatize card) { @@ -33,32 +29,3 @@ public final class Traumatize extends CardImpl { return new Traumatize(this); } } - -class TraumatizeEffect extends OneShotEffect { - - public TraumatizeEffect() { - super(Outcome.Detriment); - staticText = "Target player mills half their library, rounded down"; - } - - public TraumatizeEffect(final TraumatizeEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getFirstTarget()); - if (player != null) { - int amount = player.getLibrary().size() / 2; - player.millCards(amount, source, game); - return true; - } - return false; - } - - @Override - public TraumatizeEffect copy() { - return new TraumatizeEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/t/TravelingPlague.java b/Mage.Sets/src/mage/cards/t/TravelingPlague.java index 4683e2f5df7..3475406f8ae 100644 --- a/Mage.Sets/src/mage/cards/t/TravelingPlague.java +++ b/Mage.Sets/src/mage/cards/t/TravelingPlague.java @@ -133,7 +133,7 @@ class TravelingPlagueEffect extends OneShotEffect { && controllerOfEnchantedCreature != null) { TargetPermanent target = new TargetPermanent(new FilterCreaturePermanent("creature to enchant with " + travelingPlague.getName())); target.setNotTarget(true); - if (controllerOfEnchantedCreature.choose(Outcome.Detriment, target, source.getSourceId(), game)) { + if (controllerOfEnchantedCreature.choose(Outcome.Detriment, target, source, game)) { Permanent targetPermanent = game.getPermanent(target.getFirstTarget()); if (!targetPermanent.cantBeAttachedBy(travelingPlague, source, game, false)) { game.getState().setValue("attachTo:" + travelingPlague.getId(), targetPermanent); diff --git a/Mage.Sets/src/mage/cards/t/TraverseTheUlvenwald.java b/Mage.Sets/src/mage/cards/t/TraverseTheUlvenwald.java index 865a23dffbd..3f1bf860b31 100644 --- a/Mage.Sets/src/mage/cards/t/TraverseTheUlvenwald.java +++ b/Mage.Sets/src/mage/cards/t/TraverseTheUlvenwald.java @@ -1,16 +1,14 @@ package mage.cards.t; -import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.hint.common.CardTypesInGraveyardHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.filter.FilterCard; import mage.filter.StaticFilters; -import mage.filter.predicate.Predicates; import mage.target.common.TargetCardInLibrary; import java.util.UUID; @@ -20,29 +18,19 @@ import java.util.UUID; */ public final class TraverseTheUlvenwald extends CardImpl { - private static final FilterCard filter = new FilterCard("a creature or land card"); - - static { - filter.add(Predicates.or(CardType.CREATURE.getPredicate(), CardType.LAND.getPredicate())); - } + private static final String rule = "Search your library for a basic land card, reveal it, put it into your hand, then shuffle.
" + + AbilityWord.DELIRIUM.formatWord() + "If " + DeliriumCondition.instance.toString() + + ", instead search your library for a creature or land card, reveal it, put it into your hand, then shuffle."; public TraverseTheUlvenwald(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}"); // Search your library for a basic land card, reveal it, put it into your hand, then shuffle your library. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new SearchLibraryPutInHandEffect(new TargetCardInLibrary(1, 1, StaticFilters.FILTER_CARD_CREATURE_OR_LAND), true), new SearchLibraryPutInHandEffect(new TargetCardInLibrary(1, 1, StaticFilters.FILTER_CARD_BASIC_LAND), true), - new InvertCondition(DeliriumCondition.instance), - "Search your library for a basic land card, reveal it, put it into your hand, then shuffle.")); - - // Delirium — If there are four or more card types among cards in your graveyard, instead search your library - // for a creature or land card, reveal it, put it into your hand, then shuffle your library. - this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new SearchLibraryPutInHandEffect(new TargetCardInLibrary(1, 1, filter), true), - DeliriumCondition.instance, - "
Delirium — If there are four or more card types among cards in your graveyard, instead search your library for a creature or land card, " - + "reveal it, put it into your hand, then shuffle.")); - this.getSpellAbility().addHint(CardTypesInGraveyardHint.YOU); + DeliriumCondition.instance, rule + )); } private TraverseTheUlvenwald(final TraverseTheUlvenwald card) { diff --git a/Mage.Sets/src/mage/cards/t/TreacherousTerrain.java b/Mage.Sets/src/mage/cards/t/TreacherousTerrain.java index 4fdd97b623e..6c915d0a1a9 100644 --- a/Mage.Sets/src/mage/cards/t/TreacherousTerrain.java +++ b/Mage.Sets/src/mage/cards/t/TreacherousTerrain.java @@ -54,7 +54,7 @@ class TreacherousTerrainEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - List permanents = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), source, game); for (UUID playerId : game.getOpponents(source.getControllerId())) { Player player = game.getPlayer(playerId); if (player != null) { diff --git a/Mage.Sets/src/mage/cards/t/TreacherousUrge.java b/Mage.Sets/src/mage/cards/t/TreacherousUrge.java index fc3bc48f4ce..8f1b1dd528e 100644 --- a/Mage.Sets/src/mage/cards/t/TreacherousUrge.java +++ b/Mage.Sets/src/mage/cards/t/TreacherousUrge.java @@ -68,7 +68,7 @@ class TreacherousUrgeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player opponent = game.getPlayer(targetPointer.getFirst(game, source)); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (opponent != null && sourceObject != null) { opponent.revealCards(sourceObject.getName(), opponent.getHand(), game); Player controller = game.getPlayer(source.getControllerId()); diff --git a/Mage.Sets/src/mage/cards/t/TreasureHunter.java b/Mage.Sets/src/mage/cards/t/TreasureHunter.java index 477946a1b34..f0df756c623 100644 --- a/Mage.Sets/src/mage/cards/t/TreasureHunter.java +++ b/Mage.Sets/src/mage/cards/t/TreasureHunter.java @@ -1,32 +1,31 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterArtifactCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Loki */ public final class TreasureHunter extends CardImpl { public TreasureHunter(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.power = new MageInt(2); this.toughness = new MageInt(2); - Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), true); - ability.addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), true); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TreespringLorian.java b/Mage.Sets/src/mage/cards/t/TreespringLorian.java index 395bf7d8b99..1c54d8e6146 100644 --- a/Mage.Sets/src/mage/cards/t/TreespringLorian.java +++ b/Mage.Sets/src/mage/cards/t/TreespringLorian.java @@ -23,7 +23,7 @@ public final class TreespringLorian extends CardImpl { this.toughness = new MageInt(4); // Morph {5}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{5}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{5}{G}"))); } private TreespringLorian(final TreespringLorian card) { diff --git a/Mage.Sets/src/mage/cards/t/TreetopAmbusher.java b/Mage.Sets/src/mage/cards/t/TreetopAmbusher.java index db38f1f9bf8..e02c463cc8d 100644 --- a/Mage.Sets/src/mage/cards/t/TreetopAmbusher.java +++ b/Mage.Sets/src/mage/cards/t/TreetopAmbusher.java @@ -28,7 +28,7 @@ public final class TreetopAmbusher extends CardImpl { this.toughness = new MageInt(1); // Dash {1}{G} - this.addAbility(new DashAbility(this, "{1}{G}")); + this.addAbility(new DashAbility("{1}{G}")); // Whenever Treetop Ambusher attacks, target creature you control gets +1/+1 until end of turn. Ability ability = new AttacksTriggeredAbility(new BoostTargetEffect( diff --git a/Mage.Sets/src/mage/cards/t/TrenchGorger.java b/Mage.Sets/src/mage/cards/t/TrenchGorger.java index b7f3772777a..cfc1a6f09a7 100644 --- a/Mage.Sets/src/mage/cards/t/TrenchGorger.java +++ b/Mage.Sets/src/mage/cards/t/TrenchGorger.java @@ -68,7 +68,7 @@ class TrenchGorgerEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, Integer.MAX_VALUE, new FilterLandCard("any number of land cards")); - target.choose(outcome, controller.getId(), controller.getId(), game); + target.choose(outcome, controller.getId(), controller.getId(), source, game); int count = 0; for (UUID cardId : target.getTargets()) { Card card = game.getCard(cardId); diff --git a/Mage.Sets/src/mage/cards/t/TrespassingSouleater.java b/Mage.Sets/src/mage/cards/t/TrespassingSouleater.java index 6dc1726a4ad..6457bd0c574 100644 --- a/Mage.Sets/src/mage/cards/t/TrespassingSouleater.java +++ b/Mage.Sets/src/mage/cards/t/TrespassingSouleater.java @@ -1,27 +1,24 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.PhyrexianManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.ColoredManaSymbol; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author North */ public final class TrespassingSouleater extends CardImpl { public TrespassingSouleater(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CONSTRUCT); @@ -29,9 +26,9 @@ public final class TrespassingSouleater extends CardImpl { this.toughness = new MageInt(2); // {U/P}: Trespassing Souleater can't be blocked this turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new CantBeBlockedSourceEffect(Duration.EndOfTurn), - new PhyrexianManaCost(ColoredManaSymbol.U))); + this.addAbility(new SimpleActivatedAbility( + new CantBeBlockedSourceEffect(Duration.EndOfTurn), new ManaCostsImpl<>("{U/P}") + )); } private TrespassingSouleater(final TrespassingSouleater card) { diff --git a/Mage.Sets/src/mage/cards/t/TrevaTheRenewer.java b/Mage.Sets/src/mage/cards/t/TrevaTheRenewer.java index 18f4ba1fd3c..8df3e49fe2b 100644 --- a/Mage.Sets/src/mage/cards/t/TrevaTheRenewer.java +++ b/Mage.Sets/src/mage/cards/t/TrevaTheRenewer.java @@ -78,7 +78,7 @@ class TrevaTheRenewerEffect extends OneShotEffect { game.informPlayers(controller.getLogName() + " chooses " + choice.getColor()); FilterPermanent filter = new FilterPermanent(); filter.add(new ColorPredicate(choice.getColor())); - int cardsWithColor = game.getBattlefield().count(filter, source.getSourceId(), controller.getId(), game); + int cardsWithColor = game.getBattlefield().count(filter, controller.getId(), source, game); if (cardsWithColor > 0) { new GainLifeEffect(cardsWithColor).apply(game, source); } diff --git a/Mage.Sets/src/mage/cards/t/TrevasCharm.java b/Mage.Sets/src/mage/cards/t/TrevasCharm.java index 73cec0cde97..c70e004548c 100644 --- a/Mage.Sets/src/mage/cards/t/TrevasCharm.java +++ b/Mage.Sets/src/mage/cards/t/TrevasCharm.java @@ -26,14 +26,12 @@ public final class TrevasCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetEnchantmentPermanent()); // or exile target attacking creature; - Mode mode = new Mode(); - mode.addEffect(new ExileTargetEffect()); + Mode mode = new Mode(new ExileTargetEffect()); mode.addTarget(new TargetAttackingCreature()); this.getSpellAbility().addMode(mode); // or draw a card, then discard a card. - mode = new Mode(); - mode.addEffect(new DrawDiscardControllerEffect()); + mode = new Mode(new DrawDiscardControllerEffect()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/t/TrialOfKnowledge.java b/Mage.Sets/src/mage/cards/t/TrialOfKnowledge.java index ed566e61819..0e5eceeade4 100644 --- a/Mage.Sets/src/mage/cards/t/TrialOfKnowledge.java +++ b/Mage.Sets/src/mage/cards/t/TrialOfKnowledge.java @@ -32,7 +32,7 @@ public final class TrialOfKnowledge extends CardImpl { // When a Cartouche enters the battlefield under your control, return Trial of Knowledge to its owner's hand. this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new ReturnToHandSourceEffect(), filter, - "When a Cartouche enters the battlefield under your control, return {this} to its owner's hand")); + "When a Cartouche enters the battlefield under your control, return {this} to its owner's hand.")); } private TrialOfKnowledge(final TrialOfKnowledge card) { diff --git a/Mage.Sets/src/mage/cards/t/TriassicEgg.java b/Mage.Sets/src/mage/cards/t/TriassicEgg.java index c6e283da8ff..cc46fecb016 100644 --- a/Mage.Sets/src/mage/cards/t/TriassicEgg.java +++ b/Mage.Sets/src/mage/cards/t/TriassicEgg.java @@ -45,8 +45,7 @@ public final class TriassicEgg extends CardImpl { new SourceHasCounterCondition(CounterType.HATCHLING, 2, Integer.MAX_VALUE)); // 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.addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); + Mode mode = new Mode(new ReturnFromGraveyardToBattlefieldTargetEffect()); Target target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); mode.addTarget(target); ability.addMode(mode); diff --git a/Mage.Sets/src/mage/cards/t/TribalFlames.java b/Mage.Sets/src/mage/cards/t/TribalFlames.java index dd8cebe2a19..252a4727c45 100644 --- a/Mage.Sets/src/mage/cards/t/TribalFlames.java +++ b/Mage.Sets/src/mage/cards/t/TribalFlames.java @@ -22,7 +22,7 @@ public final class TribalFlames extends CardImpl { // Domain - Tribal Flames deals X damage to any target, where X is the number of basic land types among lands you control. - this.getSpellAbility().addEffect(new DamageTargetEffect(new DomainValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(DomainValue.REGULAR)); this.getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellAbility().addHint(DomainHint.instance); this.getSpellAbility().setAbilityWord(AbilityWord.DOMAIN); diff --git a/Mage.Sets/src/mage/cards/t/TribalForcemage.java b/Mage.Sets/src/mage/cards/t/TribalForcemage.java index 5f65eaa9d05..a0efc902fe6 100644 --- a/Mage.Sets/src/mage/cards/t/TribalForcemage.java +++ b/Mage.Sets/src/mage/cards/t/TribalForcemage.java @@ -34,7 +34,7 @@ public final class TribalForcemage extends CardImpl { this.toughness = new MageInt(1); // Morph {1}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{G}"))); // When Tribal Forcemage is turned face up, creatures of the creature type of your choice get +2/+2 and gain trample until end of turn. Effect effect = new ChooseCreatureTypeEffect(Outcome.BoostCreature); diff --git a/Mage.Sets/src/mage/cards/t/TribalUnity.java b/Mage.Sets/src/mage/cards/t/TribalUnity.java index 13f1ee817e0..b14bd4f656a 100644 --- a/Mage.Sets/src/mage/cards/t/TribalUnity.java +++ b/Mage.Sets/src/mage/cards/t/TribalUnity.java @@ -59,7 +59,7 @@ class TribalUnityEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/t/TributeToHorobi.java b/Mage.Sets/src/mage/cards/t/TributeToHorobi.java index 720eae122a7..d6379f3d6ed 100644 --- a/Mage.Sets/src/mage/cards/t/TributeToHorobi.java +++ b/Mage.Sets/src/mage/cards/t/TributeToHorobi.java @@ -55,7 +55,7 @@ class TributeToHorobiTokenEffect extends OneShotEffect { public TributeToHorobiTokenEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "Each opponent creates a 1/1 black Rat Rouge creature token"; + this.staticText = "Each opponent creates a 1/1 black Rat Rogue creature token"; } private TributeToHorobiTokenEffect(final TributeToHorobiTokenEffect effect) { diff --git a/Mage.Sets/src/mage/cards/t/TributeToHunger.java b/Mage.Sets/src/mage/cards/t/TributeToHunger.java index 2ef3150c99b..297295f1b05 100644 --- a/Mage.Sets/src/mage/cards/t/TributeToHunger.java +++ b/Mage.Sets/src/mage/cards/t/TributeToHunger.java @@ -61,7 +61,7 @@ class TributeToHungerEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null && opponent != null) { TargetControlledPermanent target = new TargetControlledPermanent(1, 1, new FilterControlledCreaturePermanent(), true); - if (target.canChoose(source.getSourceId(), opponent.getId(), game)) { + if (target.canChoose(opponent.getId(), source, game)) { opponent.chooseTarget(Outcome.Sacrifice, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/t/TrickeryCharm.java b/Mage.Sets/src/mage/cards/t/TrickeryCharm.java index a3f1364a1ee..52eedf0d991 100644 --- a/Mage.Sets/src/mage/cards/t/TrickeryCharm.java +++ b/Mage.Sets/src/mage/cards/t/TrickeryCharm.java @@ -26,13 +26,11 @@ public final class TrickeryCharm extends CardImpl { this.getSpellAbility().addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // or target creature becomes the creature type of your choice until end of turn - Mode mode = new Mode(); - mode.addEffect(new BecomesChosenCreatureTypeTargetEffect()); + Mode mode = new Mode(new BecomesChosenCreatureTypeTargetEffect()); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or look at the top four cards of your library, then put them back in any order. - mode = new Mode(); - mode.addEffect(new LookLibraryControllerEffect(4)); + mode = new Mode(new LookLibraryControllerEffect(4)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/t/TriclopeanSight.java b/Mage.Sets/src/mage/cards/t/TriclopeanSight.java index 16a8872a280..703c7e027c3 100644 --- a/Mage.Sets/src/mage/cards/t/TriclopeanSight.java +++ b/Mage.Sets/src/mage/cards/t/TriclopeanSight.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -14,41 +12,42 @@ import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.VigilanceAbility; 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.constants.*; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class TriclopeanSight extends CardImpl { public TriclopeanSight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); this.subtype.add(SubType.AURA); // Flash this.addAbility(FlashAbility.getInstance()); - + // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Neutral)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); - + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // When Triclopean Sight enters the battlefield, untap enchanted creature. this.addAbility(new EntersBattlefieldTriggeredAbility(new UntapEnchantedEffect())); - + // Enchanted creature gets +1/+1 and has vigilance. - ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1,1, Duration.WhileOnBattlefield)); - ability.addEffect(new GainAbilityAttachedEffect(VigilanceAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield)); + Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect( + 1, 1, Duration.WhileOnBattlefield + )); + ability.addEffect(new GainAbilityAttachedEffect( + VigilanceAbility.getInstance(), + AttachmentType.AURA, + Duration.WhileOnBattlefield + ).setText("and has vigilance")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TripNoose.java b/Mage.Sets/src/mage/cards/t/TripNoose.java index 40bcb0a5513..d1ccd29ca87 100644 --- a/Mage.Sets/src/mage/cards/t/TripNoose.java +++ b/Mage.Sets/src/mage/cards/t/TripNoose.java @@ -23,7 +23,7 @@ public final class TripNoose extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); // {2}, {tap}: Tap target creature. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new ManaCostsImpl("2")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new ManaCostsImpl<>("{2}")); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/t/Triskaidekaphobia.java b/Mage.Sets/src/mage/cards/t/Triskaidekaphobia.java index 22fea36bf17..1d8497a5238 100644 --- a/Mage.Sets/src/mage/cards/t/Triskaidekaphobia.java +++ b/Mage.Sets/src/mage/cards/t/Triskaidekaphobia.java @@ -27,8 +27,7 @@ public final class Triskaidekaphobia extends CardImpl { // At the beginning of your upkeep, choose one - Each player with exactly 13 life loses the game, then each player gains 1 life. // Each player with exactly 13 life loses the game, then each player loses 1 life. Ability ability = new BeginningOfUpkeepTriggeredAbility(new TriskaidekaphobiaGainLifeEffect(), TargetController.YOU, false); - Mode mode = new Mode(); - mode.addEffect(new TriskaidekaphobiaLoseLifeEffect()); + Mode mode = new Mode(new TriskaidekaphobiaLoseLifeEffect()); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TritonTactics.java b/Mage.Sets/src/mage/cards/t/TritonTactics.java index 900ad9e83a5..6c3ebedf5fe 100644 --- a/Mage.Sets/src/mage/cards/t/TritonTactics.java +++ b/Mage.Sets/src/mage/cards/t/TritonTactics.java @@ -1,12 +1,9 @@ - package mage.cards.t; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; @@ -15,37 +12,31 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.WatcherScope; -import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTargets; -import mage.util.CardUtil; import mage.watchers.Watcher; import java.util.*; +import java.util.stream.Collectors; /** - * @author LevelX2 + * @author TheElk801 */ public final class TritonTactics extends CardImpl { public TritonTactics(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); - // Up to two target creatures each get +0/+3 until end of turn. Untap those creatures. - // At this turn's next end of combat, tap each creature that was blocked by one of those - // creatures this turn and it doesn't untap during its controller's next untap step. - Effect effect = new BoostTargetEffect(0, 3, Duration.EndOfTurn); - effect.setText("Up to two target creatures each get +0/+3 until end of turn"); - this.getSpellAbility().addEffect(effect); + // Up to two target creatures each get +0/+3 until end of turn. Untap those creatures. At this turn's next end of combat, tap each creature that was blocked by one of those creatures this turn and it doesn't untap during its controller's next untap step. + this.getSpellAbility().addEffect(new BoostTargetEffect( + 0, 3, Duration.EndOfTurn + ).setText("Up to two target creatures each get +0/+3 until end of turn")); + this.getSpellAbility().addEffect(new TritonTacticsUntapEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); - this.getSpellAbility().addEffect(new TritonTacticsUntapTargetEffect()); - this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new TritonTacticsTriggeredAbility())); - - this.getSpellAbility().addWatcher(new BlockedCreaturesWatcher()); - + this.getSpellAbility().addWatcher(new TritonTacticsWatcher()); } private TritonTactics(final TritonTactics card) { @@ -58,61 +49,57 @@ public final class TritonTactics extends CardImpl { } } -class TritonTacticsUntapTargetEffect extends OneShotEffect { +class TritonTacticsUntapEffect extends OneShotEffect { - public TritonTacticsUntapTargetEffect() { + public TritonTacticsUntapEffect() { super(Outcome.Untap); - staticText = "Untap those creatures"; + staticText = "untap those creatures. At this turn's next end of combat, tap each creature that was blocked " + + "by one of those creatures this turn and it doesn't untap during its controller's next untap step"; } - public TritonTacticsUntapTargetEffect(final TritonTacticsUntapTargetEffect effect) { + public TritonTacticsUntapEffect(final TritonTacticsUntapEffect effect) { super(effect); } @Override - public TritonTacticsUntapTargetEffect copy() { - return new TritonTacticsUntapTargetEffect(this); + public TritonTacticsUntapEffect copy() { + return new TritonTacticsUntapEffect(this); } @Override public boolean apply(Game game, Ability source) { - Set targets = new HashSet<>(); - for (UUID target : targetPointer.getTargets(game, source)) { - Permanent permanent = game.getPermanent(target); - if (permanent != null) { - permanent.untap(game); - targets.add(CardUtil.getCardZoneString("", permanent.getId(), game)); - } + List permanents = getTargetPointer() + .getTargets(game, source) + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (permanents.isEmpty()) { + return false; } - if (!targets.isEmpty()) { - // save the targets for the watcher in a map with zone change counter (as the card is recast during combat it's neccessary to save with zone change counter) - Map> targetMap; - Object object = game.getState().getValue("targets" + source.getSourceId()); - if (object instanceof Map) { - targetMap = (Map>) object; - } else { - targetMap = new HashMap<>(); - } - targetMap.put(game.getCard(source.getSourceId()).getZoneChangeCounter(game), targets); - if (object == null) { - game.getState().setValue("targets" + source.getSourceId().toString(), targetMap); - } + for (Permanent permanent : permanents) { + permanent.untap(game); } + game.addDelayedTriggeredAbility(new TritonTacticsDelayedTriggeredAbility(permanents, game), source); return true; } - } -class TritonTacticsTriggeredAbility extends DelayedTriggeredAbility { +class TritonTacticsDelayedTriggeredAbility extends DelayedTriggeredAbility { - public TritonTacticsTriggeredAbility() { - super(new TritonTacticsEndOfCombatEffect(), Duration.EndOfTurn, true); + TritonTacticsDelayedTriggeredAbility(List permanents, Game game) { + super(new TritonTacticsTapEffect(permanents, game), Duration.EndOfTurn, true, false); } - public TritonTacticsTriggeredAbility(TritonTacticsTriggeredAbility ability) { + private TritonTacticsDelayedTriggeredAbility(final TritonTacticsDelayedTriggeredAbility ability) { super(ability); } + @Override + public TritonTacticsDelayedTriggeredAbility copy() { + return new TritonTacticsDelayedTriggeredAbility(this); + } + @Override public boolean checkEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.END_COMBAT_STEP_PRE; @@ -124,101 +111,79 @@ class TritonTacticsTriggeredAbility extends DelayedTriggeredAbility { } @Override - public TritonTacticsTriggeredAbility copy() { - return new TritonTacticsTriggeredAbility(this); - } - - @Override - public String getTriggerPhrase() { - return "At this turn's next end of combat, "; + public String getRule() { + return "At this turn's next end of combat, tap each creature that was blocked " + + "by one of those creatures this turn and it doesn't untap during its controller's next untap step."; } } -class TritonTacticsEndOfCombatEffect extends OneShotEffect { +class TritonTacticsTapEffect extends OneShotEffect { - public TritonTacticsEndOfCombatEffect() { - super(Outcome.Benefit); - this.staticText = "tap each creature that was blocked by one of those creatures this turn and it doesn't untap during its controller's next untap step"; + private final Set morSet = new HashSet<>(); + + TritonTacticsTapEffect(List permanents, Game game) { + super(Outcome.Tap); + permanents + .stream() + .map(permanent -> new MageObjectReference(permanent, game)) + .forEach(morSet::add); } - public TritonTacticsEndOfCombatEffect(final TritonTacticsEndOfCombatEffect effect) { + private TritonTacticsTapEffect(final TritonTacticsTapEffect effect) { super(effect); + morSet.addAll(effect.morSet); } @Override - public TritonTacticsEndOfCombatEffect copy() { - return new TritonTacticsEndOfCombatEffect(this); + public TritonTacticsTapEffect copy() { + return new TritonTacticsTapEffect(this); } @Override public boolean apply(Game game, Ability source) { - Map> attackerMap = null; - Object object = game.getState().getValue("blockedAttackers" + source.getSourceId()); - if (object instanceof Map) { - attackerMap = (Map>) object; - for (Set attackerSet : attackerMap.values()) { - List doNotUntapNextUntapStep = new ArrayList<>(); - for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), game)) { - if (attackerSet.contains(CardUtil.getCardZoneString(null, creature.getId(), game))) { - // tap creature and add the not untap effect - creature.tap(source, game); - doNotUntapNextUntapStep.add(creature); - game.informPlayers("Triton Tactics: " + creature.getName() + " doesn't untap during its controller's next untap step"); - } - } - if (!doNotUntapNextUntapStep.isEmpty()) { - ContinuousEffect effect = new DontUntapInControllersNextUntapStepTargetEffect("This creature"); - effect.setTargetPointer(new FixedTargets(doNotUntapNextUntapStep, game)); - game.addEffect(effect, source); - } - } + List permanents = TritonTacticsWatcher.getPermanents(morSet, game); + if (permanents.isEmpty()) { + return false; } - if (attackerMap != null) { - attackerMap.clear(); - } - + permanents.stream().forEach(permanent -> permanent.tap(source, game)); + game.addEffect(new DontUntapInControllersNextUntapStepTargetEffect() + .setTargetPointer(new FixedTargets(permanents, game)), source); return true; } } -class BlockedCreaturesWatcher extends Watcher { +class TritonTacticsWatcher extends Watcher { - public BlockedCreaturesWatcher() { - super(WatcherScope.CARD); + private final Map> map = new HashMap<>(); + private static final Set emptySet = Collections.unmodifiableSet(new HashSet<>()); + + TritonTacticsWatcher() { + super(WatcherScope.GAME); } @Override public void watch(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.BLOCKER_DECLARED) { - Map> targetMap; - Object object = game.getState().getValue("targets" + this.getSourceId().toString()); - if (object instanceof Map) { - Permanent blocker = game.getPermanent(event.getSourceId()); - if (blocker != null) { - targetMap = (Map>) object; - for (Map.Entry> entry : targetMap.entrySet()) { - if (entry.getValue().contains(CardUtil.getCardZoneString("", blocker.getId(), game))) { - // save the attacking creature that was blocked by a creature effected by Triton Tactics - saveAttackingCreature(event.getTargetId(), entry.getKey(), game); - } - } - } - } - + map.computeIfAbsent( + new MageObjectReference(event.getSourceId(), game), x -> new HashSet<>() + ).add(new MageObjectReference(event.getTargetId(), game)); } } - private void saveAttackingCreature(UUID attackerId, Integer zoneChangeCounter, Game game) { - Set attackers; - Map> attackerMap; - Object object = game.getState().getValue("blockedAttackers" + getSourceId()); - if (object instanceof Map) { - attackerMap = (Map>) object; - } else { - attackerMap = new HashMap<>(); - } - attackers = attackerMap.computeIfAbsent(zoneChangeCounter, k -> new HashSet<>()); - attackers.add(CardUtil.getCardZoneString(null, attackerId, game)); - game.getState().setValue("blockedAttackers" + getSourceId().toString(), attackerMap); + @Override + public void reset() { + super.reset(); + map.clear(); + } + + static List getPermanents(Set targets, Game game) { + TritonTacticsWatcher watcher = game.getState().getWatcher(TritonTacticsWatcher.class); + return targets + .stream() + .map(mor -> watcher.map.getOrDefault(mor, emptySet)) + .flatMap(Collection::stream) + .map(mor -> mor.getPermanent(game)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); } } diff --git a/Mage.Sets/src/mage/cards/t/TriumphOfGerrard.java b/Mage.Sets/src/mage/cards/t/TriumphOfGerrard.java index c0c246c8464..dd68b5f8b39 100644 --- a/Mage.Sets/src/mage/cards/t/TriumphOfGerrard.java +++ b/Mage.Sets/src/mage/cards/t/TriumphOfGerrard.java @@ -88,7 +88,7 @@ class TriumphOfGerrardTargetCreature extends TargetControlledCreaturePermanent { public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { if (super.canTarget(controllerId, id, source, game)) { int maxPower = 0; - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (permanent.getPower().getValue() > maxPower) { maxPower = permanent.getPower().getValue(); } @@ -102,11 +102,11 @@ class TriumphOfGerrardTargetCreature extends TargetControlledCreaturePermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { int maxPower = 0; - List activePermanents = game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game); + List activePermanents = game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game); Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); if(targetSource == null){ return possibleTargets; } @@ -126,8 +126,8 @@ class TriumphOfGerrardTargetCreature extends TargetControlledCreaturePermanent { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - return !possibleTargets(sourceId, sourceControllerId, game).isEmpty(); + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + return !possibleTargets(sourceControllerId, source, game).isEmpty(); } @Override diff --git a/Mage.Sets/src/mage/cards/t/TrompTheDomains.java b/Mage.Sets/src/mage/cards/t/TrompTheDomains.java index bea637c779b..805ca2b6f6b 100644 --- a/Mage.Sets/src/mage/cards/t/TrompTheDomains.java +++ b/Mage.Sets/src/mage/cards/t/TrompTheDomains.java @@ -1,22 +1,20 @@ - package mage.cards.t; -import java.util.UUID; -import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.DomainValue; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.hint.common.DomainHint; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Duration; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class TrompTheDomains extends CardImpl { @@ -25,15 +23,15 @@ public final class TrompTheDomains extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{5}{G}"); // Domain - Until end of turn, creatures you control gain trample and get +1/+1 for each basic land type among lands you control. - Effect effect = new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); - effect.setText("Domain — Until end of turn, creatures you control gain trample"); - this.getSpellAbility().addEffect(effect); - DynamicValue domain = new DomainValue(); - effect = new BoostControlledEffect(domain, domain, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, false); - effect.setText("and get +1/+1 for each basic land type among lands you control"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + ).setText("until end of turn, creatures you control gain trample")); + this.getSpellAbility().addEffect(new BoostControlledEffect( + DomainValue.REGULAR, DomainValue.REGULAR, Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE, false + ).setText("and get +1/+1 for each basic land type among lands you control")); this.getSpellAbility().addHint(DomainHint.instance); - + this.getSpellAbility().setAbilityWord(AbilityWord.DOMAIN); } private TrompTheDomains(final TrompTheDomains card) { diff --git a/Mage.Sets/src/mage/cards/t/TrophyMage.java b/Mage.Sets/src/mage/cards/t/TrophyMage.java index ef63fefacd9..83931678c9b 100644 --- a/Mage.Sets/src/mage/cards/t/TrophyMage.java +++ b/Mage.Sets/src/mage/cards/t/TrophyMage.java @@ -1,21 +1,20 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; +import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author Styxo */ public final class TrophyMage extends CardImpl { @@ -36,7 +35,9 @@ public final class TrophyMage extends CardImpl { this.toughness = new MageInt(2); // When Trophy Mage enters the battlefield, you may search your library for an artifact card with converted mana cost 3, reveal it, put it into your hand, then shuffle your library. - this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0, 1, filter), true, true), true)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect( + new TargetCardInLibrary(filter), true, true + ), true)); } private TrophyMage(final TrophyMage card) { diff --git a/Mage.Sets/src/mage/cards/t/TruefireCaptain.java b/Mage.Sets/src/mage/cards/t/TruefireCaptain.java index bc426562b06..882011676d9 100644 --- a/Mage.Sets/src/mage/cards/t/TruefireCaptain.java +++ b/Mage.Sets/src/mage/cards/t/TruefireCaptain.java @@ -4,15 +4,13 @@ import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealtDamageToSourceTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.DamageTargetEffect; -import mage.constants.SubType; import mage.abilities.keyword.MentorAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.game.Game; +import mage.constants.SubType; import mage.target.TargetPlayer; /** @@ -34,9 +32,7 @@ public final class TruefireCaptain extends CardImpl { // Whenever Truefire Captain is dealt damage, it deals that much damage to target player. Ability ability = new DealtDamageToSourceTriggeredAbility( - new TruefireCaptainEffect(), - false, false - ); + new DamageTargetEffect(SavedDamageValue.MUCH, "it"), false); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } @@ -50,26 +46,3 @@ public final class TruefireCaptain extends CardImpl { return new TruefireCaptain(this); } } - -class TruefireCaptainEffect extends OneShotEffect { - - public TruefireCaptainEffect() { - super(Outcome.Damage); - this.staticText = "it deals that much damage to target player"; - } - - public TruefireCaptainEffect(final TruefireCaptainEffect effect) { - super(effect); - } - - @Override - public TruefireCaptainEffect copy() { - return new TruefireCaptainEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int amount = (Integer) getValue("damage"); - return new DamageTargetEffect(amount).apply(game, source); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TrustyPackbeast.java b/Mage.Sets/src/mage/cards/t/TrustyPackbeast.java index a40d5ac4bce..d34e80749ba 100644 --- a/Mage.Sets/src/mage/cards/t/TrustyPackbeast.java +++ b/Mage.Sets/src/mage/cards/t/TrustyPackbeast.java @@ -1,20 +1,19 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.constants.SubType; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterArtifactCard; +import mage.constants.SubType; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class TrustyPackbeast extends CardImpl { @@ -27,8 +26,8 @@ public final class TrustyPackbeast extends CardImpl { this.toughness = new MageInt(3); // When Trusty Packbeast enters the battlefield, return target artifact card from your graveyard to your hand. - Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()); - ability.addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TruthOrTale.java b/Mage.Sets/src/mage/cards/t/TruthOrTale.java index c5dd402950a..c2cd531c52b 100644 --- a/Mage.Sets/src/mage/cards/t/TruthOrTale.java +++ b/Mage.Sets/src/mage/cards/t/TruthOrTale.java @@ -59,7 +59,7 @@ class TruthOrTaleEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/t/TsabosDecree.java b/Mage.Sets/src/mage/cards/t/TsabosDecree.java index ceba41a0abd..a6d630ea7d6 100644 --- a/Mage.Sets/src/mage/cards/t/TsabosDecree.java +++ b/Mage.Sets/src/mage/cards/t/TsabosDecree.java @@ -60,7 +60,7 @@ class TsabosDecreeEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (player == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/t/TuktukGrunts.java b/Mage.Sets/src/mage/cards/t/TuktukGrunts.java index 3239838260a..78ef44cd83c 100644 --- a/Mage.Sets/src/mage/cards/t/TuktukGrunts.java +++ b/Mage.Sets/src/mage/cards/t/TuktukGrunts.java @@ -28,7 +28,7 @@ public final class TuktukGrunts extends CardImpl { this.toughness = new MageInt(2); this.addAbility(HasteAbility.getInstance()); - this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true)); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true).setAbilityWord(null)); } private TuktukGrunts(final TuktukGrunts card) { diff --git a/Mage.Sets/src/mage/cards/t/TuktukScrapper.java b/Mage.Sets/src/mage/cards/t/TuktukScrapper.java index 84fa8af5a88..13c3e32b229 100644 --- a/Mage.Sets/src/mage/cards/t/TuktukScrapper.java +++ b/Mage.Sets/src/mage/cards/t/TuktukScrapper.java @@ -121,7 +121,7 @@ class TuktukScrapperEffect extends OneShotEffect { targetArtifact.destroy(source, game, false); Player targetController = game.getPlayer(targetArtifact.getControllerId()); if (targetController != null && game.getState().getZone(targetArtifact.getId()) == Zone.GRAVEYARD) { - int alliesControlled = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int alliesControlled = game.getBattlefield().count(filter, source.getControllerId(), source, game); if (alliesControlled > 0) { targetController.damage(alliesControlled, source.getSourceId(), source, game); } diff --git a/Mage.Sets/src/mage/cards/t/TuktukTheExplorer.java b/Mage.Sets/src/mage/cards/t/TuktukTheExplorer.java index 5ec65e7d093..f097eaa2ae1 100644 --- a/Mage.Sets/src/mage/cards/t/TuktukTheExplorer.java +++ b/Mage.Sets/src/mage/cards/t/TuktukTheExplorer.java @@ -27,7 +27,7 @@ public final class TuktukTheExplorer extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); this.addAbility(HasteAbility.getInstance()); - this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new TuktukTheReturnedToken(expansionSetCode)))); + this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new TuktukTheReturnedToken()))); } private TuktukTheExplorer(final TuktukTheExplorer card) { diff --git a/Mage.Sets/src/mage/cards/t/TundraKavu.java b/Mage.Sets/src/mage/cards/t/TundraKavu.java index f04ff13ab7d..e8cb2e1bc25 100644 --- a/Mage.Sets/src/mage/cards/t/TundraKavu.java +++ b/Mage.Sets/src/mage/cards/t/TundraKavu.java @@ -52,7 +52,7 @@ public final class TundraKavu extends CardImpl { class TundraKavuEffect extends BecomesBasicLandTargetEffect { public TundraKavuEffect() { - super(Duration.EndOfTurn, false, true); + super(Duration.EndOfTurn); staticText = "Target land becomes a Plains or an Island until end of turn."; } diff --git a/Mage.Sets/src/mage/cards/t/TurfWound.java b/Mage.Sets/src/mage/cards/t/TurfWound.java index 5b9ccd88227..7383367f0f4 100644 --- a/Mage.Sets/src/mage/cards/t/TurfWound.java +++ b/Mage.Sets/src/mage/cards/t/TurfWound.java @@ -65,7 +65,7 @@ class TurfWoundEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't play lands this turn (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/t/Turnabout.java b/Mage.Sets/src/mage/cards/t/Turnabout.java index 0f53db524cc..2cf6d251ba3 100644 --- a/Mage.Sets/src/mage/cards/t/Turnabout.java +++ b/Mage.Sets/src/mage/cards/t/Turnabout.java @@ -98,7 +98,7 @@ class TurnaboutEffect extends OneShotEffect { "Tap", "Untap", source, game ); for (Permanent permanent : game.getBattlefield().getActivePermanents( - filter, source.getFirstTarget(), source.getSourceId(), game + filter, source.getFirstTarget(), source, game )) { if (tap) { permanent.tap(source, game); diff --git a/Mage.Sets/src/mage/cards/t/TurntimberRanger.java b/Mage.Sets/src/mage/cards/t/TurntimberRanger.java index 622a344af61..2f40c219c62 100644 --- a/Mage.Sets/src/mage/cards/t/TurntimberRanger.java +++ b/Mage.Sets/src/mage/cards/t/TurntimberRanger.java @@ -32,8 +32,8 @@ public final class TurntimberRanger extends CardImpl { // Whenever Turntimber Ranger or another Ally enters the battlefield under your control, you may create a 2/2 green Wolf creature token. If you do, put a +1/+1 counter on Turntimber Ranger. Ability ability = new AllyEntersBattlefieldTriggeredAbility(new CreateTokenEffect(new WolfToken()), true); - ability.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance())); - this.addAbility(ability); + ability.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance()).concatBy("If you do,")); + this.addAbility(ability.setAbilityWord(null)); } private TurntimberRanger(final TurntimberRanger card) { diff --git a/Mage.Sets/src/mage/cards/t/TurntimberSower.java b/Mage.Sets/src/mage/cards/t/TurntimberSower.java index d52069b3c5d..ac6d2e02413 100644 --- a/Mage.Sets/src/mage/cards/t/TurntimberSower.java +++ b/Mage.Sets/src/mage/cards/t/TurntimberSower.java @@ -1,6 +1,5 @@ package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; @@ -8,7 +7,7 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -25,14 +24,14 @@ import mage.game.permanent.token.PlantToken; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class TurntimberSower extends CardImpl { - private static final FilterControlledPermanent filter - = new FilterControlledCreaturePermanent("three creatures"); + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("creatures"); public TurntimberSower(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); @@ -47,14 +46,9 @@ public final class TurntimberSower extends CardImpl { // {G}, Sacrifice three creatures: Return target land card from your graveyard to your hand. Ability ability = new SimpleActivatedAbility( - new ReturnToHandTargetEffect() - .setText("Return target land card " - + "from your graveyard to your hand"), - new ManaCostsImpl("{G}") + new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl<>("{G}") ); - ability.addCost(new SacrificeTargetCost( - new TargetControlledPermanent(3, 3, filter, true) - )); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(3, filter))); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_LAND)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TuyaBearclaw.java b/Mage.Sets/src/mage/cards/t/TuyaBearclaw.java index f4694313d94..5d3ea50ad75 100644 --- a/Mage.Sets/src/mage/cards/t/TuyaBearclaw.java +++ b/Mage.Sets/src/mage/cards/t/TuyaBearclaw.java @@ -59,7 +59,7 @@ enum TuyaBearclawValue implements DynamicValue { return game.getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, - sourceAbility.getControllerId(), sourceAbility.getSourceId(), game + sourceAbility.getControllerId(), sourceAbility, game ).stream() .filter(Objects::nonNull) .map(MageObject::getPower) diff --git a/Mage.Sets/src/mage/cards/t/TwinningGlass.java b/Mage.Sets/src/mage/cards/t/TwinningGlass.java index b4ec11930c3..1b9512ea2fc 100644 --- a/Mage.Sets/src/mage/cards/t/TwinningGlass.java +++ b/Mage.Sets/src/mage/cards/t/TwinningGlass.java @@ -1,47 +1,45 @@ package mage.cards.t; -import mage.ApprovingObject; 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.OneShotEffect; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.cost.CastFromHandForFreeEffect; 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.common.FilterNonlandCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicate; import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.stack.Spell; -import mage.players.Player; -import mage.target.TargetCard; +import mage.util.CardUtil; import mage.watchers.common.SpellsCastWatcher; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; import java.util.UUID; -import java.util.stream.Collectors; /** * @author jeffwadsworth */ public final class TwinningGlass extends CardImpl { + private static final FilterCard filter = new FilterCard(); + + static { + filter.add(TwinningGlassPredicate.instance); + } + public TwinningGlass(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // {1}, {T}: You may cast a nonland card from your hand without paying its mana cost if it has the same name as a spell that was cast this turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new TwinningGlassEffect(), new ManaCostsImpl("{1}")); + Ability ability = new SimpleActivatedAbility( + new CastFromHandForFreeEffect(filter).setText( + "you may cast a spell from your hand without paying its mana cost " + + "if it has the same name as a spell that was cast this turn" + ), new GenericManaCost(1) + ); ability.addCost(new TapSourceCost()); this.addAbility(ability, new SpellsCastWatcher()); - } private TwinningGlass(final TwinningGlass card) { @@ -54,67 +52,14 @@ public final class TwinningGlass extends CardImpl { } } -class TwinningGlassEffect extends OneShotEffect { - - public TwinningGlassEffect() { - super(Outcome.PlayForFree); - this.staticText = "You may cast a nonland card from your hand " - + "without paying its mana cost if it has the same name " - + "as a spell that was cast this turn"; - } - - public TwinningGlassEffect(final TwinningGlassEffect effect) { - super(effect); - } +enum TwinningGlassPredicate implements Predicate { + instance; @Override - public TwinningGlassEffect copy() { - return new TwinningGlassEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - List spells = new ArrayList<>(); - Permanent twinningGlass = game.getPermanent(source.getSourceId()); - Player controller = game.getPlayer(source.getControllerId()); + public boolean apply(Card input, Game game) { SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); - if (twinningGlass == null) { - twinningGlass = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD); - } - if (twinningGlass != null - && controller != null - && watcher != null) { - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - if (watcher.getSpellsCastThisTurn(playerId) != null) { - for (Spell spell : watcher.getSpellsCastThisTurn(playerId)) { - spells.add(spell); - } - } - } - if (spells.isEmpty()) { - return false; - } - List predicates = spells.stream() - .map(Spell::getName) - .filter(Objects::nonNull) - .filter(s -> !s.isEmpty()) - .map(NamePredicate::new) - .collect(Collectors.toList()); - FilterNonlandCard filterCard = new FilterNonlandCard("nonland card that was cast this turn"); - filterCard.add(Predicates.or(predicates)); - TargetCard target = new TargetCard(0, 1, Zone.HAND, filterCard); - target.withChooseHint("free cast"); - if (controller.choose(Outcome.PlayForFree, controller.getHand(), target, game)) { - Card chosenCard = game.getCard(target.getFirstTarget()); - if (chosenCard != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(chosenCard, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + chosenCard.getId(), null); - return cardWasCast; - } - } - } - return false; + return watcher != null && watcher + .getAllSpellsCastThisTurn() + .anyMatch(spell -> CardUtil.haveSameNames(spell, input)); } } diff --git a/Mage.Sets/src/mage/cards/t/TwinsOfMaurerEstate.java b/Mage.Sets/src/mage/cards/t/TwinsOfMaurerEstate.java index 5a4baa1ef37..b2c237c73a2 100644 --- a/Mage.Sets/src/mage/cards/t/TwinsOfMaurerEstate.java +++ b/Mage.Sets/src/mage/cards/t/TwinsOfMaurerEstate.java @@ -23,7 +23,7 @@ public final class TwinsOfMaurerEstate extends CardImpl { this.toughness = new MageInt(5); // Madness {2}{B} (If you discard this card, discard it into exile. When you do, cast it for its madness cost or put it into your graveyard.) - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{2}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{2}{B}"))); } private TwinsOfMaurerEstate(final TwinsOfMaurerEstate card) { diff --git a/Mage.Sets/src/mage/cards/t/TwinshotSniper.java b/Mage.Sets/src/mage/cards/t/TwinshotSniper.java index 9a35569692c..9da44c7b3dd 100644 --- a/Mage.Sets/src/mage/cards/t/TwinshotSniper.java +++ b/Mage.Sets/src/mage/cards/t/TwinshotSniper.java @@ -31,12 +31,12 @@ public final class TwinshotSniper extends CardImpl { this.addAbility(ReachAbility.getInstance()); // When Twinshot Sniper enters the battlefield, it deals 2 damage to any target. - Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2)); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(2, "it")); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); // Channel — {1}{R}, Discard Twinshot Sniper: It deals 2 damage to any target. - ability = new ChannelAbility("{1}{R}", new DamageTargetEffect(2)); + ability = new ChannelAbility("{1}{R}", new DamageTargetEffect(2, "it")); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TwistAllegiance.java b/Mage.Sets/src/mage/cards/t/TwistAllegiance.java index 8fcd1ade542..a81e3d0dd7a 100644 --- a/Mage.Sets/src/mage/cards/t/TwistAllegiance.java +++ b/Mage.Sets/src/mage/cards/t/TwistAllegiance.java @@ -65,7 +65,7 @@ class TwistAllegianceEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Player targetOpponent = game.getPlayer(getTargetPointer().getFirst(game, source)); if (controller != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { // only creatures of controller & target opponent if (permanent.isControlledBy(source.getControllerId()) || permanent.isControlledBy(targetOpponent.getId())) { UUID newController = permanent.isControlledBy(source.getControllerId()) ? targetOpponent.getId() : source.getControllerId(); diff --git a/Mage.Sets/src/mage/cards/t/TwistedEmbrace.java b/Mage.Sets/src/mage/cards/t/TwistedEmbrace.java index e9440c9ed07..c98e9d36019 100644 --- a/Mage.Sets/src/mage/cards/t/TwistedEmbrace.java +++ b/Mage.Sets/src/mage/cards/t/TwistedEmbrace.java @@ -44,7 +44,7 @@ public final class TwistedEmbrace extends CardImpl { this.subtype.add(SubType.AURA); // Enchant artifact or creature you control - TargetPermanent auraTarget = new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_CREATURE); + TargetPermanent auraTarget = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_OR_CREATURE); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); diff --git a/Mage.Sets/src/mage/cards/t/TwistedJustice.java b/Mage.Sets/src/mage/cards/t/TwistedJustice.java index 490c6965284..7e37bdf583f 100644 --- a/Mage.Sets/src/mage/cards/t/TwistedJustice.java +++ b/Mage.Sets/src/mage/cards/t/TwistedJustice.java @@ -63,8 +63,8 @@ class TwistedJusticeEffect extends OneShotEffect { //A spell or ability could have removed the only legal target this player //had, if thats the case this ability should fizzle. - if (target.canChoose(source.getSourceId(), player.getId(), game)) { - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + if (target.canChoose(player.getId(), source, game)) { + player.choose(Outcome.Sacrifice, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/t/Twitch.java b/Mage.Sets/src/mage/cards/t/Twitch.java index 1fc9120c4b0..3d8cedcaf91 100644 --- a/Mage.Sets/src/mage/cards/t/Twitch.java +++ b/Mage.Sets/src/mage/cards/t/Twitch.java @@ -34,7 +34,7 @@ public final class Twitch extends CardImpl { // Draw a card. this.getSpellAbility().addEffect(new MayTapOrUntapTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent(filter)); - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } private Twitch(final Twitch card) { diff --git a/Mage.Sets/src/mage/cards/t/TwoHeadedSliver.java b/Mage.Sets/src/mage/cards/t/TwoHeadedSliver.java index 6a30a5c5f54..09529fa6510 100644 --- a/Mage.Sets/src/mage/cards/t/TwoHeadedSliver.java +++ b/Mage.Sets/src/mage/cards/t/TwoHeadedSliver.java @@ -31,7 +31,7 @@ public final class TwoHeadedSliver extends CardImpl { // All Sliver creatures have menace. (They can't be blocked except by two or more creatures.) this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect( new MenaceAbility(), - Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, + Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS, "All Sliver creatures have menace. (They can't be blocked except by two or more creatures.)"))); } diff --git a/Mage.Sets/src/mage/cards/t/TyvarKell.java b/Mage.Sets/src/mage/cards/t/TyvarKell.java index d8bb915daac..fd3ababcc8b 100644 --- a/Mage.Sets/src/mage/cards/t/TyvarKell.java +++ b/Mage.Sets/src/mage/cards/t/TyvarKell.java @@ -2,7 +2,6 @@ package mage.cards.t; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -39,7 +38,7 @@ public final class TyvarKell extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.TYVAR); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // Elves you control have "{T}: Add {B}." this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( diff --git a/Mage.Sets/src/mage/cards/u/UginTheIneffable.java b/Mage.Sets/src/mage/cards/u/UginTheIneffable.java index 2c2c6523463..8b3743724e9 100644 --- a/Mage.Sets/src/mage/cards/u/UginTheIneffable.java +++ b/Mage.Sets/src/mage/cards/u/UginTheIneffable.java @@ -5,7 +5,6 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.Effect; @@ -57,7 +56,7 @@ public final class UginTheIneffable extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.UGIN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // Colorless spells you cast cost {2} less to cast. this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect( diff --git a/Mage.Sets/src/mage/cards/u/UginTheSpiritDragon.java b/Mage.Sets/src/mage/cards/u/UginTheSpiritDragon.java index b8170dd9fc9..29b3b53b0d3 100644 --- a/Mage.Sets/src/mage/cards/u/UginTheSpiritDragon.java +++ b/Mage.Sets/src/mage/cards/u/UginTheSpiritDragon.java @@ -6,7 +6,6 @@ import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.common.PayVariableLoyaltyCost; import mage.abilities.effects.OneShotEffect; @@ -42,7 +41,7 @@ public final class UginTheSpiritDragon extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.UGIN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(7)); + this.setStartingLoyalty(7); // +2: Ugin, the Spirit Dragon deals 3 damage to any target. LoyaltyAbility ability = new LoyaltyAbility(new DamageTargetEffect(3), 2); @@ -102,7 +101,7 @@ class UginTheSpiritDragonEffect2 extends OneShotEffect { filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, cmc + 1)); filter.add(Predicates.not(ColorlessPredicate.instance)); Set permanentsToExile = new HashSet<>(); - permanentsToExile.addAll(game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)); + permanentsToExile.addAll(game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)); controller.moveCards(permanentsToExile, Zone.EXILED, source, game); return true; } @@ -131,7 +130,7 @@ class UginTheSpiritDragonEffect3 extends OneShotEffect { controller.gainLife(7, game, source); controller.drawCards(7, source, game); TargetCardInHand target = new TargetCardInHand(0, 7, new FilterPermanentCard("permanent cards")); - if (controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCardInPlay, target, source, game)) { controller.moveCards(new CardsImpl(target.getTargets()), Zone.BATTLEFIELD, source, game); } return true; diff --git a/Mage.Sets/src/mage/cards/u/UginsNexus.java b/Mage.Sets/src/mage/cards/u/UginsNexus.java index 45235baa763..2182be37cc3 100644 --- a/Mage.Sets/src/mage/cards/u/UginsNexus.java +++ b/Mage.Sets/src/mage/cards/u/UginsNexus.java @@ -63,7 +63,7 @@ class UginsNexusSkipExtraTurnsEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player player = game.getPlayer(event.getPlayerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (player != null && sourceObject != null) { game.informPlayers(sourceObject.getLogName() + ": Extra turn of " + player.getLogName() + " skipped"); } diff --git a/Mage.Sets/src/mage/cards/u/UlamogsDespoiler.java b/Mage.Sets/src/mage/cards/u/UlamogsDespoiler.java index 1fa716eae35..c8d7288e638 100644 --- a/Mage.Sets/src/mage/cards/u/UlamogsDespoiler.java +++ b/Mage.Sets/src/mage/cards/u/UlamogsDespoiler.java @@ -78,7 +78,7 @@ class UlamogsDespoilerEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Target target = new TargetCardInExile(2, 2, filter, null); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (target.canChoose(source.getControllerId(), source, game)) { if (controller.chooseTarget(outcome, target, source, game)) { Cards cardsToGraveyard = new CardsImpl(target.getTargets()); controller.moveCards(cardsToGraveyard, Zone.GRAVEYARD, source, game); diff --git a/Mage.Sets/src/mage/cards/u/UlamogsNullifier.java b/Mage.Sets/src/mage/cards/u/UlamogsNullifier.java index 60a0647d075..5c2d36a9ecd 100644 --- a/Mage.Sets/src/mage/cards/u/UlamogsNullifier.java +++ b/Mage.Sets/src/mage/cards/u/UlamogsNullifier.java @@ -93,7 +93,7 @@ class UlamogsNullifierEffect extends OneShotEffect { Spell spell = game.getStack().getSpell(source.getFirstTarget()); if (controller != null && spell != null) { Target target = new TargetCardInExile(2, 2, filter, null); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (target.canChoose(source.getControllerId(), source, game)) { if (controller.chooseTarget(outcome, target, source, game)) { Cards cardsToGraveyard = new CardsImpl(target.getTargets()); controller.moveCards(cardsToGraveyard, Zone.GRAVEYARD, source, game); diff --git a/Mage.Sets/src/mage/cards/u/UlashtTheHateSeed.java b/Mage.Sets/src/mage/cards/u/UlashtTheHateSeed.java index 31cf77fb035..d8e0f50bd44 100644 --- a/Mage.Sets/src/mage/cards/u/UlashtTheHateSeed.java +++ b/Mage.Sets/src/mage/cards/u/UlashtTheHateSeed.java @@ -54,10 +54,9 @@ public final class UlashtTheHateSeed extends CardImpl { ability.addCost(new RemoveCountersSourceCost(CounterType.P1P1.createInstance())); ability.addTarget(new TargetCreaturePermanent()); // or create a 1/1 green Saproling creature token. - Mode mode = new Mode(); Effect effect = new CreateTokenEffect(new SaprolingToken()); effect.setText("Create a 1/1 green Saproling creature token."); - mode.addEffect(effect); + Mode mode = new Mode(effect); ability.addMode(mode); this.addAbility(ability); } @@ -98,8 +97,8 @@ class UlashtTheHateSeedEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (permanent != null && player != null) { - int amount = game.getBattlefield().count(filterRed, source.getSourceId(), source.getControllerId(), game); - amount += game.getBattlefield().count(filterGreen, source.getSourceId(), source.getControllerId(), game); + int amount = game.getBattlefield().count(filterRed, source.getControllerId(), source, game); + amount += game.getBattlefield().count(filterGreen, source.getControllerId(), source, game); if (amount > 0) { permanent.addCounters(CounterType.P1P1.createInstance(amount), source.getControllerId(), source, game); } diff --git a/Mage.Sets/src/mage/cards/u/UlvenwaldMysteries.java b/Mage.Sets/src/mage/cards/u/UlvenwaldMysteries.java index 6f2175bfb5f..10d274de9f5 100644 --- a/Mage.Sets/src/mage/cards/u/UlvenwaldMysteries.java +++ b/Mage.Sets/src/mage/cards/u/UlvenwaldMysteries.java @@ -25,7 +25,7 @@ import mage.game.permanent.token.HumanSoldierToken; */ public final class UlvenwaldMysteries extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature you control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a nontoken creature you control"); private static final FilterControlledPermanent filterClue = new FilterControlledPermanent("a Clue"); static { diff --git a/Mage.Sets/src/mage/cards/u/UmaraRaptor.java b/Mage.Sets/src/mage/cards/u/UmaraRaptor.java index d32c1db9d07..69863738cb1 100644 --- a/Mage.Sets/src/mage/cards/u/UmaraRaptor.java +++ b/Mage.Sets/src/mage/cards/u/UmaraRaptor.java @@ -27,7 +27,7 @@ public final class UmaraRaptor extends CardImpl { this.toughness = new MageInt(1); this.addAbility(FlyingAbility.getInstance()); - this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true)); + this.addAbility(new AllyEntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true).setAbilityWord(null)); } private UmaraRaptor(final UmaraRaptor card) { diff --git a/Mage.Sets/src/mage/cards/u/Umbilicus.java b/Mage.Sets/src/mage/cards/u/Umbilicus.java index e1a6e26fc71..b1765f341b9 100644 --- a/Mage.Sets/src/mage/cards/u/Umbilicus.java +++ b/Mage.Sets/src/mage/cards/u/Umbilicus.java @@ -69,7 +69,7 @@ class BloodClockEffect extends OneShotEffect { return true; } else { Target target = new TargetControlledPermanent(); - if (target.canChoose(source.getSourceId(), player.getId(), game) && player.chooseTarget(outcome, target, source, game)) { + if (target.canChoose(player.getId(), source, game) && player.chooseTarget(outcome, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { game.informPlayers(player.getLogName() + " returns " + permanent.getName() + " to hand."); diff --git a/Mage.Sets/src/mage/cards/u/UmbralMantle.java b/Mage.Sets/src/mage/cards/u/UmbralMantle.java index 31c6262b7f7..4d856ce9ef9 100644 --- a/Mage.Sets/src/mage/cards/u/UmbralMantle.java +++ b/Mage.Sets/src/mage/cards/u/UmbralMantle.java @@ -1,12 +1,10 @@ - package mage.cards.u; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.UntapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EquipAbility; @@ -14,10 +12,10 @@ 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.constants.SubType; + +import java.util.UUID; /** * @@ -26,13 +24,14 @@ import mage.constants.Zone; public final class UmbralMantle extends CardImpl { public UmbralMantle(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); this.subtype.add(SubType.EQUIPMENT); // Equipped creature has "{3}, {untap}: This creature gets +2/+2 until end of turn." - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(2, 2, Duration.EndOfTurn), new ManaCostsImpl("{3}")); + Ability ability = new SimpleActivatedAbility(new BoostSourceEffect(2, 2, Duration.EndOfTurn).setText("this creature gets +2/+2 until end of turn"), new GenericManaCost(3)); ability.addCost(new UntapSourceCost()); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ability, AttachmentType.EQUIPMENT))); + this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect(ability, AttachmentType.EQUIPMENT))); + // Equip {0} this.addAbility(new EquipAbility(0, false)); } diff --git a/Mage.Sets/src/mage/cards/u/UmezawasJitte.java b/Mage.Sets/src/mage/cards/u/UmezawasJitte.java index 5496d9e0987..2b234d3047e 100644 --- a/Mage.Sets/src/mage/cards/u/UmezawasJitte.java +++ b/Mage.Sets/src/mage/cards/u/UmezawasJitte.java @@ -41,14 +41,12 @@ public final class UmezawasJitte extends CardImpl { new RemoveCountersSourceCost(CounterType.CHARGE.createInstance())); // Target creature gets -1/-1 until end of turn. - Mode mode = new Mode(); - mode.addEffect(new BoostTargetEffect(-1, -1, Duration.EndOfTurn)); + Mode mode = new Mode(new BoostTargetEffect(-1, -1, Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); ability.addMode(mode); // You gain 2 life. - mode = new Mode(); - mode.addEffect(new GainLifeEffect(2)); + mode = new Mode(new GainLifeEffect(2)); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/u/UnblinkingBleb.java b/Mage.Sets/src/mage/cards/u/UnblinkingBleb.java index eb49172c068..f63c1b7624b 100644 --- a/Mage.Sets/src/mage/cards/u/UnblinkingBleb.java +++ b/Mage.Sets/src/mage/cards/u/UnblinkingBleb.java @@ -1,7 +1,5 @@ - package mage.cards.u; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.TurnedFaceUpAllTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -11,25 +9,32 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.Zone; import mage.filter.FilterPermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class UnblinkingBleb extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("{this} or another permanent"); + public UnblinkingBleb(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.ILLUSION); this.power = new MageInt(1); this.toughness = new MageInt(3); // Morph {2}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}"))); - + this.addAbility(new MorphAbility(new ManaCostsImpl<>("{2}{U}"))); + // Whenever Unblinking Bleb or another permanent is turned face up, you may scry 2. - this.addAbility(new TurnedFaceUpAllTriggeredAbility(new ScryEffect(2), new FilterPermanent("{this} or another permanent"), true)); + this.addAbility(new TurnedFaceUpAllTriggeredAbility( + Zone.BATTLEFIELD, new ScryEffect(2), + filter, true, true + )); } private UnblinkingBleb(final UnblinkingBleb card) { @@ -40,4 +45,4 @@ public final class UnblinkingBleb extends CardImpl { public UnblinkingBleb copy() { return new UnblinkingBleb(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/u/UnblinkingObserver.java b/Mage.Sets/src/mage/cards/u/UnblinkingObserver.java index 8f47ae7c5ae..2a52069338d 100644 --- a/Mage.Sets/src/mage/cards/u/UnblinkingObserver.java +++ b/Mage.Sets/src/mage/cards/u/UnblinkingObserver.java @@ -76,7 +76,7 @@ class UnblinkingObserverManaCondition extends ManaCondition implements Condition @Override public boolean apply(Game game, Ability source) { if (source instanceof SpellAbility) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && object.isInstantOrSorcery(game); } return source instanceof DisturbAbility; diff --git a/Mage.Sets/src/mage/cards/u/UnbreathingHorde.java b/Mage.Sets/src/mage/cards/u/UnbreathingHorde.java index 7288ab9b060..6e361dab8b4 100644 --- a/Mage.Sets/src/mage/cards/u/UnbreathingHorde.java +++ b/Mage.Sets/src/mage/cards/u/UnbreathingHorde.java @@ -96,11 +96,11 @@ class UnbreathingHordeEffect2 extends PreventionEffectImpl { public UnbreathingHordeEffect2() { super(Duration.WhileOnBattlefield); + staticText = "If damage would be dealt to {this}, prevent that damage and remove a +1/+1 counter from it"; } public UnbreathingHordeEffect2(final UnbreathingHordeEffect2 effect) { super(effect); - staticText = "If damage would be dealt to {this}, prevent that damage and remove a +1/+1 counter from it"; } @Override diff --git a/Mage.Sets/src/mage/cards/u/UncageTheMenagerie.java b/Mage.Sets/src/mage/cards/u/UncageTheMenagerie.java index 7e2e932ed09..c86ef8e16fa 100644 --- a/Mage.Sets/src/mage/cards/u/UncageTheMenagerie.java +++ b/Mage.Sets/src/mage/cards/u/UncageTheMenagerie.java @@ -2,15 +2,17 @@ package mage.cards.u; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.Outcome; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; -import mage.players.Player; -import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCardWithDifferentNameInLibrary; import java.util.UUID; @@ -38,15 +40,10 @@ public final class UncageTheMenagerie extends CardImpl { class UncageTheMenagerieEffect extends OneShotEffect { - private static final FilterCard filter = new FilterCard("creature"); - - static { - filter.add(CardType.CREATURE.getPredicate()); - } - public UncageTheMenagerieEffect() { super(Outcome.DrawCard); - this.staticText = "Search your library for up to X creature cards with different names that each have mana value X, reveal them, put them into your hand, then shuffle."; + this.staticText = "Search your library for up to X creature cards with different names " + + "that each have mana value X, reveal them, put them into your hand, then shuffle."; } public UncageTheMenagerieEffect(final UncageTheMenagerieEffect effect) { @@ -60,71 +57,11 @@ class UncageTheMenagerieEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - Card sourceCard = game.getCard(source.getSourceId()); - if (player == null || sourceCard == null) { - return false; - } - int xValue = source.getManaCostsToPay().getX(); - - UncageTheMenagerieTarget target = new UncageTheMenagerieTarget(xValue); - if (player.searchLibrary(target, source, game)) { - if (!target.getTargets().isEmpty()) { - Cards cards = new CardsImpl(); - for (UUID cardId : target.getTargets()) { - Card card = player.getLibrary().remove(cardId, game); - if (card != null) { - cards.add(card); - } - } - player.revealCards(sourceCard.getIdName(), cards, game); - player.moveCards(cards, Zone.HAND, source, game); - } - player.shuffleLibrary(source, game); - return true; - } - player.shuffleLibrary(source, game); - return false; - } -} - -class UncageTheMenagerieTarget extends TargetCardInLibrary { - - private int xValue; - - public UncageTheMenagerieTarget(int xValue) { - super(0, xValue, new FilterCreatureCard(xValue + " creature cards with different names with mana value " + xValue)); - this.xValue = xValue; - } - - public UncageTheMenagerieTarget(final UncageTheMenagerieTarget target) { - super(target); - this.xValue = target.xValue; - } - - @Override - public UncageTheMenagerieTarget copy() { - return new UncageTheMenagerieTarget(this); - } - - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Cards cards, Game game) { - Card card = cards.get(id, game); - if (card != null) { - for (UUID targetId : this.getTargets()) { - Card iCard = game.getCard(targetId); - if (iCard != null && iCard.getName().equals(card.getName())) { - return false; - } - } - - if (!(card.isCreature(game) && card.getManaValue() == xValue)) { - return false; - } - - return filter.match(card, playerId, game); - } - return false; + FilterCard filter = new FilterCreatureCard(xValue + " creature cards with different names that each have mana value " + xValue); + filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, xValue)); + return new SearchLibraryPutInHandEffect( + new TargetCardWithDifferentNameInLibrary(0, xValue, filter), true, true + ).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/u/UnclaimedTerritory.java b/Mage.Sets/src/mage/cards/u/UnclaimedTerritory.java index 76156ad2156..c2f84fb4a31 100644 --- a/Mage.Sets/src/mage/cards/u/UnclaimedTerritory.java +++ b/Mage.Sets/src/mage/cards/u/UnclaimedTerritory.java @@ -62,7 +62,7 @@ class UnclaimedTerritoryManaBuilder extends ConditionalManaBuilder { creatureType = subType; } Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null && mana.getAny() == 0) { game.informPlayers(controller.getLogName() + " produces " + mana.toString() + " with " + sourceObject.getLogName() + " (can only be spent to cast creatures of type " + creatureType + ")"); @@ -103,7 +103,7 @@ class UnclaimedTerritoryManaCondition extends CreatureCastManaCondition { // check: ... to cast a creature spell if (super.apply(game, source)) { // check: ... of the chosen type - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (creatureType != null && object != null && object.hasSubtype(creatureType, game)) { return true; } diff --git a/Mage.Sets/src/mage/cards/u/UncoveredClues.java b/Mage.Sets/src/mage/cards/u/UncoveredClues.java index 8acbbdf3868..976afa743f2 100644 --- a/Mage.Sets/src/mage/cards/u/UncoveredClues.java +++ b/Mage.Sets/src/mage/cards/u/UncoveredClues.java @@ -1,14 +1,13 @@ - - package mage.cards.u; import java.util.UUID; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; +import mage.filter.common.FilterInstantOrSorceryCard; /** * @@ -18,17 +17,13 @@ import mage.filter.predicate.Predicates; public final class UncoveredClues extends CardImpl { - private static final FilterCard filter = new FilterCard("up to two instant and/or sorcery cards"); - static { - filter.add(Predicates.or(CardType.INSTANT.getPredicate(), CardType.SORCERY.getPredicate())); - } + private static final FilterCard filter = new FilterInstantOrSorceryCard("instant and/or sorcery cards"); public UncoveredClues(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{U}"); - // Look at the top four cards of your library. You may reveal up to two instant and/or sorcery cards from among them and put the revealed cards into your hand. Put the rest on the bottom of your library in any order. - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(4, 2, filter, true)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(4, 2, filter, PutCards.HAND, PutCards.BOTTOM_ANY)); } private UncoveredClues(final UncoveredClues card) { diff --git a/Mage.Sets/src/mage/cards/u/UndercoverOperative.java b/Mage.Sets/src/mage/cards/u/UndercoverOperative.java new file mode 100644 index 00000000000..7a43720ef4c --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UndercoverOperative.java @@ -0,0 +1,68 @@ +package mage.cards.u; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.common.CopyPermanentEffect; +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.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.util.functions.CopyApplier; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UndercoverOperative extends CardImpl { + + public UndercoverOperative(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + + this.subtype.add(SubType.SHAPESHIFTER); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // You may have Undercover Operative enter the battlefield as a copy of any creature on the battlefield, except it enters with a shield counter on it if you control that creature. + this.addAbility(new EntersBattlefieldAbility(new CopyPermanentEffect( + StaticFilters.FILTER_PERMANENT_CREATURE, new UndercoverOperativeApplier() + ), true)); + } + + private UndercoverOperative(final UndercoverOperative card) { + super(card); + } + + @Override + public UndercoverOperative copy() { + return new UndercoverOperative(this); + } +} + +class UndercoverOperativeApplier extends CopyApplier { + + @Override + public String getText() { + return ", except it enters with a shield counter on it if you control that creature"; + } + + @Override + public boolean apply(Game game, MageObject blueprint, Ability source, UUID copyToObjectId) { + if (!isCopyOfCopy(source, blueprint, copyToObjectId) + && ((Permanent) blueprint).isControlledBy(source.getControllerId())) { + blueprint.getAbilities().add(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.SHIELD.createInstance(), false) + .setText("with a shield counter on it") + )); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnderrealmLich.java b/Mage.Sets/src/mage/cards/u/UnderrealmLich.java index 088531f5378..1ca93be83fd 100644 --- a/Mage.Sets/src/mage/cards/u/UnderrealmLich.java +++ b/Mage.Sets/src/mage/cards/u/UnderrealmLich.java @@ -6,9 +6,9 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.PayLifeCost; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.TapSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.IndestructibleAbility; @@ -18,8 +18,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; 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; @@ -39,13 +37,10 @@ public final class UnderrealmLich extends CardImpl { this.toughness = new MageInt(3); // If you would draw a card, instead look at the top three cards of your library, then put one into your hand and the rest into your graveyard. - this.addAbility(new SimpleStaticAbility( - Zone.BATTLEFIELD, new UnderrealmLichReplacementEffect() - )); + this.addAbility(new SimpleStaticAbility(new UnderrealmLichReplacementEffect())); // Pay 4 life: Underrealm Lich gains indestructible until end of turn. Tap it. Ability ability = new SimpleActivatedAbility( - Zone.BATTLEFIELD, new GainAbilitySourceEffect( IndestructibleAbility.getInstance(), Duration.EndOfTurn @@ -90,11 +85,8 @@ class UnderrealmLichReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - return new LookLibraryAndPickControllerEffect( - StaticValue.get(3), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.GRAVEYARD, - false, false, false, Zone.HAND, false - ).apply(game, source); + new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.GRAVEYARD).apply(game, source); + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/u/Undertaker.java b/Mage.Sets/src/mage/cards/u/Undertaker.java index 169c67c9d5a..f16c85a6b8e 100644 --- a/Mage.Sets/src/mage/cards/u/Undertaker.java +++ b/Mage.Sets/src/mage/cards/u/Undertaker.java @@ -1,24 +1,22 @@ - package mage.cards.u; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.DiscardCardCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author shieldal */ public final class Undertaker extends CardImpl { @@ -32,7 +30,7 @@ public final 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 ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl<>("{B}")); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); ability.addCost(new TapSourceCost()); ability.addCost(new DiscardCardCost()); diff --git a/Mage.Sets/src/mage/cards/u/UnforgivingOne.java b/Mage.Sets/src/mage/cards/u/UnforgivingOne.java index 8fce59a9b31..8c4248ebe74 100644 --- a/Mage.Sets/src/mage/cards/u/UnforgivingOne.java +++ b/Mage.Sets/src/mage/cards/u/UnforgivingOne.java @@ -86,6 +86,6 @@ enum UnforgivingOnePredicate implements ObjectSourcePlayerPredicate { @Override public boolean apply(ObjectSourcePlayer input, Game game) { return input.getObject().getManaValue() - <= game.getBattlefield().count(filter, input.getSourceId(), input.getPlayerId(), game); + <= game.getBattlefield().count(filter, input.getPlayerId(), input.getSource(), game); } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/u/UnifiedStrike.java b/Mage.Sets/src/mage/cards/u/UnifiedStrike.java index 1489e7586db..5b4afd8fd5b 100644 --- a/Mage.Sets/src/mage/cards/u/UnifiedStrike.java +++ b/Mage.Sets/src/mage/cards/u/UnifiedStrike.java @@ -73,8 +73,7 @@ class UnifiedStrikeEffect extends OneShotEffect { .getActivePermanents( filter, source.getControllerId(), - source.getSourceId(), - game + source, game ).size(); boolean successful = creature.getPower().getValue() <= soldierCount; if (successful) { diff --git a/Mage.Sets/src/mage/cards/u/UnityOfTheDroids.java b/Mage.Sets/src/mage/cards/u/UnityOfTheDroids.java index 8ca363ac401..381930217f4 100644 --- a/Mage.Sets/src/mage/cards/u/UnityOfTheDroids.java +++ b/Mage.Sets/src/mage/cards/u/UnityOfTheDroids.java @@ -1,18 +1,15 @@ - package mage.cards.u; import java.util.UUID; import mage.abilities.Mode; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.PreventDamageToTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Zone; -import mage.filter.FilterCard; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.target.common.TargetCreaturePermanent; @@ -40,13 +37,11 @@ public final class UnityOfTheDroids extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent(artifactCreatureFilter)); // Look at the top four cards of your library. Put one of them into your hand and the rest into your graveyard. - Mode mode = new Mode(); - mode.addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(4), false, StaticValue.get(1), new FilterCard(), Zone.GRAVEYARD, false, false)); + Mode mode = new Mode(new LookLibraryAndPickControllerEffect(4, 1, PutCards.HAND, PutCards.GRAVEYARD)); this.getSpellAbility().addMode(mode); // Destroy target nonartifact creature. - mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetCreaturePermanent(nonArtifactCreatureFilter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/u/UniversalSurveillance.java b/Mage.Sets/src/mage/cards/u/UniversalSurveillance.java new file mode 100644 index 00000000000..d45a25ce2bd --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UniversalSurveillance.java @@ -0,0 +1,35 @@ +package mage.cards.u; + +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.ImproviseAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UniversalSurveillance extends CardImpl { + + public UniversalSurveillance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{U}{U}{U}"); + + // Improvise + this.addAbility(new ImproviseAbility()); + + // Draw X cards. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(ManacostVariableValue.REGULAR)); + } + + private UniversalSurveillance(final UniversalSurveillance card) { + super(card); + } + + @Override + public UniversalSurveillance copy() { + return new UniversalSurveillance(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnleashTheInferno.java b/Mage.Sets/src/mage/cards/u/UnleashTheInferno.java new file mode 100644 index 00000000000..4f116178aa5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnleashTheInferno.java @@ -0,0 +1,86 @@ +package mage.cards.u; + +import mage.abilities.Ability; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterArtifactOrEnchantmentPermanent; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnleashTheInferno extends CardImpl { + + public UnleashTheInferno(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}{R}{G}"); + + // Unleash the Inferno deals 7 damage to target creature or planeswalker. When it deals excess damage this way destroy target artifact or enchantment an opponent controls with mana value less than or equal to that amount of excess damage. + this.getSpellAbility().addEffect(new UnleashTheInfernoEffect()); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + } + + private UnleashTheInferno(final UnleashTheInferno card) { + super(card); + } + + @Override + public UnleashTheInferno copy() { + return new UnleashTheInferno(this); + } +} + +class UnleashTheInfernoEffect extends OneShotEffect { + + UnleashTheInfernoEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 7 damage to target creature or planeswalker. " + + "When it deals excess damage this way, destroy target artifact or enchantment " + + "an opponent controls with mana value less than or equal to that amount of excess damage"; + } + + private UnleashTheInfernoEffect(final UnleashTheInfernoEffect effect) { + super(effect); + } + + @Override + public UnleashTheInfernoEffect copy() { + return new UnleashTheInfernoEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + return false; + } + int lethal = Math.min(permanent.getLethalDamage(source.getSourceId(), game), 7); + permanent.damage(7, source, game); + int excess = 7 - lethal; + if (lethal > 0) { + return true; + } + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new DestroyTargetEffect(), false); + FilterPermanent filter = new FilterArtifactOrEnchantmentPermanent( + "artifact or enchantment an opponent controls with mana value less that or equal to " + excess + ); + filter.add(TargetController.OPPONENT.getControllerPredicate()); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, excess)); + ability.addTarget(new TargetPermanent(filter)); + game.fireReflexiveTriggeredAbility(ability, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnlicensedHearse.java b/Mage.Sets/src/mage/cards/u/UnlicensedHearse.java new file mode 100644 index 00000000000..948f3c11a39 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnlicensedHearse.java @@ -0,0 +1,99 @@ +package mage.cards.u; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.ExileTargetForSourceEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.CrewAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.target.common.TargetCardInASingleGraveyard; +import mage.util.CardUtil; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Optional; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnlicensedHearse extends CardImpl { + + private static final Hint hint = new ValueHint("Cards exiled", UnlicensedHearseValue.instance); + + public UnlicensedHearse(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // {T}: Exile up to two target cards from a single graveyard. + Ability ability = new SimpleActivatedAbility(new ExileTargetForSourceEffect(), new TapSourceCost()); + ability.addTarget(new TargetCardInASingleGraveyard( + 0, 2, StaticFilters.FILTER_CARD_CARDS + )); + this.addAbility(ability); + + // Unlicensed Hearse's power and toughness are each equal to the number of cards exiled with it. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, + new SetPowerToughnessSourceEffect( + UnlicensedHearseValue.instance, Duration.Custom + ) + ).addHint(hint)); + + // Crew 2 + this.addAbility(new CrewAbility(2)); + } + + private UnlicensedHearse(final UnlicensedHearse card) { + super(card); + } + + @Override + public UnlicensedHearse copy() { + return new UnlicensedHearse(this); + } +} + +enum UnlicensedHearseValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return Optional.of(game + .getExile() + .getExileZone(CardUtil.getExileZoneId( + game, sourceAbility.getSourceId(), + game.getState().getZoneChangeCounter(sourceAbility.getSourceId()) + ))) + .filter(Objects::nonNull) + .map(HashSet::size) + .orElse(0); + } + + @Override + public UnlicensedHearseValue copy() { + return this; + } + + @Override + public String getMessage() { + return "cards exiled with it"; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/u/UnlivingPsychopath.java b/Mage.Sets/src/mage/cards/u/UnlivingPsychopath.java index 490dc55e22e..f61653b5233 100644 --- a/Mage.Sets/src/mage/cards/u/UnlivingPsychopath.java +++ b/Mage.Sets/src/mage/cards/u/UnlivingPsychopath.java @@ -67,7 +67,7 @@ class UnlivingPsychopathPowerLessThanSourcePredicate implements ObjectSourcePlay @Override public boolean apply(ObjectSourcePlayer input, Game game) { - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(input.getSourceId()); + Permanent sourcePermanent = input.getSource().getSourcePermanentOrLKI(game); return sourcePermanent != null && input.getObject().getPower().getValue() < sourcePermanent.getPower().getValue(); } diff --git a/Mage.Sets/src/mage/cards/u/UnluckyWitness.java b/Mage.Sets/src/mage/cards/u/UnluckyWitness.java new file mode 100644 index 00000000000..9b1baa9a831 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnluckyWitness.java @@ -0,0 +1,148 @@ +package mage.cards.u; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.*; + +/** + * @author TheElk801 + */ +public final class UnluckyWitness extends CardImpl { + + public UnluckyWitness(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When Unlucky Witness dies, exile the top two cards of your library. Until your next end step, you may play one of those cards. + this.addAbility(new DiesSourceTriggeredAbility(new UnluckyWitnessEffect())); + } + + private UnluckyWitness(final UnluckyWitness card) { + super(card); + } + + @Override + public UnluckyWitness copy() { + return new UnluckyWitness(this); + } +} + +class UnluckyWitnessEffect extends OneShotEffect { + + UnluckyWitnessEffect() { + super(Outcome.Benefit); + staticText = "exile the top two cards of your library. " + + "Until your next end step, you may play one of those cards"; + } + + private UnluckyWitnessEffect(final UnluckyWitnessEffect effect) { + super(effect); + } + + @Override + public UnluckyWitnessEffect copy() { + return new UnluckyWitnessEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 2)); + player.moveCards(cards, Zone.EXILED, source, game); + game.addEffect(new UnluckyWitnessPlayEffect(cards, game), source); + return true; + } +} + +class UnluckyWitnessPlayEffect extends AsThoughEffectImpl { + + private final Set morSet = new HashSet<>(); + + UnluckyWitnessPlayEffect(Cards cards, Game game) { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.UntilYourNextEndStep, Outcome.Benefit); + cards.stream() + .map(uuid -> new MageObjectReference(uuid, game)) + .forEach(morSet::add); + } + + private UnluckyWitnessPlayEffect(final UnluckyWitnessPlayEffect effect) { + super(effect); + this.morSet.addAll(effect.morSet); + } + + @Override + public UnluckyWitnessPlayEffect copy() { + return new UnluckyWitnessPlayEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + UUID objectIdToCast = CardUtil.getMainCardId(game, sourceId); + return source.isControlledBy(affectedControllerId) + && morSet.stream().anyMatch(mor -> mor.refersTo(objectIdToCast, game)) + && UnluckyWitnessWatcher.checkRef(source, morSet, game); + } +} + +class UnluckyWitnessWatcher extends Watcher { + + private final Map> morMap = new HashMap<>(); + private static final Set emptySet = new HashSet<>(); + + UnluckyWitnessWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.SPELL_CAST + || event.getAdditionalReference() == null) { + return; + } + MageObjectReference mor = event.getAdditionalReference().getApprovingMageObjectReference(); + Spell spell = game.getSpell(event.getTargetId()); + if (mor == null || spell == null) { + return; + } + morMap.computeIfAbsent(mor, x -> new HashSet<>()) + .add(new MageObjectReference(spell.getMainCard(), game, -1)); + } + + static boolean checkRef(Ability source, Set morSet, Game game) { + UnluckyWitnessWatcher watcher = game.getState().getWatcher(UnluckyWitnessWatcher.class); + return watcher != null + && watcher + .morMap + .getOrDefault(new MageObjectReference(source.getSourceObject(game), game), emptySet) + .stream() + .noneMatch(morSet::contains); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnnervingAssault.java b/Mage.Sets/src/mage/cards/u/UnnervingAssault.java index 4234257366b..200334dccb1 100644 --- a/Mage.Sets/src/mage/cards/u/UnnervingAssault.java +++ b/Mage.Sets/src/mage/cards/u/UnnervingAssault.java @@ -1,4 +1,3 @@ - package mage.cards.u; import java.util.UUID; @@ -6,13 +5,13 @@ import mage.abilities.condition.common.ManaWasSpentCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ColoredManaSymbol; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; /** * @@ -21,24 +20,16 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class UnnervingAssault extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); - private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creatures you control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - filter2.add(TargetController.YOU.getControllerPredicate()); - } - public UnnervingAssault(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U/R}"); // Creatures your opponents control get -1/-0 until end of turn if {U} was spent to cast Unnerving Assault, and creatures you control get +1/+0 until end of turn if {R} was spent to cast it. this.getSpellAbility().addEffect(new ConditionalContinuousEffect( - new BoostAllEffect(-1, 0, Duration.EndOfTurn, filter, false), + new BoostAllEffect(-1, 0, Duration.EndOfTurn, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, false), new ManaWasSpentCondition(ColoredManaSymbol.U), "Creatures your opponents control get -1/-0 until end of turn if {U} was spent to cast this spell,")); this.getSpellAbility().addEffect(new ConditionalContinuousEffect( - new BoostAllEffect(1, 0, Duration.EndOfTurn, filter2, false), - new ManaWasSpentCondition(ColoredManaSymbol.R), " and creatures you control get +1/+0 until end of turn if {R} was spent to cast it")); + new BoostControlledEffect(1, 0, Duration.EndOfTurn), + new ManaWasSpentCondition(ColoredManaSymbol.R), " and creatures you control get +1/+0 until end of turn if {R} was spent to cast this spell")); this.getSpellAbility().addEffect(new InfoEffect("(Do both if {U}{R} was spent.)")); } diff --git a/Mage.Sets/src/mage/cards/u/UnquenchableFury.java b/Mage.Sets/src/mage/cards/u/UnquenchableFury.java new file mode 100644 index 00000000000..282ad79c8da --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnquenchableFury.java @@ -0,0 +1,118 @@ +package mage.cards.u; + +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnquenchableFury extends CardImpl { + + public UnquenchableFury(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // Enchanted creature has "Whenever this creature attacks, it deals X damage to defending player, where X is the number of cards in their hand." + this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect(new AttacksTriggeredAbility( + new UnquenchableFuryEffect(), false, null, SetTargetPointer.PLAYER + ), AttachmentType.AURA))); + + // When Unquenchable Fury is put into your graveyard from the battlfield, return it to your hand. + this.addAbility(new UnquenchableFuryTriggeredAbility()); + } + + private UnquenchableFury(final UnquenchableFury card) { + super(card); + } + + @Override + public UnquenchableFury copy() { + return new UnquenchableFury(this); + } +} + +class UnquenchableFuryEffect extends OneShotEffect { + + UnquenchableFuryEffect() { + super(Outcome.Benefit); + staticText = "it deals X damage to defending player, where X is the number of cards in their hand"; + } + + private UnquenchableFuryEffect(final UnquenchableFuryEffect effect) { + super(effect); + } + + @Override + public UnquenchableFuryEffect copy() { + return new UnquenchableFuryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + return player != null + && !player.getHand().isEmpty() + && player.damage(player.getHand().size(), source, game) > 0; + } +} + +class UnquenchableFuryTriggeredAbility extends TriggeredAbilityImpl { + + UnquenchableFuryTriggeredAbility() { + super(Zone.BATTLEFIELD, new ReturnSourceFromGraveyardToHandEffect()); + } + + private UnquenchableFuryTriggeredAbility(final UnquenchableFuryTriggeredAbility ability) { + super(ability); + } + + @Override + public UnquenchableFuryTriggeredAbility copy() { + return new UnquenchableFuryTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + Permanent permanent = zEvent.getTarget(); + return permanent != null && zEvent.isDiesEvent() + && permanent.getId().equals(this.getSourceId()) + && permanent.isOwnedBy(permanent.getControllerId()); + } + + @Override + public String getRule() { + return "When {this} is put into your graveyard from the battlfield, return it to your hand."; + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnquenchableThirst.java b/Mage.Sets/src/mage/cards/u/UnquenchableThirst.java index 60d883cd1b0..c826269c660 100644 --- a/Mage.Sets/src/mage/cards/u/UnquenchableThirst.java +++ b/Mage.Sets/src/mage/cards/u/UnquenchableThirst.java @@ -1,13 +1,9 @@ package mage.cards.u; -import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.OrCondition; -import mage.abilities.condition.common.CardsInControllerGraveyardCondition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.condition.common.DesertControlledOrGraveyardCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect; @@ -18,26 +14,16 @@ 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.common.FilterControlledPermanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author spjspj */ public final class UnquenchableThirst extends CardImpl { - private static final FilterControlledPermanent filterDesertPermanent = new FilterControlledPermanent("Desert"); - private static final FilterCard filterDesertCard = new FilterCard("Desert card"); - - static { - filterDesertPermanent.add(SubType.DESERT.getPredicate()); - filterDesertCard.add(SubType.DESERT.getPredicate()); - } - public UnquenchableThirst(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); @@ -47,20 +33,17 @@ public final class UnquenchableThirst extends CardImpl { TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // When Unquenchable Thirst enters the battlefield, if you control a Desert or there is a Desert card in your graveyard, tap enchanted creature. - Ability ability2 = new ConditionalInterveningIfTriggeredAbility( + this.addAbility(new ConditionalInterveningIfTriggeredAbility( new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect()), - new OrCondition( - new PermanentsOnTheBattlefieldCondition(new FilterControlledPermanent(filterDesertPermanent)), - new CardsInControllerGraveyardCondition(1, filterDesertCard)), - "When {this} enters the battlefield, if you control a Desert or there is a Desert card in your graveyard, tap enchanted creature."); - this.addAbility(ability2); + DesertControlledOrGraveyardCondition.instance, "When {this} enters the battlefield, " + + "if you control a Desert or there is a Desert card in your graveyard, tap enchanted creature." + ).addHint(DesertControlledOrGraveyardCondition.getHint())); // Enchanted creature doesn't untap during its controller's untap step. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DontUntapInControllersUntapStepEnchantedEffect())); + this.addAbility(new SimpleStaticAbility(new DontUntapInControllersUntapStepEnchantedEffect())); } private UnquenchableThirst(final UnquenchableThirst card) { diff --git a/Mage.Sets/src/mage/cards/u/UnscytheKillerOfKings.java b/Mage.Sets/src/mage/cards/u/UnscytheKillerOfKings.java index b2b7e00f0e4..82a47394ca6 100644 --- a/Mage.Sets/src/mage/cards/u/UnscytheKillerOfKings.java +++ b/Mage.Sets/src/mage/cards/u/UnscytheKillerOfKings.java @@ -1,12 +1,9 @@ - package mage.cards.u; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; @@ -23,29 +20,32 @@ import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.game.permanent.token.ZombieToken; import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class UnscytheKillerOfKings extends CardImpl { public UnscytheKillerOfKings(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{U}{B}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{U}{B}{B}{R}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +3/+3 and has first strike. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(3, 3))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.EQUIPMENT))); + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(3, 3)); + ability.addEffect(new GainAbilityAttachedEffect( + FirstStrikeAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and has first strike")); + this.addAbility(ability); // Whenever a creature dealt damage by equipped creature this turn dies, you may exile that card. If you do, create a 2/2 black Zombie creature token. this.addAbility(new UnscytheKillerOfKingsTriggeredAbility(new UnscytheEffect())); // Equip {2} - this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2), new TargetControlledCreaturePermanent(), false)); + this.addAbility(new EquipAbility(2), false); } private UnscytheKillerOfKings(final UnscytheKillerOfKings card) { @@ -80,25 +80,23 @@ class UnscytheKillerOfKingsTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (((ZoneChangeEvent) event).isDiesEvent()) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getTarget().isCreature(game)) { // target token can't create Zombie - Permanent equipment = game.getPermanent(getSourceId()); - // the currently equiped creature must have done damage to the dying creature - if (equipment != null && equipment.getAttachedTo() != null) { - boolean damageDealt = false; - for (MageObjectReference mor : zEvent.getTarget().getDealtDamageByThisTurn()) { - if (mor.refersTo(equipment.getAttachedTo(), game)) { - damageDealt = true; - break; - } - } - if (damageDealt) { - Effect effect = this.getEffects().get(0); - effect.setTargetPointer(new FixedTarget(event.getTargetId())); - return true; - } - } + if (!((ZoneChangeEvent) event).isDiesEvent()) { + return false; + } + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (!zEvent.getTarget().isCreature(game)) { + return false; + } // target token can't create Zombie + Permanent equipment = game.getPermanent(getSourceId()); + // the currently equiped creature must have done damage to the dying creature + if (equipment == null || equipment.getAttachedTo() == null) { + return false; + } + boolean damageDealt = false; + for (MageObjectReference mor : zEvent.getTarget().getDealtDamageByThisTurn()) { + if (mor.refersTo(equipment.getAttachedTo(), game)) { + getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); + return true; } } return false; @@ -106,7 +104,7 @@ class UnscytheKillerOfKingsTriggeredAbility extends TriggeredAbilityImpl { @Override public String getTriggerPhrase() { - return "Whenever a creature dealt damage by equipped creature this turn dies, " ; + return "Whenever a creature dealt damage by equipped creature this turn dies, "; } } @@ -129,13 +127,16 @@ class UnscytheEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Card card = game.getCard(targetPointer.getFirst(game, source)); - if (card != null && game.getState().getZone(card.getId()) == Zone.GRAVEYARD && controller.moveCardToExileWithInfo(card, null, "", source, game, Zone.GRAVEYARD, true)) { - ZombieToken zombie = new ZombieToken(); - return zombie.putOntoBattlefield(1, game, source, source.getControllerId()); - } - return true; + if (controller == null) { + return false; + } + Card card = game.getCard(targetPointer.getFirst(game, source)); + if (card == null) { + return false; + } + if (game.getState().getZone(card.getId()) == Zone.GRAVEYARD && controller.moveCardToExileWithInfo(card, null, "", source, game, Zone.GRAVEYARD, true)) { + ZombieToken zombie = new ZombieToken(); + return zombie.putOntoBattlefield(1, game, source, source.getControllerId()); } return false; } diff --git a/Mage.Sets/src/mage/cards/u/UnstableHulk.java b/Mage.Sets/src/mage/cards/u/UnstableHulk.java index 3e2b970b65c..3725e0cf6f7 100644 --- a/Mage.Sets/src/mage/cards/u/UnstableHulk.java +++ b/Mage.Sets/src/mage/cards/u/UnstableHulk.java @@ -33,7 +33,7 @@ public final class UnstableHulk extends CardImpl { this.toughness = new MageInt(2); // Morph {3}{R}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{R}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{R}{R}"))); //When Unstable Hulk is turned face up, it gets +6/+6 and gains trample until end of turn. You skip your next turn. Effect effect = new GainAbilitySourceEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); diff --git a/Mage.Sets/src/mage/cards/u/UnstoppableAsh.java b/Mage.Sets/src/mage/cards/u/UnstoppableAsh.java index 91e013ad7fe..9ee9c39e64d 100644 --- a/Mage.Sets/src/mage/cards/u/UnstoppableAsh.java +++ b/Mage.Sets/src/mage/cards/u/UnstoppableAsh.java @@ -1,8 +1,5 @@ - package mage.cards.u; -import java.util.EnumSet; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.BecomesBlockedAllTriggeredAbility; import mage.abilities.effects.Effect; @@ -17,10 +14,10 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth - * */ public final class UnstoppableAsh extends CardImpl { @@ -31,7 +28,7 @@ public final class UnstoppableAsh extends CardImpl { } public UnstoppableAsh(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.TREEFOLK); this.subtype.add(SubType.WARRIOR); @@ -42,13 +39,12 @@ public final class UnstoppableAsh extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Champion a Treefolk or Warrior - this.addAbility(new ChampionAbility(this, EnumSet.of(SubType.TREEFOLK, SubType.WARRIOR), false)); - + this.addAbility(new ChampionAbility(this, SubType.TREEFOLK, SubType.WARRIOR)); + // Whenever a creature you control becomes blocked, it gets +0/+5 until end of turn. Effect effect = new BoostTargetEffect(0, 5, Duration.EndOfTurn); effect.setText("it gets +0/+5 until end of turn"); this.addAbility(new BecomesBlockedAllTriggeredAbility(effect, false, filter, true)); - } private UnstoppableAsh(final UnstoppableAsh card) { diff --git a/Mage.Sets/src/mage/cards/u/UntaidakeTheCloudKeeper.java b/Mage.Sets/src/mage/cards/u/UntaidakeTheCloudKeeper.java index 7257d219aa9..b1a93996612 100644 --- a/Mage.Sets/src/mage/cards/u/UntaidakeTheCloudKeeper.java +++ b/Mage.Sets/src/mage/cards/u/UntaidakeTheCloudKeeper.java @@ -77,7 +77,7 @@ class LegendaryCastManaCondition extends ManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { if (source instanceof SpellAbility) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object != null && object.isLegendary()) { return true; } diff --git a/Mage.Sets/src/mage/cards/u/UntetheredExpress.java b/Mage.Sets/src/mage/cards/u/UntetheredExpress.java index 6ac63afece8..4c097b1ab7a 100644 --- a/Mage.Sets/src/mage/cards/u/UntetheredExpress.java +++ b/Mage.Sets/src/mage/cards/u/UntetheredExpress.java @@ -30,7 +30,7 @@ public final class UntetheredExpress extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Whenever Untethered Express attacks, put a +1/+1 counter on it. - this.addAbility(new AttacksTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false)); + this.addAbility(new AttacksTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()).setText("put a +1/+1 counter on it"), false)); // Crew 1 this.addAbility(new CrewAbility(1)); diff --git a/Mage.Sets/src/mage/cards/u/UnyaroBees.java b/Mage.Sets/src/mage/cards/u/UnyaroBees.java index 05c9a14042c..d797d3087fe 100644 --- a/Mage.Sets/src/mage/cards/u/UnyaroBees.java +++ b/Mage.Sets/src/mage/cards/u/UnyaroBees.java @@ -35,7 +35,7 @@ public final class UnyaroBees extends CardImpl { // {G}: Unyaro Bees gets +1/+1 until end of turn. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 1, Duration.EndOfTurn), new ManaCostsImpl("{G}"))); // {3}{G}, Sacrifice Unyaro Bees: Unyaro Bees deals 2 damage to any target. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new ManaCostsImpl("{3}{G}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2, "it"), new ManaCostsImpl("{3}{G}")); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/u/UrabraskHereticPraetor.java b/Mage.Sets/src/mage/cards/u/UrabraskHereticPraetor.java new file mode 100644 index 00000000000..ccaa51f7fe0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UrabraskHereticPraetor.java @@ -0,0 +1,109 @@ +package mage.cards.u; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.ExileTopXMayPlayUntilEndOfTurnEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UrabraskHereticPraetor extends CardImpl { + + public UrabraskHereticPraetor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); + this.subtype.add(SubType.PRAETOR); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // At the beginning of your upkeep, exile the top card of your library. You may play it this turn. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new ExileTopXMayPlayUntilEndOfTurnEffect(1, false), + TargetController.YOU, false + )); + + // At the beginning of each opponent's upkeep, the next time they would draw a card this turn, instead they exile the top card of their library. They may play it this turn. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new UrabraskHereticPraetorEffect(), TargetController.OPPONENT, false + )); + } + + private UrabraskHereticPraetor(final UrabraskHereticPraetor card) { + super(card); + } + + @Override + public UrabraskHereticPraetor copy() { + return new UrabraskHereticPraetor(this); + } +} + +class UrabraskHereticPraetorEffect extends ReplacementEffectImpl { + + UrabraskHereticPraetorEffect() { + super(Duration.EndOfTurn, Outcome.Detriment); + staticText = "the next time they would draw a card this turn, " + + "instead they exile the top card of their library. They may play it this turn"; + } + + private UrabraskHereticPraetorEffect(final UrabraskHereticPraetorEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DRAW_CARD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return game.isActivePlayer(event.getPlayerId()); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player player = game.getPlayer(game.getActivePlayerId()); + if (player == null) { + discard(); + return false; + } + Card card = player.getLibrary().getFromTop(game); + if (card != null) { + player.moveCards(card, Zone.EXILED, source, game); + CardUtil.makeCardPlayable( + game, source, card, Duration.EndOfTurn, + false, player.getId(), null + ); + } + discard(); + return true; + } + + @Override + public UrabraskHereticPraetorEffect copy() { + return new UrabraskHereticPraetorEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UrborgPanther.java b/Mage.Sets/src/mage/cards/u/UrborgPanther.java index 7f26d33f4fd..ce9179a2010 100644 --- a/Mage.Sets/src/mage/cards/u/UrborgPanther.java +++ b/Mage.Sets/src/mage/cards/u/UrborgPanther.java @@ -1,10 +1,9 @@ package mage.cards.u; -import java.util.UUID; - import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.CompositeCost; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ColoredManaCost; @@ -16,57 +15,64 @@ import mage.constants.CardType; import mage.constants.ColoredManaSymbol; import mage.constants.SubType; import mage.filter.FilterCard; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.NamePredicate; -import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; +import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; /** - * * @author Ketsuban */ public class UrborgPanther extends CardImpl { - private static final FilterControlledCreaturePermanent filter1 = new FilterControlledCreaturePermanent("creature named Feral Shadow"); - private static final FilterControlledCreaturePermanent filter2 = new FilterControlledCreaturePermanent("creature named Breathstealer"); - + private static final FilterPermanent filter = new FilterCreaturePermanent("creature blocking {this}"); + private static final FilterControlledCreaturePermanent filter1 + = new FilterControlledCreaturePermanent("creature named Feral Shadow"); + private static final FilterControlledCreaturePermanent filter2 + = new FilterControlledCreaturePermanent("creature named Breathstealer"); private static final FilterCard filterCard = new FilterCreatureCard("card named Spirit of the Night"); static { + filter.add(BlockingOrBlockedBySourcePredicate.BLOCKING); filter1.add(new NamePredicate("Feral Shadow")); filter2.add(new NamePredicate("Breathstealer")); filterCard.add(new NamePredicate("Spirit of the Night")); } public UrborgPanther(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.NIGHTSTALKER); this.subtype.add(SubType.CAT); this.power = new MageInt(2); this.toughness = new MageInt(2); // B, Sacrifice Urborg Panther: Destroy target creature blocking Urborg Panther. - Ability ability1 = new SimpleActivatedAbility(new DestroyTargetEffect(), - new ColoredManaCost(ColoredManaSymbol.B)); - ability1.addCost(new SacrificeSourceCost()); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking {this}"); - filter.add(new BlockingAttackerIdPredicate(this.getId())); - ability1.addTarget(new TargetCreaturePermanent(filter)); - this.addAbility(ability1); + Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ColoredManaCost(ColoredManaSymbol.B)); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); // Sacrifice a creature named Feral Shadow, a creature named Breathstealer, and // Urborg Panther: Search your library for a card named Spirit of the Night and // put that card onto the battlefield. Then shuffle your library. - Ability ability2 = new SimpleActivatedAbility( - new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(1, 1, new FilterCard(filterCard))), - new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, filter1, true))); - ability2.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, filter2, true))); - ability2.addCost(new SacrificeSourceCost()); - this.addAbility(ability2); + this.addAbility(new SimpleActivatedAbility( + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary( + 1, 1, filterCard + )), + new CompositeCost(new CompositeCost( + new SacrificeTargetCost(new TargetControlledCreaturePermanent(filter1)), + new SacrificeTargetCost(new TargetControlledCreaturePermanent(filter2)), + "" + ), new SacrificeSourceCost(), "sacrifice a creature named Feral Shadow, " + + "a creature named Breathstealer, and {this}") + )); } private UrborgPanther(final UrborgPanther card) { @@ -77,5 +83,4 @@ public class UrborgPanther extends CardImpl { public UrborgPanther copy() { return new UrborgPanther(this); } - } diff --git a/Mage.Sets/src/mage/cards/u/UrgeToFeed.java b/Mage.Sets/src/mage/cards/u/UrgeToFeed.java index 5633f662d04..cc018dc916e 100644 --- a/Mage.Sets/src/mage/cards/u/UrgeToFeed.java +++ b/Mage.Sets/src/mage/cards/u/UrgeToFeed.java @@ -63,7 +63,7 @@ class UrgeToFeedEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { TargetCreaturePermanent target = new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) && target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), game)) { + if (target.canChoose(source.getControllerId(), source, game) && target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), source, game)) { for (UUID vampireId : target.getTargets()) { Permanent vampire = game.getPermanent(vampireId); if (vampire != null) { diff --git a/Mage.Sets/src/mage/cards/u/UrzaAcademyHeadmaster.java b/Mage.Sets/src/mage/cards/u/UrzaAcademyHeadmaster.java index 43021ee3c4c..5e24861e04c 100644 --- a/Mage.Sets/src/mage/cards/u/UrzaAcademyHeadmaster.java +++ b/Mage.Sets/src/mage/cards/u/UrzaAcademyHeadmaster.java @@ -3,7 +3,6 @@ package mage.cards.u; import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.ControllerLifeCount; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.dynamicvalue.common.PermanentsTargetOpponentControlsCount; @@ -11,6 +10,7 @@ import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.*; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.continuous.*; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.DistributeCountersEffect; @@ -55,7 +55,7 @@ public final class UrzaAcademyHeadmaster extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.URZA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Head to AskUrza.com and click +1. this.addAbility(new LoyaltyAbility(new UrzaAcademyHeadmasterRandomEffect(1, setInfo), 1)); @@ -213,7 +213,7 @@ class UrzaAcademyHeadmasterRandomEffect extends OneShotEffect { break; case 17: // TEZZERET AGENT OF BOLAS 1 sb.append("Look at the top five cards of your library. You may reveal an artifact card from among them and put it into your hand. Put the rest on the bottom of your library in any order."); - effects.add(new LookLibraryAndPickControllerEffect(5, 1, new FilterArtifactCard(), true)); + effects.add(new LookLibraryAndPickControllerEffect(5, 1, StaticFilters.FILTER_CARD_ARTIFACT_AN, PutCards.HAND, PutCards.BOTTOM_ANY)); break; case 18: // UGIN 1 sb.append("Urza deals 3 damage to any target."); @@ -431,7 +431,7 @@ class UrzaAcademyHeadmasterRandomEffect extends OneShotEffect { game.informPlayers(sb.toString()); if (target != null) { - if (target.canChoose(source.getSourceId(), controller.getId(), game) && controller.canRespond()) { + if (target.canChoose(controller.getId(), source, game) && controller.canRespond()) { target.chooseTarget(outcome, controller.getId(), source, game); } else { // 1/19/2018 (...) If the ability that comes up requires a target and there are no legal targets available, click again until that’s not true. @@ -486,7 +486,7 @@ class UrzaAcademyHeadmasterManaEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - int x = game.getBattlefield().count(new FilterControlledCreaturePermanent(), source.getSourceId(), source.getControllerId(), game); + int x = game.getBattlefield().count(new FilterControlledCreaturePermanent(), source.getControllerId(), source, game); Choice manaChoice = new ChoiceImpl(); Set choices = new LinkedHashSet<>(); choices.add("White"); @@ -559,7 +559,7 @@ class UrzaAcademyHeadmasterBrainstormEffect extends OneShotEffect { private boolean putOnLibrary(Player player, Ability source, Game game) { TargetCardInHand target = new TargetCardInHand(); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.ReturnToHand, target, source, game); Card card = player.getHand().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/u/UrzaLordHighArtificer.java b/Mage.Sets/src/mage/cards/u/UrzaLordHighArtificer.java index 71cf2f80418..6a541f44a82 100644 --- a/Mage.Sets/src/mage/cards/u/UrzaLordHighArtificer.java +++ b/Mage.Sets/src/mage/cards/u/UrzaLordHighArtificer.java @@ -125,7 +125,7 @@ class UrzaLordHighArtificerManaEffect extends BasicManaEffect { @Override public List getNetMana(Game game, Ability source) { if (game != null && game.inCheckPlayableState()) { - int count = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int count = game.getBattlefield().count(filter, source.getControllerId(), source, game); List netMana = new ArrayList<>(); if (count > 0) { netMana.add(Mana.BlueMana(count)); diff --git a/Mage.Sets/src/mage/cards/u/UrzasBauble.java b/Mage.Sets/src/mage/cards/u/UrzasBauble.java index 9a170b0770e..4360f9b830b 100644 --- a/Mage.Sets/src/mage/cards/u/UrzasBauble.java +++ b/Mage.Sets/src/mage/cards/u/UrzasBauble.java @@ -69,7 +69,7 @@ class LookAtRandomCardEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Player targetPlayer = game.getPlayer(source.getFirstTarget()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && targetPlayer != null && sourceObject != null) { diff --git a/Mage.Sets/src/mage/cards/u/UrzasScienceFairProject.java b/Mage.Sets/src/mage/cards/u/UrzasScienceFairProject.java index e84bf07addd..29e314fbfee 100644 --- a/Mage.Sets/src/mage/cards/u/UrzasScienceFairProject.java +++ b/Mage.Sets/src/mage/cards/u/UrzasScienceFairProject.java @@ -1,12 +1,11 @@ package mage.cards.u; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.Effect; +import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.PreventCombatDamageBySourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; @@ -16,16 +15,13 @@ import mage.abilities.keyword.FlyingAbility; 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.SubType; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author spjspj */ public final class UrzasScienceFairProject extends CardImpl { @@ -56,7 +52,13 @@ class UrzasScienceFairProjectEffect extends OneShotEffect { public UrzasScienceFairProjectEffect() { super(Outcome.Benefit); - this.staticText = "Roll a six-sided die. {this} gets the indicated result. 1 - -2/-2 until end of turn. 2 - Prevent all combat damage it would deal this turn. 3 - gains vigilance until end of turn. 4 - gains first strike until end of turn. 5 - gains flying until end of turn. 6 - gets +2/+2 until end of turn"; + this.staticText = "Roll a six-sided die. {this} gets the indicated result." + + "
1 - It gets -2/-2 until end of turn." + + "
2 - Prevent all combat damage it would deal this turn." + + "
3 - It gains vigilance until end of turn." + + "
4 - It gains first strike until end of turn." + + "
5 - It gains flying until end of turn." + + "
6 - It gets +2/+2 until end of turn"; } public UrzasScienceFairProjectEffect(final UrzasScienceFairProjectEffect effect) { @@ -71,31 +73,41 @@ class UrzasScienceFairProjectEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - int amount = controller.rollDice(outcome, source, game, 6); - - Effect effect = null; - // 1 - -2/-2 until end of turn. - // 2 - Prevent all combat damage it would deal this turn. - // 3 - gains vigilance until end of turn. - // 4 - gains first strike until end of turn. - // 5 - gains flying until end of turn. - // 6 - gets +2/+2 until end of turn"; - if (amount == 1) { - game.addEffect(new BoostSourceEffect(-2, -2, Duration.EndOfTurn), source); - } else if (amount == 2) { - game.addEffect(new PreventCombatDamageBySourceEffect(Duration.EndOfTurn), source); - } else if (amount == 3) { - game.addEffect(new GainAbilitySourceEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn), source); - } else if (amount == 4) { - game.addEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn), source); - } else if (amount == 5) { - game.addEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), source); - } else if (amount == 6) { - game.addEffect(new BoostSourceEffect(+2, +2, Duration.EndOfTurn), source); - } - return true; + if (controller == null) { + return false; } - return false; + int amount = controller.rollDice(outcome, source, game, 6); + + ContinuousEffect effect; + // 1 - -2/-2 until end of turn. + // 2 - Prevent all combat damage it would deal this turn. + // 3 - gains vigilance until end of turn. + // 4 - gains first strike until end of turn. + // 5 - gains flying until end of turn. + // 6 - gets +2/+2 until end of turn"; + switch (amount) { + case 1: + effect = new BoostSourceEffect(-2, -2, Duration.EndOfTurn); + break; + case 2: + effect = new PreventCombatDamageBySourceEffect(Duration.EndOfTurn); + break; + case 3: + effect = new GainAbilitySourceEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn); + break; + case 4: + effect = new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn); + break; + case 5: + effect = new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn); + break; + case 6: + effect = new BoostSourceEffect(+2, +2, Duration.EndOfTurn); + break; + default: + return true; + } + game.addEffect(effect, source); + return true; } } diff --git a/Mage.Sets/src/mage/cards/v/Vacuumelt.java b/Mage.Sets/src/mage/cards/v/Vacuumelt.java index 803fdea8f96..ab53f590a1a 100644 --- a/Mage.Sets/src/mage/cards/v/Vacuumelt.java +++ b/Mage.Sets/src/mage/cards/v/Vacuumelt.java @@ -20,7 +20,7 @@ public final class Vacuumelt extends CardImpl { // Replicate {2}{U} - this.addAbility(new ReplicateAbility(this, "{2}{U}")); + this.addAbility(new ReplicateAbility("{2}{U}")); // Return target creature to its owner's hand. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); diff --git a/Mage.Sets/src/mage/cards/v/VadersCommand.java b/Mage.Sets/src/mage/cards/v/VadersCommand.java index 074a9c05f35..a1aa2db0f09 100644 --- a/Mage.Sets/src/mage/cards/v/VadersCommand.java +++ b/Mage.Sets/src/mage/cards/v/VadersCommand.java @@ -45,20 +45,17 @@ public final class VadersCommand extends CardImpl { this.getSpellAbility().addTarget(new TargetSpell()); // Destroy target planeswalker. - Mode mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + Mode mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetPermanent(filterPlaneswalker)); this.getSpellAbility().addMode(mode); // Destroy target nonartifact creature. - mode = new Mode(); - mode.addEffect(new DestroyTargetEffect()); + mode = new Mode(new DestroyTargetEffect()); mode.addTarget(new TargetCreaturePermanent(filterNonArtifact)); this.getSpellAbility().addMode(mode); // Gain 5 life. - mode = new Mode(); - mode.addEffect(new GainLifeEffect(5).setText("Gain 5 life")); + mode = new Mode(new GainLifeEffect(5).setText("Gain 5 life")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/v/ValakutFireboar.java b/Mage.Sets/src/mage/cards/v/ValakutFireboar.java index 63774bc62c8..83529ba2d02 100644 --- a/Mage.Sets/src/mage/cards/v/ValakutFireboar.java +++ b/Mage.Sets/src/mage/cards/v/ValakutFireboar.java @@ -25,7 +25,7 @@ public final class ValakutFireboar extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(7); - this.addAbility(new AttacksTriggeredAbility(new SwitchPowerToughnessSourceEffect(Duration.EndOfTurn), false)); + this.addAbility(new AttacksTriggeredAbility(new SwitchPowerToughnessSourceEffect(Duration.EndOfTurn).setText("switch its power and toughness until end of turn"), false)); } private ValakutFireboar(final ValakutFireboar card) { diff --git a/Mage.Sets/src/mage/cards/v/ValakutTheMoltenPinnacle.java b/Mage.Sets/src/mage/cards/v/ValakutTheMoltenPinnacle.java index b1410f17f19..9308cd121ac 100644 --- a/Mage.Sets/src/mage/cards/v/ValakutTheMoltenPinnacle.java +++ b/Mage.Sets/src/mage/cards/v/ValakutTheMoltenPinnacle.java @@ -66,7 +66,7 @@ class ValakutTheMoltenPinnacleTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkInterveningIfClause(Game game) { - return game.getBattlefield().count(ValakutTheMoltenPinnacle.filter, getSourceId(), getControllerId(), game) > 5; + return game.getBattlefield().count(ValakutTheMoltenPinnacle.filter, getControllerId(), this, game) > 5; } @Override diff --git a/Mage.Sets/src/mage/cards/v/ValiantChangeling.java b/Mage.Sets/src/mage/cards/v/ValiantChangeling.java index f9ae21df218..0511eddac43 100644 --- a/Mage.Sets/src/mage/cards/v/ValiantChangeling.java +++ b/Mage.Sets/src/mage/cards/v/ValiantChangeling.java @@ -68,7 +68,7 @@ class ValiantChangelingCostReductionEffect extends CostModificationEffectImpl { Set subTypes = new HashSet(); int reductionAmount = 0; for (Permanent permanent : game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_CONTROLLED_CREATURE, source.getControllerId(), source.getSourceId(), game + StaticFilters.FILTER_CONTROLLED_CREATURE, source.getControllerId(), source, game )) { if (permanent.isAllCreatureTypes(game)) { reductionAmount = 5; diff --git a/Mage.Sets/src/mage/cards/v/ValkiGodOfLies.java b/Mage.Sets/src/mage/cards/v/ValkiGodOfLies.java index 3769775caac..78e85638f85 100644 --- a/Mage.Sets/src/mage/cards/v/ValkiGodOfLies.java +++ b/Mage.Sets/src/mage/cards/v/ValkiGodOfLies.java @@ -11,7 +11,6 @@ import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.ContinuousEffect; @@ -67,7 +66,7 @@ public final class ValkiGodOfLies extends ModalDoubleFacesCard { // Tibalt, Cosmic Impostor // Legendary Planeswalker — Tibalt this.getRightHalfCard().addSuperType(SuperType.LEGENDARY); - this.getRightHalfCard().addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.getRightHalfCard().setStartingLoyalty(5); // As Tibalt enters the battlefield, you get an emblem with “You may play cards exiled with Tibalt, Cosmic Impostor, and you may spend mana as though it were mana of any color to cast those spells.” this.getRightHalfCard().addAbility(new AsEntersBattlefieldAbility(new GetEmblemEffect(new TibaltCosmicImpostorEmblem()))); @@ -114,7 +113,7 @@ class ValkiGodOfLiesRevealExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject Valki = game.getObject(source.getSourceId()); + MageObject Valki = game.getObject(source); Set cardsToExile = new LinkedHashSet<>(); if (controller != null && Valki != null) { @@ -232,7 +231,7 @@ class ValkiGodOfLiesCopyExiledEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject Valki = game.getObject(source.getSourceId()); + MageObject Valki = game.getObject(source); Player controller = game.getPlayer(source.getControllerId()); if (controller != null && Valki != null) { diff --git a/Mage.Sets/src/mage/cards/v/ValorousStance.java b/Mage.Sets/src/mage/cards/v/ValorousStance.java index 2a5aeabcf16..12db80dab56 100644 --- a/Mage.Sets/src/mage/cards/v/ValorousStance.java +++ b/Mage.Sets/src/mage/cards/v/ValorousStance.java @@ -35,8 +35,7 @@ public final class ValorousStance extends CardImpl { this.getSpellAbility().addEffect(new GainAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // or destroy target creature with toughness 4 or greater. - Mode mode1 = new Mode(); - mode1.addEffect(new DestroyTargetEffect()); + Mode mode1 = new Mode(new DestroyTargetEffect()); mode1.addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addMode(mode1); diff --git a/Mage.Sets/src/mage/cards/v/VampireScrivener.java b/Mage.Sets/src/mage/cards/v/VampireScrivener.java new file mode 100644 index 00000000000..8da71789ddb --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VampireScrivener.java @@ -0,0 +1,86 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.GainLifeControllerTriggeredAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VampireScrivener extends CardImpl { + + public VampireScrivener(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.WARLOCK); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever you gain life during your turn, put a +1/+1 counter on Vampire Scrivener. + this.addAbility(new ConditionalTriggeredAbility(new GainLifeControllerTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance())), MyTurnCondition.instance, + "Whenever you gain life during your turn, put a +1/+1 counter on {this}." + )); + + // Whenever you lose life during your turn, put a +1/+1 counter on Vampire Scrivener. + this.addAbility(new VampireScrivenerTriggeredAbility()); + } + + private VampireScrivener(final VampireScrivener card) { + super(card); + } + + @Override + public VampireScrivener copy() { + return new VampireScrivener(this); + } +} + +class VampireScrivenerTriggeredAbility extends TriggeredAbilityImpl { + + VampireScrivenerTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance())); + } + + private VampireScrivenerTriggeredAbility(final VampireScrivenerTriggeredAbility ability) { + super(ability); + } + + @Override + public VampireScrivenerTriggeredAbility copy() { + return new VampireScrivenerTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.LOST_LIFE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return game.isActivePlayer(event.getPlayerId()) && game.isActivePlayer(getControllerId()); + } + + @Override + public String getRule() { + return "Whenever you lose life during your turn, put a +1/+1 counter on {this}."; + } +} diff --git a/Mage.Sets/src/mage/cards/v/VampireSocialite.java b/Mage.Sets/src/mage/cards/v/VampireSocialite.java index 758ebec5507..2660d5bc732 100644 --- a/Mage.Sets/src/mage/cards/v/VampireSocialite.java +++ b/Mage.Sets/src/mage/cards/v/VampireSocialite.java @@ -99,7 +99,7 @@ class VampireSocialiteReplacementEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (OpponentsLostLifeCondition.instance.apply(game, source)) { Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); - return permanent != null && filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return permanent != null && filter.match(permanent, source.getControllerId(), source, game); } return false; } diff --git a/Mage.Sets/src/mage/cards/v/VampiricLink.java b/Mage.Sets/src/mage/cards/v/VampiricLink.java index f1d394c5909..0913cec0350 100644 --- a/Mage.Sets/src/mage/cards/v/VampiricLink.java +++ b/Mage.Sets/src/mage/cards/v/VampiricLink.java @@ -1,10 +1,9 @@ - package mage.cards.v; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DealsDamageAttachedTriggeredAbility; -import mage.abilities.dynamicvalue.common.NumericSetToEffectValues; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.keyword.EnchantAbility; @@ -30,12 +29,11 @@ public final class VampiricLink extends CardImpl { // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Whenever enchanted creature deals damage, you gain that much life. - this.addAbility(new DealsDamageAttachedTriggeredAbility(Zone.BATTLEFIELD, new GainLifeEffect(new NumericSetToEffectValues("that much", "damage")), false)); + this.addAbility(new DealsDamageAttachedTriggeredAbility(Zone.BATTLEFIELD, new GainLifeEffect(SavedDamageValue.MUCH), false)); } private VampiricLink(final VampiricLink card) { diff --git a/Mage.Sets/src/mage/cards/v/Vampirism.java b/Mage.Sets/src/mage/cards/v/Vampirism.java index 0e691bf1738..bfcd2f3759a 100644 --- a/Mage.Sets/src/mage/cards/v/Vampirism.java +++ b/Mage.Sets/src/mage/cards/v/Vampirism.java @@ -80,7 +80,7 @@ class VampirismBoostEnchantedEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - int count = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) - 1; + int count = game.getBattlefield().count(filter, source.getControllerId(), source, game) - 1; if (count > 0) { Permanent enchantment = game.getPermanent(source.getSourceId()); if (enchantment != null && enchantment.getAttachedTo() != null) { diff --git a/Mage.Sets/src/mage/cards/v/Vandalize.java b/Mage.Sets/src/mage/cards/v/Vandalize.java index d3d7615d37a..fcdd45d031e 100644 --- a/Mage.Sets/src/mage/cards/v/Vandalize.java +++ b/Mage.Sets/src/mage/cards/v/Vandalize.java @@ -25,8 +25,7 @@ public final class Vandalize extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetArtifactPermanent().withChooseHint("destroy")); // Destroy target land - Mode mode1 = new Mode(); - mode1.addEffect(new DestroyTargetEffect()); + Mode mode1 = new Mode(new DestroyTargetEffect()); mode1.addTarget(new TargetLandPermanent().withChooseHint("destroy")); this.getSpellAbility().addMode(mode1); diff --git a/Mage.Sets/src/mage/cards/v/VanishIntoMemory.java b/Mage.Sets/src/mage/cards/v/VanishIntoMemory.java index 98023881e88..cc36c1e5411 100644 --- a/Mage.Sets/src/mage/cards/v/VanishIntoMemory.java +++ b/Mage.Sets/src/mage/cards/v/VanishIntoMemory.java @@ -69,7 +69,7 @@ class VanishIntoMemoryEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && permanent != null && sourceObject != null) { if (controller.moveCardsToExile(permanent, source, game, true, source.getSourceId(), sourceObject.getIdName())) { controller.drawCards(permanent.getPower().getValue(), source, game); diff --git a/Mage.Sets/src/mage/cards/v/VaporSnare.java b/Mage.Sets/src/mage/cards/v/VaporSnare.java index 2fba8df6579..8d2070ecf4c 100644 --- a/Mage.Sets/src/mage/cards/v/VaporSnare.java +++ b/Mage.Sets/src/mage/cards/v/VaporSnare.java @@ -80,8 +80,8 @@ class VaporSnareEffect extends OneShotEffect { TargetPermanent target = new TargetPermanent(1, 1, filter, false); if (controller != null - && target.canChoose(source.getSourceId(), controller.getId(), game)) { - controller.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + && target.canChoose(controller.getId(), source, game)) { + controller.choose(Outcome.Sacrifice, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if ( permanent != null ) { diff --git a/Mage.Sets/src/mage/cards/v/VarchildBetrayerOfKjeldor.java b/Mage.Sets/src/mage/cards/v/VarchildBetrayerOfKjeldor.java index c0ade46159a..4a9919d8294 100644 --- a/Mage.Sets/src/mage/cards/v/VarchildBetrayerOfKjeldor.java +++ b/Mage.Sets/src/mage/cards/v/VarchildBetrayerOfKjeldor.java @@ -6,8 +6,7 @@ import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.common.CreateTokenTargetEffect; import mage.abilities.effects.common.combat.CantAttackYouOrPlaneswalkerAllEffect; import mage.abilities.effects.common.combat.CantBlockAllEffect; @@ -16,13 +15,10 @@ 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.SuperType; import mage.constants.TargetController; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; -import mage.game.Game; import mage.game.permanent.token.SurvivorToken; /** @@ -31,11 +27,8 @@ import mage.game.permanent.token.SurvivorToken; */ public final class VarchildBetrayerOfKjeldor extends CardImpl { - private static final FilterCreaturePermanent filter1 - = new FilterCreaturePermanent( - SubType.SURVIVOR, - "Survivors your opponents control" - ); + private static final FilterCreaturePermanent filter1 = new FilterCreaturePermanent(SubType.SURVIVOR, "Survivors your opponents control"); + private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent(SubType.SURVIVOR, "all Survivors"); static { filter1.add(TargetController.OPPONENT.getControllerPredicate()); @@ -52,16 +45,10 @@ public final class VarchildBetrayerOfKjeldor extends CardImpl { // Whenever Varchild, Betrayer of Kjeldor deals combat damage to a player, that player creates that many 1/1 red Survivor creature tokens. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( - new VarchildBetrayerOfKjeldorEffect(), false, true - )); + new CreateTokenTargetEffect(new SurvivorToken(), SavedDamageValue.MANY), false, true)); // Survivors your opponents control can't block, and they can't attack you or a planeswalker you control. - Ability ability = new SimpleStaticAbility( - Zone.BATTLEFIELD, - new CantBlockAllEffect( - filter1, Duration.WhileOnBattlefield - ) - ); + Ability ability = new SimpleStaticAbility(new CantBlockAllEffect(filter1, Duration.WhileOnBattlefield)); ability.addEffect(new CantAttackYouOrPlaneswalkerAllEffect( Duration.WhileOnBattlefield, filter1 ).setText("and can't attack you or planeswalkers you control")); @@ -69,8 +56,7 @@ public final class VarchildBetrayerOfKjeldor extends CardImpl { // When Varchild leaves the battlefield, gain control of all Survivors. this.addAbility(new LeavesBattlefieldTriggeredAbility( - new GainControlAllEffect(Duration.Custom, new FilterCreaturePermanent(SubType.SURVIVOR, "all Survivors")), false - )); + new GainControlAllEffect(Duration.Custom, filter2), false)); } private VarchildBetrayerOfKjeldor(final VarchildBetrayerOfKjeldor card) { @@ -82,32 +68,3 @@ public final class VarchildBetrayerOfKjeldor extends CardImpl { return new VarchildBetrayerOfKjeldor(this); } } - -class VarchildBetrayerOfKjeldorEffect extends OneShotEffect { - - public VarchildBetrayerOfKjeldorEffect() { - super(Outcome.Benefit); - this.staticText = "that player creates " - + "that many 1/1 red Survivor creature tokens"; - } - - public VarchildBetrayerOfKjeldorEffect(final VarchildBetrayerOfKjeldorEffect effect) { - super(effect); - } - - @Override - public VarchildBetrayerOfKjeldorEffect copy() { - return new VarchildBetrayerOfKjeldorEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int damage = (int) this.getValue("damage"); - if (damage > 0) { - Effect effect = new CreateTokenTargetEffect(new SurvivorToken(), damage); - effect.setTargetPointer(getTargetPointer()); - return effect.apply(game, source); - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/v/Vaultbreaker.java b/Mage.Sets/src/mage/cards/v/Vaultbreaker.java index 46f60663c15..9afe53ea9d2 100644 --- a/Mage.Sets/src/mage/cards/v/Vaultbreaker.java +++ b/Mage.Sets/src/mage/cards/v/Vaultbreaker.java @@ -31,7 +31,7 @@ public final class Vaultbreaker extends CardImpl { new DiscardCardCost()), false, "Whenever {this} attacks, you may discard a card. If you do, draw a card")); // Dash {2}{R} - this.addAbility(new DashAbility(this, "{2}{R}")); + this.addAbility(new DashAbility("{2}{R}")); } diff --git a/Mage.Sets/src/mage/cards/v/VectisAgents.java b/Mage.Sets/src/mage/cards/v/VectisAgents.java index 836bc2e67b3..ae0fc338a9c 100644 --- a/Mage.Sets/src/mage/cards/v/VectisAgents.java +++ b/Mage.Sets/src/mage/cards/v/VectisAgents.java @@ -1,8 +1,5 @@ - - package mage.cards.v; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -12,19 +9,18 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect; 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.constants.SubType; + +import java.util.UUID; /** - * * @author Loki */ public final class VectisAgents extends CardImpl { public VectisAgents(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}{U}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{U}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ROGUE); @@ -32,10 +28,10 @@ public final class VectisAgents extends CardImpl { this.toughness = new MageInt(3); // {U}{B}: Vectis Agents gets -2/-0 until end of turn and can't be blocked this turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new BoostSourceEffect(-2, -0, Duration.EndOfTurn), - new ManaCostsImpl("{U}{B}")); - ability.addEffect(new CantBeBlockedSourceEffect(Duration.EndOfTurn)); + Ability ability = new SimpleActivatedAbility(new BoostSourceEffect( + -2, -0, Duration.EndOfTurn + ), new ManaCostsImpl<>("{U}{B}")); + ability.addEffect(new CantBeBlockedSourceEffect(Duration.EndOfTurn).setText("and can't be blocked this turn")); this.addAbility(ability); } @@ -47,5 +43,4 @@ public final class VectisAgents extends CardImpl { public VectisAgents copy() { return new VectisAgents(this); } - } diff --git a/Mage.Sets/src/mage/cards/v/VedalkenEngineer.java b/Mage.Sets/src/mage/cards/v/VedalkenEngineer.java index e937485f268..f4f3ae2a841 100644 --- a/Mage.Sets/src/mage/cards/v/VedalkenEngineer.java +++ b/Mage.Sets/src/mage/cards/v/VedalkenEngineer.java @@ -76,7 +76,7 @@ class VedalkenEngineerManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && object.isArtifact(game); } } diff --git a/Mage.Sets/src/mage/cards/v/VelomachusLorehold.java b/Mage.Sets/src/mage/cards/v/VelomachusLorehold.java index 1e3e42c0fad..0fdcc0d99b0 100644 --- a/Mage.Sets/src/mage/cards/v/VelomachusLorehold.java +++ b/Mage.Sets/src/mage/cards/v/VelomachusLorehold.java @@ -1,6 +1,5 @@ package mage.cards.v; -import mage.ApprovingObject; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; @@ -8,7 +7,10 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.*; import mage.filter.FilterCard; import mage.filter.common.FilterInstantOrSorceryCard; @@ -16,10 +18,8 @@ import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; -import java.util.Set; import java.util.UUID; /** @@ -84,26 +84,11 @@ class VelomachusLoreholdEffect extends OneShotEffect { if (controller == null || permanent == null) { return false; } - Set cardsSet = controller.getLibrary().getTopCards(game, 7); - Cards cards = new CardsImpl(cardsSet); - FilterCard filter = new FilterInstantOrSorceryCard( - "instant or sorcery card with mana value " + permanent.getPower().getValue() + " or less" - ); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 7)); + FilterCard filter = new FilterInstantOrSorceryCard(); filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, permanent.getPower().getValue() + 1)); - TargetCard target = new TargetCardInLibrary(0, 1, filter); - controller.choose(Outcome.PlayForFree, cards, target, game); - Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); - if (card == null) { - controller.putCardsOnBottomOfLibrary(cards, game, source, false); - return true; - } - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - if (cardWasCast) { - cards.remove(card); - } + CardUtil.castSpellWithAttributesForFree(controller, source, game, cards, filter); + cards.retainZone(Zone.LIBRARY, game); controller.putCardsOnBottomOfLibrary(cards, game, source, false); return true; } diff --git a/Mage.Sets/src/mage/cards/v/VengefulAncestor.java b/Mage.Sets/src/mage/cards/v/VengefulAncestor.java new file mode 100644 index 00000000000..19b31e4d148 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VengefulAncestor.java @@ -0,0 +1,106 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksAllTriggeredAbility; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.combat.GoadTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VengefulAncestor extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a goaded creature"); + + static { + filter.add(VengefulAncestorPredicate.instance); + } + + public VengefulAncestor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + + this.subtype.add(SubType.SPIRIT); + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Vengeful Ancestor enters the battlefield or attacks, goad target creature. + Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new GoadTargetEffect()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + // Whenever a goaded creature attacks, it deals 1 damage to its controller. + this.addAbility(new AttacksAllTriggeredAbility( + new VengefulAncestorEffect(), false, filter, + SetTargetPointer.NONE, false + )); + } + + private VengefulAncestor(final VengefulAncestor card) { + super(card); + } + + @Override + public VengefulAncestor copy() { + return new VengefulAncestor(this); + } +} + +enum VengefulAncestorPredicate implements Predicate { + instance; + + @Override + public boolean apply(Permanent input, Game game) { + return !input.getGoadingPlayers().isEmpty(); + } +} + +class VengefulAncestorEffect extends OneShotEffect { + + VengefulAncestorEffect() { + super(Outcome.Benefit); + staticText = "it deals 1 damage to its controller"; + } + + private VengefulAncestorEffect(final VengefulAncestorEffect effect) { + super(effect); + } + + @Override + public VengefulAncestorEffect copy() { + return new VengefulAncestorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = (Permanent) getValue("attacker"); + if (permanent == null) { + return false; + } + Player player = game.getPlayer(permanent.getControllerId()); + if (player == null) { + return false; + } + return player.damage(1, permanent.getId(), source, game) > 0; + } +} diff --git a/Mage.Sets/src/mage/cards/v/VengefulRebirth.java b/Mage.Sets/src/mage/cards/v/VengefulRebirth.java index f2022b53798..5d26d76951e 100644 --- a/Mage.Sets/src/mage/cards/v/VengefulRebirth.java +++ b/Mage.Sets/src/mage/cards/v/VengefulRebirth.java @@ -31,7 +31,7 @@ public final class VengefulRebirth extends CardImpl { this.getSpellAbility().addEffect(new VengefulRebirthEffect()); // Exile Vengeful Rebirth. - this.getSpellAbility().addEffect(new ExileSpellEffect()); + this.getSpellAbility().addEffect(new ExileSpellEffect().concatBy("
")); } private VengefulRebirth(final VengefulRebirth card) { diff --git a/Mage.Sets/src/mage/cards/v/VengefulStrangler.java b/Mage.Sets/src/mage/cards/v/VengefulStrangler.java index 1b1de179298..89d335b6562 100644 --- a/Mage.Sets/src/mage/cards/v/VengefulStrangler.java +++ b/Mage.Sets/src/mage/cards/v/VengefulStrangler.java @@ -92,8 +92,7 @@ class VengefulStranglerEffect extends OneShotEffect { } game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); - UUID secondFaceId = game.getCard(source.getSourceId()).getSecondCardFace().getId(); - game.getState().setValue("attachTo:" + secondFaceId, permanent.getId()); + game.getState().setValue("attachTo:" + source.getSourceId(), permanent); if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { permanent.addAttachment(card.getId(), source, game); } diff --git a/Mage.Sets/src/mage/cards/v/VenomConnoisseur.java b/Mage.Sets/src/mage/cards/v/VenomConnoisseur.java new file mode 100644 index 00000000000..5af54d9d1b8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VenomConnoisseur.java @@ -0,0 +1,55 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AllianceAbility; +import mage.abilities.effects.common.IfAbilityHasResolvedXTimesEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.DeathtouchAbility; +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.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VenomConnoisseur extends CardImpl { + + public VenomConnoisseur(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Alliance — Whenever another creature enters the battlefield under your control, Venom Connoisseur gains deathtouch until end of turn. If this is the second time this ability has resolved this turn, all creatures you control gain deathtouch until end of turn. + Ability ability = new AllianceAbility(new GainAbilitySourceEffect( + DeathtouchAbility.getInstance(), Duration.EndOfTurn + )); + ability.addEffect(new IfAbilityHasResolvedXTimesEffect( + Outcome.AddAbility, 2, + new GainAbilityAllEffect( + DeathtouchAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("all creatures you control gain deathtouch until end of turn") + )); + this.addAbility(ability); + } + + private VenomConnoisseur(final VenomConnoisseur card) { + super(card); + } + + @Override + public VenomConnoisseur copy() { + return new VenomConnoisseur(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VenomSliver.java b/Mage.Sets/src/mage/cards/v/VenomSliver.java index c0335b474d1..4ae8cbbf267 100644 --- a/Mage.Sets/src/mage/cards/v/VenomSliver.java +++ b/Mage.Sets/src/mage/cards/v/VenomSliver.java @@ -30,7 +30,7 @@ public final class VenomSliver extends CardImpl { // Sliver creatures you control have deathtouch. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(DeathtouchAbility.getInstance(), - Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS))); + Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_SLIVERS))); } private VenomSliver(final VenomSliver card) { diff --git a/Mage.Sets/src/mage/cards/v/VenomousBreath.java b/Mage.Sets/src/mage/cards/v/VenomousBreath.java index 4b8321d67cb..8dd6a4fac4c 100644 --- a/Mage.Sets/src/mage/cards/v/VenomousBreath.java +++ b/Mage.Sets/src/mage/cards/v/VenomousBreath.java @@ -100,7 +100,7 @@ class VenomousBreathEffect extends OneShotEffect { BlockedAttackerWatcher watcher = game.getState().getWatcher(BlockedAttackerWatcher.class); if (watcher != null) { List toDestroy = new ArrayList<>(); - for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { if (!creature.getId().equals(targetCreature.getSourceId())) { if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), targetCreature, game) || watcher.creatureHasBlockedAttacker(targetCreature, new MageObjectReference(creature, game), game)) { toDestroy.add(creature); diff --git a/Mage.Sets/src/mage/cards/v/VenomspoutBrackus.java b/Mage.Sets/src/mage/cards/v/VenomspoutBrackus.java index c9c41a90771..0b53797dc37 100644 --- a/Mage.Sets/src/mage/cards/v/VenomspoutBrackus.java +++ b/Mage.Sets/src/mage/cards/v/VenomspoutBrackus.java @@ -45,7 +45,7 @@ public final class VenomspoutBrackus extends CardImpl { ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); // Morph {3}{G}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{G}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{G}{G}"))); } diff --git a/Mage.Sets/src/mage/cards/v/VenserTheSojourner.java b/Mage.Sets/src/mage/cards/v/VenserTheSojourner.java index 1afea41ade6..5e0d1f4985e 100644 --- a/Mage.Sets/src/mage/cards/v/VenserTheSojourner.java +++ b/Mage.Sets/src/mage/cards/v/VenserTheSojourner.java @@ -5,7 +5,6 @@ import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -41,7 +40,7 @@ public final class VenserTheSojourner extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.VENSER); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +2: Exile target permanent you own. Return it to the battlefield under your control at the beginning of the next end step. LoyaltyAbility ability1 = new LoyaltyAbility(new VenserTheSojournerEffect(), 2); @@ -84,7 +83,7 @@ class VenserTheSojournerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { if (getTargetPointer().getFirst(game, source) != null) { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); diff --git a/Mage.Sets/src/mage/cards/v/VerdantConfluence.java b/Mage.Sets/src/mage/cards/v/VerdantConfluence.java index 032bc14ef50..7cb9519ed2d 100644 --- a/Mage.Sets/src/mage/cards/v/VerdantConfluence.java +++ b/Mage.Sets/src/mage/cards/v/VerdantConfluence.java @@ -36,15 +36,13 @@ public final class VerdantConfluence extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Return target permanent card from your graveyard to your hand; - Mode mode = new Mode(); - mode.addEffect(new ReturnFromGraveyardToHandTargetEffect()); + Mode mode = new Mode(new ReturnFromGraveyardToHandTargetEffect()); mode.addTarget(new TargetCardInYourGraveyard(new FilterPermanentCard())); this.getSpellAbility().getModes().addMode(mode); // Search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library. TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND); - mode = new Mode(); - mode.addEffect(new SearchLibraryPutInPlayEffect(target, true)); + mode = new Mode(new SearchLibraryPutInPlayEffect(target, true)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/v/VerdantSuccession.java b/Mage.Sets/src/mage/cards/v/VerdantSuccession.java index 4f8bdf989df..b9b251ccc31 100644 --- a/Mage.Sets/src/mage/cards/v/VerdantSuccession.java +++ b/Mage.Sets/src/mage/cards/v/VerdantSuccession.java @@ -117,7 +117,7 @@ class VerdantSuccessionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if(mageObject != null) { permanent = (Permanent) game.getState().getValue("verdantSuccession" + mageObject); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/v/VerdelothTheAncient.java b/Mage.Sets/src/mage/cards/v/VerdelothTheAncient.java index d8269f60b52..7e243abcc7c 100644 --- a/Mage.Sets/src/mage/cards/v/VerdelothTheAncient.java +++ b/Mage.Sets/src/mage/cards/v/VerdelothTheAncient.java @@ -1,6 +1,7 @@ package mage.cards.v; import mage.MageInt; +import mage.MageObject; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.KickedCondition; @@ -11,10 +12,15 @@ import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.keyword.KickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.SaprolingToken; import java.util.UUID; @@ -24,6 +30,13 @@ import java.util.UUID; */ public final class VerdelothTheAncient extends CardImpl { + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("Saproling creatures and other Treefolk creatures"); + + static { + filter.add(VerdelothTheAncientPredicate.instance); + } + public VerdelothTheAncient(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); addSuperType(SuperType.LEGENDARY); @@ -36,20 +49,15 @@ public final class VerdelothTheAncient extends CardImpl { this.addAbility(new KickerAbility("{X}")); // Saproling creatures and other Treefolk creatures get +1/+1. - FilterCreaturePermanent filter = new FilterCreaturePermanent("Saproling creatures and other Treefolk creatures"); - filter.add(Predicates.or( - Predicates.and(SubType.TREEFOLK.getPredicate(), Predicates.not(new PermanentIdPredicate(this.getId()))), - SubType.SAPROLING.getPredicate()) - ); - filter.add(Predicates.not(new PermanentIdPredicate(this.getId()))); - - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, false))); + this.addAbility(new SimpleStaticAbility(new BoostAllEffect( + 1, 1, Duration.WhileOnBattlefield, filter, false + ))); // When Verdeloth the Ancient enters the battlefield, if it was kicked, create X 1/1 green Saproling creature tokens. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new SaprolingToken(), GetKickerXValue.instance), false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.instance, - "When {this} enters the battlefield, if it was kicked, create X 1/1 green Saproling creature tokens.")); - + this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility( + new CreateTokenEffect(new SaprolingToken(), GetKickerXValue.instance), false + ), KickedCondition.instance, "When {this} enters the battlefield, " + + "if it was kicked, create X 1/1 green Saproling creature tokens.")); } private VerdelothTheAncient(final VerdelothTheAncient card) { @@ -60,4 +68,18 @@ public final class VerdelothTheAncient extends CardImpl { public VerdelothTheAncient copy() { return new VerdelothTheAncient(this); } -} \ No newline at end of file +} + +enum VerdelothTheAncientPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + MageObject obj = input.getObject(); + if (obj.getId().equals(input.getSourceId())) { + return obj.hasSubtype(SubType.SAPROLING, game); + } + return obj.hasSubtype(SubType.TREEFOLK, game) + || obj.hasSubtype(SubType.SAPROLING, game); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VertigoSpawn.java b/Mage.Sets/src/mage/cards/v/VertigoSpawn.java index 8c8c4c79751..86153b040bf 100644 --- a/Mage.Sets/src/mage/cards/v/VertigoSpawn.java +++ b/Mage.Sets/src/mage/cards/v/VertigoSpawn.java @@ -1,10 +1,9 @@ - package mage.cards.v; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.BlocksSourceTriggeredAbility; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.keyword.DefenderAbility; @@ -29,7 +28,7 @@ public final class VertigoSpawn extends CardImpl { this.addAbility(DefenderAbility.getInstance()); // Whenever Vertigo Spawn blocks a creature, tap that creature. That creature doesn't untap during its controller's next untap step. - Ability ability = new BlocksSourceTriggeredAbility(new TapTargetEffect("tap that creature"), false, true); + Ability ability = new BlocksCreatureTriggeredAbility(new TapTargetEffect("tap that creature")); ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("that creature")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VeryCrypticCommandD.java b/Mage.Sets/src/mage/cards/v/VeryCrypticCommandD.java index e81cac28413..58157a7a24b 100644 --- a/Mage.Sets/src/mage/cards/v/VeryCrypticCommandD.java +++ b/Mage.Sets/src/mage/cards/v/VeryCrypticCommandD.java @@ -54,22 +54,19 @@ public final class VeryCrypticCommandD extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent()); // Draw two cards, then discard a card. - Mode mode = new Mode(); - mode.addEffect(new DrawCardSourceControllerEffect(2)); + Mode mode = new Mode(new DrawCardSourceControllerEffect(2)); Effect effect = new DiscardControllerEffect(1); effect.setText(", then discard a card"); mode.addEffect(effect); this.getSpellAbility().getModes().addMode(mode); // Change the target of target spell with a single target. - mode = new Mode(); - mode.addEffect(new ChooseNewTargetsTargetEffect(true, true)); + mode = new Mode(new ChooseNewTargetsTargetEffect(true, true)); mode.addTarget(new TargetStackObject(filter)); this.getSpellAbility().getModes().addMode(mode); // Turn over target nontoken creature. - mode = new Mode(); - mode.addEffect(new TurnOverEffect()); + mode = new Mode(new TurnOverEffect()); mode.addTarget(new TargetCreaturePermanent(filter2)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/v/VesselOfNascency.java b/Mage.Sets/src/mage/cards/v/VesselOfNascency.java index b6dbb4432e8..16672da473c 100644 --- a/Mage.Sets/src/mage/cards/v/VesselOfNascency.java +++ b/Mage.Sets/src/mage/cards/v/VesselOfNascency.java @@ -1,39 +1,43 @@ - package mage.cards.v; import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.abilities.effects.common.RevealLibraryPickControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.players.Player; -import mage.target.TargetCard; /** * - * @author fireshoes + * @author awjackson */ public final class VesselOfNascency extends CardImpl { + private static final FilterCard filter = new FilterCard("an artifact, creature, enchantment, land, or planeswalker card"); + + static { + filter.add(Predicates.or(CardType.ARTIFACT.getPredicate(), + CardType.CREATURE.getPredicate(), + CardType.ENCHANTMENT.getPredicate(), + CardType.LAND.getPredicate(), + CardType.PLANESWALKER.getPredicate() + )); + } + public VesselOfNascency(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}"); // {1}{G}, Sacrifice Vessel of Nascency: Reveal the top four cards of your library. You may put an artifact, creature, enchantment, land, or // planeswalker card from among them into your hand. Put the rest into your graveyard. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new VesselOfNascencyEffect(), new ManaCostsImpl("{1}{G}")); + Ability ability = new SimpleActivatedAbility( + new RevealLibraryPickControllerEffect(4, 1, filter, PutCards.HAND, PutCards.GRAVEYARD), + new ManaCostsImpl("{1}{G}")); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } @@ -47,58 +51,3 @@ public final class VesselOfNascency extends CardImpl { return new VesselOfNascency(this); } } - -class VesselOfNascencyEffect extends OneShotEffect { - - private static final FilterCard filterPutInHand = new FilterCard("an artifact, creature, enchantment, land, or planeswalker card"); - - static { - filterPutInHand.add(Predicates.or(CardType.ARTIFACT.getPredicate(), - CardType.CREATURE.getPredicate(), - CardType.ENCHANTMENT.getPredicate(), - CardType.LAND.getPredicate(), - CardType.PLANESWALKER.getPredicate())); - } - - public VesselOfNascencyEffect() { - super(Outcome.DrawCard); - this.staticText = "reveal the top four cards of your library. You may put artifact, creature, enchantment, land, or planeswalker card from among " - + "them into your hand. Put the rest into your graveyard"; - } - - public VesselOfNascencyEffect(final VesselOfNascencyEffect effect) { - super(effect); - } - - @Override - public VesselOfNascencyEffect copy() { - return new VesselOfNascencyEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller != null && sourceObject != null) { - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 4)); - boolean properCardFound = cards.count(filterPutInHand, source.getControllerId(), source.getSourceId(), game) > 0; - if (!cards.isEmpty()) { - controller.revealCards(sourceObject.getName(), cards, game); - TargetCard target = new TargetCard(Zone.LIBRARY, filterPutInHand); - if (properCardFound - && controller.chooseUse(outcome, "Put an artifact, creature, enchantment, land, or planeswalker card into your hand?", source, game) - && controller.choose(Outcome.DrawCard, cards, target, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - cards.remove(card); - controller.moveCards(card, Zone.HAND, source, game); - } - - } - controller.moveCards(cards, Zone.GRAVEYARD, source, game); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/v/VesselOfTheAllConsuming.java b/Mage.Sets/src/mage/cards/v/VesselOfTheAllConsuming.java new file mode 100644 index 00000000000..c032a42e8ef --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VesselOfTheAllConsuming.java @@ -0,0 +1,139 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DealsDamageToAPlayerTriggeredAbility; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.LoseGameTargetPlayerEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.DamagedEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.watchers.Watcher; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VesselOfTheAllConsuming extends CardImpl { + + public VesselOfTheAllConsuming(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, ""); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + this.color.setBlack(true); + this.color.setRed(true); + this.nightCard = true; + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever Vessel of the All-Consuming deals damage, put a +1/+1 counter on it. + this.addAbility(new VesselOfTheAllConsumingTriggeredAbility()); + + // Whenever Vessel of the All-Consuming deals damage to a player, if it has dealt 10 or more damage to that player this turn, they lose the game. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new DealsDamageToAPlayerTriggeredAbility( + new LoseGameTargetPlayerEffect(), false, true + ), VesselOfTheAllConsumingWatcher::checkPermanent, "Whenever {this} deals damage to a player, " + + "if it has dealt 10 or more damage to that player this turn, they lose the game." + )); + } + + private VesselOfTheAllConsuming(final VesselOfTheAllConsuming card) { + super(card); + } + + @Override + public VesselOfTheAllConsuming copy() { + return new VesselOfTheAllConsuming(this); + } + + public static Watcher makeWatcher() { + return new VesselOfTheAllConsumingWatcher(); + } +} + +class VesselOfTheAllConsumingTriggeredAbility extends TriggeredAbilityImpl { + + VesselOfTheAllConsumingTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance())); + } + + private VesselOfTheAllConsumingTriggeredAbility(final VesselOfTheAllConsumingTriggeredAbility ability) { + super(ability); + } + + @Override + public VesselOfTheAllConsumingTriggeredAbility copy() { + return new VesselOfTheAllConsumingTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event instanceof DamagedEvent; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getSourceId().equals(getSourceId()); + } + + @Override + public String getRule() { + return "Whenever {this} deals damage, put a +1/+1 counter on it."; + } +} + +class VesselOfTheAllConsumingWatcher extends Watcher { + + private final Map> morMap = new HashMap<>(); + private static final Map emptyMap = new HashMap<>(); + + VesselOfTheAllConsumingWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.DAMAGED_PLAYER) { + return; + } + Permanent permanent = game.getPermanent(event.getSourceId()); + if (permanent != null) { + morMap.computeIfAbsent(new MageObjectReference(permanent, game), x -> new HashMap<>()) + .compute(event.getTargetId(), (u, i) -> i == null ? 1 : Integer.sum(i, 1)); + } + } + + @Override + public void reset() { + super.reset(); + morMap.clear(); + } + + static boolean checkPermanent(Game game, Ability source) { + return game.getState() + .getWatcher(VesselOfTheAllConsumingWatcher.class) + .morMap + .getOrDefault(new MageObjectReference(source), emptyMap) + .getOrDefault(source.getEffects().get(0).getTargetPointer().getFirst(game, source), 0) >= 10; + } +} diff --git a/Mage.Sets/src/mage/cards/v/VesuvanDoppelganger.java b/Mage.Sets/src/mage/cards/v/VesuvanDoppelganger.java index b54036913f8..1c72b7ea6e1 100644 --- a/Mage.Sets/src/mage/cards/v/VesuvanDoppelganger.java +++ b/Mage.Sets/src/mage/cards/v/VesuvanDoppelganger.java @@ -82,8 +82,8 @@ class VesuvanDoppelgangerCopyEffect extends OneShotEffect { target.setRequired(false); target.setNotTarget(true); } - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { - controller.choose(Outcome.Copy, target, source.getSourceId(), game); + if (target.canChoose(source.getControllerId(), source, game)) { + controller.choose(Outcome.Copy, target, source, game); Permanent copyFromPermanent = game.getPermanent(target.getFirstTarget()); if (copyFromPermanent != null) { game.copyPermanent(copyFromPermanent, sourcePermanent.getId(), source, new CopyApplier() { diff --git a/Mage.Sets/src/mage/cards/v/VesuvanShapeshifter.java b/Mage.Sets/src/mage/cards/v/VesuvanShapeshifter.java index 69e6e3c5193..77352641072 100644 --- a/Mage.Sets/src/mage/cards/v/VesuvanShapeshifter.java +++ b/Mage.Sets/src/mage/cards/v/VesuvanShapeshifter.java @@ -58,7 +58,7 @@ public final class VesuvanShapeshifter extends CardImpl { this.addAbility(ability); // Morph {1}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{U}"))); } private VesuvanShapeshifter(final VesuvanShapeshifter card) { diff --git a/Mage.Sets/src/mage/cards/v/VeteranBodyguard.java b/Mage.Sets/src/mage/cards/v/VeteranBodyguard.java index c121568e1bd..2fe265a5b11 100644 --- a/Mage.Sets/src/mage/cards/v/VeteranBodyguard.java +++ b/Mage.Sets/src/mage/cards/v/VeteranBodyguard.java @@ -3,7 +3,6 @@ package mage.cards.v; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.SourceTappedCondition; import mage.abilities.decorator.ConditionalPreventionEffect; import mage.abilities.effects.PreventionEffectImpl; @@ -92,7 +91,7 @@ class VeteranBodyguardEffect extends PreventionEffectImpl { && ((DamageEvent) event).isCombatDamage()) { Permanent p = game.getPermanent(source.getSourceId()); if (p != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (event.getSourceId().equals(permanent.getId())) { return true; } diff --git a/Mage.Sets/src/mage/cards/v/VeteranOfTheDepths.java b/Mage.Sets/src/mage/cards/v/VeteranOfTheDepths.java index 47081f9c855..866de657964 100644 --- a/Mage.Sets/src/mage/cards/v/VeteranOfTheDepths.java +++ b/Mage.Sets/src/mage/cards/v/VeteranOfTheDepths.java @@ -1,9 +1,6 @@ - package mage.cards.v; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.BecomesTappedSourceTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; @@ -12,22 +9,25 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; +import java.util.UUID; + /** - * * @author Wehk */ public final class VeteranOfTheDepths extends CardImpl { public VeteranOfTheDepths(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.subtype.add(SubType.MERFOLK); this.subtype.add(SubType.SOLDIER); this.power = new MageInt(2); this.toughness = new MageInt(2); // Whenever Veteran of the Depths becomes tapped, you may put a +1/+1 counter on it. - Ability ability = new BecomesTappedSourceTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true); - this.addAbility(ability); + this.addAbility(new BecomesTappedSourceTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on it"), true + )); } private VeteranOfTheDepths(final VeteranOfTheDepths card) { @@ -38,4 +38,4 @@ public final class VeteranOfTheDepths extends CardImpl { public VeteranOfTheDepths copy() { return new VeteranOfTheDepths(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/v/VeteranSwordsmith.java b/Mage.Sets/src/mage/cards/v/VeteranSwordsmith.java index 928962eff42..70b35a7ec77 100644 --- a/Mage.Sets/src/mage/cards/v/VeteranSwordsmith.java +++ b/Mage.Sets/src/mage/cards/v/VeteranSwordsmith.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.BoostControlledEffect; @@ -10,28 +8,28 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import java.util.UUID; + /** * @author Loki */ public final class VeteranSwordsmith extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Soldier"); - - static { - filter.add(SubType.SOLDIER.getPredicate()); - } + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent(SubType.SOLDIER, "Soldier creatures"); public VeteranSwordsmith(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.SOLDIER); this.power = new MageInt(3); this.toughness = new MageInt(2); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 0, Duration.WhileOnBattlefield, filter, true))); + this.addAbility(new SimpleStaticAbility(new BoostControlledEffect( + 1, 0, Duration.WhileOnBattlefield, filter, true + ))); } private VeteranSwordsmith(final VeteranSwordsmith card) { diff --git a/Mage.Sets/src/mage/cards/v/VeteranWarleader.java b/Mage.Sets/src/mage/cards/v/VeteranWarleader.java index c359c93b8af..6f7a380f6f4 100644 --- a/Mage.Sets/src/mage/cards/v/VeteranWarleader.java +++ b/Mage.Sets/src/mage/cards/v/VeteranWarleader.java @@ -86,7 +86,7 @@ class VeteranWarleaderEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && controller != null) { Choice abilityChoice = new ChoiceImpl(); abilityChoice.setMessage("Choose an ability to add"); diff --git a/Mage.Sets/src/mage/cards/v/VeteransArmaments.java b/Mage.Sets/src/mage/cards/v/VeteransArmaments.java index f5e0d5c9350..64e9fed407d 100644 --- a/Mage.Sets/src/mage/cards/v/VeteransArmaments.java +++ b/Mage.Sets/src/mage/cards/v/VeteransArmaments.java @@ -1,4 +1,3 @@ - package mage.cards.v; import java.util.UUID; @@ -26,10 +25,8 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class VeteransArmaments extends CardImpl { - private static final FilterPermanent filter = new FilterCreaturePermanent("a Soldier creature"); - static { - filter.add(SubType.SOLDIER.getPredicate()); - } + private static final FilterPermanent filter = new FilterCreaturePermanent(SubType.SOLDIER, "a Soldier creature"); + private static final DynamicValue xValue = new AttackingCreatureCount(); public VeteransArmaments(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.TRIBAL,CardType.ARTIFACT},"{2}"); @@ -37,8 +34,7 @@ public final class VeteransArmaments extends CardImpl { this.subtype.add(SubType.EQUIPMENT); // Equipped creature has "Whenever this creature attacks or blocks, it gets +1/+1 until end of turn for each attacking creature." - DynamicValue attackingCreatures = new AttackingCreatureCount("attacking creature"); - Ability gainedAbility = new AttacksOrBlocksTriggeredAbility(new BoostSourceEffect(attackingCreatures,attackingCreatures, Duration.EndOfTurn),false); + Ability gainedAbility = new AttacksOrBlocksTriggeredAbility(new BoostSourceEffect(xValue, xValue, Duration.EndOfTurn, true), false); Effect effect = new GainAbilityAttachedEffect(gainedAbility, AttachmentType.EQUIPMENT); effect.setText("Equipped creature has \"Whenever this creature attacks or blocks, it gets +1/+1 until end of turn for each attacking creature.\""); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); diff --git a/Mage.Sets/src/mage/cards/v/VeteransReflexes.java b/Mage.Sets/src/mage/cards/v/VeteransReflexes.java index 17e52a611d7..3c8279ec231 100644 --- a/Mage.Sets/src/mage/cards/v/VeteransReflexes.java +++ b/Mage.Sets/src/mage/cards/v/VeteransReflexes.java @@ -21,7 +21,7 @@ public final class VeteransReflexes extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}"); this.getSpellAbility().addEffect(new BoostTargetEffect(1, 1, Duration.EndOfTurn)); - this.getSpellAbility().addEffect(new UntapTargetEffect()); + this.getSpellAbility().addEffect(new UntapTargetEffect().setText("untap that creature")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/v/VeteransVoice.java b/Mage.Sets/src/mage/cards/v/VeteransVoice.java index 8c909a52702..b8e8cec615e 100644 --- a/Mage.Sets/src/mage/cards/v/VeteransVoice.java +++ b/Mage.Sets/src/mage/cards/v/VeteransVoice.java @@ -1,9 +1,8 @@ - package mage.cards.v; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.AttachedToMatchesFilterCondition; import mage.abilities.costs.common.TapAttachedCost; import mage.abilities.effects.common.AttachEffect; @@ -11,33 +10,33 @@ import mage.abilities.effects.common.continuous.BoostTargetEffect; 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.Duration; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author L_J */ public final class VeteransVoice extends CardImpl { - private static final FilterCreaturePermanent filterUntapped = new FilterCreaturePermanent("enchanted creature is untapped"); - + private static final FilterPermanent filterUntapped = new FilterCreaturePermanent("enchanted creature is untapped"); + static { filterUntapped.add(TappedPredicate.UNTAPPED); } + private static final Condition condition = new AttachedToMatchesFilterCondition(filterUntapped); + public VeteransVoice(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}"); this.subtype.add(SubType.AURA); @@ -46,16 +45,15 @@ public final class VeteransVoice extends CardImpl { TargetPermanent auraTarget = new TargetControlledCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // Tap enchanted creature: Target creature other than the creature tapped this way gets +2/+1 until end of turn. Activate this ability only if enchanted creature is untapped. - FilterPermanent filterTarget = new FilterCreaturePermanent("creature other than the creature tapped this way"); - filterTarget.add(Predicates.not(new AttachmentByUUIDPredicate(this.getId()))); - Ability ability2 = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, - new BoostTargetEffect(2, 1, Duration.EndOfTurn), new TapAttachedCost(), new AttachedToMatchesFilterCondition(filterUntapped)); - ability2.addTarget(new TargetPermanent(filterTarget)); - this.addAbility(ability2); + this.addAbility(new ActivateIfConditionActivatedAbility( + Zone.BATTLEFIELD, + new BoostTargetEffect(2, 1, Duration.EndOfTurn) + .setText("target creature other than the creature tapped this way gets +2/+1 until end of turn"), + new TapAttachedCost(), condition + ).setTargetAdjuster(VeteransVoiceAdjuster.instance)); } private VeteransVoice(final VeteransVoice card) { @@ -68,21 +66,18 @@ public final class VeteransVoice extends CardImpl { } } -class AttachmentByUUIDPredicate implements Predicate { - - private final UUID id; - - public AttachmentByUUIDPredicate(UUID id) { - this.id = id; - } +enum VeteransVoiceAdjuster implements TargetAdjuster { + instance; @Override - public boolean apply(Permanent input, Game game) { - return input.getAttachments().contains(id); - } - - @Override - public String toString() { - return "AttachmentUUID(" + id + ')'; + public void adjustTargets(Ability ability, Game game) { + Permanent permanent = ability.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + return; + } + FilterPermanent filter = new FilterCreaturePermanent(); + filter.add(Predicates.not(new PermanentIdPredicate(permanent.getAttachedTo()))); + ability.getTargets().clear(); + ability.addTarget(new TargetPermanent(filter)); } } diff --git a/Mage.Sets/src/mage/cards/v/VexingShusher.java b/Mage.Sets/src/mage/cards/v/VexingShusher.java index 1b626ac9a24..34c279e0bdb 100644 --- a/Mage.Sets/src/mage/cards/v/VexingShusher.java +++ b/Mage.Sets/src/mage/cards/v/VexingShusher.java @@ -76,7 +76,7 @@ class VexingShusherCantCounterTargetEffect extends ContinuousRuleModifyingEffect @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null) { return "This spell can't be countered (" + sourceObject.getName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/v/VialSmasherTheFierce.java b/Mage.Sets/src/mage/cards/v/VialSmasherTheFierce.java index 920a008321e..52b9e34382f 100644 --- a/Mage.Sets/src/mage/cards/v/VialSmasherTheFierce.java +++ b/Mage.Sets/src/mage/cards/v/VialSmasherTheFierce.java @@ -141,7 +141,7 @@ class VialSmasherTheFierceEffect extends OneShotEffect { FilterPlaneswalkerPermanent filter = new FilterPlaneswalkerPermanent("a planeswalker controlled by " + opponent.getLogName()); filter.add(new ControllerIdPredicate(opponent.getId())); TargetPermanent target = new TargetPermanent(1, 1, filter, false); - if (target.choose(Outcome.Damage, controller.getId(), source.getSourceId(), game)) { + if (target.choose(Outcome.Damage, controller.getId(), source.getSourceId(), source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { return permanent.damage(damage, source.getSourceId(), source, game, false, true) > 0; diff --git a/Mage.Sets/src/mage/cards/v/ViashinoBey.java b/Mage.Sets/src/mage/cards/v/ViashinoBey.java index d9dafab5b2f..09c115906fb 100644 --- a/Mage.Sets/src/mage/cards/v/ViashinoBey.java +++ b/Mage.Sets/src/mage/cards/v/ViashinoBey.java @@ -72,9 +72,9 @@ class ViashinoBeyEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); TargetOpponent targetDefender = new TargetOpponent(); if (controller != null) { - game.getBattlefield().getAllActivePermanents(CardType.CREATURE, game).stream().filter((permanent) -> (filter.match(permanent, source.getSourceId(), source.getControllerId(), game))).forEachOrdered((permanent) -> { + game.getBattlefield().getAllActivePermanents(CardType.CREATURE, game).stream().filter((permanent) -> (filter.match(permanent, source.getControllerId(), source, game))).forEachOrdered((permanent) -> { if (game.getOpponents(controller.getId()).size() > 1) { - controller.choose(outcome.Benefit, targetDefender, source.getSourceId(), game); + controller.choose(outcome.Benefit, targetDefender, source, game); } else { targetDefender.add(game.getOpponents(controller.getId()).iterator().next(), game); } diff --git a/Mage.Sets/src/mage/cards/v/ViciousShadows.java b/Mage.Sets/src/mage/cards/v/ViciousShadows.java index defd4a31363..43a58af8b70 100644 --- a/Mage.Sets/src/mage/cards/v/ViciousShadows.java +++ b/Mage.Sets/src/mage/cards/v/ViciousShadows.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.dynamicvalue.common.CardsInTargetHandCount; @@ -11,18 +9,19 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author Plopman */ public final class ViciousShadows extends CardImpl { public ViciousShadows(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{6}{R}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{6}{R}"); // Whenever a creature dies, you may have Vicious Shadows deal damage to target player equal to the number of cards in that player's hand. - Ability ability = new DiesCreatureTriggeredAbility(new DamageTargetEffect(CardsInTargetHandCount.instance), true); + Ability ability = new DiesCreatureTriggeredAbility(new DamageTargetEffect(CardsInTargetHandCount.instance) + .setText("you may have {this} deal damage to target player equal to the number of cards in that player's hand"), true); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VictualSliver.java b/Mage.Sets/src/mage/cards/v/VictualSliver.java index 392f7d0e069..84edf3f8f78 100644 --- a/Mage.Sets/src/mage/cards/v/VictualSliver.java +++ b/Mage.Sets/src/mage/cards/v/VictualSliver.java @@ -37,7 +37,7 @@ public final class VictualSliver extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(ability, - Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS, + Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS, "All Slivers have \"{2}, Sacrifice this permanent: You gain 4 life.\""))); } diff --git a/Mage.Sets/src/mage/cards/v/VigeanIntuition.java b/Mage.Sets/src/mage/cards/v/VigeanIntuition.java index ee22e295248..253e9c103a1 100644 --- a/Mage.Sets/src/mage/cards/v/VigeanIntuition.java +++ b/Mage.Sets/src/mage/cards/v/VigeanIntuition.java @@ -71,7 +71,7 @@ class VigeanIntuitionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Player player = game.getPlayer(source.getControllerId()); if (sourceObject == null || player == null) { return false; diff --git a/Mage.Sets/src/mage/cards/v/Vigor.java b/Mage.Sets/src/mage/cards/v/Vigor.java index 22ccb02da71..1d62170daf1 100644 --- a/Mage.Sets/src/mage/cards/v/Vigor.java +++ b/Mage.Sets/src/mage/cards/v/Vigor.java @@ -57,7 +57,7 @@ class VigorReplacementEffect extends ReplacementEffectImpl { VigorReplacementEffect() { super(Duration.WhileOnBattlefield, Outcome.BoostCreature); - staticText = "If damage would be dealt to a creature you control other than {this}, prevent that damage. Put a +1/+1 counter on that creature for each 1 damage prevented this way"; + staticText = "if damage would be dealt to another creature you control, prevent that damage. Put a +1/+1 counter on that creature for each 1 damage prevented this way"; } VigorReplacementEffect(final VigorReplacementEffect effect) { diff --git a/Mage.Sets/src/mage/cards/v/VigorsporeWurm.java b/Mage.Sets/src/mage/cards/v/VigorsporeWurm.java index 5c4b9838085..bd249b60590 100644 --- a/Mage.Sets/src/mage/cards/v/VigorsporeWurm.java +++ b/Mage.Sets/src/mage/cards/v/VigorsporeWurm.java @@ -11,12 +11,9 @@ import mage.abilities.effects.common.combat.CantBeBlockedByMoreThanOneSourceEffe import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.VigilanceAbility; -import mage.constants.SubType; +import mage.constants.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Zone; import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; @@ -48,7 +45,7 @@ public final class VigorsporeWurm extends CardImpl { ).setText("and gets +X/+X until end of turn, " + "where X is the number of creature cards in your graveyard.")); ability.addTarget(new TargetCreaturePermanent()); - ability.withFlavorWord("Undergrowth"); + ability.setAbilityWord(AbilityWord.UNDERGROWTH); this.addAbility(ability); // Vigorspore Wurm can't be blocked by more than one creature. diff --git a/Mage.Sets/src/mage/cards/v/VillainousWealth.java b/Mage.Sets/src/mage/cards/v/VillainousWealth.java index 97f078d8586..0425449da67 100644 --- a/Mage.Sets/src/mage/cards/v/VillainousWealth.java +++ b/Mage.Sets/src/mage/cards/v/VillainousWealth.java @@ -1,24 +1,23 @@ package mage.cards.v; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.common.FilterNonlandCard; import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.players.Player; -import mage.target.common.TargetCardInExile; import mage.target.common.TargetOpponent; import mage.util.CardUtil; import java.util.UUID; -import mage.ApprovingObject; /** * @author LevelX2 @@ -30,9 +29,8 @@ public final class VillainousWealth extends CardImpl { // Target opponent exiles the top X cards of their library. You may cast any number of nonland cards // with converted mana cost X or less from among them without paying their mana cost. - this.getSpellAbility().addTarget(new TargetOpponent()); this.getSpellAbility().addEffect(new VillainousWealthEffect()); - + this.getSpellAbility().addTarget(new TargetOpponent()); } private VillainousWealth(final VillainousWealth card) { @@ -66,48 +64,16 @@ class VillainousWealthEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); - if (controller != null && mageObject != null) { - Player player = game.getPlayer(targetPointer.getFirst(game, source)); - FilterCard filter = new FilterNonlandCard(); - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, source.getManaCostsToPay().getX() + 1)); - UUID exileId = CardUtil.getCardExileZoneId(game, source); - if (player != null) { - Cards cardsToExile = new CardsImpl(); - cardsToExile.addAll(player.getLibrary().getTopCards(game, source.getManaCostsToPay().getX())); - controller.moveCards(cardsToExile, Zone.EXILED, source, game); - if (controller.chooseUse(Outcome.PlayForFree, "Cast cards exiled with " + mageObject.getLogName() - + " without paying its mana cost?", source, game)) { - OuterLoop: - while (cardsToExile.count(filter, game) > 0) { - if (!controller.canRespond()) { - return false; - } - TargetCardInExile target = new TargetCardInExile(0, 1, filter, exileId, false); - target.setNotTarget(true); - while (controller.canRespond() - && cardsToExile.count(filter, game) > 0 - && controller.choose(Outcome.PlayForFree, cardsToExile, target, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - if (cardWasCast) { - cardsToExile.remove(card); - } - } else { - break OuterLoop; - } - target.clearChosen(); - } - } - } - } - return true; + Player opponent = game.getPlayer(targetPointer.getFirst(game, source)); + int xValue = source.getManaCostsToPay().getX(); + if (controller == null || opponent == null || xValue < 1) { + return false; } - - return false; + Cards cards = new CardsImpl(opponent.getLibrary().getTopCards(game, xValue)); + opponent.moveCards(cards, Zone.EXILED, source, game); + FilterCard filter = new FilterCard(); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, source.getManaCostsToPay().getX() + 1)); + CardUtil.castMultipleWithAttributeForFree(controller, source, game, cards, filter); + return true; } } diff --git a/Mage.Sets/src/mage/cards/v/VindictiveLich.java b/Mage.Sets/src/mage/cards/v/VindictiveLich.java index 23608e37504..9ec09cfb4ca 100644 --- a/Mage.Sets/src/mage/cards/v/VindictiveLich.java +++ b/Mage.Sets/src/mage/cards/v/VindictiveLich.java @@ -46,8 +46,7 @@ public final class VindictiveLich extends CardImpl { ability.addTarget(target); // * Target opponent discards two cards. - Mode mode = new Mode(); - mode.addEffect(new DiscardTargetEffect(2, false)); + Mode mode = new Mode(new DiscardTargetEffect(2, false)); filter = new FilterOpponent(); filter.add(new AnotherTargetPredicate(2, true)); target = new TargetOpponent(filter, false); @@ -56,8 +55,7 @@ public final class VindictiveLich extends CardImpl { ability.addMode(mode); // * Target opponent loses 5 life. - mode = new Mode(); - mode.addEffect(new LoseLifeTargetEffect(5)); + mode = new Mode(new LoseLifeTargetEffect(5)); filter = new FilterOpponent(); filter.add(new AnotherTargetPredicate(3, true)); target = new TargetOpponent(filter, false); diff --git a/Mage.Sets/src/mage/cards/v/VindictiveVampire.java b/Mage.Sets/src/mage/cards/v/VindictiveVampire.java index 7df37bc0d39..380c1998d18 100644 --- a/Mage.Sets/src/mage/cards/v/VindictiveVampire.java +++ b/Mage.Sets/src/mage/cards/v/VindictiveVampire.java @@ -111,7 +111,7 @@ class VindictiveVampireTriggeredAbility extends TriggeredAbilityImpl { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; if (zEvent.isDiesEvent()) { if (zEvent.getTarget() != null) { - if (filter.match(zEvent.getTarget(), getSourceId(), getControllerId(), game)) { + if (filter.match(zEvent.getTarget(), getControllerId(), this, game)) { if (setTargetPointer) { for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(event.getTargetId(), game)); diff --git a/Mage.Sets/src/mage/cards/v/VineDryad.java b/Mage.Sets/src/mage/cards/v/VineDryad.java index 8f89cdeb36b..4ee18644434 100644 --- a/Mage.Sets/src/mage/cards/v/VineDryad.java +++ b/Mage.Sets/src/mage/cards/v/VineDryad.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.costs.AlternativeCostSourceAbility; @@ -13,19 +11,25 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterOwnedCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetCardInHand; +import java.util.UUID; + /** - * * @author fireshoes */ public final class VineDryad extends CardImpl { + private static final FilterOwnedCard filter + = new FilterOwnedCard("a green card from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.GREEN)); + } + public VineDryad(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.DRYAD); this.power = new MageInt(1); this.toughness = new MageInt(3); @@ -37,10 +41,6 @@ public final class VineDryad extends CardImpl { this.addAbility(new ForestwalkAbility()); // You may exile a green card from your hand rather than pay Vine Dryad's mana cost. - FilterOwnedCard filter = new FilterOwnedCard("a green card from your hand"); - filter.add(new ColorPredicate(ObjectColor.GREEN)); - filter.add(Predicates.not(new CardIdPredicate(this.getId()))); // the exile cost can never be paid with the card itself - this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter)))); } diff --git a/Mage.Sets/src/mage/cards/v/VineGecko.java b/Mage.Sets/src/mage/cards/v/VineGecko.java index 420e3b37194..e4ebe9681ab 100644 --- a/Mage.Sets/src/mage/cards/v/VineGecko.java +++ b/Mage.Sets/src/mage/cards/v/VineGecko.java @@ -101,9 +101,7 @@ class VineGeckoWatcher extends Watcher { return; } Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null && StaticFilters.FILTER_SPELL_KICKED_A.match( - spell, getSourceId(), getControllerId(), game - )) { + if (spell != null && StaticFilters.FILTER_SPELL_KICKED_A.match(spell, game)) { playerSet.add(event.getPlayerId()); } } diff --git a/Mage.Sets/src/mage/cards/v/ViolentEruption.java b/Mage.Sets/src/mage/cards/v/ViolentEruption.java index 9adee177633..531e6adb942 100644 --- a/Mage.Sets/src/mage/cards/v/ViolentEruption.java +++ b/Mage.Sets/src/mage/cards/v/ViolentEruption.java @@ -23,7 +23,7 @@ public final class ViolentEruption extends CardImpl { this.getSpellAbility().addTarget(new TargetAnyTargetAmount(4)); // Madness {1}{R}{R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{R}{R}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{1}{R}{R}"))); } private ViolentEruption(final ViolentEruption card) { diff --git a/Mage.Sets/src/mage/cards/v/ViolentUltimatum.java b/Mage.Sets/src/mage/cards/v/ViolentUltimatum.java index 1f1b2ec894b..ffc29e16556 100644 --- a/Mage.Sets/src/mage/cards/v/ViolentUltimatum.java +++ b/Mage.Sets/src/mage/cards/v/ViolentUltimatum.java @@ -1,30 +1,28 @@ - - package mage.cards.v; -import java.util.UUID; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class ViolentUltimatum extends CardImpl { - public ViolentUltimatum (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{B}{B}{R}{R}{R}{G}{G}"); + public ViolentUltimatum(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}{B}{R}{R}{R}{G}{G}"); this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetPermanent(3, 3, new FilterPermanent(), false)); + this.getSpellAbility().addTarget(new TargetPermanent(3, StaticFilters.FILTER_PERMANENTS)); } - public ViolentUltimatum (final ViolentUltimatum card) { + public ViolentUltimatum(final ViolentUltimatum card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/v/ViridescentWisps.java b/Mage.Sets/src/mage/cards/v/ViridescentWisps.java index d14abd7e928..bbefe907961 100644 --- a/Mage.Sets/src/mage/cards/v/ViridescentWisps.java +++ b/Mage.Sets/src/mage/cards/v/ViridescentWisps.java @@ -1,8 +1,5 @@ - - package mage.cards.v; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.BecomesColorTargetEffect; @@ -13,24 +10,30 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX */ public final class ViridescentWisps extends CardImpl { - public ViridescentWisps (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{G}"); + public ViridescentWisps(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}"); // Target creature becomes green and gets +1/+0 until end of turn. + this.getSpellAbility().addEffect(new BecomesColorTargetEffect( + ObjectColor.GREEN, Duration.EndOfTurn + ).setText("target creature becomes green")); + this.getSpellAbility().addEffect(new BoostTargetEffect( + 1, 0, Duration.EndOfTurn + ).setText("and gets +1/+0 until end of turn")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new BecomesColorTargetEffect(ObjectColor.GREEN, Duration.EndOfTurn)); - this.getSpellAbility().addEffect(new BoostTargetEffect(1,0, Duration.EndOfTurn)); + // Draw a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } - public ViridescentWisps (final ViridescentWisps card) { + public ViridescentWisps(final ViridescentWisps card) { super(card); } @@ -38,6 +41,4 @@ public final class ViridescentWisps extends CardImpl { public ViridescentWisps copy() { return new ViridescentWisps(this); } - } - diff --git a/Mage.Sets/src/mage/cards/v/VirtussManeuver.java b/Mage.Sets/src/mage/cards/v/VirtussManeuver.java index 8a31c0587e9..5f22150292c 100644 --- a/Mage.Sets/src/mage/cards/v/VirtussManeuver.java +++ b/Mage.Sets/src/mage/cards/v/VirtussManeuver.java @@ -81,7 +81,7 @@ class VirtussManeuverEffect extends OneShotEffect { filter.add(new OwnerIdPredicate(player.getId())); TargetCardInGraveyard target = new TargetCardInGraveyard(filter); getBackMap.put(player.getId(), null); - if (player.choose(Outcome.ReturnToHand, target, source.getSourceId(), game)) { + if (player.choose(Outcome.ReturnToHand, target, source, game)) { getBackMap.put(player.getId(), game.getCard(target.getFirstTarget())); } } @@ -101,7 +101,7 @@ class VirtussManeuverEffect extends OneShotEffect { continue; } TargetControlledPermanent target = new TargetControlledPermanent(1, 1, StaticFilters.FILTER_CONTROLLED_A_CREATURE, true); - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + player.choose(Outcome.Sacrifice, target, source, game); perms.addAll(target.getTargets()); } for (UUID permID : perms) { diff --git a/Mage.Sets/src/mage/cards/v/VisionsOfDread.java b/Mage.Sets/src/mage/cards/v/VisionsOfDread.java index f86f6534086..becee61ec98 100644 --- a/Mage.Sets/src/mage/cards/v/VisionsOfDread.java +++ b/Mage.Sets/src/mage/cards/v/VisionsOfDread.java @@ -76,7 +76,7 @@ class VisionsOfDreadEffect extends OneShotEffect { StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD ); target.setNotTarget(true); - opponent.choose(Outcome.Detriment, target, source.getSourceId(), game); + opponent.choose(Outcome.Detriment, target, source, game); return controller.moveCards(game.getCard(target.getFirstTarget()), Zone.BATTLEFIELD, source, game); } } diff --git a/Mage.Sets/src/mage/cards/v/VisionsOfRuin.java b/Mage.Sets/src/mage/cards/v/VisionsOfRuin.java index de41c1c2d23..a3b9d021c43 100644 --- a/Mage.Sets/src/mage/cards/v/VisionsOfRuin.java +++ b/Mage.Sets/src/mage/cards/v/VisionsOfRuin.java @@ -71,13 +71,13 @@ class VisionsOfRuinEffect extends OneShotEffect { Player opponent = game.getPlayer(playerId); if (opponent == null || game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, - source.getSourceId(), playerId, game + playerId, source, game ) < 1) { continue; } TargetPermanent target = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT); target.setNotTarget(true); - opponent.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + opponent.choose(Outcome.Sacrifice, target, source, game); permanents.add(game.getPermanent(target.getFirstTarget())); } int sacrificed = 0; diff --git a/Mage.Sets/src/mage/cards/v/VitalityCharm.java b/Mage.Sets/src/mage/cards/v/VitalityCharm.java index 4865a5e56d4..c24d8bb58a0 100644 --- a/Mage.Sets/src/mage/cards/v/VitalityCharm.java +++ b/Mage.Sets/src/mage/cards/v/VitalityCharm.java @@ -37,18 +37,16 @@ public final class VitalityCharm extends CardImpl { // Choose one - Create a 1/1 green Insect creature token this.getSpellAbility().addEffect(new CreateTokenEffect(new InsectToken())); // or target creature gets +1/+1 and gains trample until end of turn - Mode mode = new Mode(); Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); effect.setText("target creature gets +1/+1"); - mode.addEffect(effect); + Mode mode = new Mode(effect); effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); effect.setText("and gains trample until end of turn"); mode.addEffect(effect); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or regenerate target Beast. - mode = new Mode(); - mode.addEffect(new RegenerateTargetEffect()); + mode = new Mode(new RegenerateTargetEffect()); mode.addTarget(new TargetPermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/v/VivienArkbowRanger.java b/Mage.Sets/src/mage/cards/v/VivienArkbowRanger.java index ac170c7e55c..97f6c5c36d6 100644 --- a/Mage.Sets/src/mage/cards/v/VivienArkbowRanger.java +++ b/Mage.Sets/src/mage/cards/v/VivienArkbowRanger.java @@ -2,7 +2,6 @@ package mage.cards.v; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DamageWithPowerFromOneToAnotherTargetEffect; import mage.abilities.effects.common.WishEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; @@ -35,7 +34,7 @@ public final class VivienArkbowRanger extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.VIVIEN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Distribute two +1/+1 counters among up to two target creatures. They gain trample until end of turn. Ability ability = new LoyaltyAbility(new DistributeCountersEffect( diff --git a/Mage.Sets/src/mage/cards/v/VivienChampionOfTheWilds.java b/Mage.Sets/src/mage/cards/v/VivienChampionOfTheWilds.java index 2549312f7ee..1b2432a6767 100644 --- a/Mage.Sets/src/mage/cards/v/VivienChampionOfTheWilds.java +++ b/Mage.Sets/src/mage/cards/v/VivienChampionOfTheWilds.java @@ -2,7 +2,6 @@ package mage.cards.v; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.ContinuousEffect; @@ -40,7 +39,7 @@ public final class VivienChampionOfTheWilds extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.VIVIEN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // You may cast creature spells as though they had flash. this.addAbility(new SimpleStaticAbility(new CastAsThoughItHadFlashAllEffect( diff --git a/Mage.Sets/src/mage/cards/v/VivienMonstersAdvocate.java b/Mage.Sets/src/mage/cards/v/VivienMonstersAdvocate.java index 1985e62cf9a..5349862629b 100644 --- a/Mage.Sets/src/mage/cards/v/VivienMonstersAdvocate.java +++ b/Mage.Sets/src/mage/cards/v/VivienMonstersAdvocate.java @@ -3,7 +3,6 @@ package mage.cards.v; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; @@ -46,7 +45,7 @@ public final class VivienMonstersAdvocate extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.VIVIEN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // You may look at the top card of your library any time. this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect())); diff --git a/Mage.Sets/src/mage/cards/v/VivienNaturesAvenger.java b/Mage.Sets/src/mage/cards/v/VivienNaturesAvenger.java index 09e97030e53..3280173988a 100644 --- a/Mage.Sets/src/mage/cards/v/VivienNaturesAvenger.java +++ b/Mage.Sets/src/mage/cards/v/VivienNaturesAvenger.java @@ -2,7 +2,6 @@ package mage.cards.v; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.RevealCardsFromLibraryUntilEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; @@ -27,7 +26,7 @@ public final class VivienNaturesAvenger extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.VIVIEN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Put three +1/+1 counters on up to one target creature. Ability ability = new LoyaltyAbility(new AddCountersTargetEffect( diff --git a/Mage.Sets/src/mage/cards/v/VivienOfTheArkbow.java b/Mage.Sets/src/mage/cards/v/VivienOfTheArkbow.java index 34c82d0c40c..c48c7ff6b9f 100644 --- a/Mage.Sets/src/mage/cards/v/VivienOfTheArkbow.java +++ b/Mage.Sets/src/mage/cards/v/VivienOfTheArkbow.java @@ -2,7 +2,6 @@ package mage.cards.v; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DamageWithPowerFromOneToAnotherTargetEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -31,7 +30,7 @@ public final class VivienOfTheArkbow extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.VIVIEN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +2: Put two +1/+1 counters on up to one target creature. Ability ability = new LoyaltyAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)), 2); diff --git a/Mage.Sets/src/mage/cards/v/VivienOnTheHunt.java b/Mage.Sets/src/mage/cards/v/VivienOnTheHunt.java new file mode 100644 index 00000000000..559f9fb13c8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VivienOnTheHunt.java @@ -0,0 +1,133 @@ +package mage.cards.v; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.*; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.RhinoWarriorToken; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VivienOnTheHunt extends CardImpl { + + public VivienOnTheHunt(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{G}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.VIVIEN); + this.setStartingLoyalty(4); + + // +2: You may sacrifice a creature. If you do, search your library for a creature card with mana value equal to 1 plus the sacrificed creature's mana value, put it onto the battlefield, then shuffle. + this.addAbility(new LoyaltyAbility(new VivienOnTheHuntSacrificeEffect(), 2)); + + // +1: Mill five cards, then put any number of creature cards milled this way into your hand. + this.addAbility(new LoyaltyAbility(new VivienOnTheHuntMillEffect(), 1)); + + // −1: Create a 4/4 green Rhino Warrior creature token. + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new RhinoWarriorToken()), -1)); + } + + private VivienOnTheHunt(final VivienOnTheHunt card) { + super(card); + } + + @Override + public VivienOnTheHunt copy() { + return new VivienOnTheHunt(this); + } +} + +class VivienOnTheHuntSacrificeEffect extends OneShotEffect { + + VivienOnTheHuntSacrificeEffect() { + super(Outcome.Benefit); + staticText = "you may sacrifice a creature. If you do, search your library for a creature card with mana " + + "value equal to 1 plus the sacrificed creature's mana value, put it onto the battlefield, then shuffle"; + } + + private VivienOnTheHuntSacrificeEffect(final VivienOnTheHuntSacrificeEffect effect) { + super(effect); + } + + @Override + public VivienOnTheHuntSacrificeEffect copy() { + return new VivienOnTheHuntSacrificeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetPermanent target = new TargetPermanent( + 0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, true + ); + player.choose(Outcome.Sacrifice, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null || !permanent.sacrifice(source, game)) { + return false; + } + int mv = permanent.getManaValue() + 1; + FilterCard filter = new FilterCreatureCard("creature card with mana value " + mv); + filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, mv)); + TargetCardInLibrary targetCardInLibrary = new TargetCardInLibrary(filter); + player.searchLibrary(targetCardInLibrary, source, game); + Card card = player.getLibrary().getCard(targetCardInLibrary.getFirstTarget(), game); + if (card != null) { + player.moveCards(card, Zone.BATTLEFIELD, source, game); + } + player.shuffleLibrary(source, game); + return true; + } +} + +class VivienOnTheHuntMillEffect extends OneShotEffect { + + VivienOnTheHuntMillEffect() { + super(Outcome.Benefit); + staticText = "mill five cards, then put any number of creature cards milled this way into your hand"; + } + + private VivienOnTheHuntMillEffect(final VivienOnTheHuntMillEffect effect) { + super(effect); + } + + @Override + public VivienOnTheHuntMillEffect copy() { + return new VivienOnTheHuntMillEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = player.millCards(5, source, game); + if (cards.count(StaticFilters.FILTER_CARD_CREATURE, game) < 1) { + return true; + } + TargetCard target = new TargetCard( + 0, Integer.MAX_VALUE, Zone.ALL, StaticFilters.FILTER_CARD_CREATURE + ); + player.choose(outcome, cards, target, game); + player.moveCards(new CardsImpl(target.getTargets()), Zone.HAND, source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/v/VivienReid.java b/Mage.Sets/src/mage/cards/v/VivienReid.java index 74e03a599d3..afc38b1b9c2 100644 --- a/Mage.Sets/src/mage/cards/v/VivienReid.java +++ b/Mage.Sets/src/mage/cards/v/VivienReid.java @@ -3,19 +3,17 @@ package mage.cards.v; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.FlyingAbility; import mage.constants.SubType; import mage.constants.SuperType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.FilterCard; +import mage.filter.StaticFilters; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; @@ -28,15 +26,10 @@ import mage.target.TargetPermanent; */ public final class VivienReid extends CardImpl { - private static final FilterCard filter = new FilterCard("a creature or land card"); - private static final FilterPermanent filter2 = new FilterPermanent("artifact, enchantment, or creature with flying"); + private static final FilterPermanent filter = new FilterPermanent("artifact, enchantment, or creature with flying"); static { filter.add(Predicates.or( - CardType.CREATURE.getPredicate(), - CardType.LAND.getPredicate() - )); - filter2.add(Predicates.or( CardType.ARTIFACT.getPredicate(), CardType.ENCHANTMENT.getPredicate(), Predicates.and( @@ -51,21 +44,16 @@ public final class VivienReid extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.VIVIEN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); - // +1: Look at the top four cards of your library. You may reveal a creature or land card from among them and put it into your hand. Put the rest on the bottom of your library in any order. - this.addAbility(new LoyaltyAbility( - new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(1), filter, - Zone.LIBRARY, false, true, false, Zone.HAND, true, false, false) - .setBackInRandomOrder(true) - .setText("Look at the top four cards of your library. You may reveal a creature or land card from among them" - + " and put it into your hand. Put the rest on the bottom of your library in a random order."), 1 - )); + // +1: Look at the top four cards of your library. You may reveal a creature or land card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. + this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect( + 4, 1, StaticFilters.FILTER_CARD_CREATURE_OR_LAND, PutCards.HAND, PutCards.BOTTOM_RANDOM), 1)); // -3: Destroy target artifact, enchantment, or creature with flying. Ability ability = new LoyaltyAbility(new DestroyTargetEffect(), -3); - ability.addTarget(new TargetPermanent(filter2)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // -8: You get an emblem with "Creatures you control get +2/+2 and have vigilance, trample, and indestructible. diff --git a/Mage.Sets/src/mage/cards/v/ViviensStampede.java b/Mage.Sets/src/mage/cards/v/ViviensStampede.java new file mode 100644 index 00000000000..487f23c2d19 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/ViviensStampede.java @@ -0,0 +1,118 @@ +package mage.cards.v; + +import mage.abilities.Ability; +import mage.abilities.common.delayed.AtTheBeginOfMainPhaseDelayedTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.MeleeAbility; +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.Duration; +import mage.constants.TargetController; +import mage.constants.WatcherScope; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.DamagedEvent; +import mage.game.events.GameEvent; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ViviensStampede extends CardImpl { + + public ViviensStampede(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}{G}"); + + // Each creature you control gains vigilance, trample, and melee until end of turn. + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText("each creature you control gains vigilance")); + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText(", trample")); + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + new MeleeAbility(), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURE + ).setText(", and melee until end of turn")); + + // At the beginning of the next main phase this turn, draw a card for each player who was dealt combat damage this turn. + this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect( + new AtTheBeginOfMainPhaseDelayedTriggeredAbility( + new DrawCardSourceControllerEffect(ViviensStampedeValue.instance), + false, TargetController.ANY, + AtTheBeginOfMainPhaseDelayedTriggeredAbility.PhaseSelection.NEXT_MAIN_THIS_TURN + ) + ).concatBy("
")); + this.getSpellAbility().addWatcher(new ViviensStampedeWatcher()); + } + + private ViviensStampede(final ViviensStampede card) { + super(card); + } + + @Override + public ViviensStampede copy() { + return new ViviensStampede(this); + } +} + +enum ViviensStampedeValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return ViviensStampedeWatcher.getCount(game); + } + + @Override + public ViviensStampedeValue copy() { + return this; + } + + @Override + public String getMessage() { + return "player who was dealt combat damage this turn"; + } + + @Override + public String toString() { + return "1"; + } +} + +class ViviensStampedeWatcher extends Watcher { + + private final Set players = new HashSet<>(); + + ViviensStampedeWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.DAMAGED_PLAYER + && ((DamagedEvent) event).isCombatDamage()) { + players.add(event.getTargetId()); + } + } + + @Override + public void reset() { + super.reset(); + players.clear(); + } + + static int getCount(Game game) { + return game.getState().getWatcher(ViviensStampedeWatcher.class).players.size(); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VodalianWarMachine.java b/Mage.Sets/src/mage/cards/v/VodalianWarMachine.java index ff4b32081b8..67849e1cdca 100644 --- a/Mage.Sets/src/mage/cards/v/VodalianWarMachine.java +++ b/Mage.Sets/src/mage/cards/v/VodalianWarMachine.java @@ -97,7 +97,7 @@ class VodalianWarMachineEffect extends OneShotEffect { if (sourcePermanent != null) { VodalianWarMachineWatcher watcher = game.getState().getWatcher(VodalianWarMachineWatcher.class); if (watcher != null && watcher.getTappedMerfolkIds(sourcePermanent, game) != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (watcher.getTappedMerfolkIds(sourcePermanent, game).contains(new MageObjectReference(permanent, game))) { permanent.destroy(source, game, false); } diff --git a/Mage.Sets/src/mage/cards/v/VoiceOfTheVermin.java b/Mage.Sets/src/mage/cards/v/VoiceOfTheVermin.java new file mode 100644 index 00000000000..96f1aae0332 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VoiceOfTheVermin.java @@ -0,0 +1,55 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.common.continuous.SetPowerToughnessTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VoiceOfTheVermin extends CardImpl { + + public VoiceOfTheVermin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Voice of the Vermin enters the battlefield with a shield counter on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.SHIELD.createInstance(1)), + "with a shield counter on it. (If it would be dealt damage " + + "or destroyed, remove a shield counter from it instead.)" + )); + + // Whenever Voice of the Vermin attacks, target creature you control has base power and toughness 4/4 until end of turn. + Ability ability = new AttacksTriggeredAbility( + new SetPowerToughnessTargetEffect(4, 4, Duration.EndOfTurn) + ); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private VoiceOfTheVermin(final VoiceOfTheVermin card) { + super(card); + } + + @Override + public VoiceOfTheVermin copy() { + return new VoiceOfTheVermin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VoicesFromTheVoid.java b/Mage.Sets/src/mage/cards/v/VoicesFromTheVoid.java index bea4bb4db94..497b1bae3b7 100644 --- a/Mage.Sets/src/mage/cards/v/VoicesFromTheVoid.java +++ b/Mage.Sets/src/mage/cards/v/VoicesFromTheVoid.java @@ -1,29 +1,29 @@ - package mage.cards.v; -import java.util.UUID; import mage.abilities.dynamicvalue.common.DomainValue; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.abilities.hint.common.DomainHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author Loki */ public final class VoicesFromTheVoid extends CardImpl { public VoicesFromTheVoid(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); // Domain - Target player discards a card for each basic land type among lands you control. - this.getSpellAbility().addEffect(new DiscardTargetEffect(new DomainValue())); + this.getSpellAbility().addEffect(new DiscardTargetEffect(DomainValue.REGULAR)); this.getSpellAbility().addTarget(new TargetPlayer()); this.getSpellAbility().addHint(DomainHint.instance); + this.getSpellAbility().setAbilityWord(AbilityWord.DOMAIN); } private VoicesFromTheVoid(final VoicesFromTheVoid card) { diff --git a/Mage.Sets/src/mage/cards/v/VoidRend.java b/Mage.Sets/src/mage/cards/v/VoidRend.java new file mode 100644 index 00000000000..dd1cb372a8d --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VoidRend.java @@ -0,0 +1,36 @@ +package mage.cards.v; + +import mage.abilities.common.CantBeCounteredSourceAbility; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VoidRend extends CardImpl { + + public VoidRend(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}{U}{B}"); + + // This spell can't be countered. + this.addAbility(new CantBeCounteredSourceAbility().setRuleAtTheTop(true)); + + // Destroy target nonland permanent. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetNonlandPermanent()); + } + + private VoidRend(final VoidRend card) { + super(card); + } + + @Override + public VoidRend copy() { + return new VoidRend(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VoidWinnower.java b/Mage.Sets/src/mage/cards/v/VoidWinnower.java index d985f2957e4..05598b5e0de 100644 --- a/Mage.Sets/src/mage/cards/v/VoidWinnower.java +++ b/Mage.Sets/src/mage/cards/v/VoidWinnower.java @@ -68,7 +68,7 @@ class VoidWinnowerCantCastEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast spells with even mana values (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/v/VoidmageApprentice.java b/Mage.Sets/src/mage/cards/v/VoidmageApprentice.java index 590b450790c..2094448457b 100644 --- a/Mage.Sets/src/mage/cards/v/VoidmageApprentice.java +++ b/Mage.Sets/src/mage/cards/v/VoidmageApprentice.java @@ -28,7 +28,7 @@ public final class VoidmageApprentice extends CardImpl { this.toughness = new MageInt(1); // Morph {2}{U}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{U}{U}"))); // When Voidmage Apprentice is turned face up, counter target spell. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new CounterTargetEffect(), false); diff --git a/Mage.Sets/src/mage/cards/v/VoidmageProdigy.java b/Mage.Sets/src/mage/cards/v/VoidmageProdigy.java index ba115615238..c4440d9c3e6 100644 --- a/Mage.Sets/src/mage/cards/v/VoidmageProdigy.java +++ b/Mage.Sets/src/mage/cards/v/VoidmageProdigy.java @@ -47,7 +47,7 @@ public final class VoidmageProdigy extends CardImpl { this.addAbility(ability); // Morph {U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{U}"))); } private VoidmageProdigy(final VoidmageProdigy card) { diff --git a/Mage.Sets/src/mage/cards/v/VoidstoneGargoyle.java b/Mage.Sets/src/mage/cards/v/VoidstoneGargoyle.java index 8596b9668e6..34bf91bd86e 100644 --- a/Mage.Sets/src/mage/cards/v/VoidstoneGargoyle.java +++ b/Mage.Sets/src/mage/cards/v/VoidstoneGargoyle.java @@ -73,7 +73,7 @@ class VoidstoneGargoyleReplacementEffect1 extends ContinuousRuleModifyingEffectI @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast a spell with that name (" + mageObject.getName() + ")."; } @@ -115,7 +115,7 @@ class VoidstoneGargoyleRuleModifyingEffect2 extends ContinuousRuleModifyingEffec @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't activate abilities of sources with that name (" + mageObject.getName() + " in play)."; } diff --git a/Mage.Sets/src/mage/cards/v/Voidwalk.java b/Mage.Sets/src/mage/cards/v/Voidwalk.java index 680eaa277e9..4e533d37de7 100644 --- a/Mage.Sets/src/mage/cards/v/Voidwalk.java +++ b/Mage.Sets/src/mage/cards/v/Voidwalk.java @@ -61,7 +61,7 @@ class VoidwalkEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && permanent != null && sourceObject != null) { if (controller.moveCardToExileWithInfo(permanent, source.getSourceId(), sourceObject.getIdName(), source, game, Zone.BATTLEFIELD, true)) { //create delayed triggered ability diff --git a/Mage.Sets/src/mage/cards/v/VolatileClaws.java b/Mage.Sets/src/mage/cards/v/VolatileClaws.java index 720dc0cd483..f65ab4419a5 100644 --- a/Mage.Sets/src/mage/cards/v/VolatileClaws.java +++ b/Mage.Sets/src/mage/cards/v/VolatileClaws.java @@ -59,7 +59,7 @@ class VolatileClawsEffect extends ContinuousEffectImpl { public void init(Ability source, Game game) { super.init(source, game); for (Permanent perm : game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_CONTROLLED_CREATURES, source.getControllerId(), source.getSourceId(), game + StaticFilters.FILTER_CONTROLLED_CREATURES, source.getControllerId(), source, game )) { affectedObjectList.add(new MageObjectReference(perm, game)); } diff --git a/Mage.Sets/src/mage/cards/v/VolcanicVision.java b/Mage.Sets/src/mage/cards/v/VolcanicVision.java index 7db71625e67..996b712a6b7 100644 --- a/Mage.Sets/src/mage/cards/v/VolcanicVision.java +++ b/Mage.Sets/src/mage/cards/v/VolcanicVision.java @@ -80,7 +80,7 @@ class VolcanicVisionReturnToHandTargetEffect extends OneShotEffect { controller.moveCards(card, Zone.HAND, source, game); int damage = card.getManaValue(); if (damage > 0) { - for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { creature.damage(damage, source.getSourceId(), source, game, false, true); } } diff --git a/Mage.Sets/src/mage/cards/v/VoldarenBloodcaster.java b/Mage.Sets/src/mage/cards/v/VoldarenBloodcaster.java index 9620ea4b8bb..4795e38dfb0 100644 --- a/Mage.Sets/src/mage/cards/v/VoldarenBloodcaster.java +++ b/Mage.Sets/src/mage/cards/v/VoldarenBloodcaster.java @@ -107,7 +107,7 @@ class VoldarenBloodcasterTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkInterveningIfClause(Game game) { - return game.getBattlefield().count(filter, getSourceId(), getControllerId(), game) >= 5; + return game.getBattlefield().count(filter, getControllerId(), this, game) >= 5; } @Override diff --git a/Mage.Sets/src/mage/cards/v/VoldarenEstate.java b/Mage.Sets/src/mage/cards/v/VoldarenEstate.java index 0637f52e233..6f42614ec8b 100644 --- a/Mage.Sets/src/mage/cards/v/VoldarenEstate.java +++ b/Mage.Sets/src/mage/cards/v/VoldarenEstate.java @@ -75,7 +75,7 @@ class VoldarenEstateManaBuilder extends ConditionalManaBuilder { @Override public ConditionalManaBuilder setMana(Mana mana, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null && mana.getAny() == 0) { game.informPlayers(controller.getLogName() + " produces " + mana.toString() + " with " + sourceObject.getLogName() + " (can only be spent to cast a Vampire spell"); @@ -108,7 +108,7 @@ class VoldarenEstateManaCondition extends ManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { if (source instanceof SpellAbility) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && object.hasSubtype(SubType.VAMPIRE, game); } return false; diff --git a/Mage.Sets/src/mage/cards/v/VoldarenPariah.java b/Mage.Sets/src/mage/cards/v/VoldarenPariah.java index d5ead032805..0e683e68206 100644 --- a/Mage.Sets/src/mage/cards/v/VoldarenPariah.java +++ b/Mage.Sets/src/mage/cards/v/VoldarenPariah.java @@ -49,7 +49,7 @@ public final class VoldarenPariah extends CardImpl { new SacrificeTargetCost(new TargetControlledPermanent(3, 3, filter, false)))); // Madness {B}{B}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{B}{B}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{B}{B}{B}"))); } private VoldarenPariah(final VoldarenPariah card) { diff --git a/Mage.Sets/src/mage/cards/v/VolrathsLaboratory.java b/Mage.Sets/src/mage/cards/v/VolrathsLaboratory.java index cb3abe296c7..d4658618bb9 100644 --- a/Mage.Sets/src/mage/cards/v/VolrathsLaboratory.java +++ b/Mage.Sets/src/mage/cards/v/VolrathsLaboratory.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; @@ -19,11 +17,11 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; -import mage.game.permanent.token.Token; import mage.game.permanent.token.VolrathsLaboratoryToken; +import java.util.UUID; + /** - * * @author emerald000 */ public final class VolrathsLaboratory extends CardImpl { @@ -74,7 +72,9 @@ class VolrathsLaboratoryEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { ObjectColor color = (ObjectColor) game.getState().getValue(source.getSourceId() + "_color"); SubType subType = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game); - Token token = new VolrathsLaboratoryToken(color, subType); - return token.putOntoBattlefield(1, game, source, source.getControllerId()); + if (subType == null || color == null) { + return false; + } + return new VolrathsLaboratoryToken(color, subType).putOntoBattlefield(1, game, source, source.getControllerId()); } } diff --git a/Mage.Sets/src/mage/cards/v/VoltageSurge.java b/Mage.Sets/src/mage/cards/v/VoltageSurge.java new file mode 100644 index 00000000000..ca2d7c391c2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VoltageSurge.java @@ -0,0 +1,78 @@ +package mage.cards.v; + +import mage.abilities.Ability; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreatureOrPlaneswalker; +import mage.util.CardUtil; + +import java.util.Collection; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VoltageSurge extends CardImpl { + + public VoltageSurge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); + + // As an additional cost to cast this spell, you may sacrifice an artifact. + this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledPermanent( + 0, 1, StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_AN, true + )).setText("you may sacrifice an artifact")); + + // Voltage Surge deals 2 damage to target creature or planeswalker. If this spell's additional cost was paid, Voltage Surge deals 4 damage instead. + this.getSpellAbility().addEffect(new VoltageSurgeEffect()); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + } + + private VoltageSurge(final VoltageSurge card) { + super(card); + } + + @Override + public VoltageSurge copy() { + return new VoltageSurge(this); + } +} + +class VoltageSurgeEffect extends OneShotEffect { + + VoltageSurgeEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 2 damage to target creature or planeswalker. " + + "If this spell's additional cost was paid, {this} deals 4 damage instead"; + } + + private VoltageSurgeEffect(final VoltageSurgeEffect effect) { + super(effect); + } + + @Override + public VoltageSurgeEffect copy() { + return new VoltageSurgeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + boolean wasPaid = CardUtil.castStream(source.getCosts().stream(), SacrificeTargetCost.class) + .map(SacrificeTargetCost::getPermanents) + .flatMap(Collection::stream) + .findFirst() + .isPresent(); + return permanent.damage(wasPaid ? 4 : 2, source, game) > 0; + } +} diff --git a/Mage.Sets/src/mage/cards/v/VonasHunger.java b/Mage.Sets/src/mage/cards/v/VonasHunger.java index 179fd5d6cae..2a5e2cde9a8 100644 --- a/Mage.Sets/src/mage/cards/v/VonasHunger.java +++ b/Mage.Sets/src/mage/cards/v/VonasHunger.java @@ -82,7 +82,7 @@ class VonasHungerEffect extends OneShotEffect { int numTargets = (game.getBattlefield().countAll(StaticFilters.FILTER_CONTROLLED_CREATURE, player.getId(), game) + 1) / 2; if (numTargets > 0) { TargetPermanent target = new TargetPermanent(numTargets, numTargets, StaticFilters.FILTER_CONTROLLED_CREATURE, true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Sacrifice, target, source, game); perms.addAll(target.getTargets()); } diff --git a/Mage.Sets/src/mage/cards/v/VorelOfTheHullClade.java b/Mage.Sets/src/mage/cards/v/VorelOfTheHullClade.java index 9596598e9aa..a744d7e09f6 100644 --- a/Mage.Sets/src/mage/cards/v/VorelOfTheHullClade.java +++ b/Mage.Sets/src/mage/cards/v/VorelOfTheHullClade.java @@ -68,7 +68,7 @@ class VorelOfTheHullCladeEffect extends OneShotEffect { public VorelOfTheHullCladeEffect() { super(Outcome.Benefit); - staticText = "For each counter on target artifact, creature, or land, put another of those counters on that permanent"; + staticText = "double the number of each kind of counter on target artifact, creature, or land"; } public VorelOfTheHullCladeEffect(VorelOfTheHullCladeEffect effect) { diff --git a/Mage.Sets/src/mage/cards/v/VraskaGolgariQueen.java b/Mage.Sets/src/mage/cards/v/VraskaGolgariQueen.java index 209f27da528..c69f628b9b1 100644 --- a/Mage.Sets/src/mage/cards/v/VraskaGolgariQueen.java +++ b/Mage.Sets/src/mage/cards/v/VraskaGolgariQueen.java @@ -3,7 +3,6 @@ package mage.cards.v; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.DoIfCostPaid; @@ -46,7 +45,7 @@ public final class VraskaGolgariQueen extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.VRASKA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +2: You may sacrifice another permanent. If you do, you gain 1 life and draw a card. DoIfCostPaid effect = new DoIfCostPaid( diff --git a/Mage.Sets/src/mage/cards/v/VraskaRegalGorgon.java b/Mage.Sets/src/mage/cards/v/VraskaRegalGorgon.java index d04676476da..0f008121a26 100644 --- a/Mage.Sets/src/mage/cards/v/VraskaRegalGorgon.java +++ b/Mage.Sets/src/mage/cards/v/VraskaRegalGorgon.java @@ -3,7 +3,6 @@ package mage.cards.v; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; @@ -34,7 +33,7 @@ public final class VraskaRegalGorgon extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.VRASKA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +2: Put a +1/+1 counter on up to one target creature. That creature gains menace until end of turn. Ability ability = new LoyaltyAbility(new AddCountersTargetEffect( diff --git a/Mage.Sets/src/mage/cards/v/VraskaRelicSeeker.java b/Mage.Sets/src/mage/cards/v/VraskaRelicSeeker.java index 906ccb60e44..e38e6e63a96 100644 --- a/Mage.Sets/src/mage/cards/v/VraskaRelicSeeker.java +++ b/Mage.Sets/src/mage/cards/v/VraskaRelicSeeker.java @@ -2,7 +2,6 @@ package mage.cards.v; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyTargetEffect; @@ -33,7 +32,7 @@ public final class VraskaRelicSeeker extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.VRASKA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(6)); + this.setStartingLoyalty(6); //+2: Create a 2/2 black Pirate creature token with menace. this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new PirateToken()), 2)); diff --git a/Mage.Sets/src/mage/cards/v/VraskaSchemingGorgon.java b/Mage.Sets/src/mage/cards/v/VraskaSchemingGorgon.java index 6a7e023b2be..cc97be26051 100644 --- a/Mage.Sets/src/mage/cards/v/VraskaSchemingGorgon.java +++ b/Mage.Sets/src/mage/cards/v/VraskaSchemingGorgon.java @@ -3,7 +3,6 @@ package mage.cards.v; import mage.abilities.LoyaltyAbility; import mage.abilities.TriggeredAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.LoseGameTargetPlayerEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; @@ -29,7 +28,7 @@ public final class VraskaSchemingGorgon extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.VRASKA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +2: Creatures you control get +1/+0 until end of turn. this.addAbility(new LoyaltyAbility(new BoostControlledEffect(1, 0, Duration.EndOfTurn), 2)); diff --git a/Mage.Sets/src/mage/cards/v/VraskaSwarmsEminence.java b/Mage.Sets/src/mage/cards/v/VraskaSwarmsEminence.java index 2c0746be50a..9302ca3d35a 100644 --- a/Mage.Sets/src/mage/cards/v/VraskaSwarmsEminence.java +++ b/Mage.Sets/src/mage/cards/v/VraskaSwarmsEminence.java @@ -2,7 +2,6 @@ package mage.cards.v; import mage.abilities.LoyaltyAbility; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; @@ -41,7 +40,7 @@ public final class VraskaSwarmsEminence extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.VRASKA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // Whenever a creature you control with deathtouch deals damage to a player or planeswalker, put a +1/+1 counter on that creature. this.addAbility(new VraskaSwarmsEminenceTriggeredAbility(Zone.BATTLEFIELD, @@ -91,7 +90,7 @@ class VraskaSwarmsEminenceTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanent(event.getSourceId()); - if (permanent == null || !filter.match(permanent, getSourceId(), getControllerId(), game)) { + if (permanent == null || !filter.match(permanent, getControllerId(), this, game)) { return false; } Permanent damaged = game.getPermanentOrLKIBattlefield(event.getTargetId()); diff --git a/Mage.Sets/src/mage/cards/v/VraskaTheUnseen.java b/Mage.Sets/src/mage/cards/v/VraskaTheUnseen.java index 4d3d28fab79..c55e5e1c357 100644 --- a/Mage.Sets/src/mage/cards/v/VraskaTheUnseen.java +++ b/Mage.Sets/src/mage/cards/v/VraskaTheUnseen.java @@ -3,7 +3,6 @@ package mage.cards.v; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; @@ -37,7 +36,7 @@ public final class VraskaTheUnseen extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.VRASKA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Until your next turn, whenever a creature deals combat damage to Vraska the Unseen, destroy that creature. this.addAbility(new LoyaltyAbility(new VraskaTheUnseenGainAbilityEffect(new VraskaTheUnseenTriggeredAbility()), 1)); diff --git a/Mage.Sets/src/mage/cards/v/VrondissRageOfAncients.java b/Mage.Sets/src/mage/cards/v/VrondissRageOfAncients.java index 3309514180d..023d77b3286 100644 --- a/Mage.Sets/src/mage/cards/v/VrondissRageOfAncients.java +++ b/Mage.Sets/src/mage/cards/v/VrondissRageOfAncients.java @@ -35,7 +35,7 @@ public final class VrondissRageOfAncients extends CardImpl { // Whenever you roll one or more dice, you may have Vrondiss, Rage of Ancients deal 1 damage to itself. this.addAbility(new OneOrMoreDiceRolledTriggeredAbility( - new DamageSelfEffect(1).setText("{this} deal 1 damage to itself"), true + new DamageSelfEffect(1).setText("have {this} deal 1 damage to itself"), true )); } diff --git a/Mage.Sets/src/mage/cards/w/WailOfTheNim.java b/Mage.Sets/src/mage/cards/w/WailOfTheNim.java index 9cf86705570..9fab248aff3 100644 --- a/Mage.Sets/src/mage/cards/w/WailOfTheNim.java +++ b/Mage.Sets/src/mage/cards/w/WailOfTheNim.java @@ -24,8 +24,7 @@ public final class WailOfTheNim extends CardImpl { this.getSpellAbility().addEffect(new RegenerateAllEffect(new FilterControlledCreaturePermanent())); // or Wail of the Nim deals 1 damage to each creature and each player. - Mode mode = new Mode(); - mode.addEffect(new DamageEverythingEffect(1)); + Mode mode = new Mode(new DamageEverythingEffect(1)); this.getSpellAbility().getModes().addMode(mode); // Entwine {B} diff --git a/Mage.Sets/src/mage/cards/w/WakerOfWaves.java b/Mage.Sets/src/mage/cards/w/WakerOfWaves.java index 7f843ae618e..fd0ab8f41ee 100644 --- a/Mage.Sets/src/mage/cards/w/WakerOfWaves.java +++ b/Mage.Sets/src/mage/cards/w/WakerOfWaves.java @@ -1,4 +1,3 @@ - package mage.cards.w; import mage.MageInt; @@ -7,14 +6,13 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.DiscardSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; import java.util.UUID; @@ -24,12 +22,6 @@ import java.util.UUID; */ public final class WakerOfWaves extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public WakerOfWaves(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}"); this.subtype.add(SubType.WHALE); @@ -38,11 +30,13 @@ public final class WakerOfWaves extends CardImpl { this.toughness = new MageInt(7); // Creatures your opponents control get -1/-0. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(-1, -0, Duration.WhileOnBattlefield, filter, false))); + this.addAbility(new SimpleStaticAbility( + new BoostAllEffect(-1, -0, Duration.WhileOnBattlefield, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, false))); // {1}{U}, Discard Waker of Waves: Look at the top two cards of your library. Put one of them into your hand and the other into your graveyard. - Ability ability = new SimpleActivatedAbility(Zone.HAND, new LookLibraryAndPickControllerEffect(StaticValue.get(2), false, StaticValue.get(1), - StaticFilters.FILTER_CARD, Zone.GRAVEYARD, false, false), new ManaCostsImpl("{1}{U}")); + Ability ability = new SimpleActivatedAbility(Zone.HAND, + new LookLibraryAndPickControllerEffect(2, 1, PutCards.HAND, PutCards.GRAVEYARD), + new ManaCostsImpl("{1}{U}")); ability.addCost(new DiscardSourceCost()); this.addAbility(ability); } @@ -56,4 +50,3 @@ public final class WakerOfWaves extends CardImpl { return new WakerOfWaves(this); } } - diff --git a/Mage.Sets/src/mage/cards/w/WakingTheTrolls.java b/Mage.Sets/src/mage/cards/w/WakingTheTrolls.java index e8753fa5934..5f647571718 100644 --- a/Mage.Sets/src/mage/cards/w/WakingTheTrolls.java +++ b/Mage.Sets/src/mage/cards/w/WakingTheTrolls.java @@ -90,11 +90,11 @@ class WakingTheTrollsEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { int myLands = game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, - source.getSourceId(), source.getControllerId(), game + source.getControllerId(), source, game ); int theirLands = game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, - source.getSourceId(), source.getFirstTarget(), game + source.getFirstTarget(), source, game ); if (myLands <= theirLands) { return false; diff --git a/Mage.Sets/src/mage/cards/w/WalkingDesecration.java b/Mage.Sets/src/mage/cards/w/WalkingDesecration.java index b6a3d0c6867..b372f53116a 100644 --- a/Mage.Sets/src/mage/cards/w/WalkingDesecration.java +++ b/Mage.Sets/src/mage/cards/w/WalkingDesecration.java @@ -62,7 +62,7 @@ class WalkingDesecrationEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (player != null) { if (sourceObject != null) { Choice typeChoice = new ChoiceCreatureType(sourceObject); diff --git a/Mage.Sets/src/mage/cards/w/WallOfCaltrops.java b/Mage.Sets/src/mage/cards/w/WallOfCaltrops.java index 6fb5850498c..10376b4f3b5 100644 --- a/Mage.Sets/src/mage/cards/w/WallOfCaltrops.java +++ b/Mage.Sets/src/mage/cards/w/WallOfCaltrops.java @@ -3,7 +3,7 @@ package mage.cards.w; import java.util.UUID; import mage.MageInt; -import mage.abilities.common.BlocksSourceTriggeredAbility; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.BandingAbility; import mage.abilities.keyword.DefenderAbility; @@ -47,7 +47,7 @@ public final class WallOfCaltrops extends CardImpl { } } -class WallOfCaltropsAbility extends BlocksSourceTriggeredAbility { +class WallOfCaltropsAbility extends BlocksCreatureTriggeredAbility { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Wall creature"); @@ -56,7 +56,7 @@ class WallOfCaltropsAbility extends BlocksSourceTriggeredAbility { } public WallOfCaltropsAbility() { - super(new GainAbilitySourceEffect(BandingAbility.getInstance(), Duration.EndOfTurn), false, false); + super(new GainAbilitySourceEffect(BandingAbility.getInstance(), Duration.EndOfTurn)); } public WallOfCaltropsAbility(WallOfCaltropsAbility ability) { diff --git a/Mage.Sets/src/mage/cards/w/WallOfCorpses.java b/Mage.Sets/src/mage/cards/w/WallOfCorpses.java index 4b4e73dbc77..5a599138777 100644 --- a/Mage.Sets/src/mage/cards/w/WallOfCorpses.java +++ b/Mage.Sets/src/mage/cards/w/WallOfCorpses.java @@ -1,27 +1,34 @@ package mage.cards.w; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.DefenderAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.BlockedByIdPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class WallOfCorpses extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("creature {this} is blocking"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.BLOCKED_BY); + } + public WallOfCorpses(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); this.subtype.add(SubType.WALL); @@ -32,14 +39,10 @@ public final class WallOfCorpses extends CardImpl { this.addAbility(DefenderAbility.getInstance()); // {B}, Sacrifice Wall of Corpses: Destroy target creature Wall of Corpses is blocking. - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature Wall of Corpses is blocking"); - filter.add(new BlockedByIdPredicate(this.getId())); - Effect effect = new DestroyTargetEffect(); - SimpleActivatedAbility ability = new SimpleActivatedAbility(effect, new ManaCostsImpl("{B}")); + Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{B}")); + ability.addTarget(new TargetPermanent(filter)); ability.addCost(new SacrificeSourceCost()); - ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); - } private WallOfCorpses(final WallOfCorpses card) { diff --git a/Mage.Sets/src/mage/cards/w/WallOfDeceit.java b/Mage.Sets/src/mage/cards/w/WallOfDeceit.java index a4df92b7685..ca619f7b956 100644 --- a/Mage.Sets/src/mage/cards/w/WallOfDeceit.java +++ b/Mage.Sets/src/mage/cards/w/WallOfDeceit.java @@ -37,7 +37,7 @@ public final class WallOfDeceit extends CardImpl { this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new WallOfDeceitEffect(), new ManaCostsImpl("{3}"))); // Morph {U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{U}"))); } private WallOfDeceit(final WallOfDeceit card) { diff --git a/Mage.Sets/src/mage/cards/w/WallOfDust.java b/Mage.Sets/src/mage/cards/w/WallOfDust.java index 5a5c40947cb..af110164e2e 100644 --- a/Mage.Sets/src/mage/cards/w/WallOfDust.java +++ b/Mage.Sets/src/mage/cards/w/WallOfDust.java @@ -3,7 +3,7 @@ package mage.cards.w; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.common.BlocksSourceTriggeredAbility; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.effects.RestrictionEffect; import mage.abilities.keyword.DefenderAbility; import mage.cards.CardImpl; @@ -32,7 +32,7 @@ public final class WallOfDust extends CardImpl { this.addAbility(DefenderAbility.getInstance()); // Whenever Wall of Dust blocks a creature, that creature can't attack during its controller's next turn. - this.addAbility(new BlocksSourceTriggeredAbility(new WallOfDustRestrictionEffect(), false, true)); + this.addAbility(new BlocksCreatureTriggeredAbility(new WallOfDustRestrictionEffect())); } private WallOfDust(final WallOfDust card) { diff --git a/Mage.Sets/src/mage/cards/w/WallOfForgottenPharaohs.java b/Mage.Sets/src/mage/cards/w/WallOfForgottenPharaohs.java index 87eebd0b6f9..08b743db0d8 100644 --- a/Mage.Sets/src/mage/cards/w/WallOfForgottenPharaohs.java +++ b/Mage.Sets/src/mage/cards/w/WallOfForgottenPharaohs.java @@ -1,13 +1,9 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; -import mage.abilities.condition.OrCondition; -import mage.abilities.condition.common.CardsInControllerGraveyardCondition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.condition.common.DesertControlledOrGraveyardCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.keyword.DefenderAbility; @@ -16,24 +12,15 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.common.FilterControlledPermanent; import mage.target.common.TargetPlayerOrPlaneswalker; +import java.util.UUID; + /** - * * @author spjspj */ public final class WallOfForgottenPharaohs extends CardImpl { - private static final FilterControlledPermanent filterDesertPermanent = new FilterControlledPermanent("Desert"); - private static final FilterCard filterDesertCard = new FilterCard("Desert card"); - - static { - filterDesertPermanent.add(SubType.DESERT.getPredicate()); - filterDesertCard.add(SubType.DESERT.getPredicate()); - } - public WallOfForgottenPharaohs(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); @@ -46,17 +33,11 @@ public final class WallOfForgottenPharaohs extends CardImpl { // {T}: Wall of Forgotten Pharaohs deals 1 damage to target player. Activate this ability only if you control a Desert or there is a Desert card in your graveyard. Ability ability = new ActivateIfConditionActivatedAbility( - Zone.BATTLEFIELD, - new DamageTargetEffect(1), - new TapSourceCost(), - new OrCondition( - "you control a Desert or there is a Desert card in your graveyard", - new PermanentsOnTheBattlefieldCondition(new FilterControlledPermanent(filterDesertPermanent)), - new CardsInControllerGraveyardCondition(1, filterDesertCard) - ) + Zone.BATTLEFIELD, new DamageTargetEffect(1), + new TapSourceCost(), DesertControlledOrGraveyardCondition.instance ); ability.addTarget(new TargetPlayerOrPlaneswalker()); - this.addAbility(ability); + this.addAbility(ability.addHint(DesertControlledOrGraveyardCondition.getHint())); } private WallOfForgottenPharaohs(final WallOfForgottenPharaohs card) { diff --git a/Mage.Sets/src/mage/cards/w/WallOfFrost.java b/Mage.Sets/src/mage/cards/w/WallOfFrost.java index df94ac34cbc..2c676efff99 100644 --- a/Mage.Sets/src/mage/cards/w/WallOfFrost.java +++ b/Mage.Sets/src/mage/cards/w/WallOfFrost.java @@ -1,9 +1,8 @@ - package mage.cards.w; import java.util.UUID; import mage.MageInt; -import mage.abilities.common.BlocksSourceTriggeredAbility; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; import mage.abilities.keyword.DefenderAbility; import mage.cards.CardImpl; @@ -27,7 +26,9 @@ public final class WallOfFrost extends CardImpl { this.addAbility(DefenderAbility.getInstance()); // Whenever Wall of Frost blocks a creature, that creature doesn't untap during its controller's next untap step. - this.addAbility(new BlocksSourceTriggeredAbility(new DontUntapInControllersNextUntapStepTargetEffect("that creature"), false, true)); + this.addAbility(new BlocksCreatureTriggeredAbility( + new DontUntapInControllersNextUntapStepTargetEffect("that creature") + )); } private WallOfFrost(final WallOfFrost card) { diff --git a/Mage.Sets/src/mage/cards/w/WallOfJunk.java b/Mage.Sets/src/mage/cards/w/WallOfJunk.java index 58d2962fd45..8142b7b8e68 100644 --- a/Mage.Sets/src/mage/cards/w/WallOfJunk.java +++ b/Mage.Sets/src/mage/cards/w/WallOfJunk.java @@ -33,7 +33,7 @@ public final class WallOfJunk extends CardImpl { Effect effect = new CreateDelayedTriggeredAbilityEffect( new AtTheEndOfCombatDelayedTriggeredAbility(new ReturnToHandSourceEffect(true))); effect.setText("return it to its owner's hand at end of combat"); - this.addAbility(new BlocksSourceTriggeredAbility(effect, false, false, true)); + this.addAbility(new BlocksSourceTriggeredAbility(effect).setTriggerPhrase("When {this} blocks, ")); } private WallOfJunk(final WallOfJunk card) { diff --git a/Mage.Sets/src/mage/cards/w/WallOfMulch.java b/Mage.Sets/src/mage/cards/w/WallOfMulch.java index 76907a4ad5c..c9f999c3443 100644 --- a/Mage.Sets/src/mage/cards/w/WallOfMulch.java +++ b/Mage.Sets/src/mage/cards/w/WallOfMulch.java @@ -41,7 +41,7 @@ public final class WallOfMulch extends CardImpl { // Defender this.addAbility(DefenderAbility.getInstance()); // {G}, Sacrifice a Wall: Draw a card. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl("G")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{G}")); ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/w/WallOfNets.java b/Mage.Sets/src/mage/cards/w/WallOfNets.java index ddc5a01be73..3a96cd905bb 100644 --- a/Mage.Sets/src/mage/cards/w/WallOfNets.java +++ b/Mage.Sets/src/mage/cards/w/WallOfNets.java @@ -11,8 +11,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.BlockedByIdPredicate; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; import java.util.UUID; @@ -21,6 +22,12 @@ import java.util.UUID; */ public final class WallOfNets extends CardImpl { + private static final FilterPermanent filter = new FilterCreaturePermanent("creatures blocked by {this}"); + + static { + filter.add(BlockingOrBlockedBySourcePredicate.BLOCKED_BY); + } + public WallOfNets(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); this.subtype.add(SubType.WALL); @@ -31,12 +38,15 @@ public final class WallOfNets extends CardImpl { this.addAbility(DefenderAbility.getInstance()); // At end of combat, exile all creatures blocked by Wall of Nets. - FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures blocked by {this}"); - filter.add(new BlockedByIdPredicate(this.getId())); - this.addAbility(new EndOfCombatTriggeredAbility(new ExileAllEffect(filter, true), false)); + this.addAbility(new EndOfCombatTriggeredAbility( + new ExileAllEffect(filter, true), false + )); // When Wall of Nets leaves the battlefield, return all cards exiled with Wall of Nets to the battlefield under their owners' control. - this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileEffect(Zone.BATTLEFIELD, "return all cards exiled with {this} to the battlefield under their owners' control"), false)); + this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileEffect( + Zone.BATTLEFIELD, "return all cards exiled with {this} " + + "to the battlefield under their owners' control" + ), false)); } private WallOfNets(final WallOfNets card) { diff --git a/Mage.Sets/src/mage/cards/w/WallOfSouls.java b/Mage.Sets/src/mage/cards/w/WallOfSouls.java index 4004cbc40f2..1df5ee113c9 100644 --- a/Mage.Sets/src/mage/cards/w/WallOfSouls.java +++ b/Mage.Sets/src/mage/cards/w/WallOfSouls.java @@ -1,17 +1,16 @@ - package mage.cards.w; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.keyword.DefenderAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.game.events.DamagedEvent; @@ -33,7 +32,7 @@ public final class WallOfSouls extends CardImpl { // Defender this.addAbility(DefenderAbility.getInstance()); - // Whenever Wall of Souls is dealt combat damage, it deals that much damage to target opponent. + // Whenever Wall of Souls is dealt combat damage, it deals that much damage to target opponent or planeswalker. Ability ability = new WallOfSoulsTriggeredAbility(); ability.addTarget(new TargetOpponentOrPlaneswalker()); this.addAbility(ability); @@ -52,7 +51,7 @@ public final class WallOfSouls extends CardImpl { class WallOfSoulsTriggeredAbility extends TriggeredAbilityImpl { public WallOfSoulsTriggeredAbility() { - super(Zone.BATTLEFIELD, new WallOfSoulsDealDamageEffect()); + super(Zone.BATTLEFIELD, new DamageTargetEffect(SavedDamageValue.MUCH, "it")); } public WallOfSoulsTriggeredAbility(final WallOfSoulsTriggeredAbility effect) { @@ -72,7 +71,7 @@ class WallOfSoulsTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getTargetId().equals(this.sourceId) && ((DamagedEvent) event).isCombatDamage()) { - this.getEffects().get(0).setValue("damage", event.getAmount()); + this.getEffects().setValue("damage", event.getAmount()); return true; } return false; @@ -83,29 +82,3 @@ class WallOfSoulsTriggeredAbility extends TriggeredAbilityImpl { return "Whenever {this} is dealt combat damage, " ; } } - -class WallOfSoulsDealDamageEffect extends OneShotEffect { - - public WallOfSoulsDealDamageEffect() { - super(Outcome.Damage); - this.staticText = "it deals that much damage to target opponent or planeswalker"; - } - - public WallOfSoulsDealDamageEffect(final WallOfSoulsDealDamageEffect effect) { - super(effect); - } - - @Override - public WallOfSoulsDealDamageEffect copy() { - return new WallOfSoulsDealDamageEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - int amount = (Integer) getValue("damage"); - if (amount > 0) { - return game.damagePlayerOrPlaneswalker(source.getFirstTarget(), amount, source.getSourceId(), source, game, false, true) > 0; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/w/WallOfStolenIdentity.java b/Mage.Sets/src/mage/cards/w/WallOfStolenIdentity.java index fb50a9c4fc2..f2604e1d4a3 100644 --- a/Mage.Sets/src/mage/cards/w/WallOfStolenIdentity.java +++ b/Mage.Sets/src/mage/cards/w/WallOfStolenIdentity.java @@ -94,10 +94,10 @@ class WallOfStolenIdentityCopyEffect extends OneShotEffect { target.setRequired(false); target.setNotTarget(true); } - if (!target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (!target.canChoose(source.getControllerId(), source, game)) { return false; } - controller.choose(Outcome.Copy, target, source.getSourceId(), game); + controller.choose(Outcome.Copy, target, source, game); Permanent copyFromPermanent = game.getPermanent(target.getFirstTarget()); if (copyFromPermanent == null) { return false; diff --git a/Mage.Sets/src/mage/cards/w/WallOfTears.java b/Mage.Sets/src/mage/cards/w/WallOfTears.java index 71be945367d..c2424a1260e 100644 --- a/Mage.Sets/src/mage/cards/w/WallOfTears.java +++ b/Mage.Sets/src/mage/cards/w/WallOfTears.java @@ -1,11 +1,9 @@ - package mage.cards.w; import java.util.UUID; import mage.MageInt; -import mage.abilities.common.BlocksSourceTriggeredAbility; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.keyword.DefenderAbility; @@ -30,9 +28,11 @@ public final class WallOfTears extends CardImpl { this.addAbility(DefenderAbility.getInstance()); // Whenever Wall of Tears blocks a creature, return that creature to its owner's hand at end of combat. - Effect effect = new ReturnToHandTargetEffect(); - effect.setText("return that creature to its owner's hand at end of combat"); - this.addAbility(new BlocksSourceTriggeredAbility(new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(effect)), false, true)); + this.addAbility(new BlocksCreatureTriggeredAbility( + new CreateDelayedTriggeredAbilityEffect( + new AtTheEndOfCombatDelayedTriggeredAbility(new ReturnToHandTargetEffect()) + ).setText("return that creature to its owner's hand at end of combat") + )); } private WallOfTears(final WallOfTears card) { diff --git a/Mage.Sets/src/mage/cards/w/WallOfVipers.java b/Mage.Sets/src/mage/cards/w/WallOfVipers.java index a3c3016fc4b..b82b64302e7 100644 --- a/Mage.Sets/src/mage/cards/w/WallOfVipers.java +++ b/Mage.Sets/src/mage/cards/w/WallOfVipers.java @@ -3,6 +3,7 @@ package mage.cards.w; import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DestroySourceEffect; @@ -72,11 +73,11 @@ class WallOfVipersFilter extends FilterCreaturePermanent { } @Override - public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { - if (super.match(permanent, sourceId, playerId, game)) { - SubType subtype = (SubType) game.getState().getValue(sourceId + "_type"); + public boolean match(Permanent permanent, UUID playerId, Ability source, Game game) { + if (super.match(permanent, playerId, source, game)) { + SubType subtype = (SubType) game.getState().getValue(source.getSourceId() + "_type"); for (CombatGroup combatGroup : game.getCombat().getGroups()) { - if (combatGroup.getBlockers().contains(sourceId) && combatGroup.getAttackers().contains(permanent.getId())) { + if (combatGroup.getBlockers().contains(source.getSourceId()) && combatGroup.getAttackers().contains(permanent.getId())) { return true; } } diff --git a/Mage.Sets/src/mage/cards/w/WandOfDenial.java b/Mage.Sets/src/mage/cards/w/WandOfDenial.java index 525da0ebd20..2e59b5fd9fe 100644 --- a/Mage.Sets/src/mage/cards/w/WandOfDenial.java +++ b/Mage.Sets/src/mage/cards/w/WandOfDenial.java @@ -66,7 +66,7 @@ class WandOfDenialEffect extends OneShotEffect { if (controller != null && targetPlayer != null) { Card card = targetPlayer.getLibrary().getFromTop(game); if (card != null) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); controller.lookAtCards(sourceObject != null ? sourceObject.getName() : "", new CardsImpl(card), game); if (!card.isLand(game) && controller.canPayLifeCost(source) diff --git a/Mage.Sets/src/mage/cards/w/WandOfOrcus.java b/Mage.Sets/src/mage/cards/w/WandOfOrcus.java index bee72fa4680..5acbb587e78 100644 --- a/Mage.Sets/src/mage/cards/w/WandOfOrcus.java +++ b/Mage.Sets/src/mage/cards/w/WandOfOrcus.java @@ -3,8 +3,9 @@ package mage.cards.w; import mage.abilities.Ability; import mage.abilities.common.AttacksOrBlocksAttachedTriggeredAbility; import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.common.SavedDamageValue; +import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.DeathtouchAbility; @@ -13,7 +14,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterPermanent; -import mage.game.Game; import mage.game.permanent.token.ZombieToken; import java.util.UUID; @@ -44,9 +44,9 @@ public final class WandOfOrcus extends CardImpl { // Whenever equipped creature deals combat damage to a player, create that many // 2/2 black Zombie creature tokens. this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility( - new WandOfOrcusZombieEffect(), "equipped creature", - false, true - )); + new CreateTokenEffect(new ZombieToken(), SavedDamageValue.MANY), + "equipped creature", + false)); // Equip {3} this.addAbility(new EquipAbility(3, false)); @@ -61,29 +61,3 @@ public final class WandOfOrcus extends CardImpl { return new WandOfOrcus(this); } } - -class WandOfOrcusZombieEffect extends OneShotEffect { - - public WandOfOrcusZombieEffect() { - super(Outcome.Benefit); - this.staticText = "create that many 2/2 black Zombie creature tokens"; - } - - public WandOfOrcusZombieEffect(final WandOfOrcusZombieEffect effect) { - super(effect); - } - - @Override - public WandOfOrcusZombieEffect copy() { - return new WandOfOrcusZombieEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Integer damage = (Integer) this.getValue("damage"); - if (damage != null) { - return new ZombieToken().putOntoBattlefield(damage, game, source, source.getControllerId()); - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/w/WandOfWonder.java b/Mage.Sets/src/mage/cards/w/WandOfWonder.java new file mode 100644 index 00000000000..724c445a445 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WandOfWonder.java @@ -0,0 +1,115 @@ +package mage.cards.w; + +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.OneShotEffect; +import mage.abilities.effects.common.RollDieWithResultTableEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WandOfWonder extends CardImpl { + + public WandOfWonder(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}{R}"); + + // {4}, {T}: Roll a d20. Each opponent exiles cards from the top of their library until they exile an instant or sorcery card, then shuffles the rest into their library. You may cast up to X instant and/or sorcery spells from among cards exiled this way without paying their mana costs. + RollDieWithResultTableEffect effect = new RollDieWithResultTableEffect( + 20, "roll a d20. Each opponent exiles cards from the top of their library " + + "until they exile an instant or sorcery card, then shuffles the rest into their library. " + + "You may cast up to X instant and/or sorcery spells from among cards exiled this way " + + "without paying their mana costs" + ); + + // 1-9 | X is one + effect.addTableEntry(1, 9, new WandOfWonderEffect(1)); + + // 10-19 | X is two. + effect.addTableEntry(10, 19, new WandOfWonderEffect(2)); + + // 20 | X is three. + effect.addTableEntry(20, 20, new WandOfWonderEffect(3)); + + Ability ability = new SimpleActivatedAbility(effect, new GenericManaCost(4)); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private WandOfWonder(final WandOfWonder card) { + super(card); + } + + @Override + public WandOfWonder copy() { + return new WandOfWonder(this); + } +} + +class WandOfWonderEffect extends OneShotEffect { + + private final int xValue; + + WandOfWonderEffect(int xValue) { + super(Outcome.Benefit); + staticText = "X is " + CardUtil.numberToText(xValue); + this.xValue = xValue; + } + + private WandOfWonderEffect(final WandOfWonderEffect effect) { + super(effect); + this.xValue = effect.xValue; + } + + @Override + public WandOfWonderEffect copy() { + return new WandOfWonderEffect(this); + } + + // {4}, {T}: Roll a d20. Each opponent exiles cards from the top of their library until + // they exile an instant or sorcery card, then shuffles the rest into their library. + // You may cast up to X instant and/or sorcery spells from among cards exiled this way without paying their mana costs. + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Cards cards = new CardsImpl(); + Cards toCast = new CardsImpl(); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player opponent = game.getPlayer(playerId); + if (opponent == null) { + continue; + } + for (Card card : opponent.getLibrary().getCards(game)) { + opponent.moveCards(card, Zone.EXILED, source, game); + if (card.isInstantOrSorcery(game)) { + toCast.add(card); + break; + } else { + cards.add(card); + } + } + opponent.putCardsOnBottomOfLibrary(cards, game, source, false); + opponent.shuffleLibrary(source, game); + cards.clear(); + } + CardUtil.castMultipleWithAttributeForFree( + controller, source, game, toCast, + StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, xValue + ); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/w/WanderingGoblins.java b/Mage.Sets/src/mage/cards/w/WanderingGoblins.java index 836158673e3..a14d6b8a04e 100644 --- a/Mage.Sets/src/mage/cards/w/WanderingGoblins.java +++ b/Mage.Sets/src/mage/cards/w/WanderingGoblins.java @@ -1,7 +1,5 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.GenericManaCost; @@ -11,19 +9,20 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.hint.common.DomainHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author Loki */ public final class WanderingGoblins extends CardImpl { public WanderingGoblins(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.WARRIOR); @@ -31,7 +30,9 @@ public final class WanderingGoblins extends CardImpl { this.toughness = new MageInt(3); // Domain - {3}: Wandering Goblins gets +1/+0 until end of turn for each basic land type among lands you control. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(new DomainValue(), StaticValue.get(0), Duration.EndOfTurn, true), new GenericManaCost(3)).addHint(DomainHint.instance)); + this.addAbility(new SimpleActivatedAbility(new BoostSourceEffect( + DomainValue.REGULAR, StaticValue.get(0), Duration.EndOfTurn, true + ), new GenericManaCost(3)).addHint(DomainHint.instance).setAbilityWord(AbilityWord.DOMAIN)); } private WanderingGoblins(final WanderingGoblins card) { diff --git a/Mage.Sets/src/mage/cards/w/WanderingMind.java b/Mage.Sets/src/mage/cards/w/WanderingMind.java index a1eb906b85d..bea533fceaf 100644 --- a/Mage.Sets/src/mage/cards/w/WanderingMind.java +++ b/Mage.Sets/src/mage/cards/w/WanderingMind.java @@ -2,14 +2,13 @@ package mage.cards.w; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterNonlandCard; import mage.filter.predicate.Predicates; @@ -21,7 +20,7 @@ import java.util.UUID; */ public final class WanderingMind extends CardImpl { - private static final FilterCard filter = new FilterNonlandCard("noncreature, nonland card"); + private static final FilterCard filter = new FilterNonlandCard("a noncreature, nonland card"); static { filter.add(Predicates.not(CardType.CREATURE.getPredicate())); @@ -38,12 +37,8 @@ public final class WanderingMind extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Wandering Mind enters the battlefield, look at the top six cards of your library. You may reveal a noncreature, nonland card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. - this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(6), false, StaticValue.get(1), filter, Zone.LIBRARY, false, - true, false, Zone.HAND, true, false, false - ).setBackInRandomOrder(true).setText("look at the top six cards of your library. " + - "You may reveal a noncreature, nonland card from among them and put it into your hand. " + - "Put the rest on the bottom of your library in a random order"))); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new LookLibraryAndPickControllerEffect(6, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM))); } private WanderingMind(final WanderingMind card) { diff --git a/Mage.Sets/src/mage/cards/w/WanderingStream.java b/Mage.Sets/src/mage/cards/w/WanderingStream.java index c876fde2158..92f797f0c92 100644 --- a/Mage.Sets/src/mage/cards/w/WanderingStream.java +++ b/Mage.Sets/src/mage/cards/w/WanderingStream.java @@ -21,7 +21,7 @@ public final class WanderingStream extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{G}"); // Domain - You gain 2 life for each basic land type among lands you control. - Effect effect = new GainLifeEffect(new MultipliedValue(new DomainValue(), 2)); + Effect effect = new GainLifeEffect(new MultipliedValue(DomainValue.REGULAR, 2)); effect.setText("Domain — You gain 2 life for each basic land type among lands you control"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addHint(DomainHint.instance); diff --git a/Mage.Sets/src/mage/cards/w/WanderwineProphets.java b/Mage.Sets/src/mage/cards/w/WanderwineProphets.java index 7ef1432adf4..ed1ab990f6e 100644 --- a/Mage.Sets/src/mage/cards/w/WanderwineProphets.java +++ b/Mage.Sets/src/mage/cards/w/WanderwineProphets.java @@ -35,7 +35,7 @@ public final class WanderwineProphets extends CardImpl { this.toughness = new MageInt(4); // Champion a Merfolk - this.addAbility(new ChampionAbility(this, SubType.MERFOLK, false)); + this.addAbility(new ChampionAbility(this, SubType.MERFOLK)); // Whenever Wanderwine Prophets deals combat damage to a player, you may sacrifice a Merfolk. If you do, take an extra turn after this one. Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DoIfCostPaid( new AddExtraTurnControllerEffect(), diff --git a/Mage.Sets/src/mage/cards/w/WarBehemoth.java b/Mage.Sets/src/mage/cards/w/WarBehemoth.java index 3ec49a16dee..c2f8422e56a 100644 --- a/Mage.Sets/src/mage/cards/w/WarBehemoth.java +++ b/Mage.Sets/src/mage/cards/w/WarBehemoth.java @@ -24,7 +24,7 @@ public final class WarBehemoth extends CardImpl { this.toughness = new MageInt(6); // Morph {4}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{W}"))); } private WarBehemoth(final WarBehemoth card) { diff --git a/Mage.Sets/src/mage/cards/w/WarReport.java b/Mage.Sets/src/mage/cards/w/WarReport.java index 1517fc408a3..d876bdf850f 100644 --- a/Mage.Sets/src/mage/cards/w/WarReport.java +++ b/Mage.Sets/src/mage/cards/w/WarReport.java @@ -55,8 +55,8 @@ class WarReportEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - int lifeToGain = game.getBattlefield().count(StaticFilters.FILTER_PERMANENT_CREATURE, source.getSourceId(), source.getControllerId(), game); - lifeToGain += game.getBattlefield().count(new FilterArtifactPermanent(), source.getSourceId(), source.getControllerId(), game); + int lifeToGain = game.getBattlefield().count(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game); + lifeToGain += game.getBattlefield().count(new FilterArtifactPermanent(), source.getControllerId(), source, game); player.gainLife(lifeToGain, game, source); } return true; diff --git a/Mage.Sets/src/mage/cards/w/WarbreakTrumpeter.java b/Mage.Sets/src/mage/cards/w/WarbreakTrumpeter.java index 9294633e3ab..5ce640adae1 100644 --- a/Mage.Sets/src/mage/cards/w/WarbreakTrumpeter.java +++ b/Mage.Sets/src/mage/cards/w/WarbreakTrumpeter.java @@ -28,7 +28,7 @@ public final class WarbreakTrumpeter extends CardImpl { this.toughness = new MageInt(1); // Morph {X}{X}{R} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{X}{X}{R}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{X}{X}{R}"))); // When Warbreak Trumpeter is turned face up, create X 1/1 red Goblin creature tokens. DynamicValue morphX = MorphManacostVariableValue.instance; diff --git a/Mage.Sets/src/mage/cards/w/Warbringer.java b/Mage.Sets/src/mage/cards/w/Warbringer.java index 72002ebaf8f..d4690bc3ffa 100644 --- a/Mage.Sets/src/mage/cards/w/Warbringer.java +++ b/Mage.Sets/src/mage/cards/w/Warbringer.java @@ -1,7 +1,5 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.SpellAbility; @@ -9,35 +7,32 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.DashedCondition; import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.abilities.keyword.DashAbility; +import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.CostModificationType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Warbringer extends CardImpl { public Warbringer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.subtype.add(SubType.ORC); this.subtype.add(SubType.BERSERKER); this.power = new MageInt(3); this.toughness = new MageInt(3); // Dash costs you pay cost {2} less (as long as this creature is on the battlefield). - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new WarbringerSpellsCostReductionEffect())); + this.addAbility(new SimpleStaticAbility(new WarbringerSpellsCostReductionEffect())); // Dash {2}{R} - this.addAbility(new DashAbility(this, "{2}{R}")); + this.addAbility(new DashAbility("{2}{R}")); } private Warbringer(final Warbringer card) { @@ -54,7 +49,7 @@ class WarbringerSpellsCostReductionEffect extends CostModificationEffectImpl { public WarbringerSpellsCostReductionEffect() { super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); - this.staticText = "Dash costs you pay cost {2} less (as long as this creature is on the battlefield)"; + this.staticText = "Dash costs you pay cost {2} less (as long as this creature is on the battlefield)"; } protected WarbringerSpellsCostReductionEffect(final WarbringerSpellsCostReductionEffect effect) { @@ -69,12 +64,15 @@ class WarbringerSpellsCostReductionEffect extends CostModificationEffectImpl { @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof SpellAbility) { - if (abilityToModify.isControlledBy(source.getControllerId())) { - return DashedCondition.instance.apply(game, abilityToModify); - } + if (!(abilityToModify instanceof SpellAbility) + || !abilityToModify.isControlledBy(source.getControllerId())) { + return false; } - return false; + if (game == null || !game.inCheckPlayableState()) { + return DashedCondition.instance.apply(game, abilityToModify); + } + Card card = game.getCard(source.getSourceId()); + return card != null && card.getAbilities(game).stream().anyMatch(DashAbility.class::isInstance); } @Override diff --git a/Mage.Sets/src/mage/cards/w/WarchanterOfMogis.java b/Mage.Sets/src/mage/cards/w/WarchanterOfMogis.java index d369a8a8d7d..db87371f9c0 100644 --- a/Mage.Sets/src/mage/cards/w/WarchanterOfMogis.java +++ b/Mage.Sets/src/mage/cards/w/WarchanterOfMogis.java @@ -1,9 +1,9 @@ - package mage.cards.w; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.InspiredAbility; import mage.abilities.keyword.IntimidateAbility; @@ -29,7 +29,9 @@ public final class WarchanterOfMogis extends CardImpl { this.toughness = new MageInt(3); // Inspired — Whenever Warchanter of Mogis becomes untapped, target creature you control gains intimidate until end of turn. - Ability ability = new InspiredAbility(new GainAbilityTargetEffect(IntimidateAbility.getInstance(), Duration.EndOfTurn), false); + Effect effect = new GainAbilityTargetEffect(IntimidateAbility.getInstance(), Duration.EndOfTurn); + effect.setText("target creature you control gains intimidate until end of turn. (A creature with intimidate can't be blocked except by artifact creatures and/or creatures that share a color with it.)"); + Ability ability = new InspiredAbility(effect); ability.addTarget(new TargetControlledCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WardOfBones.java b/Mage.Sets/src/mage/cards/w/WardOfBones.java index 5b7ce8d7744..71b3050d7ef 100644 --- a/Mage.Sets/src/mage/cards/w/WardOfBones.java +++ b/Mage.Sets/src/mage/cards/w/WardOfBones.java @@ -71,7 +71,7 @@ class WardOfBonesEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't play the land or cast the spell (" + mageObject.getLogName() + " in play)."; } diff --git a/Mage.Sets/src/mage/cards/w/WardSliver.java b/Mage.Sets/src/mage/cards/w/WardSliver.java index a0417bcf7af..a4d02eb8fed 100644 --- a/Mage.Sets/src/mage/cards/w/WardSliver.java +++ b/Mage.Sets/src/mage/cards/w/WardSliver.java @@ -14,6 +14,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; @@ -56,17 +57,11 @@ public final class WardSliver extends CardImpl { class WardSliverGainAbilityControlledEffect extends ContinuousEffectImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Slivers"); - - static { - filter.add(SubType.SLIVER.getPredicate()); - } - protected FilterPermanent protectionFilter; public WardSliverGainAbilityControlledEffect() { super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); - staticText = "Slivers have protection from the chosen color"; + staticText = "all Slivers have protection from the chosen color"; } public WardSliverGainAbilityControlledEffect(final WardSliverGainAbilityControlledEffect effect) { @@ -92,7 +87,7 @@ class WardSliverGainAbilityControlledEffect extends ContinuousEffectImpl { } } if (protectionFilter != null) { - for (Permanent perm: game.getBattlefield().getAllActivePermanents(filter, game)) { + for (Permanent perm: game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_ALL_SLIVERS, game)) { perm.addAbility(new ProtectionAbility(protectionFilter), source.getSourceId(), game); } return true; diff --git a/Mage.Sets/src/mage/cards/w/WardenOfTheWoods.java b/Mage.Sets/src/mage/cards/w/WardenOfTheWoods.java index 4091621422b..001903736c0 100644 --- a/Mage.Sets/src/mage/cards/w/WardenOfTheWoods.java +++ b/Mage.Sets/src/mage/cards/w/WardenOfTheWoods.java @@ -33,8 +33,7 @@ public final class WardenOfTheWoods extends CardImpl { new DrawCardSourceControllerEffect(2), StaticFilters.FILTER_SPELL_OR_ABILITY_OPPONENTS, SetTargetPointer.NONE, true - )); - + ).setTriggerPhrase("Whenever {this} becomes the target of a spell or ability an opponent controls, ")); } private WardenOfTheWoods(final WardenOfTheWoods card) { diff --git a/Mage.Sets/src/mage/cards/w/WarlockClass.java b/Mage.Sets/src/mage/cards/w/WarlockClass.java index 8b325b0cf87..a4e89a1e33d 100644 --- a/Mage.Sets/src/mage/cards/w/WarlockClass.java +++ b/Mage.Sets/src/mage/cards/w/WarlockClass.java @@ -6,9 +6,9 @@ import mage.abilities.common.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.MorbidCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.effects.common.continuous.GainClassAbilitySourceEffect; import mage.abilities.hint.common.MorbidHint; @@ -17,7 +17,6 @@ import mage.abilities.keyword.ClassReminderAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.watchers.common.PlayerLostLifeWatcher; @@ -49,10 +48,8 @@ public final class WarlockClass extends CardImpl { this.addAbility(new ClassLevelAbility(2, "{1}{B}")); // When this Class becomes level 2, look at the top three cards of your library. Put one of them into your hand and the rest into your graveyard. - this.addAbility(new BecomesClassLevelTriggeredAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(3), false, StaticValue.get(1), StaticFilters.FILTER_CARD, - Zone.GRAVEYARD, false, false, false, Zone.HAND, false - ), 2)); + this.addAbility(new BecomesClassLevelTriggeredAbility( + new LookLibraryAndPickControllerEffect(3, 1, PutCards.HAND, PutCards.GRAVEYARD), 2)); // {6}{B}: Level 3 this.addAbility(new ClassLevelAbility(3, "{6}{B}")); diff --git a/Mage.Sets/src/mage/cards/w/WarmWelcome.java b/Mage.Sets/src/mage/cards/w/WarmWelcome.java new file mode 100644 index 00000000000..7627fdd79f4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WarmWelcome.java @@ -0,0 +1,40 @@ +package mage.cards.w; + +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.CitizenGreenWhiteToken; + +import java.util.UUID; + +/** + * @author awjackson + */ +public final class WarmWelcome extends CardImpl { + + public WarmWelcome(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); + + // Look at the top five cards of your library. + // You may reveal a creature card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + 5, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_RANDOM)); + + // Create a 1/1 green and white Citizen creature token. + this.getSpellAbility().addEffect(new CreateTokenEffect(new CitizenGreenWhiteToken())); + } + + private WarmWelcome(final WarmWelcome card) { + super(card); + } + + @Override + public WarmWelcome copy() { + return new WarmWelcome(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WarmongerHellkite.java b/Mage.Sets/src/mage/cards/w/WarmongerHellkite.java index 87cc9ce01d9..a29a363f0a0 100644 --- a/Mage.Sets/src/mage/cards/w/WarmongerHellkite.java +++ b/Mage.Sets/src/mage/cards/w/WarmongerHellkite.java @@ -33,7 +33,7 @@ public final class WarmongerHellkite extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // All creatures attack each combat if able. - this.addAbility(new SimpleStaticAbility(new AttacksIfAbleAllEffect(StaticFilters.FILTER_PERMANENT_ALL_CREATURES, Duration.WhileOnBattlefield, true))); + this.addAbility(new SimpleStaticAbility(new AttacksIfAbleAllEffect(StaticFilters.FILTER_PERMANENT_ALL_CREATURES))); // {1}{R}: Attacking creatures get +1/+0 until end of turn. this.addAbility(new SimpleActivatedAbility(new BoostAllEffect(1, 0, Duration.EndOfTurn, StaticFilters.FILTER_ATTACKING_CREATURES, false), new ManaCostsImpl("{1}{R}"))); diff --git a/Mage.Sets/src/mage/cards/w/WarpingWail.java b/Mage.Sets/src/mage/cards/w/WarpingWail.java index 669257bc7e2..c11b0014321 100644 --- a/Mage.Sets/src/mage/cards/w/WarpingWail.java +++ b/Mage.Sets/src/mage/cards/w/WarpingWail.java @@ -46,17 +46,14 @@ public final class WarpingWail extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterCreature)); // Counter target sorcery spell. - Mode mode = new Mode(); - mode.addEffect(new CounterTargetEffect()); + Mode mode = new Mode(new CounterTargetEffect()); mode.addTarget(new TargetSpell(filterSorcery)); this.getSpellAbility().addMode(mode); // Create a 1/1 colorless Eldrazi Scion creature token. It has "Sacrifice this creature: Add {C}." - mode = new Mode(); effect = new CreateTokenEffect(new EldraziScionToken()); effect.setText("Create a 1/1 colorless Eldrazi Scion creature token. It has \"Sacrifice this creature: Add {C}.\""); - mode.addEffect(effect); - this.getSpellAbility().addMode(mode); + this.getSpellAbility().addMode(new Mode(effect)); } private WarpingWail(final WarpingWail card) { diff --git a/Mage.Sets/src/mage/cards/w/WarrenWeirding.java b/Mage.Sets/src/mage/cards/w/WarrenWeirding.java index aa88e6a54eb..c88181b0845 100644 --- a/Mage.Sets/src/mage/cards/w/WarrenWeirding.java +++ b/Mage.Sets/src/mage/cards/w/WarrenWeirding.java @@ -1,13 +1,7 @@ - package mage.cards.w; -import java.util.UUID; - import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateTokenTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; @@ -16,17 +10,18 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SubType; -import mage.filter.common.FilterControlledPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.GoblinRogueToken; import mage.game.permanent.token.Token; import mage.players.Player; +import mage.target.TargetPermanent; import mage.target.TargetPlayer; -import mage.target.common.TargetControlledPermanent; -import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.FixedTargets; + +import java.util.UUID; /** * @author LevelX2 @@ -37,7 +32,6 @@ public final class WarrenWeirding extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.TRIBAL, CardType.SORCERY}, "{1}{B}"); this.subtype.add(SubType.GOBLIN); - // Target player sacrifices a creature. If a Goblin is sacrificed this way, that player creates two 1/1 black Goblin Rogue creature tokens, and those tokens gain haste until end of turn. this.getSpellAbility().addEffect(new WarrenWeirdingEffect()); this.getSpellAbility().addTarget(new TargetPlayer()); @@ -63,7 +57,8 @@ class WarrenWeirdingEffect extends OneShotEffect { WarrenWeirdingEffect() { super(Outcome.Sacrifice); - staticText = "Target player sacrifices a creature. If a Goblin is sacrificed this way, that player creates two 1/1 black Goblin Rogue creature tokens, and those tokens gain haste until end of turn"; + staticText = "Target player sacrifices a creature. If a Goblin is sacrificed this way, that player " + + "creates two 1/1 black Goblin Rogue creature tokens, and those tokens gain haste until end of turn"; } WarrenWeirdingEffect(WarrenWeirdingEffect effect) { @@ -73,45 +68,30 @@ class WarrenWeirdingEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (player == null) { + if (player == null || game.getBattlefield().count( + StaticFilters.FILTER_CONTROLLED_CREATURE, player.getId(), source, game + ) < 1) { return false; } - FilterControlledPermanent filter = new FilterControlledPermanent("creature"); - filter.add(CardType.CREATURE.getPredicate()); - filter.add(new ControllerIdPredicate(player.getId())); - TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); - - //A spell or ability could have removed the only legal target this player - //had, if thats the case this ability should fizzle. - if (target.canChoose(source.getSourceId(), player.getId(), game)) { - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); - Permanent permanent = game.getPermanent(target.getFirstTarget()); - if (permanent != null) { - permanent.sacrifice(source, game); - if (filterGoblin.match(permanent, game)) { - for (int i = 0; i < 2; i++) { - Token token = new GoblinRogueToken(); - Effect effect = new CreateTokenTargetEffect(token); - effect.setTargetPointer(new FixedTarget(player.getId())); - if (effect.apply(game, source)) { - Permanent tokenPermanent = game.getPermanent(token.getLastAddedToken()); - if (tokenPermanent != null) { - ContinuousEffect hasteEffect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); - hasteEffect.setTargetPointer(new FixedTarget(tokenPermanent.getId())); - game.addEffect(hasteEffect, source); - } - } - } - } - } - return true; + TargetPermanent target = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_CREATURE); + target.setNotTarget(true); + player.choose(outcome, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null || !permanent.sacrifice(source, game)) { + return false; } - return false; + if (permanent.hasSubtype(SubType.GOBLIN, game)) { + Token token = new GoblinRogueToken(); + token.putOntoBattlefield(2, game, source, player.getId()); + game.addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setTargetPointer(new FixedTargets(token, game)), source); + } + return true; } @Override public WarrenWeirdingEffect copy() { return new WarrenWeirdingEffect(this); } - } diff --git a/Mage.Sets/src/mage/cards/w/WashOut.java b/Mage.Sets/src/mage/cards/w/WashOut.java index de7251549bd..b0a3261c9da 100644 --- a/Mage.Sets/src/mage/cards/w/WashOut.java +++ b/Mage.Sets/src/mage/cards/w/WashOut.java @@ -63,7 +63,7 @@ class WashOutEffect extends OneShotEffect { ObjectColor color = choice.getColor(); FilterPermanent filter = new FilterPermanent(); filter.add(new ColorPredicate(color)); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { cardsToReturn.add((Card) permanent); } return controller.moveCards(cardsToReturn, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/w/WasitoraNekoruQueen.java b/Mage.Sets/src/mage/cards/w/WasitoraNekoruQueen.java index f0ec664b390..c6ea65345fd 100644 --- a/Mage.Sets/src/mage/cards/w/WasitoraNekoruQueen.java +++ b/Mage.Sets/src/mage/cards/w/WasitoraNekoruQueen.java @@ -81,7 +81,7 @@ class WasitoraNekoruQueenEffect extends OneShotEffect { FilterControlledPermanent filter = new FilterControlledPermanent("creature"); filter.add(CardType.CREATURE.getPredicate()); TargetPermanent target = new TargetPermanent(1, 1, filter, true); - if (damagedPlayer.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) { + if (damagedPlayer.choose(Outcome.Sacrifice, target, source, game)) { Permanent objectToBeSacrificed = game.getPermanent(target.getFirstTarget()); if (objectToBeSacrificed != null) { if (objectToBeSacrificed.sacrifice(source, game)) { diff --git a/Mage.Sets/src/mage/cards/w/WasteManagement.java b/Mage.Sets/src/mage/cards/w/WasteManagement.java new file mode 100644 index 00000000000..87cb8b3c610 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WasteManagement.java @@ -0,0 +1,108 @@ +package mage.cards.w; + +import mage.abilities.Ability; +import mage.abilities.condition.common.KickedCondition; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.KickerAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.token.RogueToken; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInASingleGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WasteManagement extends CardImpl { + + public WasteManagement(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); + + // Kicker {3}{B} + this.addAbility(new KickerAbility("{3}{B}")); + + // Exile up to two target cards from a single graveyard. If this spell was kicked, instead exile target player's graveyard. Create a 2/2 black Rogue creature token for each creature card exiled this way. + this.getSpellAbility().addEffect(new WasteManagementEffect()); + this.getSpellAbility().setTargetAdjuster(WasteManagementAdjuster.instance); + } + + private WasteManagement(final WasteManagement card) { + super(card); + } + + @Override + public WasteManagement copy() { + return new WasteManagement(this); + } +} + +enum WasteManagementAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + if (KickedCondition.instance.apply(game, ability)) { + ability.addTarget(new TargetPlayer()); + } else { + ability.addTarget(new TargetCardInASingleGraveyard(0, 2, StaticFilters.FILTER_CARD)); + } + } +} + +class WasteManagementEffect extends OneShotEffect { + + WasteManagementEffect() { + super(Outcome.Benefit); + staticText = "exile up to two target cards from a single graveyard. " + + "If this spell was kicked, instead exile target player's graveyard. " + + "Create a 2/2 black Rogue creature token for each creature card exiled this way"; + } + + private WasteManagementEffect(final WasteManagementEffect effect) { + super(effect); + } + + @Override + public WasteManagementEffect copy() { + return new WasteManagementEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Cards cards = new CardsImpl(); + if (KickedCondition.instance.apply(game, source)) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (player != null) { + cards.addAll(player.getGraveyard()); + } + } else { + cards.addAll(getTargetPointer().getTargets(game, source)); + } + if (cards.isEmpty()) { + return false; + } + controller.moveCards(cards, Zone.EXILED, source, game); + cards.retainZone(Zone.EXILED, game); + int count = cards.count(StaticFilters.FILTER_CARD_CREATURE, game); + if (count > 0) { + new RogueToken().putOntoBattlefield(count, game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/w/Watchdog.java b/Mage.Sets/src/mage/cards/w/Watchdog.java index f32ef7b8d4a..677527204fe 100644 --- a/Mage.Sets/src/mage/cards/w/Watchdog.java +++ b/Mage.Sets/src/mage/cards/w/Watchdog.java @@ -3,8 +3,8 @@ package mage.cards.w; import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.SourceTappedCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.combat.BlocksIfAbleSourceEffect; @@ -65,8 +65,8 @@ class WatchdogFilter extends FilterAttackingCreature { } @Override - public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { - if (!super.match(permanent, sourceId, playerId, game)) { + public boolean match(Permanent permanent, UUID playerId, Ability source, Game game) { + if (!super.match(permanent, playerId, source, game)) { return false; } diff --git a/Mage.Sets/src/mage/cards/w/WatcherForTomorrow.java b/Mage.Sets/src/mage/cards/w/WatcherForTomorrow.java index a6751c12d3e..3b3e5e2145b 100644 --- a/Mage.Sets/src/mage/cards/w/WatcherForTomorrow.java +++ b/Mage.Sets/src/mage/cards/w/WatcherForTomorrow.java @@ -2,13 +2,12 @@ package mage.cards.w; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.HideawayAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; @@ -19,7 +18,6 @@ import mage.players.Player; import mage.util.CardUtil; import java.util.UUID; -import mage.game.permanent.Permanent; /** * @author TheElk801 @@ -35,7 +33,8 @@ public final class WatcherForTomorrow extends CardImpl { this.toughness = new MageInt(1); // Hideaway - this.addAbility(new HideawayAbility("creatures")); + this.addAbility(new HideawayAbility(4)); + this.addAbility(new EntersBattlefieldTappedAbility()); // When Watcher for Tomorrow leaves the battlefield, put the exiled card into its owner's hand. this.addAbility(new LeavesBattlefieldTriggeredAbility(new WatcherForTomorrowEffect(), false)); @@ -70,18 +69,10 @@ class WatcherForTomorrowEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + ExileZone zone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source, -1)); + if (player == null || zone == null || zone.isEmpty()) { return false; } - Permanent permanentLeftBattlefield = (Permanent) getValue("permanentLeftBattlefield"); - if (permanentLeftBattlefield == null) { - return false; - } - ExileZone zone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), permanentLeftBattlefield.getZoneChangeCounter(game))); - if (zone == null) { - return false; - } - Cards cards = new CardsImpl(zone.getCards(game)); - return player.moveCards(cards, Zone.HAND, source, game); + return player.moveCards(zone, Zone.HAND, source, game); } } diff --git a/Mage.Sets/src/mage/cards/w/WatcherOfTheRoost.java b/Mage.Sets/src/mage/cards/w/WatcherOfTheRoost.java index d4b25d76769..306b7903b71 100644 --- a/Mage.Sets/src/mage/cards/w/WatcherOfTheRoost.java +++ b/Mage.Sets/src/mage/cards/w/WatcherOfTheRoost.java @@ -41,7 +41,7 @@ public final class WatcherOfTheRoost extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Morph - Reveal a white card in your hand - this.addAbility(new MorphAbility(this, new RevealTargetFromHandCost(new TargetCardInHand(filter)))); + this.addAbility(new MorphAbility(new RevealTargetFromHandCost(new TargetCardInHand(filter)))); // When Watcher of the Roost is turned face up, you gain 2 life. Effect effect = new GainLifeEffect(2); diff --git a/Mage.Sets/src/mage/cards/w/WaterfrontDistrict.java b/Mage.Sets/src/mage/cards/w/WaterfrontDistrict.java new file mode 100644 index 00000000000..59a46c50171 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WaterfrontDistrict.java @@ -0,0 +1,50 @@ +package mage.cards.w; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; +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.DrawCardSourceControllerEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WaterfrontDistrict extends CardImpl { + + public WaterfrontDistrict(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Waterfront District enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {U} or {B}. + this.addAbility(new BlueManaAbility()); + this.addAbility(new BlackManaAbility()); + + // {2}{U}{B}, {T}, Sacrifice Waterfront District: Draw a card. + Ability ability = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{2}{U}{B}") + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private WaterfrontDistrict(final WaterfrontDistrict card) { + super(card); + } + + @Override + public WaterfrontDistrict copy() { + return new WaterfrontDistrict(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WaterspoutWeavers.java b/Mage.Sets/src/mage/cards/w/WaterspoutWeavers.java index c7443a563d8..2f626530d24 100644 --- a/Mage.Sets/src/mage/cards/w/WaterspoutWeavers.java +++ b/Mage.Sets/src/mage/cards/w/WaterspoutWeavers.java @@ -1,7 +1,5 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.abilityword.KinshipAbility; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; @@ -9,18 +7,19 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.filter.common.FilterCreaturePermanent; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class WaterspoutWeavers extends CardImpl { public WaterspoutWeavers(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.MERFOLK); this.subtype.add(SubType.WIZARD); @@ -29,7 +28,10 @@ public final class WaterspoutWeavers extends CardImpl { // Kinship - At the beginning of your upkeep, you may look at the top card of your library. If it shares a creature type with Waterspout Weavers, you may reveal it. // If you do, each creature you control gains flying until end of turn. - this.addAbility(new KinshipAbility(new GainAbilityControlledEffect(FlyingAbility.getInstance(), Duration.EndOfTurn, new FilterCreaturePermanent()))); + this.addAbility(new KinshipAbility(new GainAbilityControlledEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("each creature you control gains flying until end of turn"))); } private WaterspoutWeavers(final WaterspoutWeavers card) { diff --git a/Mage.Sets/src/mage/cards/w/WaveOfReckoning.java b/Mage.Sets/src/mage/cards/w/WaveOfReckoning.java index 0903372a6cf..f45bc486d92 100644 --- a/Mage.Sets/src/mage/cards/w/WaveOfReckoning.java +++ b/Mage.Sets/src/mage/cards/w/WaveOfReckoning.java @@ -53,7 +53,7 @@ class WaveOfReckoningDamageEffect extends OneShotEffect { FilterPermanent filter = new FilterPermanent(); filter.add(CardType.CREATURE.getPredicate()); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { int amount = permanent.getPower().getValue(); permanent.damage(amount, permanent.getId(), source, game, false, true); } diff --git a/Mage.Sets/src/mage/cards/w/WaxmaneBaku.java b/Mage.Sets/src/mage/cards/w/WaxmaneBaku.java index 79f40306bfb..adc0c455924 100644 --- a/Mage.Sets/src/mage/cards/w/WaxmaneBaku.java +++ b/Mage.Sets/src/mage/cards/w/WaxmaneBaku.java @@ -1,8 +1,5 @@ - - package mage.cards.w; -import java.util.List; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; @@ -11,21 +8,18 @@ import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.common.RemoveVariableCountersSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.TapTargetEffect; 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.Outcome; -import mage.constants.Zone; import mage.counters.CounterType; -import mage.filter.FilterPermanent; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + /** * @author LevelX2 @@ -43,8 +37,9 @@ public final class WaxmaneBaku extends CardImpl { this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.FILTER_SPIRIT_OR_ARCANE_CARD, true)); // {1}, Remove X ki counters from Waxmane Baku: Tap X target creatures. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new WaxmaneBakuTapEffect(), new GenericManaCost(1)); - ability.addCost(new RemoveVariableCountersSourceCost(CounterType.KI.createInstance(1))); + Ability ability = new SimpleActivatedAbility(new TapTargetEffect("tap X target creatures"), new GenericManaCost(1)); + ability.addCost(new RemoveVariableCountersSourceCost(CounterType.KI.createInstance())); + ability.setTargetAdjuster(WaxmaneBakuAdjuster.instance); this.addAbility(ability); } @@ -58,45 +53,18 @@ public final class WaxmaneBaku extends CardImpl { } } -class WaxmaneBakuTapEffect extends OneShotEffect { - - private static final FilterPermanent filter = new FilterCreaturePermanent(); - - public WaxmaneBakuTapEffect() { - super(Outcome.Tap); - staticText = "Tap X target creatures"; - } - - public WaxmaneBakuTapEffect(final WaxmaneBakuTapEffect effect) { - super(effect); - } +enum WaxmaneBakuAdjuster implements TargetAdjuster { + instance; @Override - public boolean apply(Game game, Ability source) { - int numberToTap = 0; - for (Cost cost : source.getCosts()) { + public void adjustTargets(Ability ability, Game game) { + int xValue = 0; + for (Cost cost : ability.getCosts()) { if (cost instanceof RemoveVariableCountersSourceCost) { - numberToTap = ((RemoveVariableCountersSourceCost) cost).getAmount(); + xValue = ((RemoveVariableCountersSourceCost) cost).getAmount(); } } - TargetPermanent target = new TargetPermanent(numberToTap, filter); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) && target.choose(Outcome.Tap, source.getControllerId(), source.getSourceId(), game)) { - if (!target.getTargets().isEmpty()) { - List targets = target.getTargets(); - for (UUID targetId : targets) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null) { - permanent.tap(source, game); - } - } - } - return true; - } - return false; - } - - @Override - public WaxmaneBakuTapEffect copy() { - return new WaxmaneBakuTapEffect(this); + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(xValue)); } } diff --git a/Mage.Sets/src/mage/cards/w/WayfaringGiant.java b/Mage.Sets/src/mage/cards/w/WayfaringGiant.java index 93ba8004d76..cd0c0ae5a89 100644 --- a/Mage.Sets/src/mage/cards/w/WayfaringGiant.java +++ b/Mage.Sets/src/mage/cards/w/WayfaringGiant.java @@ -1,38 +1,35 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.DomainValue; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.hint.common.DomainHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author LoneFox - */ public final class WayfaringGiant extends CardImpl { public WayfaringGiant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}"); this.subtype.add(SubType.GIANT); this.power = new MageInt(1); this.toughness = new MageInt(3); // Domain - Wayfaring Giant gets +1/+1 for each basic land type among lands you control. - DomainValue dv = new DomainValue(); - Effect effect = new BoostSourceEffect(dv, dv, Duration.WhileOnBattlefield); - effect.setText("Domain — {this} gets +1/+1 for each basic land type among lands you control."); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect).addHint(DomainHint.instance)); + this.addAbility(new SimpleStaticAbility(new BoostSourceEffect( + DomainValue.REGULAR, DomainValue.REGULAR, Duration.WhileOnBattlefield + ).setText("{this} gets +1/+1 for each basic land type among lands you control.")) + .addHint(DomainHint.instance).setAbilityWord(AbilityWord.DOMAIN)); } private WayfaringGiant(final WayfaringGiant card) { diff --git a/Mage.Sets/src/mage/cards/w/WaywardGuideBeast.java b/Mage.Sets/src/mage/cards/w/WaywardGuideBeast.java index fedb8cd2510..49a34a8280b 100644 --- a/Mage.Sets/src/mage/cards/w/WaywardGuideBeast.java +++ b/Mage.Sets/src/mage/cards/w/WaywardGuideBeast.java @@ -72,14 +72,14 @@ class WaywardGuideBeastEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player == null || game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, - source.getSourceId(), source.getControllerId(), game + source.getControllerId(), source, game ) == 0) { return false; } TargetPermanent target = new TargetPermanent( 1, 1, StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, true ); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); player.moveCards(game.getCard(target.getFirstTarget()), Zone.HAND, source, game); return true; } diff --git a/Mage.Sets/src/mage/cards/w/WeatheredBodyguards.java b/Mage.Sets/src/mage/cards/w/WeatheredBodyguards.java index 7ba853e9df5..873c3a4070b 100644 --- a/Mage.Sets/src/mage/cards/w/WeatheredBodyguards.java +++ b/Mage.Sets/src/mage/cards/w/WeatheredBodyguards.java @@ -38,7 +38,7 @@ public final class WeatheredBodyguards extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new WeatheredBodyguardsEffect())); // Morph {3}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}{W}"))); } diff --git a/Mage.Sets/src/mage/cards/w/Weatherlight.java b/Mage.Sets/src/mage/cards/w/Weatherlight.java index bb2e15f3467..a88e76e3a28 100644 --- a/Mage.Sets/src/mage/cards/w/Weatherlight.java +++ b/Mage.Sets/src/mage/cards/w/Weatherlight.java @@ -1,10 +1,9 @@ - package mage.cards.w; import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.CrewAbility; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -12,7 +11,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.HistoricPredicate; @@ -40,14 +38,12 @@ public final class Weatherlight extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - // Whenever Weatherlight deals combat damage to a player, look at the top five cards of your library. You may reveal a historic card from among them and put it into your hand. Put the rest on the bottom of your library in any order. + // Whenever Weatherlight deals combat damage to a player, look at the top five cards of your library. + // You may reveal a historic card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( - new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), filter, - Zone.LIBRARY, false, true, false, Zone.HAND, - true, false, false - ).setBackInRandomOrder(true), false - )); + new LookLibraryAndPickControllerEffect(5, 1, filter, PutCards.HAND, PutCards.BOTTOM_RANDOM), + false)); // Crew 3 this.addAbility(new CrewAbility(3)); diff --git a/Mage.Sets/src/mage/cards/w/WeatherseedTotem.java b/Mage.Sets/src/mage/cards/w/WeatherseedTotem.java index c19b02d91f0..213b85b457a 100644 --- a/Mage.Sets/src/mage/cards/w/WeatherseedTotem.java +++ b/Mage.Sets/src/mage/cards/w/WeatherseedTotem.java @@ -1,15 +1,12 @@ - package mage.cards.w; -import java.util.UUID; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.keyword.TrampleAbility; import mage.abilities.mana.GreenManaAbility; @@ -18,13 +15,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.permanent.token.TokenImpl; +import mage.game.permanent.token.custom.CreatureToken; + +import java.util.Objects; +import java.util.UUID; /** - * * @author TheElk801 */ public final class WeatherseedTotem extends CardImpl { @@ -36,13 +33,19 @@ public final class WeatherseedTotem extends CardImpl { this.addAbility(new GreenManaAbility()); // {2}{G}{G}{G}: Weatherseed Totem becomes a 5/3 green Treefolk artifact creature with trample until end of turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new WeatherseedTotemToken(), "", Duration.EndOfTurn), new ManaCostsImpl<>("{2}{G}{G}{G}"))); + this.addAbility(new SimpleActivatedAbility(new BecomesCreatureSourceEffect( + new CreatureToken(5, 3, "5/3 green Treefolk artifact creature with trample") + .withColor("G") + .withSubType(SubType.TREEFOLK) + .withType(CardType.ARTIFACT) + .withAbility(TrampleAbility.getInstance()), + "", Duration.EndOfTurn + ), new ManaCostsImpl<>("{2}{G}{G}{G}"))); // When Weatherseed Totem is put into a graveyard from the battlefield, if it was a creature, return this card to its owner's hand. this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new ReturnToHandSourceEffect()), - new WeatherseedTotemCondition(), - "When {this} is put into a graveyard from the battlefield, " + new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new ReturnSourceFromGraveyardToHandEffect()), + WeatherseedTotemCondition.instance, "When {this} is put into a graveyard from the battlefield, " + "if it was a creature, return this card to its owner's hand" )); } @@ -57,38 +60,16 @@ public final class WeatherseedTotem extends CardImpl { } } -class WeatherseedTotemCondition implements Condition { - - public WeatherseedTotemCondition() { - } +enum WeatherseedTotemCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (permanent != null) { - return permanent.isCreature(game); - } - return false; - } -} - -class WeatherseedTotemToken extends TokenImpl { - - public WeatherseedTotemToken() { - super("", "5/3 green Treefolk artifact creature with trample"); - cardType.add(CardType.CREATURE); - cardType.add(CardType.ARTIFACT); - subtype.add(SubType.TREEFOLK); - color.setGreen(true); - power = new MageInt(5); - toughness = new MageInt(3); - this.addAbility(TrampleAbility.getInstance()); - } - public WeatherseedTotemToken(final WeatherseedTotemToken token) { - super(token); - } - - public WeatherseedTotemToken copy() { - return new WeatherseedTotemToken(this); + return source + .getEffects() + .stream() + .map(effect -> effect.getValue("permanentWasCreature")) + .filter(Objects::nonNull) + .anyMatch(Boolean.class::cast); } } diff --git a/Mage.Sets/src/mage/cards/w/WeaverOfLies.java b/Mage.Sets/src/mage/cards/w/WeaverOfLies.java index d5c53665d30..144b913e016 100644 --- a/Mage.Sets/src/mage/cards/w/WeaverOfLies.java +++ b/Mage.Sets/src/mage/cards/w/WeaverOfLies.java @@ -45,7 +45,7 @@ public final class WeaverOfLies extends CardImpl { this.toughness = new MageInt(4); // Morph {4}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{4}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{4}{U}"))); // When Weaver of Lies is turned face up, turn any number of target creatures with a morph ability other than Weaver of Lies face down. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new WeaverOfLiesEffect(), false, false); diff --git a/Mage.Sets/src/mage/cards/w/WebOfInertia.java b/Mage.Sets/src/mage/cards/w/WebOfInertia.java index 441254f5950..deee9777e48 100644 --- a/Mage.Sets/src/mage/cards/w/WebOfInertia.java +++ b/Mage.Sets/src/mage/cards/w/WebOfInertia.java @@ -54,7 +54,7 @@ class WebOfInertiaEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (player != null && sourceObject != null) { Cost cost = new ExileFromGraveCost(new TargetCardInYourGraveyard()); if (cost.canPay(source, source, player.getId(), game) && player.chooseUse(Outcome.Detriment, "Exile a card from your graveyard?", source, game)) { diff --git a/Mage.Sets/src/mage/cards/w/WebspinnerCuff.java b/Mage.Sets/src/mage/cards/w/WebspinnerCuff.java index b3fae27debe..a2666edeaab 100644 --- a/Mage.Sets/src/mage/cards/w/WebspinnerCuff.java +++ b/Mage.Sets/src/mage/cards/w/WebspinnerCuff.java @@ -36,6 +36,7 @@ public final class WebspinnerCuff extends CardImpl { ability.addEffect(new GainAbilityAttachedEffect( ReachAbility.getInstance(), AttachmentType.EQUIPMENT ).setText("and has reach")); + this.addAbility(ability); // Reconfigure {4} this.addAbility(new ReconfigureAbility("{4}")); diff --git a/Mage.Sets/src/mage/cards/w/WeddingInvitation.java b/Mage.Sets/src/mage/cards/w/WeddingInvitation.java index a05d10eaa68..4f32e2d98ed 100644 --- a/Mage.Sets/src/mage/cards/w/WeddingInvitation.java +++ b/Mage.Sets/src/mage/cards/w/WeddingInvitation.java @@ -15,6 +15,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; @@ -71,7 +72,7 @@ class WeddingInvitationEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (permanent == null) { + if (permanent == null || !permanent.hasSubtype(SubType.VAMPIRE, game)) { return false; } game.addEffect(new GainAbilityTargetEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn), source); diff --git a/Mage.Sets/src/mage/cards/w/WeddingRing.java b/Mage.Sets/src/mage/cards/w/WeddingRing.java index d0bf4debbf2..efe1a89df41 100644 --- a/Mage.Sets/src/mage/cards/w/WeddingRing.java +++ b/Mage.Sets/src/mage/cards/w/WeddingRing.java @@ -124,7 +124,7 @@ class WeddingRingTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (!game.isActivePlayer(event.getPlayerId()) || !game.getOpponents(getControllerId()).contains(event.getPlayerId()) - || !game.getBattlefield().contains(filter, getSourceId(), event.getPlayerId(), game, 1)) { + || !game.getBattlefield().contains(filter, getSourceId(), event.getPlayerId(), this, game, 1)) { return false; } this.getEffects().clear(); diff --git a/Mage.Sets/src/mage/cards/w/WeiAssassins.java b/Mage.Sets/src/mage/cards/w/WeiAssassins.java index 9d0a01df27b..b0b4930a988 100644 --- a/Mage.Sets/src/mage/cards/w/WeiAssassins.java +++ b/Mage.Sets/src/mage/cards/w/WeiAssassins.java @@ -76,8 +76,8 @@ class WeiAssassinsEffect extends OneShotEffect { FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); filter.add(new ControllerIdPredicate(player.getId())); Target target = new TargetPermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { - while (!target.isChosen() && target.canChoose(source.getSourceId(), player.getId(), game) && player.canRespond()) { + if (target.canChoose(player.getId(), source, game)) { + while (!target.isChosen() && target.canChoose(player.getId(), source, game) && player.canRespond()) { player.chooseTarget(Outcome.DestroyPermanent, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/w/WeightOfConscience.java b/Mage.Sets/src/mage/cards/w/WeightOfConscience.java index e0ff6e12b24..f4e6c265ea0 100644 --- a/Mage.Sets/src/mage/cards/w/WeightOfConscience.java +++ b/Mage.Sets/src/mage/cards/w/WeightOfConscience.java @@ -77,7 +77,7 @@ class WeightOfConscienceTarget extends TargetControlledCreaturePermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Player player = game.getPlayer(sourceControllerId); Set possibleTargets = new HashSet<>(0); if (player == null) { @@ -85,7 +85,7 @@ class WeightOfConscienceTarget extends TargetControlledCreaturePermanent { } // Choosing first target if (this.getTargets().isEmpty()) { - List permanentList = game.getBattlefield().getActivePermanents(filterUntapped, sourceControllerId, sourceId, game); + List permanentList = game.getBattlefield().getActivePermanents(filterUntapped, sourceControllerId, source, game); if (permanentList.size() < 2) { return possibleTargets; } @@ -96,7 +96,7 @@ class WeightOfConscienceTarget extends TargetControlledCreaturePermanent { } FilterPermanent filter = filterUntapped.copy(); filter.add(new SharesCreatureTypePredicate(permanent)); - if (game.getBattlefield().count(filter, sourceId, sourceControllerId, game) > 1) { + if (game.getBattlefield().count(filter, sourceControllerId, source, game) > 1) { possibleTargets.add(permanent.getId()); } } @@ -108,7 +108,7 @@ class WeightOfConscienceTarget extends TargetControlledCreaturePermanent { } FilterPermanent filter = filterUntapped.copy(); filter.add(new SharesCreatureTypePredicate(firstTargetCreature)); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filterUntapped, sourceControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filterUntapped, sourceControllerId, source, game)) { if (permanent != null) { possibleTargets.add(permanent.getId()); } @@ -118,9 +118,9 @@ class WeightOfConscienceTarget extends TargetControlledCreaturePermanent { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - for (Permanent permanent1 : game.getBattlefield().getActivePermanents(filterUntapped, sourceControllerId, sourceId, game)) { - for (Permanent permanent2 : game.getBattlefield().getActivePermanents(filterUntapped, sourceControllerId, sourceId, game)) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + for (Permanent permanent1 : game.getBattlefield().getActivePermanents(filterUntapped, sourceControllerId, source, game)) { + for (Permanent permanent2 : game.getBattlefield().getActivePermanents(filterUntapped, sourceControllerId, source, game)) { if (!Objects.equals(permanent1, permanent2) && permanent1.shareCreatureTypes(game, permanent2)) { return true; } @@ -139,7 +139,7 @@ class WeightOfConscienceTarget extends TargetControlledCreaturePermanent { return false; } if (this.getTargets().isEmpty()) { - List permanentList = game.getBattlefield().getActivePermanents(filterUntapped, source.getControllerId(), source.getSourceId(), game); + List permanentList = game.getBattlefield().getActivePermanents(filterUntapped, source.getControllerId(), source, game); if (permanentList.size() < 2) { return false; } @@ -149,7 +149,7 @@ class WeightOfConscienceTarget extends TargetControlledCreaturePermanent { } FilterPermanent filter = filterUntapped.copy(); filter.add(new SharesCreatureTypePredicate(permanent)); - if (game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 1) { + if (game.getBattlefield().count(filter, source.getControllerId(), source, game) > 1) { return true; } } diff --git a/Mage.Sets/src/mage/cards/w/WeirdHarvest.java b/Mage.Sets/src/mage/cards/w/WeirdHarvest.java index d77c0e7170b..7ff1551ccbe 100644 --- a/Mage.Sets/src/mage/cards/w/WeirdHarvest.java +++ b/Mage.Sets/src/mage/cards/w/WeirdHarvest.java @@ -60,7 +60,7 @@ class WeirdHarvestEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { int xValue = source.getManaCostsToPay().getX(); if (xValue > 0) { diff --git a/Mage.Sets/src/mage/cards/w/WeirdedVampire.java b/Mage.Sets/src/mage/cards/w/WeirdedVampire.java index fd7b94305c7..4c39160da44 100644 --- a/Mage.Sets/src/mage/cards/w/WeirdedVampire.java +++ b/Mage.Sets/src/mage/cards/w/WeirdedVampire.java @@ -24,7 +24,7 @@ public final class WeirdedVampire extends CardImpl { this.toughness = new MageInt(3); // Madness {2}{B} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{2}{B}"))); + this.addAbility(new MadnessAbility(new ManaCostsImpl("{2}{B}"))); } private WeirdedVampire(final WeirdedVampire card) { diff --git a/Mage.Sets/src/mage/cards/w/WelcomeToTheFold.java b/Mage.Sets/src/mage/cards/w/WelcomeToTheFold.java index 8b4f281459a..96ceb056782 100644 --- a/Mage.Sets/src/mage/cards/w/WelcomeToTheFold.java +++ b/Mage.Sets/src/mage/cards/w/WelcomeToTheFold.java @@ -28,7 +28,7 @@ public final class WelcomeToTheFold extends CardImpl { // Madness {X}{U}{U} (If you discard this card // discard it into exile. When you do // cast it for its madness cost or put it into your graveyard. - Ability ability = new MadnessAbility(this, new ManaCostsImpl("{X}{U}{U}")); + Ability ability = new MadnessAbility(new ManaCostsImpl("{X}{U}{U}")); ability.setRuleAtTheTop(true); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/w/WelkinGuide.java b/Mage.Sets/src/mage/cards/w/WelkinGuide.java index 2ea9afc774c..7ea0f42200c 100644 --- a/Mage.Sets/src/mage/cards/w/WelkinGuide.java +++ b/Mage.Sets/src/mage/cards/w/WelkinGuide.java @@ -1,7 +1,5 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -11,18 +9,19 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class WelkinGuide extends CardImpl { public WelkinGuide(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); this.subtype.add(SubType.BIRD); this.subtype.add(SubType.CLERIC); @@ -30,8 +29,12 @@ public final class WelkinGuide extends CardImpl { this.toughness = new MageInt(2); this.addAbility(FlyingAbility.getInstance()); - Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(2, 2, Duration.EndOfTurn), false); - ability.addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); + Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect( + 2, 2, Duration.EndOfTurn + ).setText("target creature gets +2/+2"), false); + ability.addEffect(new GainAbilityTargetEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains flying until end of turn")); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WellgabberApothecary.java b/Mage.Sets/src/mage/cards/w/WellgabberApothecary.java index 957b1d5d096..e73aec31ea5 100644 --- a/Mage.Sets/src/mage/cards/w/WellgabberApothecary.java +++ b/Mage.Sets/src/mage/cards/w/WellgabberApothecary.java @@ -23,7 +23,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class WellgabberApothecary extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("target tapped Merfolk or Kithkin creature this turn"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped Merfolk or Kithkin creature"); static { filter.add(TappedPredicate.TAPPED); diff --git a/Mage.Sets/src/mage/cards/w/WillTheWise.java b/Mage.Sets/src/mage/cards/w/WernogRidersChaplain.java similarity index 81% rename from Mage.Sets/src/mage/cards/w/WillTheWise.java rename to Mage.Sets/src/mage/cards/w/WernogRidersChaplain.java index 3540e693943..47578b92509 100644 --- a/Mage.Sets/src/mage/cards/w/WillTheWise.java +++ b/Mage.Sets/src/mage/cards/w/WernogRidersChaplain.java @@ -22,9 +22,9 @@ import java.util.UUID; /** * @author TheElk801 */ -public final class WillTheWise extends CardImpl { +public final class WernogRidersChaplain extends CardImpl { - public WillTheWise(UUID ownerId, CardSetInfo setInfo) { + public WernogRidersChaplain(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{B}"); this.addSuperType(SuperType.LEGENDARY); @@ -33,37 +33,37 @@ public final class WillTheWise extends CardImpl { this.toughness = new MageInt(2); // When Will the Wise enters or leaves the battlefield, each opponent may investigate. Each opponent who doesn't loses 1 life. You investigate X times, where X is one plus the number of opponents who investigated this way. - this.addAbility(new EntersBattlefieldOrLeavesSourceTriggeredAbility(new WillTheWiseEffect(), false)); + this.addAbility(new EntersBattlefieldOrLeavesSourceTriggeredAbility(new WernogRidersChaplainEffect(), false)); // Friends forever this.addAbility(FriendsForeverAbility.getInstance()); } - private WillTheWise(final WillTheWise card) { + private WernogRidersChaplain(final WernogRidersChaplain card) { super(card); } @Override - public WillTheWise copy() { - return new WillTheWise(this); + public WernogRidersChaplain copy() { + return new WernogRidersChaplain(this); } } -class WillTheWiseEffect extends OneShotEffect { +class WernogRidersChaplainEffect extends OneShotEffect { - WillTheWiseEffect() { + WernogRidersChaplainEffect() { super(Outcome.Benefit); staticText = "each opponent may investigate. Each opponent who doesn't loses 1 life. " + "You investigate X times, where X is one plus the number of opponents who investigated this way"; } - private WillTheWiseEffect(final WillTheWiseEffect effect) { + private WernogRidersChaplainEffect(final WernogRidersChaplainEffect effect) { super(effect); } @Override - public WillTheWiseEffect copy() { - return new WillTheWiseEffect(this); + public WernogRidersChaplainEffect copy() { + return new WernogRidersChaplainEffect(this); } @Override diff --git a/Mage.Sets/src/mage/cards/w/Whack.java b/Mage.Sets/src/mage/cards/w/Whack.java new file mode 100644 index 00000000000..c32d9bf9447 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/Whack.java @@ -0,0 +1,55 @@ +package mage.cards.w; + +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceTargetsPermanentCondition; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Whack extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("a white creature"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + } + + private static final Condition condition = new SourceTargetsPermanentCondition(filter); + + public Whack(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); + + // This spell costs {3} less to cast if it targets a white creature. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SpellCostReductionSourceEffect(3, condition).setCanWorksOnStackOnly(true) + ).setRuleAtTheTop(true)); + + // Target creature gets -4/-4 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(-4, -4)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private Whack(final Whack card) { + super(card); + } + + @Override + public Whack copy() { + return new Whack(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WheelOfSunAndMoon.java b/Mage.Sets/src/mage/cards/w/WheelOfSunAndMoon.java index 0396b8ead84..8bc1dd2da75 100644 --- a/Mage.Sets/src/mage/cards/w/WheelOfSunAndMoon.java +++ b/Mage.Sets/src/mage/cards/w/WheelOfSunAndMoon.java @@ -96,7 +96,7 @@ class WheelOfSunAndMoonEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { Card card = game.getCard(event.getTargetId()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/w/WhenFluffyBunniesAttack.java b/Mage.Sets/src/mage/cards/w/WhenFluffyBunniesAttack.java index 0bc489b16b0..c996a66bc54 100644 --- a/Mage.Sets/src/mage/cards/w/WhenFluffyBunniesAttack.java +++ b/Mage.Sets/src/mage/cards/w/WhenFluffyBunniesAttack.java @@ -70,7 +70,7 @@ class WhenFluffyBunniesAttackEffect extends OneShotEffect { if (controller != null && permanent != null && controller.choose(outcome, choice, game)) { if (!game.isSimulation()) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { game.informPlayers(mageObject.getLogName() + ": " + controller.getLogName() + " has chosen " + choice.getChoice()); } diff --git a/Mage.Sets/src/mage/cards/w/WhereAncientsTread.java b/Mage.Sets/src/mage/cards/w/WhereAncientsTread.java index 46d2662de3f..67b806600dc 100644 --- a/Mage.Sets/src/mage/cards/w/WhereAncientsTread.java +++ b/Mage.Sets/src/mage/cards/w/WhereAncientsTread.java @@ -20,7 +20,7 @@ import mage.target.common.TargetAnyTarget; */ public final class WhereAncientsTread extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with power 5 or greater"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature with power 5 or greater"); static { filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 4)); } @@ -30,7 +30,7 @@ import mage.target.common.TargetAnyTarget; // Whenever a creature with power 5 or greater enters the battlefield under your control, you may have Where Ancients Tread deal 5 damage to any target. - Ability ability = new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, new DamageTargetEffect(5), filter, true); + Ability ability = new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, new DamageTargetEffect(5).setText("you may have {this} deal 5 damage to any target"), filter, true); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/Whetwheel.java b/Mage.Sets/src/mage/cards/w/Whetwheel.java index d6a5f80369c..f242143fdd3 100644 --- a/Mage.Sets/src/mage/cards/w/Whetwheel.java +++ b/Mage.Sets/src/mage/cards/w/Whetwheel.java @@ -31,7 +31,7 @@ public final class Whetwheel extends CardImpl { ability.addTarget(new TargetPlayer()); this.addAbility(ability); // Morph {3} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{3}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{3}"))); } private Whetwheel(final Whetwheel card) { diff --git a/Mage.Sets/src/mage/cards/w/WhimsOfTheFates.java b/Mage.Sets/src/mage/cards/w/WhimsOfTheFates.java index a376107ca62..d90bd674863 100644 --- a/Mage.Sets/src/mage/cards/w/WhimsOfTheFates.java +++ b/Mage.Sets/src/mage/cards/w/WhimsOfTheFates.java @@ -177,11 +177,11 @@ class TargetSecondPilePermanent extends TargetPermanent { } @Override - public boolean canTarget(UUID controllerId, UUID id, UUID sourceId, Game game, boolean flag) { + public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game, boolean flag) { if (firstPile.contains(id)) { return false; } - return super.canTarget(controllerId, id, sourceId, game, flag); + return super.canTarget(controllerId, id, source, game, flag); } @Override diff --git a/Mage.Sets/src/mage/cards/w/WhipSpineDrake.java b/Mage.Sets/src/mage/cards/w/WhipSpineDrake.java index 71b42fb6623..fd52c580585 100644 --- a/Mage.Sets/src/mage/cards/w/WhipSpineDrake.java +++ b/Mage.Sets/src/mage/cards/w/WhipSpineDrake.java @@ -26,7 +26,7 @@ public final class WhipSpineDrake extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Morph {2}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{W}"))); } private WhipSpineDrake(final WhipSpineDrake card) { diff --git a/Mage.Sets/src/mage/cards/w/WhipVine.java b/Mage.Sets/src/mage/cards/w/WhipVine.java index 35c2370227d..6c87a2c6d6f 100644 --- a/Mage.Sets/src/mage/cards/w/WhipVine.java +++ b/Mage.Sets/src/mage/cards/w/WhipVine.java @@ -1,7 +1,5 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -16,20 +14,29 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.filter.predicate.permanent.BlockedByIdPredicate; -import mage.target.common.TargetCreaturePermanent; +import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LoneFox */ public final class WhipVine extends CardImpl { + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature with flying blocked by {this}"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + filter.add(BlockingOrBlockedBySourcePredicate.BLOCKED_BY); + } + public WhipVine(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.PLANT); this.subtype.add(SubType.WALL); this.power = new MageInt(1); @@ -37,17 +44,17 @@ public final class WhipVine extends CardImpl { // Defender this.addAbility(DefenderAbility.getInstance()); + // Reach this.addAbility(ReachAbility.getInstance()); + // You may choose not to untap Whip Vine during your untap step. this.addAbility(new SkipUntapOptionalAbility()); + // {tap}: Tap target creature with flying blocked by Whip Vine. That creature doesn't untap during its controller's untap step for as long as Whip Vine remains tapped. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new TapSourceCost()); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying blocked by {this}"); - filter.add(new AbilityPredicate(FlyingAbility.class)); - filter.add(new BlockedByIdPredicate(this.getId())); - ability.addTarget(new TargetCreaturePermanent(filter)); + Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new TapSourceCost()); ability.addEffect(new DontUntapAsLongAsSourceTappedEffect()); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/Whipcorder.java b/Mage.Sets/src/mage/cards/w/Whipcorder.java index b465fe2cfea..5b63a9718e4 100644 --- a/Mage.Sets/src/mage/cards/w/Whipcorder.java +++ b/Mage.Sets/src/mage/cards/w/Whipcorder.java @@ -37,7 +37,7 @@ public final class Whipcorder extends CardImpl { ability.addCost(new TapSourceCost()); this.addAbility(ability); // Morph {W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{W}"))); } private Whipcorder(final Whipcorder card) { diff --git a/Mage.Sets/src/mage/cards/w/WhiptongueHydra.java b/Mage.Sets/src/mage/cards/w/WhiptongueHydra.java index a37a3aaecef..656371315c7 100644 --- a/Mage.Sets/src/mage/cards/w/WhiptongueHydra.java +++ b/Mage.Sets/src/mage/cards/w/WhiptongueHydra.java @@ -60,7 +60,7 @@ class WhiptongueHydraEffect extends OneShotEffect { public WhiptongueHydraEffect() { super(Outcome.DestroyPermanent); this.staticText = "destroy all creatures with flying. " - + "Put a +1/+1 counter on {this} for each permanent destroyed this way"; + + "Put a +1/+1 counter on {this} for each creature destroyed this way"; } public WhiptongueHydraEffect(final WhiptongueHydraEffect effect) { @@ -76,7 +76,7 @@ class WhiptongueHydraEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { int destroyedPermanents = 0; destroyedPermanents = game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game ).stream().filter( (permanent) -> (permanent.destroy(source, game, false)) ).map((_item) -> 1).reduce(destroyedPermanents, Integer::sum); diff --git a/Mage.Sets/src/mage/cards/w/WhispersilkCloak.java b/Mage.Sets/src/mage/cards/w/WhispersilkCloak.java index dc6d23706e5..3edd7d6b733 100644 --- a/Mage.Sets/src/mage/cards/w/WhispersilkCloak.java +++ b/Mage.Sets/src/mage/cards/w/WhispersilkCloak.java @@ -1,8 +1,6 @@ - - package mage.cards.w; -import java.util.UUID; +import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.combat.CantBeBlockedAttachedEffect; @@ -13,24 +11,27 @@ 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.Zone; +import mage.constants.SubType; +import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public final class WhispersilkCloak extends CardImpl { public WhispersilkCloak(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); this.subtype.add(SubType.EQUIPMENT); // Equipped creature can't be blocked and has shroud. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeBlockedAttachedEffect(AttachmentType.EQUIPMENT))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ShroudAbility.getInstance(), AttachmentType.EQUIPMENT))); + Ability ability = new SimpleStaticAbility(new CantBeBlockedAttachedEffect(AttachmentType.EQUIPMENT)); + ability.addEffect(new GainAbilityAttachedEffect( + ShroudAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and has shroud")); + this.addAbility(ability); + // Equip {2} this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2), false)); } @@ -43,5 +44,4 @@ public final class WhispersilkCloak extends CardImpl { public WhispersilkCloak copy() { return new WhispersilkCloak(this); } - } diff --git a/Mage.Sets/src/mage/cards/w/WhiteWard.java b/Mage.Sets/src/mage/cards/w/WhiteWard.java index 7d44b76e44a..b5bbdbddb47 100644 --- a/Mage.Sets/src/mage/cards/w/WhiteWard.java +++ b/Mage.Sets/src/mage/cards/w/WhiteWard.java @@ -1,10 +1,7 @@ - package mage.cards.w; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; @@ -13,28 +10,20 @@ 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.Zone; -import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.ColorPredicate; +import mage.constants.SubType; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LoneFox */ public final class WhiteWard extends CardImpl { - private static final FilterCard filter = new FilterCard("white"); - - static { - filter.add(new ColorPredicate(ObjectColor.WHITE)); - } - public WhiteWard(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -42,12 +31,11 @@ public final class WhiteWard extends CardImpl { this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Protect)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // Enchanted creature has protection from white. This effect doesn't remove White Ward. - ProtectionAbility gainedAbility = new ProtectionAbility(filter); - gainedAbility.setAuraIdNotToBeRemoved(this.getId()); - Effect effect = new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA); - effect.setText("Enchanted creature has protection from white. This effect doesn't remove {this}."); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + this.addAbility(new SimpleStaticAbility(new GainAbilityAttachedEffect( + ProtectionAbility.from(ObjectColor.WHITE), AttachmentType.AURA + ).setDoesntRemoveItself(true))); } private WhiteWard(final WhiteWard card) { diff --git a/Mage.Sets/src/mage/cards/w/WickedGuardian.java b/Mage.Sets/src/mage/cards/w/WickedGuardian.java index cb562cf9af9..1e0063ad7d7 100644 --- a/Mage.Sets/src/mage/cards/w/WickedGuardian.java +++ b/Mage.Sets/src/mage/cards/w/WickedGuardian.java @@ -75,11 +75,11 @@ class WickedGuardianEffect extends OneShotEffect { if (player == null) { return false; } - if (game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) == 0) { + if (game.getBattlefield().count(filter, source.getControllerId(), source, game) == 0) { return false; } TargetPermanent target = new TargetPermanent(0, 1, filter, true); - if (!player.choose(outcome, target, source.getSourceId(), game)) { + if (!player.choose(outcome, target, source, game)) { return false; } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/w/WickerWarcrawler.java b/Mage.Sets/src/mage/cards/w/WickerWarcrawler.java index deea93a0187..27d61d8d206 100644 --- a/Mage.Sets/src/mage/cards/w/WickerWarcrawler.java +++ b/Mage.Sets/src/mage/cards/w/WickerWarcrawler.java @@ -1,12 +1,8 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; -import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.AttacksOrBlocksTriggeredAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; @@ -15,24 +11,25 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class WickerWarcrawler extends CardImpl { public WickerWarcrawler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{5}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{5}"); this.subtype.add(SubType.SCARECROW); this.power = new MageInt(6); this.toughness = new MageInt(6); // Whenever Wicker Warcrawler attacks or blocks, put a -1/-1 counter on it at end of combat. - Effect effect = new AddCountersSourceEffect(CounterType.M1M1.createInstance(), true); - effect.setText("put a -1/-1 counter on it at end of combat"); - DelayedTriggeredAbility ability = new AtTheEndOfCombatDelayedTriggeredAbility(effect); - this.addAbility(new AttacksOrBlocksTriggeredAbility(new CreateDelayedTriggeredAbilityEffect(ability, false, false), false)); - + this.addAbility(new AttacksOrBlocksTriggeredAbility( + new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility( + new AddCountersSourceEffect(CounterType.M1M1.createInstance(), true) + ), false, false).setText("put a -1/-1 counter on it at end of combat"), false + ).setTriggerPhrase("Whenever {this} attacks or blocks, ")); } private WickerWarcrawler(final WickerWarcrawler card) { diff --git a/Mage.Sets/src/mage/cards/w/WidespreadPanic.java b/Mage.Sets/src/mage/cards/w/WidespreadPanic.java index 4aa1d4ad436..51aa73afe69 100644 --- a/Mage.Sets/src/mage/cards/w/WidespreadPanic.java +++ b/Mage.Sets/src/mage/cards/w/WidespreadPanic.java @@ -14,7 +14,6 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.players.Player; import mage.target.common.TargetCardInHand; import mage.target.targetpointer.FixedTarget; @@ -104,7 +103,7 @@ class WidespreadPanicEffect extends OneShotEffect { TargetCardInHand target = new TargetCardInHand(); target.setNotTarget(true); target.setTargetName("a card from your hand to put on top of your library"); - shuffler.choose(Outcome.Detriment, target, source.getSourceId(), game); + shuffler.choose(Outcome.Detriment, target, source, game); Card card = shuffler.getHand().get(target.getFirstTarget(), game); if (card != null) { shuffler.moveCardToLibraryWithInfo(card, source, game, Zone.HAND, true, false); diff --git a/Mage.Sets/src/mage/cards/w/WidespreadThieving.java b/Mage.Sets/src/mage/cards/w/WidespreadThieving.java new file mode 100644 index 00000000000..ea77d732fa7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WidespreadThieving.java @@ -0,0 +1,54 @@ +package mage.cards.w; + +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.HideawayPlayEffect; +import mage.abilities.keyword.HideawayAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.MulticoloredPredicate; +import mage.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WidespreadThieving extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a multicolored spell"); + + static { + filter.add(MulticoloredPredicate.instance); + } + + public WidespreadThieving(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); + + // Hideaway 5 + this.addAbility(new HideawayAbility(5)); + + // Whenever you cast a multicolored spell, create a Treasure token. Then you may pay {W}{U}{B}{R}{G}. If you do, you may play the exiled card without paying its mana cost. + Ability ability = new SpellCastControllerTriggeredAbility( + new CreateTokenEffect(new TreasureToken()), filter, false + ); + ability.addEffect(new DoIfCostPaid( + new HideawayPlayEffect(), new ManaCostsImpl<>("{W}{U}{B}{R}{G}") + ).concatBy("Then")); + this.addAbility(ability); + } + + private WidespreadThieving(final WidespreadThieving card) { + super(card); + } + + @Override + public WidespreadThieving copy() { + return new WidespreadThieving(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WightOfPrecinctSix.java b/Mage.Sets/src/mage/cards/w/WightOfPrecinctSix.java index acb349c8df2..09f92fd5e21 100644 --- a/Mage.Sets/src/mage/cards/w/WightOfPrecinctSix.java +++ b/Mage.Sets/src/mage/cards/w/WightOfPrecinctSix.java @@ -71,7 +71,7 @@ class CardsInOpponentGraveyardsCount implements DynamicValue { for (UUID playerUUID : game.getOpponents(sourceAbility.getControllerId())) { Player player = game.getPlayer(playerUUID); if (player != null) { - amount += player.getGraveyard().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + amount += player.getGraveyard().count(filter, sourceAbility.getControllerId(), sourceAbility, game); } } return amount; diff --git a/Mage.Sets/src/mage/cards/w/WildEndeavor.java b/Mage.Sets/src/mage/cards/w/WildEndeavor.java index 0a4786619d6..8c5d663bfc0 100644 --- a/Mage.Sets/src/mage/cards/w/WildEndeavor.java +++ b/Mage.Sets/src/mage/cards/w/WildEndeavor.java @@ -50,7 +50,7 @@ class WildEndeavorEffect extends OneShotEffect { WildEndeavorEffect() { super(Outcome.PutCardInPlay); this.staticText = "Roll two d4 and choose one result. " + - "Create a number of 3/3 green Beast creature tokens equal to that result." + + "Create a number of 3/3 green Beast creature tokens equal to that result. " + "Then search your library for a number of basic land cards " + "equal to the other result, put them onto the battlefield tapped, then shuffle."; } diff --git a/Mage.Sets/src/mage/cards/w/WildResearch.java b/Mage.Sets/src/mage/cards/w/WildResearch.java index 6a0ede40b72..51e5ebbbbda 100644 --- a/Mage.Sets/src/mage/cards/w/WildResearch.java +++ b/Mage.Sets/src/mage/cards/w/WildResearch.java @@ -1,8 +1,5 @@ - package mage.cards.w; -import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -10,39 +7,42 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; +import mage.filter.common.FilterEnchantmentCard; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author emerald000 */ public final class WildResearch extends CardImpl { - private static final FilterCard filterEnchantment = new FilterCard("enchantment card"); + private static final FilterCard filterEnchantment = new FilterEnchantmentCard(); private static final FilterCard filterInstant = new FilterCard("instant card"); static { - filterEnchantment.add(CardType.ENCHANTMENT.getPredicate()); filterInstant.add(CardType.INSTANT.getPredicate()); } public WildResearch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); // {1}{W}: Search your library for an enchantment card and reveal that card. Put it into your hand, then discard a card at random. Then shuffle your library. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new WildResearchEffect(filterEnchantment), new ManaCostsImpl<>("{1}{W}"))); + this.addAbility(new SimpleActivatedAbility( + new WildResearchEffect(filterEnchantment), new ManaCostsImpl<>("{1}{W}") + )); // {1}{U}: Search your library for an instant card and reveal that card. Put it into your hand, then discard a card at random. Then shuffle your library. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new WildResearchEffect(filterInstant), new ManaCostsImpl<>("{1}{U}"))); - + this.addAbility(new SimpleActivatedAbility( + new WildResearchEffect(filterInstant), new ManaCostsImpl<>("{1}{U}") + )); } private WildResearch(final WildResearch card) { @@ -61,11 +61,12 @@ class WildResearchEffect extends OneShotEffect { WildResearchEffect(FilterCard filter) { super(Outcome.DrawCard); - this.staticText = "Search your library for an " + filter.getMessage() + " and reveal that card. Put it into your hand, then discard a card at random. Then shuffle."; + this.staticText = "Search your library for an " + filter.getMessage() + " and reveal that card. " + + "Put it into your hand, then discard a card at random. Then shuffle."; this.filter = filter; } - WildResearchEffect(final WildResearchEffect effect) { + private WildResearchEffect(final WildResearchEffect effect) { super(effect); this.filter = effect.filter; } @@ -78,23 +79,18 @@ class WildResearchEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller != null && sourceObject != null) { - TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, source, game)) { - if (!target.getTargets().isEmpty()) { - Card card = controller.getLibrary().remove(target.getFirstTarget(), game); - if (card != null) { - controller.moveCards(card, Zone.HAND, source, game); - Cards cards = new CardsImpl(card); - controller.revealCards(sourceObject.getIdName(), cards, game, true); - } - } - } - controller.discardOne(true, false, source, game); - controller.shuffleLibrary(source, game); - return true; + if (controller == null) { + return false; } - return false; + TargetCardInLibrary target = new TargetCardInLibrary(filter); + controller.searchLibrary(target, source, game); + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); + if (card != null) { + controller.revealCards(source, new CardsImpl(card), game); + controller.moveCards(card, Zone.HAND, source, game); + } + controller.discardOne(true, false, source, game); + controller.shuffleLibrary(source, game); + return true; } } diff --git a/Mage.Sets/src/mage/cards/w/WildfireEternal.java b/Mage.Sets/src/mage/cards/w/WildfireEternal.java index 9bf0ef31a1b..ba47cf24e72 100644 --- a/Mage.Sets/src/mage/cards/w/WildfireEternal.java +++ b/Mage.Sets/src/mage/cards/w/WildfireEternal.java @@ -1,30 +1,25 @@ package mage.cards.w; -import java.util.UUID; -import mage.ApprovingObject; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.cost.CastFromHandForFreeEffect; import mage.abilities.keyword.AfflictAbility; -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.filter.FilterCard; import mage.filter.common.FilterInstantOrSorceryCard; -import mage.game.Game; -import mage.players.Player; -import mage.target.common.TargetCardInHand; + +import java.util.UUID; /** - * * @author spjspj */ public final class WildfireEternal extends CardImpl { + private static final FilterCard filter = new FilterInstantOrSorceryCard("an instant or sorcery spell"); + public WildfireEternal(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); @@ -35,10 +30,12 @@ public final class WildfireEternal extends CardImpl { this.toughness = new MageInt(4); // Afflict 4 - addAbility(new AfflictAbility(4)); + this.addAbility(new AfflictAbility(4)); // Whenever Wildfire Eternal attacks and isn't blocked, you may cast an instant or sorcery card from your hand without paying its mana cost. - this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility(new WildfireEternalCastEffect(), false, true)); + this.addAbility(new AttacksAndIsNotBlockedTriggeredAbility( + new CastFromHandForFreeEffect(filter), false, true + )); } private WildfireEternal(final WildfireEternal card) { @@ -50,45 +47,3 @@ public final class WildfireEternal extends CardImpl { return new WildfireEternal(this); } } - -class WildfireEternalCastEffect extends OneShotEffect { - - public WildfireEternalCastEffect() { - super(Outcome.Benefit); - this.staticText = "you may cast an instant or sorcery card " - + "from your hand without paying its mana cost"; - } - - public WildfireEternalCastEffect(final WildfireEternalCastEffect effect) { - super(effect); - } - - @Override - public WildfireEternalCastEffect copy() { - return new WildfireEternalCastEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - FilterCard filter = new FilterInstantOrSorceryCard(); - int cardsToCast = controller.getHand().count(filter, source.getControllerId(), source.getSourceId(), game); - if (cardsToCast > 0 - && controller.chooseUse(outcome, "Cast an instant or sorcery card from your " - + "hand without paying its mana cost?", source, game)) { - TargetCardInHand target = new TargetCardInHand(filter); - controller.chooseTarget(outcome, target, source, game); - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - } - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/w/WildsongHowler.java b/Mage.Sets/src/mage/cards/w/WildsongHowler.java index 39ef19a7e50..263b258493f 100644 --- a/Mage.Sets/src/mage/cards/w/WildsongHowler.java +++ b/Mage.Sets/src/mage/cards/w/WildsongHowler.java @@ -2,14 +2,13 @@ package mage.cards.w; import mage.MageInt; import mage.abilities.common.TransformsOrEntersTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.keyword.NightboundAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.StaticFilters; import java.util.UUID; @@ -28,12 +27,12 @@ public final class WildsongHowler extends CardImpl { this.color.setGreen(true); this.nightCard = true; - // Whenever this creature enters the battlefield or transforms into Wildsong Howler, look at the top six cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. - this.addAbility(new TransformsOrEntersTriggeredAbility(new LookLibraryAndPickControllerEffect( - StaticValue.get(5), false, StaticValue.get(1), - StaticFilters.FILTER_CARD_CREATURE, Zone.LIBRARY, false, - true, false, Zone.HAND, true, false, false - ).setText("look at the top six cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order"), false)); + // Whenever this creature enters the battlefield or transforms into Wildsong Howler, look at the top six cards of your library. + // You may reveal a creature card from among them and put it into your hand. + // Put the rest on the bottom of your library in a random order. + this.addAbility(new TransformsOrEntersTriggeredAbility( + new LookLibraryAndPickControllerEffect(6, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_RANDOM), + false)); // Nightbound this.addAbility(new NightboundAbility()); diff --git a/Mage.Sets/src/mage/cards/w/WillKenrith.java b/Mage.Sets/src/mage/cards/w/WillKenrith.java index 5cf2c4e7713..acf8238397b 100644 --- a/Mage.Sets/src/mage/cards/w/WillKenrith.java +++ b/Mage.Sets/src/mage/cards/w/WillKenrith.java @@ -3,7 +3,6 @@ package mage.cards.w; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardTargetEffect; @@ -34,7 +33,7 @@ public final class WillKenrith extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.WILL); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +2: Until your next turn, up to two target creatures each have base power and toughness 0/3 and lose all abilities. Ability ability = new LoyaltyAbility( diff --git a/Mage.Sets/src/mage/cards/w/Willbender.java b/Mage.Sets/src/mage/cards/w/Willbender.java index e5549ae89f6..a768c03026b 100644 --- a/Mage.Sets/src/mage/cards/w/Willbender.java +++ b/Mage.Sets/src/mage/cards/w/Willbender.java @@ -37,7 +37,7 @@ public final class Willbender extends CardImpl { this.toughness = new MageInt(2); // Morph {1}{U} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{1}{U}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{1}{U}"))); // When Willbender is turned face up, change the target of target spell or ability with a single target. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new ChooseNewTargetsTargetEffect(true, true)); ability.addTarget(new TargetStackObject(FILTER)); diff --git a/Mage.Sets/src/mage/cards/w/WindborneCharge.java b/Mage.Sets/src/mage/cards/w/WindborneCharge.java index 4ac01482626..7e732d461be 100644 --- a/Mage.Sets/src/mage/cards/w/WindborneCharge.java +++ b/Mage.Sets/src/mage/cards/w/WindborneCharge.java @@ -1,7 +1,5 @@ - package mage.cards.w; -import java.util.UUID; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.FlyingAbility; @@ -11,20 +9,24 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class WindborneCharge extends CardImpl { public WindborneCharge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{W}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}{W}"); // Two target creatures you control each get +2/+2 and gain flying until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect( + 2, 2, Duration.EndOfTurn + ).setText("two target creatures you control each get +2/+2")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ).setText("and gain flying until end of turn")); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(2)); - this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn)); - this.getSpellAbility().addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); } private WindborneCharge(final WindborneCharge card) { diff --git a/Mage.Sets/src/mage/cards/w/WindbriskHeights.java b/Mage.Sets/src/mage/cards/w/WindbriskHeights.java index c5c821f4c69..a1e998e525f 100644 --- a/Mage.Sets/src/mage/cards/w/WindbriskHeights.java +++ b/Mage.Sets/src/mage/cards/w/WindbriskHeights.java @@ -1,6 +1,7 @@ package mage.cards.w; import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; @@ -26,7 +27,8 @@ public final class WindbriskHeights extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // Hideaway (This land enters the battlefield tapped. When it does, look at the top four cards of your library, exile one face down, then put the rest on the bottom of your library.) - this.addAbility(new HideawayAbility()); + this.addAbility(new HideawayAbility(4)); + this.addAbility(new EntersBattlefieldTappedAbility()); // {tap}: Add {W}. this.addAbility(new WhiteManaAbility()); diff --git a/Mage.Sets/src/mage/cards/w/WindsOfAbandon.java b/Mage.Sets/src/mage/cards/w/WindsOfAbandon.java index 68d31a6c17d..c4ee3546c42 100644 --- a/Mage.Sets/src/mage/cards/w/WindsOfAbandon.java +++ b/Mage.Sets/src/mage/cards/w/WindsOfAbandon.java @@ -123,7 +123,7 @@ class WindsOfAbandonOverloadEffect extends OneShotEffect { } Map playerMap = new HashMap<>(); CardsImpl cards = new CardsImpl(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL, source.getControllerId(), source, game)) { int count = playerMap.getOrDefault(permanent.getControllerId(), 0); playerMap.put(permanent.getControllerId(), count + 1); cards.add(permanent); diff --git a/Mage.Sets/src/mage/cards/w/WindsOfQalSisma.java b/Mage.Sets/src/mage/cards/w/WindsOfQalSisma.java index 6deb207485c..8c3e1c7ba66 100644 --- a/Mage.Sets/src/mage/cards/w/WindsOfQalSisma.java +++ b/Mage.Sets/src/mage/cards/w/WindsOfQalSisma.java @@ -10,8 +10,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; import java.util.UUID; @@ -20,19 +19,13 @@ import java.util.UUID; */ public final class WindsOfQalSisma extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponents control"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public WindsOfQalSisma(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); // Prevent all combat damage that would be dealt this turn. // Ferocious - If you control a creature with power 4 or greater, instead prevent all combat damage that would be dealt this turn by creatures your opponents control. Effect effect = new ConditionalReplacementEffect( - new PreventAllDamageByAllPermanentsEffect(filter, Duration.EndOfTurn, true), + new PreventAllDamageByAllPermanentsEffect(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES, Duration.EndOfTurn, true), new LockedInCondition(FerociousCondition.instance), new PreventAllDamageByAllPermanentsEffect(Duration.EndOfTurn, true)); effect.setText("Prevent all combat damage that would be dealt this turn.
" + diff --git a/Mage.Sets/src/mage/cards/w/WingbeatWarrior.java b/Mage.Sets/src/mage/cards/w/WingbeatWarrior.java index 8fabccbcd8d..e5b209b817c 100644 --- a/Mage.Sets/src/mage/cards/w/WingbeatWarrior.java +++ b/Mage.Sets/src/mage/cards/w/WingbeatWarrior.java @@ -34,7 +34,7 @@ public final class WingbeatWarrior extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Morph {2}{W} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{W}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{W}"))); // When Wingbeat Warrior is turned face up, target creature gains first strike until end of turn. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn)); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/w/WingedSliver.java b/Mage.Sets/src/mage/cards/w/WingedSliver.java index b4d95a0adc5..8c6695dbf13 100644 --- a/Mage.Sets/src/mage/cards/w/WingedSliver.java +++ b/Mage.Sets/src/mage/cards/w/WingedSliver.java @@ -1,7 +1,5 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; @@ -11,27 +9,25 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; /** * @author Loki */ public final class WingedSliver extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("All sliver creatures"); - - static { - filter.add(SubType.SLIVER.getPredicate()); - } - public WingedSliver(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.SLIVER); this.power = new MageInt(1); this.toughness = new MageInt(1); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield, filter, false))); + this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( + FlyingAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_ALL_SLIVERS, false + ))); } private WingedSliver(final WingedSliver card) { diff --git a/Mage.Sets/src/mage/cards/w/WingmateRoc.java b/Mage.Sets/src/mage/cards/w/WingmateRoc.java index 78788eb975b..8449b80d250 100644 --- a/Mage.Sets/src/mage/cards/w/WingmateRoc.java +++ b/Mage.Sets/src/mage/cards/w/WingmateRoc.java @@ -38,7 +38,7 @@ public final class WingmateRoc extends CardImpl { // Raid — When Wingmate Roc enters the battlefield, if you attacked this turn, create a 3/4 white Bird creature token with flying. this.addAbility(new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new WingmateRocToken())), RaidCondition.instance, - "Raid — When {this} enters the battlefield, if you attacked this turn, create a 3/4 white Bird creature token with flying.") + "When {this} enters the battlefield, if you attacked this turn, create a 3/4 white Bird creature token with flying.") .setAbilityWord(AbilityWord.RAID) .addHint(RaidHint.instance), new PlayerAttackedWatcher()); diff --git a/Mage.Sets/src/mage/cards/w/WingsOfVelisVel.java b/Mage.Sets/src/mage/cards/w/WingsOfVelisVel.java index 9d13d2df672..573c1477dcb 100644 --- a/Mage.Sets/src/mage/cards/w/WingsOfVelisVel.java +++ b/Mage.Sets/src/mage/cards/w/WingsOfVelisVel.java @@ -28,11 +28,11 @@ public final class WingsOfVelisVel extends CardImpl { // Target creature becomes 4/4, gains all creature types, and gains flying until end of turn. this.getSpellAbility().addEffect(new SetPowerToughnessTargetEffect(4, 4, Duration.EndOfTurn) - .setText("Target creature becomes 4/4")); + .setText("Until end of turn, target creature has base power and toughness 4/4")); this.getSpellAbility().addEffect(new GainAllCreatureTypesTargetEffect(Duration.EndOfTurn) .setText(", gains all creature types")); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn) - .setText(", and gains flying until end of turn")); + .setText(", and gains flying")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/w/WingshieldAgent.java b/Mage.Sets/src/mage/cards/w/WingshieldAgent.java new file mode 100644 index 00000000000..8753e573121 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WingshieldAgent.java @@ -0,0 +1,62 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WingshieldAgent extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("other target creature"); + + static { + filter.add(AnotherPredicate.instance); + } + + public WingshieldAgent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Wingshield Agent enters the battlefield with a shield counter on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.SHIELD.createInstance(1)), + "with a shield counter on it. (If it would be dealt damage " + + "or destroyed, remove a shield counter from it instead.)" + )); + + // Whenever Wingshield Agent attacks, up to one other target creature gains flying until end of turn. + Ability ability = new AttacksTriggeredAbility(new GainAbilityTargetEffect(FlyingAbility.getInstance())); + ability.addTarget(new TargetPermanent(0, 1, filter)); + this.addAbility(ability); + } + + private WingshieldAgent(final WingshieldAgent card) { + super(card); + } + + @Override + public WingshieldAgent copy() { + return new WingshieldAgent(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/Winterflame.java b/Mage.Sets/src/mage/cards/w/Winterflame.java index 753bab5129b..5af29441f3a 100644 --- a/Mage.Sets/src/mage/cards/w/Winterflame.java +++ b/Mage.Sets/src/mage/cards/w/Winterflame.java @@ -26,8 +26,7 @@ public final class Winterflame extends CardImpl { this.getSpellAbility().addEffect(new TapTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("tap")); // * Winterflame deals 2 damage to target creature - Mode mode = new Mode(); - mode.addEffect(new DamageTargetEffect(2)); + Mode mode = new Mode(new DamageTargetEffect(2)); mode.addTarget(new TargetCreaturePermanent().withChooseHint("deals 2 damage to")); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/w/WintersRest.java b/Mage.Sets/src/mage/cards/w/WintersRest.java index 546d6443a72..b26c180c8d5 100644 --- a/Mage.Sets/src/mage/cards/w/WintersRest.java +++ b/Mage.Sets/src/mage/cards/w/WintersRest.java @@ -85,7 +85,7 @@ class WintersRestEffect extends DontUntapInControllersUntapStepEnchantedEffect { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game ).isEmpty()) { return false; } diff --git a/Mage.Sets/src/mage/cards/w/Wiretapping.java b/Mage.Sets/src/mage/cards/w/Wiretapping.java new file mode 100644 index 00000000000..cf0c6d161dc --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/Wiretapping.java @@ -0,0 +1,87 @@ +package mage.cards.w; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.CardsInHandCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.HideawayPlayEffect; +import mage.abilities.keyword.HideawayAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.watchers.common.CardsDrawnDuringDrawStepWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Wiretapping extends CardImpl { + + public Wiretapping(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{U}"); + + // Hideaway 5 + this.addAbility(new HideawayAbility(5)); + + // Whenever you draw your first card during each of your draw steps, draw a card. Then if you have nine or more cards in hand, you may play the exiled card without paying its mana cost. + this.addAbility(new WiretappingTriggeredAbility()); + } + + private Wiretapping(final Wiretapping card) { + super(card); + } + + @Override + public Wiretapping copy() { + return new Wiretapping(this); + } +} + +class WiretappingTriggeredAbility extends TriggeredAbilityImpl { + + private static final Condition condition = new CardsInHandCondition(ComparisonType.MORE_THAN, 8); + + WiretappingTriggeredAbility() { + super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1)); + this.addEffect(new ConditionalOneShotEffect(new HideawayPlayEffect(), condition)); + this.addWatcher(new CardsDrawnDuringDrawStepWatcher()); + } + + private WiretappingTriggeredAbility(final WiretappingTriggeredAbility ability) { + super(ability); + } + + @Override + public WiretappingTriggeredAbility copy() { + return new WiretappingTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DREW_CARD; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return game.isActivePlayer(event.getPlayerId()) + && game.getStep().getType() == PhaseStep.DRAW + && isControlledBy(event.getPlayerId()) + && game + .getState() + .getWatcher(CardsDrawnDuringDrawStepWatcher.class) + .getAmountCardsDrawn(event.getPlayerId()) == 1; + } + + @Override + public String getRule() { + return "Whenever you draw your first card during each of your draw steps, draw a card. " + + "Then if you have nine or more cards in hand, you may play the exiled card without paying its mana cost."; + } +} diff --git a/Mage.Sets/src/mage/cards/w/WisdomOfTheJedi.java b/Mage.Sets/src/mage/cards/w/WisdomOfTheJedi.java index d764e71ed49..396f213fbf0 100644 --- a/Mage.Sets/src/mage/cards/w/WisdomOfTheJedi.java +++ b/Mage.Sets/src/mage/cards/w/WisdomOfTheJedi.java @@ -37,10 +37,9 @@ public final class WisdomOfTheJedi extends CardImpl { this.getSpellAbility().addEffect(new PreventAllDamageToPlayersEffect(Duration.EndOfTurn, false)); // Target creature you control gets +1/+1 and protection from the color of your choice until end of turn. - Mode mode = new Mode(); Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); effect.setText("Target creature you control gets +1/+1"); - mode.addEffect(effect); + Mode mode = new Mode(effect); effect = new GainProtectionFromColorTargetEffect(Duration.EndOfTurn); effect.setText("and protection from the color of your choice until end of turn"); mode.addEffect(effect); @@ -48,8 +47,7 @@ public final class WisdomOfTheJedi extends CardImpl { this.getSpellAbility().addMode(mode); // Counter target spell with converted mana cost of 3 or less. - mode = new Mode(); - mode.addEffect(new CounterTargetEffect()); + mode = new Mode(new CounterTargetEffect()); mode.addTarget(new TargetSpell(filterSpell)); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/w/WishclawTalisman.java b/Mage.Sets/src/mage/cards/w/WishclawTalisman.java index 5a3264ba9cd..45cccbf08a1 100644 --- a/Mage.Sets/src/mage/cards/w/WishclawTalisman.java +++ b/Mage.Sets/src/mage/cards/w/WishclawTalisman.java @@ -92,7 +92,7 @@ class WishclawTalismanEffect extends OneShotEffect { } TargetPlayer target = new TargetOpponent(); target.setNotTarget(true); - if (!player.choose(outcome, target, source.getSourceId(), game)) { + if (!player.choose(outcome, target, source, game)) { return false; } ContinuousEffect continuousEffect diff --git a/Mage.Sets/src/mage/cards/w/WispweaverAngel.java b/Mage.Sets/src/mage/cards/w/WispweaverAngel.java index cf28a17d89f..6ae0e572d8a 100644 --- a/Mage.Sets/src/mage/cards/w/WispweaverAngel.java +++ b/Mage.Sets/src/mage/cards/w/WispweaverAngel.java @@ -38,7 +38,7 @@ public final class WispweaverAngel extends CardImpl { // When Wispweaver Angel enters the battlefield, you may exile another target creature you control, then return that card to the battlefield under its owner's control. Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect(), true); - ability.addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false)); + ability.addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false).concatBy(",")); ability.addTarget(new TargetControlledCreaturePermanent(1, 1, filter, false)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WitherbloomCommand.java b/Mage.Sets/src/mage/cards/w/WitherbloomCommand.java index 8ebc8f61768..36bc8b57ba2 100644 --- a/Mage.Sets/src/mage/cards/w/WitherbloomCommand.java +++ b/Mage.Sets/src/mage/cards/w/WitherbloomCommand.java @@ -107,10 +107,10 @@ class WitherbloomCommandEffect extends OneShotEffect { } TargetCard target = new TargetCardInYourGraveyard(1, StaticFilters.FILTER_CARD_LAND); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (!target.canChoose(source.getControllerId(), source, game)) { return false; } - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); return card != null && player.moveCards(card, Zone.HAND, source, game); } diff --git a/Mage.Sets/src/mage/cards/w/WitherscaleWurm.java b/Mage.Sets/src/mage/cards/w/WitherscaleWurm.java index 2c5ab14081b..05d46868d40 100644 --- a/Mage.Sets/src/mage/cards/w/WitherscaleWurm.java +++ b/Mage.Sets/src/mage/cards/w/WitherscaleWurm.java @@ -34,7 +34,7 @@ public final class WitherscaleWurm extends CardImpl { // Whenever Witherscale Wurm blocks or becomes blocked by a creature, that creature gains wither until end of turn. Effect effect = new GainAbilityTargetEffect(WitherAbility.getInstance(), Duration.EndOfTurn); effect.setText("that creature gains wither until end of turn"); - Ability ability = new BlocksOrBecomesBlockedSourceTriggeredAbility(effect, StaticFilters.FILTER_PERMANENT_A_CREATURE, false, null, true); + Ability ability = new BlocksOrBecomesBlockedSourceTriggeredAbility(effect, StaticFilters.FILTER_PERMANENT_CREATURE, false, null, true); this.addAbility(ability); // Whenever Witherscale Wurm deals damage to an opponent, remove all -1/-1 counters from it. diff --git a/Mage.Sets/src/mage/cards/w/WitnessOfTheAges.java b/Mage.Sets/src/mage/cards/w/WitnessOfTheAges.java index f0bc0a5a031..7ac769d030b 100644 --- a/Mage.Sets/src/mage/cards/w/WitnessOfTheAges.java +++ b/Mage.Sets/src/mage/cards/w/WitnessOfTheAges.java @@ -24,7 +24,7 @@ public final class WitnessOfTheAges extends CardImpl { this.toughness = new MageInt(4); // Morph {5} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{5}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{5}"))); } private WitnessOfTheAges(final WitnessOfTheAges card) { diff --git a/Mage.Sets/src/mage/cards/w/WitnessProtection.java b/Mage.Sets/src/mage/cards/w/WitnessProtection.java new file mode 100644 index 00000000000..397067180a9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WitnessProtection.java @@ -0,0 +1,119 @@ +package mage.cards.w; + +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WitnessProtection extends CardImpl { + + public WitnessProtection(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // Enchanted creature loses all abilities and is a green and white Citizen creature with base power and toughness 1/1 named Legitimate Businessperson. + this.addAbility(new SimpleStaticAbility(new WitnessProtectionEffect())); + } + + private WitnessProtection(final WitnessProtection card) { + super(card); + } + + @Override + public WitnessProtection copy() { + return new WitnessProtection(this); + } +} + +class WitnessProtectionEffect extends ContinuousEffectImpl { + + private static final ObjectColor color = new ObjectColor("GW"); + + WitnessProtectionEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "enchanted creature loses all abilities and is a green and white Citizen creature " + + "with base power and toughness 1/1 named Legitimate Businessperson"; + } + + private WitnessProtectionEffect(final WitnessProtectionEffect effect) { + super(effect); + } + + @Override + public WitnessProtectionEffect copy() { + return new WitnessProtectionEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent enchantment = source.getSourcePermanentIfItStillExists(game); + if (enchantment == null) { + return false; + } + Permanent permanent = game.getPermanent(enchantment.getAttachedTo()); + if (permanent == null) { + return false; + } + switch (layer) { + case TextChangingEffects_3: + permanent.setName("Legitimate Businessperson"); + return true; + case TypeChangingEffects_4: + permanent.removeAllCardTypes(game); + permanent.addCardType(game, CardType.CREATURE); + permanent.removeAllSubTypes(game); + permanent.addSubType(game, SubType.CITIZEN); + return true; + case ColorChangingEffects_5: + permanent.getColor(game).setColor(color); + case AbilityAddingRemovingEffects_6: + permanent.removeAllAbilities(source.getSourceId(), game); + return true; + case PTChangingEffects_7: + if (sublayer == SubLayer.SetPT_7b) { + permanent.getPower().setValue(1); + permanent.getToughness().setValue(1); + } + } + return true; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + switch (layer) { + case TextChangingEffects_3: + case TypeChangingEffects_4: + case ColorChangingEffects_5: + case AbilityAddingRemovingEffects_6: + case PTChangingEffects_7: + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/w/WitnessTheFuture.java b/Mage.Sets/src/mage/cards/w/WitnessTheFuture.java index c5d103a3730..8f994100c71 100644 --- a/Mage.Sets/src/mage/cards/w/WitnessTheFuture.java +++ b/Mage.Sets/src/mage/cards/w/WitnessTheFuture.java @@ -2,14 +2,12 @@ package mage.cards.w; import java.util.UUID; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.TargetPlayerShufflesTargetCardsEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.StaticFilters; import mage.target.TargetPlayer; import mage.target.common.TargetCardInTargetPlayersGraveyard; @@ -23,14 +21,12 @@ public final class WitnessTheFuture extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}"); // Target player shuffles up to four target cards from their graveyard into their library. - // You look at the top four cards of your library, then put one of those cards into your hand and the rest on the bottom of your library in a random order. + // You look at the top four cards of your library, then put one of those cards into your hand + // and the rest on the bottom of your library in a random order. this.getSpellAbility().addTarget(new TargetPlayer()); this.getSpellAbility().addTarget(new TargetCardInTargetPlayersGraveyard(4)); this.getSpellAbility().addEffect(new TargetPlayerShufflesTargetCardsEffect()); - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( - StaticValue.get(4), false, StaticValue.get(1), StaticFilters.FILTER_CARD, - Zone.LIBRARY, false, false, false, Zone.HAND, false, false, false - ).setBackInRandomOrder(true)); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(4, 1, PutCards.HAND, PutCards.BOTTOM_RANDOM).concatBy("You")); } private WitnessTheFuture(final WitnessTheFuture card) { diff --git a/Mage.Sets/src/mage/cards/w/WittyRoastmaster.java b/Mage.Sets/src/mage/cards/w/WittyRoastmaster.java new file mode 100644 index 00000000000..bc6148fb297 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WittyRoastmaster.java @@ -0,0 +1,39 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.AllianceAbility; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WittyRoastmaster extends CardImpl { + + public WittyRoastmaster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.DEVIL); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Alliance — Whenever another creature enters the battlefield under your control, Witty Roastmaster deals 1 damage to each opponent. + this.addAbility(new AllianceAbility(new DamagePlayersEffect(1, TargetController.OPPONENT))); + } + + private WittyRoastmaster(final WittyRoastmaster card) { + super(card); + } + + @Override + public WittyRoastmaster copy() { + return new WittyRoastmaster(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/Woebearer.java b/Mage.Sets/src/mage/cards/w/Woebearer.java index 03009f47be2..88e5497878a 100644 --- a/Mage.Sets/src/mage/cards/w/Woebearer.java +++ b/Mage.Sets/src/mage/cards/w/Woebearer.java @@ -1,11 +1,9 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.FearAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -14,8 +12,9 @@ import mage.constants.SubType; import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author LoneFox */ public final class Woebearer extends CardImpl { @@ -28,8 +27,9 @@ public final class Woebearer extends CardImpl { // Fear 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 ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect(), true); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WoebringerDemon.java b/Mage.Sets/src/mage/cards/w/WoebringerDemon.java index 1df06a583ea..16a418ac65e 100644 --- a/Mage.Sets/src/mage/cards/w/WoebringerDemon.java +++ b/Mage.Sets/src/mage/cards/w/WoebringerDemon.java @@ -75,7 +75,7 @@ class WoebringerDemonEffect extends OneShotEffect { if (currentPlayer != null) { TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), currentPlayer.getId(), game)) { + if (target.canChoose(currentPlayer.getId(), source, game)) { currentPlayer.chooseTarget(Outcome.Sacrifice, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/w/WojekApothecary.java b/Mage.Sets/src/mage/cards/w/WojekApothecary.java index b0f4c0d3a8e..a02e2e48d07 100644 --- a/Mage.Sets/src/mage/cards/w/WojekApothecary.java +++ b/Mage.Sets/src/mage/cards/w/WojekApothecary.java @@ -80,7 +80,7 @@ class WojekApothecaryEffect extends OneShotEffect { Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source)); if (target != null) { ObjectColor color = target.getColor(game); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { if (permanent.getColor(game).shares(color)) { ContinuousEffect effect = new PreventDamageToTargetEffect(Duration.EndOfTurn, 1); effect.setTargetPointer(new FixedTarget(permanent, game)); diff --git a/Mage.Sets/src/mage/cards/w/WojekSiren.java b/Mage.Sets/src/mage/cards/w/WojekSiren.java index 4979664e688..7b12d852118 100644 --- a/Mage.Sets/src/mage/cards/w/WojekSiren.java +++ b/Mage.Sets/src/mage/cards/w/WojekSiren.java @@ -57,7 +57,7 @@ class WojekSirenBoostEffect extends ContinuousEffectImpl { if (target != null) { affectedObjectList.add(new MageObjectReference(target, game)); ObjectColor color = target.getColor(game); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game)) { if (!permanent.getId().equals(target.getId()) && permanent.getColor(game).shares(color)) { affectedObjectList.add(new MageObjectReference(permanent, game)); } diff --git a/Mage.Sets/src/mage/cards/w/WoodElemental.java b/Mage.Sets/src/mage/cards/w/WoodElemental.java index 610f4ee01d9..3fa2db35426 100644 --- a/Mage.Sets/src/mage/cards/w/WoodElemental.java +++ b/Mage.Sets/src/mage/cards/w/WoodElemental.java @@ -84,7 +84,7 @@ class WoodElementalEffect extends OneShotEffect { Card sourceCard = game.getCard(source.getSourceId()); if (controller != null && sourceCard != null) { Target target = new TargetControlledPermanent(0, Integer.MAX_VALUE, filter, true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + if (target.canChoose(source.getControllerId(), source, game) && controller.chooseTarget(Outcome.Detriment, target, source, game)) { if (!target.getTargets().isEmpty()) { int sacrificedForests = target.getTargets().size(); diff --git a/Mage.Sets/src/mage/cards/w/Woodcloaker.java b/Mage.Sets/src/mage/cards/w/Woodcloaker.java index 9d1d16acf84..fcd7ce60542 100644 --- a/Mage.Sets/src/mage/cards/w/Woodcloaker.java +++ b/Mage.Sets/src/mage/cards/w/Woodcloaker.java @@ -29,7 +29,7 @@ public final class Woodcloaker extends CardImpl { this.toughness = new MageInt(3); // Morph {2}{G}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{G}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{G}{G}"))); // When Woodcloaker is turned face up, target creature gains trample until end of turn. Ability ability = new TurnedFaceUpSourceTriggeredAbility(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn)); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/w/WoodlurkerMimic.java b/Mage.Sets/src/mage/cards/w/WoodlurkerMimic.java index b8ad68085f4..93d15f85cbf 100644 --- a/Mage.Sets/src/mage/cards/w/WoodlurkerMimic.java +++ b/Mage.Sets/src/mage/cards/w/WoodlurkerMimic.java @@ -32,7 +32,7 @@ public final class WoodlurkerMimic extends CardImpl { filter.add(new ColorPredicate(ObjectColor.GREEN)); } - private String rule = "Whenever you cast a spell that's both black and green, {this} has base power and toughness 4/5 until end of turn and gains wither until end of turn."; + private static final String rule = "Whenever you cast a spell that's both black and green, {this} has base power and toughness 4/5 until end of turn and gains wither until end of turn."; public WoodlurkerMimic(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B/G}"); diff --git a/Mage.Sets/src/mage/cards/w/WoollyLoxodon.java b/Mage.Sets/src/mage/cards/w/WoollyLoxodon.java index 52ce808c5f6..e1dc9de9607 100644 --- a/Mage.Sets/src/mage/cards/w/WoollyLoxodon.java +++ b/Mage.Sets/src/mage/cards/w/WoollyLoxodon.java @@ -25,7 +25,7 @@ public final class WoollyLoxodon extends CardImpl { this.toughness = new MageInt(7); // Morph 5G - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{5}{G}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{5}{G}"))); } private WoollyLoxodon(final WoollyLoxodon card) { diff --git a/Mage.Sets/src/mage/cards/w/WoollySpider.java b/Mage.Sets/src/mage/cards/w/WoollySpider.java index 20d3b92dd85..c0674ac5a21 100644 --- a/Mage.Sets/src/mage/cards/w/WoollySpider.java +++ b/Mage.Sets/src/mage/cards/w/WoollySpider.java @@ -3,8 +3,7 @@ package mage.cards.w; import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.ReachAbility; @@ -13,10 +12,8 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; /** * @@ -24,6 +21,12 @@ import mage.game.events.GameEvent.EventType; */ public final class WoollySpider extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + public WoollySpider(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{G}"); this.subtype.add(SubType.SPIDER); @@ -33,8 +36,9 @@ public final class WoollySpider extends CardImpl { // Reach this.addAbility(ReachAbility.getInstance()); + // Whenever Woolly Spider blocks a creature with flying, Woolly Spider gets +0/+2 until end of turn. - this.addAbility(new BlocksCreatureWithFlyingTriggeredAbility(new BoostSourceEffect(0, 2, Duration.EndOfTurn), false)); + this.addAbility(new BlocksCreatureTriggeredAbility(new BoostSourceEffect(0, 2, Duration.EndOfTurn), filter, false)); } private WoollySpider(final WoollySpider card) { @@ -45,35 +49,4 @@ public final class WoollySpider extends CardImpl { public WoollySpider copy() { return new WoollySpider(this); } -} - -class BlocksCreatureWithFlyingTriggeredAbility extends TriggeredAbilityImpl { - - public BlocksCreatureWithFlyingTriggeredAbility(Effect effect, boolean optional) { - super(Zone.BATTLEFIELD, effect, optional); - } - - public BlocksCreatureWithFlyingTriggeredAbility(final BlocksCreatureWithFlyingTriggeredAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.BLOCKER_DECLARED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return event.getSourceId().equals(this.getSourceId()) && game.getPermanent(event.getTargetId()).getAbilities().containsKey(FlyingAbility.getInstance().getId()); - } - - @Override - public String getTriggerPhrase() { - return "Whenever {this} blocks a creature with flying, " ; - } - - @Override - public BlocksCreatureWithFlyingTriggeredAbility copy() { - return new BlocksCreatureWithFlyingTriggeredAbility(this); - } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/w/WordOfCommand.java b/Mage.Sets/src/mage/cards/w/WordOfCommand.java index 0bb6b35bbd3..b6a27986f67 100644 --- a/Mage.Sets/src/mage/cards/w/WordOfCommand.java +++ b/Mage.Sets/src/mage/cards/w/WordOfCommand.java @@ -74,7 +74,7 @@ class WordOfCommandEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player sourceController = game.getPlayer(source.getControllerId()); Player targetPlayer = game.getPlayer(source.getFirstTarget()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Card card = null; if (sourceController != null && targetPlayer != null && sourceObject != null) { Player controller = null; diff --git a/Mage.Sets/src/mage/cards/w/WordsOfWind.java b/Mage.Sets/src/mage/cards/w/WordsOfWind.java index 4544a0e2d9a..57cc1af92fe 100644 --- a/Mage.Sets/src/mage/cards/w/WordsOfWind.java +++ b/Mage.Sets/src/mage/cards/w/WordsOfWind.java @@ -68,7 +68,7 @@ class WordsOfWindEffect extends ReplacementEffectImpl { TargetControlledPermanent target = new TargetControlledPermanent(); List liste = game.getBattlefield().getActivePermanents(new FilterControlledPermanent(), playerId, game); if (!liste.isEmpty()) { - while (!player.choose(Outcome.ReturnToHand, target, source.getSourceId(), game)) { + while (!player.choose(Outcome.ReturnToHand, target, source, game)) { if (!player.canRespond()) { return false; } diff --git a/Mage.Sets/src/mage/cards/w/WorkshopAssistant.java b/Mage.Sets/src/mage/cards/w/WorkshopAssistant.java index 2eb034b5e2b..c9ab1d82513 100644 --- a/Mage.Sets/src/mage/cards/w/WorkshopAssistant.java +++ b/Mage.Sets/src/mage/cards/w/WorkshopAssistant.java @@ -12,7 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterArtifactCard; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.target.common.TargetCardInYourGraveyard; /** @@ -24,7 +24,7 @@ public final class WorkshopAssistant extends CardImpl { private static final FilterArtifactCard filter = new FilterArtifactCard("another target artifact card from your graveyard"); static { - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); } public WorkshopAssistant(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/WorkshopWarchief.java b/Mage.Sets/src/mage/cards/w/WorkshopWarchief.java new file mode 100644 index 00000000000..a81d5187572 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WorkshopWarchief.java @@ -0,0 +1,52 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.BlitzAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.RhinoWarriorToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WorkshopWarchief extends CardImpl { + + public WorkshopWarchief(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); + + this.subtype.add(SubType.RHINO); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(5); + this.toughness = new MageInt(3); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When Workshop Warchief enters the battlefield, you gain 3 life. + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3))); + + // When Workshop Warchief dies, create a 4/4 green Rhino Warrior creature token. + this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new RhinoWarriorToken()))); + + // Blitz {4}{G}{G} + this.addAbility(new BlitzAbility(this, "{4}{G}{G}")); + } + + private WorkshopWarchief(final WorkshopWarchief card) { + super(card); + } + + @Override + public WorkshopWarchief copy() { + return new WorkshopWarchief(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WorldBottlingKit.java b/Mage.Sets/src/mage/cards/w/WorldBottlingKit.java index 67c9e15a143..a5ab1ecd19f 100644 --- a/Mage.Sets/src/mage/cards/w/WorldBottlingKit.java +++ b/Mage.Sets/src/mage/cards/w/WorldBottlingKit.java @@ -77,7 +77,7 @@ class WorldBottlingKitEffect extends OneShotEffect { game.informPlayers(controller.getLogName() + " has chosen set " + setChosen); FilterPermanent filter = new FilterPermanent(); filter.add(Predicates.not(Predicates.and(CardType.LAND.getPredicate(), SuperType.BASIC.getPredicate()))); - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); for (Permanent permanent : permanents) { if (permanent.getExpansionSetCode().equals(setChosen)) { controller.moveCardToExileWithInfo(permanent, null, "", source, game, Zone.BATTLEFIELD, true); diff --git a/Mage.Sets/src/mage/cards/w/WorldQueller.java b/Mage.Sets/src/mage/cards/w/WorldQueller.java index b282544c392..b5767f69e2b 100644 --- a/Mage.Sets/src/mage/cards/w/WorldQueller.java +++ b/Mage.Sets/src/mage/cards/w/WorldQueller.java @@ -118,8 +118,8 @@ class WorldQuellerEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player2 = game.getPlayer(playerId); - if (player2 != null && target.canChoose(source.getSourceId(), playerId, game)) { - while (player2.canRespond() && !target.isChosen() && target.canChoose(source.getSourceId(), playerId, game)) { + if (player2 != null && target.canChoose(playerId, source, game)) { + while (player2.canRespond() && !target.isChosen() && target.canChoose(playerId, source, game)) { player2.chooseTarget(Outcome.Sacrifice, target, source, game); } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/w/WorldShaper.java b/Mage.Sets/src/mage/cards/w/WorldShaper.java index e33e53e2899..109acb83ef3 100644 --- a/Mage.Sets/src/mage/cards/w/WorldShaper.java +++ b/Mage.Sets/src/mage/cards/w/WorldShaper.java @@ -53,7 +53,7 @@ class WorldShaperEffect extends OneShotEffect { public WorldShaperEffect() { super(Outcome.PutLandInPlay); - this.staticText = "put all land cards from your graveyard onto the battlefield tapped"; + this.staticText = "return all land cards from your graveyard to the battlefield tapped"; } public WorldShaperEffect(final WorldShaperEffect effect) { diff --git a/Mage.Sets/src/mage/cards/w/Worldfire.java b/Mage.Sets/src/mage/cards/w/Worldfire.java index 8fed1fa6e7a..bf3e26a9a2e 100644 --- a/Mage.Sets/src/mage/cards/w/Worldfire.java +++ b/Mage.Sets/src/mage/cards/w/Worldfire.java @@ -57,7 +57,7 @@ class WorldfireEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanent.moveToExile(null, "", source, game); } for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { diff --git a/Mage.Sets/src/mage/cards/w/WorldgorgerDragon.java b/Mage.Sets/src/mage/cards/w/WorldgorgerDragon.java index b86c549b73d..a595c3ede52 100644 --- a/Mage.Sets/src/mage/cards/w/WorldgorgerDragon.java +++ b/Mage.Sets/src/mage/cards/w/WorldgorgerDragon.java @@ -89,7 +89,7 @@ class WorldgorgerDragonEntersEffect extends OneShotEffect { UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); if (exileId != null) { Set cardsToExile = new LinkedHashSet<>(); - cardsToExile.addAll(game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)); + cardsToExile.addAll(game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)); controller.moveCardsToExile(cardsToExile, source, game, true, exileId, sourceObject.getIdName()); return true; } diff --git a/Mage.Sets/src/mage/cards/w/WorldlyCounsel.java b/Mage.Sets/src/mage/cards/w/WorldlyCounsel.java index 204e8fa2819..a1a10324efe 100644 --- a/Mage.Sets/src/mage/cards/w/WorldlyCounsel.java +++ b/Mage.Sets/src/mage/cards/w/WorldlyCounsel.java @@ -66,7 +66,7 @@ class WorldlyCounselEffect extends OneShotEffect { return false; } - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, (new DomainValue()).calculate(game, source, this))); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, (DomainValue.REGULAR).calculate(game, source, this))); controller.lookAtCards(source, null, cards, game); if (!cards.isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/w/Worldpurge.java b/Mage.Sets/src/mage/cards/w/Worldpurge.java index cf2bf1dfcb8..d2f119de674 100644 --- a/Mage.Sets/src/mage/cards/w/Worldpurge.java +++ b/Mage.Sets/src/mage/cards/w/Worldpurge.java @@ -63,10 +63,10 @@ class WorldpurgeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { Set allPermanents = new HashSet<>(); - allPermanents.addAll(game.getBattlefield().getActivePermanents(new FilterPermanent(), source.getControllerId(), source.getSourceId(), game)); + allPermanents.addAll(game.getBattlefield().getActivePermanents(new FilterPermanent(), source.getControllerId(), source, game)); controller.moveCards(allPermanents, Zone.HAND, source, game, false, false, true, null); game.informPlayers(sourceObject.getLogName() + " - All permanents returned to owners' hands"); @@ -78,7 +78,7 @@ class WorldpurgeEffect extends OneShotEffect { TargetCardInHand target = new TargetCardInHand(0, numberInHand, new FilterCard("cards to keep in hand")); Cards cardsToLibrary = new CardsImpl(); cardsToLibrary.addAll(player.getHand()); - if (player.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + if (player.choose(Outcome.Benefit, target, source, game)) { cardsToLibrary.removeAll(target.getTargets()); } player.shuffleCardsToLibrary(cardsToLibrary, game, source); diff --git a/Mage.Sets/src/mage/cards/w/WormfangBehemoth.java b/Mage.Sets/src/mage/cards/w/WormfangBehemoth.java new file mode 100644 index 00000000000..a9df4888050 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WormfangBehemoth.java @@ -0,0 +1,82 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnFromExileForSourceEffect; +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.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WormfangBehemoth extends CardImpl { + + public WormfangBehemoth(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); + + this.subtype.add(SubType.NIGHTMARE); + this.subtype.add(SubType.FISH); + this.subtype.add(SubType.BEAST); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // When Wormfang Behemoth enters the battlefield, exile all cards from your hand. + this.addAbility(new EntersBattlefieldTriggeredAbility(new WormfangBehemothEffect())); + + // When Wormfang Behemoth leaves the battlefield, return the exiled cards to their owner's hand. + this.addAbility(new LeavesBattlefieldTriggeredAbility( + new ReturnFromExileForSourceEffect(Zone.HAND), false + )); + } + + private WormfangBehemoth(final WormfangBehemoth card) { + super(card); + } + + @Override + public WormfangBehemoth copy() { + return new WormfangBehemoth(this); + } +} + +class WormfangBehemothEffect extends OneShotEffect { + + WormfangBehemothEffect() { + super(Outcome.Benefit); + staticText = "exile all cards from your hand"; + } + + private WormfangBehemothEffect(final WormfangBehemothEffect effect) { + super(effect); + } + + @Override + public WormfangBehemothEffect copy() { + return new WormfangBehemothEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null || player.getHand().isEmpty()) { + return false; + } + return player.moveCardsToExile( + player.getHand().getCards(game), source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WormfangDrake.java b/Mage.Sets/src/mage/cards/w/WormfangDrake.java index 3d839dddab0..fed9e9ba016 100644 --- a/Mage.Sets/src/mage/cards/w/WormfangDrake.java +++ b/Mage.Sets/src/mage/cards/w/WormfangDrake.java @@ -82,7 +82,7 @@ class WormfangDrakeExileCost extends CostImpl { Player controller = game.getPlayer(controllerId); MageObject sourceObject = ability.getSourceObject(game); if (controller != null && sourceObject != null) { - if (targets.choose(Outcome.Exile, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.Exile, controllerId, source.getSourceId(), source, game)) { UUID exileId = CardUtil.getExileZoneId(game, ability.getSourceId(), ability.getSourceObjectZoneChangeCounter()); for (UUID targetId : targets.get(0).getTargets()) { Permanent permanent = game.getPermanent(targetId); @@ -98,7 +98,7 @@ class WormfangDrakeExileCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override diff --git a/Mage.Sets/src/mage/cards/w/Worship.java b/Mage.Sets/src/mage/cards/w/Worship.java index 7b30f28a871..9189e3d6e32 100644 --- a/Mage.Sets/src/mage/cards/w/Worship.java +++ b/Mage.Sets/src/mage/cards/w/Worship.java @@ -62,7 +62,7 @@ class WorshipReplacementEffect extends ReplacementEffectImpl { Player controller = game.getPlayer(source.getControllerId()); if (controller != null && (controller.getLife() - event.getAmount()) < 1 - && game.getBattlefield().count(new FilterControlledCreaturePermanent(), source.getSourceId(), event.getPlayerId(), game) > 0 + && game.getBattlefield().count(new FilterControlledCreaturePermanent(), event.getPlayerId(), source, game) > 0 ) { event.setAmount(controller.getLife() - 1); } diff --git a/Mage.Sets/src/mage/cards/w/WortBoggartAuntie.java b/Mage.Sets/src/mage/cards/w/WortBoggartAuntie.java index c685f4e50f0..5383ae46459 100644 --- a/Mage.Sets/src/mage/cards/w/WortBoggartAuntie.java +++ b/Mage.Sets/src/mage/cards/w/WortBoggartAuntie.java @@ -1,11 +1,9 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.keyword.FearAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -16,8 +14,9 @@ import mage.constants.TargetController; import mage.filter.FilterCard; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Loki */ public final class WortBoggartAuntie extends CardImpl { @@ -29,7 +28,7 @@ public final class WortBoggartAuntie extends CardImpl { } public WortBoggartAuntie(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{R}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.SHAMAN); @@ -40,7 +39,9 @@ public final class WortBoggartAuntie extends CardImpl { this.addAbility(FearAbility.getInstance()); // At the beginning of your upkeep, you may return target Goblin card from your graveyard to your hand. - Ability ability = new BeginningOfUpkeepTriggeredAbility(new ReturnToHandTargetEffect(), TargetController.YOU, true); + Ability ability = new BeginningOfUpkeepTriggeredAbility( + new ReturnFromGraveyardToHandTargetEffect(), TargetController.YOU, true + ); ability.addTarget(new TargetCardInYourGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WortTheRaidmother.java b/Mage.Sets/src/mage/cards/w/WortTheRaidmother.java index f8bc5b1c0cd..89a60079743 100644 --- a/Mage.Sets/src/mage/cards/w/WortTheRaidmother.java +++ b/Mage.Sets/src/mage/cards/w/WortTheRaidmother.java @@ -35,10 +35,12 @@ public final class WortTheRaidmother extends CardImpl { this.toughness = new MageInt(3); // When Wort, the Raidmother enters the battlefield, create two 1/1 red and green Goblin Warrior creature tokens. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GoblinWarriorToken(), 2), false)); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new CreateTokenEffect(new GoblinWarriorToken(), 2) + )); // Each red or green instant or sorcery spell you cast has conspire. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new WortGainConspireEffect())); + this.addAbility(new SimpleStaticAbility(new WortGainConspireEffect())); } private WortTheRaidmother(final WortTheRaidmother card) { @@ -64,12 +66,12 @@ class WortGainConspireEffect extends ContinuousEffectImpl { public WortGainConspireEffect() { super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); staticText = "Each red or green instant or sorcery spell you cast has conspire. (As you cast the spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose new targets for the copy.)"; - conspireAbility = new ConspireAbility(getId(), ConspireAbility.ConspireTargets.MORE); + this.conspireAbility = new ConspireAbility(ConspireAbility.ConspireTargets.MORE); } public WortGainConspireEffect(final WortGainConspireEffect effect) { super(effect); - this.conspireAbility = new ConspireAbility(getId(), ConspireAbility.ConspireTargets.MORE); + this.conspireAbility = effect.conspireAbility; } @Override @@ -81,11 +83,13 @@ class WortGainConspireEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { for (StackObject stackObject : game.getStack()) { // only spells cast, so no copies of spells - if ((stackObject instanceof Spell) && !stackObject.isCopy() && stackObject.isControlledBy(source.getControllerId())) { - Spell spell = (Spell) stackObject; - if (filter.match(stackObject, game)) { - game.getState().addOtherAbility(spell.getCard(), conspireAbility); - } + if (!(stackObject instanceof Spell) || stackObject.isCopy() + || !stackObject.isControlledBy(source.getControllerId())) { + continue; + } + Spell spell = (Spell) stackObject; + if (filter.match(stackObject, game)) { + game.getState().addOtherAbility(spell.getCard(), conspireAbility.setAddedById(source.getSourceId())); } } return true; diff --git a/Mage.Sets/src/mage/cards/w/WreckingCrew.java b/Mage.Sets/src/mage/cards/w/WreckingCrew.java new file mode 100644 index 00000000000..7981fb44bd3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WreckingCrew.java @@ -0,0 +1,41 @@ +package mage.cards.w; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author weirddan455 + */ +public final class WreckingCrew extends CardImpl { + + public WreckingCrew(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + } + + private WreckingCrew(final WreckingCrew card) { + super(card); + } + + @Override + public WreckingCrew copy() { + return new WreckingCrew(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WrenchMind.java b/Mage.Sets/src/mage/cards/w/WrenchMind.java index 27b335baff0..0108204e86b 100644 --- a/Mage.Sets/src/mage/cards/w/WrenchMind.java +++ b/Mage.Sets/src/mage/cards/w/WrenchMind.java @@ -65,7 +65,7 @@ class WrenchMindEffect extends OneShotEffect { return !targetPlayer.discard(2, false, false, source, game).isEmpty(); } TargetDiscard target = new TargetDiscard(StaticFilters.FILTER_CARD_ARTIFACT_AN, targetPlayer.getId()); - targetPlayer.choose(Outcome.Discard, target, source.getSourceId(), game); + targetPlayer.choose(Outcome.Discard, target, source, game); Card card = targetPlayer.getHand().get(target.getFirstTarget(), game); if (card != null && targetPlayer.discard(card, false, source, game)) { return true; diff --git a/Mage.Sets/src/mage/cards/w/WrennAndSeven.java b/Mage.Sets/src/mage/cards/w/WrennAndSeven.java index e1d9d4270d9..524b56c76a6 100644 --- a/Mage.Sets/src/mage/cards/w/WrennAndSeven.java +++ b/Mage.Sets/src/mage/cards/w/WrennAndSeven.java @@ -2,7 +2,6 @@ package mage.cards.w; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GetEmblemEffect; @@ -30,7 +29,7 @@ public final class WrennAndSeven extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.WRENN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + this.setStartingLoyalty(5); // +1: Reveal the top four cards of your library. Put all land cards revealed this way into your hand and the rest into your graveyard. this.addAbility(new LoyaltyAbility(new RevealLibraryPutIntoHandEffect( diff --git a/Mage.Sets/src/mage/cards/w/WrennAndSix.java b/Mage.Sets/src/mage/cards/w/WrennAndSix.java index 8288e659d40..6a5a1cbadac 100644 --- a/Mage.Sets/src/mage/cards/w/WrennAndSix.java +++ b/Mage.Sets/src/mage/cards/w/WrennAndSix.java @@ -2,7 +2,6 @@ package mage.cards.w; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; @@ -35,7 +34,7 @@ public final class WrennAndSix extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.WRENN); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Return up to one target land card from your graveyard to your hand. Ability ability = new LoyaltyAbility(new ReturnFromGraveyardToHandTargetEffect(), 1); diff --git a/Mage.Sets/src/mage/cards/w/WrensRunPackmaster.java b/Mage.Sets/src/mage/cards/w/WrensRunPackmaster.java index f8dd682a04b..7993a58885e 100644 --- a/Mage.Sets/src/mage/cards/w/WrensRunPackmaster.java +++ b/Mage.Sets/src/mage/cards/w/WrensRunPackmaster.java @@ -1,36 +1,32 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.ChampionAbility; import mage.abilities.keyword.DeathtouchAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.game.permanent.token.WolfToken; +import java.util.UUID; + /** - * * @author emerald000 */ public final class WrensRunPackmaster extends CardImpl { - - private static final FilterPermanent filter = new FilterPermanent("Wolf"); - static { - filter.add(TargetController.YOU.getControllerPredicate()); - filter.add(SubType.WOLF.getPredicate()); - } + + private static final FilterPermanent filter = new FilterPermanent(SubType.WOLF, "Wolves"); public WrensRunPackmaster(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.WARRIOR); @@ -38,15 +34,17 @@ public final class WrensRunPackmaster extends CardImpl { this.toughness = new MageInt(5); // Champion an Elf - this.addAbility(new ChampionAbility(this, SubType.ELF, false)); - + this.addAbility(new ChampionAbility(this, SubType.ELF)); + // {2}{G}: Create a 2/2 green Wolf creature token. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new WolfToken()), new ManaCostsImpl<>("{2}{G}"))); - + this.addAbility(new SimpleActivatedAbility( + new CreateTokenEffect(new WolfToken()), new ManaCostsImpl<>("{2}{G}") + )); + // Each Wolf you control has deathtouch. - Effect effect = new GainAbilityAllEffect(DeathtouchAbility.getInstance(), Duration.WhileOnBattlefield, filter); - effect.setText("Each Wolf you control has deathtouch"); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + DeathtouchAbility.getInstance(), Duration.WhileOnBattlefield, filter + ))); } private WrensRunPackmaster(final WrensRunPackmaster card) { diff --git a/Mage.Sets/src/mage/cards/w/WrensRunVanquisher.java b/Mage.Sets/src/mage/cards/w/WrensRunVanquisher.java index e07f8299d02..7aa9903a825 100644 --- a/Mage.Sets/src/mage/cards/w/WrensRunVanquisher.java +++ b/Mage.Sets/src/mage/cards/w/WrensRunVanquisher.java @@ -35,9 +35,9 @@ public final class WrensRunVanquisher extends CardImpl { // As an additional cost to cast Wren's Run Vanquisher, reveal an Elf card from your hand or pay {3}. this.getSpellAbility().addCost(new OrCost( - new RevealTargetFromHandCost(new TargetCardInHand(filter)), - new GenericManaCost(3), - "reveal an Elf card from your hand or pay {3}")); + "reveal an Elf card from your hand or pay {3}", new RevealTargetFromHandCost(new TargetCardInHand(filter)), + new GenericManaCost(3) + )); // Deathtouch this.addAbility(DeathtouchAbility.getInstance()); diff --git a/Mage.Sets/src/mage/cards/w/WretchedBanquet.java b/Mage.Sets/src/mage/cards/w/WretchedBanquet.java index d67316a87ad..b6221a53ece 100644 --- a/Mage.Sets/src/mage/cards/w/WretchedBanquet.java +++ b/Mage.Sets/src/mage/cards/w/WretchedBanquet.java @@ -60,7 +60,7 @@ class WretchedBanquetEffect extends OneShotEffect { if (targetCreature == null) { return false; } - List creatures = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game); + List creatures = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source, game); int minPower = targetCreature.getPower().getValue() + 1; for (Permanent creature : creatures) { diff --git a/Mage.Sets/src/mage/cards/w/WretchedCamel.java b/Mage.Sets/src/mage/cards/w/WretchedCamel.java index 7829df2d1e7..1a865b57a42 100644 --- a/Mage.Sets/src/mage/cards/w/WretchedCamel.java +++ b/Mage.Sets/src/mage/cards/w/WretchedCamel.java @@ -1,37 +1,24 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; -import mage.abilities.condition.OrCondition; -import mage.abilities.condition.common.CardsInControllerGraveyardCondition; -import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.condition.common.DesertControlledOrGraveyardCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.FilterCard; -import mage.filter.common.FilterControlledPermanent; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author spjspj */ public final class WretchedCamel extends CardImpl { - private static final FilterControlledPermanent filterDesertPermanent = new FilterControlledPermanent("Desert"); - private static final FilterCard filterDesertCard = new FilterCard("Desert card"); - - static { - filterDesertPermanent.add(SubType.DESERT.getPredicate()); - filterDesertCard.add(SubType.DESERT.getPredicate()); - } - public WretchedCamel(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); @@ -43,13 +30,11 @@ public final class WretchedCamel extends CardImpl { // When Wretched Camel dies, if you control a Desert or there is a Desert card in your graveyard, target player discards a card. Ability ability = new ConditionalInterveningIfTriggeredAbility( new DiesSourceTriggeredAbility(new DiscardTargetEffect(1)), - new OrCondition( - new PermanentsOnTheBattlefieldCondition(new FilterControlledPermanent(filterDesertPermanent)), - new CardsInControllerGraveyardCondition(1, filterDesertCard)), - "When {this} dies, if you control a Desert or there is a Desert card in your graveyard, target player discards a card."); - + DesertControlledOrGraveyardCondition.instance, "When {this} dies, " + + "if you control a Desert or there is a Desert card in your graveyard, target player discards a card." + ); ability.addTarget(new TargetPlayer()); - this.addAbility(ability); + this.addAbility(ability.addHint(DesertControlledOrGraveyardCondition.getHint())); } private WretchedCamel(final WretchedCamel card) { diff --git a/Mage.Sets/src/mage/cards/w/WretchedConfluence.java b/Mage.Sets/src/mage/cards/w/WretchedConfluence.java index fd200706646..68572eef2e3 100644 --- a/Mage.Sets/src/mage/cards/w/WretchedConfluence.java +++ b/Mage.Sets/src/mage/cards/w/WretchedConfluence.java @@ -39,14 +39,12 @@ public final class WretchedConfluence extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayer()); // Target creature gets -2/-2 until end of turn; - Mode mode = new Mode(); - mode.addEffect(new BoostTargetEffect(-2, -2, Duration.EndOfTurn)); + Mode mode = new Mode(new BoostTargetEffect(-2, -2, Duration.EndOfTurn)); mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().getModes().addMode(mode); // Return target creature card from your graveyard to your hand. - mode = new Mode(); - mode.addEffect(new ReturnFromGraveyardToHandTargetEffect()); + mode = new Mode(new ReturnFromGraveyardToHandTargetEffect()); mode.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java b/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java index 2acdaa76228..94e598b7849 100644 --- a/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java +++ b/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java @@ -108,7 +108,7 @@ class WrexialTheRisenDeepTriggeredAbility extends TriggeredAbilityImpl { return "Whenever {this} deals combat damage to a player, " + "you may cast target instant or sorcery card " + "from that player's graveyard without paying its mana cost. " - + "If that spell would be put into a graveyard this turn, exile it instead"; + + "If that spell would be put into a graveyard this turn, exile it instead."; } } diff --git a/Mage.Sets/src/mage/cards/w/WritOfReturn.java b/Mage.Sets/src/mage/cards/w/WritOfReturn.java new file mode 100644 index 00000000000..ad96db98855 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WritOfReturn.java @@ -0,0 +1,37 @@ +package mage.cards.w; + +import mage.abilities.effects.common.CipherEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WritOfReturn extends CardImpl { + + public WritOfReturn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}{B}"); + + // Return target creature card from your graveyard to the battlefield tapped. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect(true)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + + // Cipher + this.getSpellAbility().addEffect(new CipherEffect()); + } + + private WritOfReturn(final WritOfReturn card) { + super(card); + } + + @Override + public WritOfReturn copy() { + return new WritOfReturn(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WriteIntoBeing.java b/Mage.Sets/src/mage/cards/w/WriteIntoBeing.java index 2823f77cc10..5e0c8e4c3a4 100644 --- a/Mage.Sets/src/mage/cards/w/WriteIntoBeing.java +++ b/Mage.Sets/src/mage/cards/w/WriteIntoBeing.java @@ -61,7 +61,7 @@ class WriteIntoBeingEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && controller != null) { Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 2)); controller.lookAtCards(source, null, cards, game); diff --git a/Mage.Sets/src/mage/cards/x/XanatharGuildKingpin.java b/Mage.Sets/src/mage/cards/x/XanatharGuildKingpin.java index 5fe1b5ac9df..5e70924a501 100644 --- a/Mage.Sets/src/mage/cards/x/XanatharGuildKingpin.java +++ b/Mage.Sets/src/mage/cards/x/XanatharGuildKingpin.java @@ -88,7 +88,7 @@ class XanatharGuildKingpinRuleModifyingEffect extends ContinuousRuleModifyingEff @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (targetPlayer != null && mageObject != null) { return "This turn you can't cast spells" + " (" + mageObject.getLogName() + ')'; diff --git a/Mage.Sets/src/mage/cards/x/XandersLounge.java b/Mage.Sets/src/mage/cards/x/XandersLounge.java new file mode 100644 index 00000000000..76304ba21a8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/x/XandersLounge.java @@ -0,0 +1,48 @@ +package mage.cards.x; + +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.keyword.CyclingAbility; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class XandersLounge extends CardImpl { + + public XandersLounge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + this.subtype.add(SubType.ISLAND); + this.subtype.add(SubType.SWAMP); + this.subtype.add(SubType.MOUNTAIN); + + // ({T}: Add {U}, {B}, or {R}.) + this.addAbility(new BlueManaAbility()); + this.addAbility(new BlackManaAbility()); + this.addAbility(new RedManaAbility()); + + // Xander's Lounge enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // Cycling {3} + this.addAbility(new CyclingAbility(new GenericManaCost(3))); + } + + private XandersLounge(final XandersLounge card) { + super(card); + } + + @Override + public XandersLounge copy() { + return new XandersLounge(this); + } +} diff --git a/Mage.Sets/src/mage/cards/x/XandersPact.java b/Mage.Sets/src/mage/cards/x/XandersPact.java new file mode 100644 index 00000000000..db9c911e034 --- /dev/null +++ b/Mage.Sets/src/mage/cards/x/XandersPact.java @@ -0,0 +1,126 @@ +package mage.cards.x; + +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.Costs; +import mage.abilities.costs.CostsImpl; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.asthought.CanPlayCardControllerEffect; +import mage.abilities.keyword.CasualtyAbility; +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.players.Player; + +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class XandersPact extends CardImpl { + + public XandersPact(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}{B}"); + + // Casualty 2 + this.addAbility(new CasualtyAbility(this, 2)); + + // Each opponent exiles the top card of their library. You may cast spells from among those cards this turn. If you cast a spell this way, pay life equal to that spell's mana value rather than pay its mana cost. + this.getSpellAbility().addEffect(new XandersPactExileEffect()); + } + + private XandersPact(final XandersPact card) { + super(card); + } + + @Override + public XandersPact copy() { + return new XandersPact(this); + } +} + +class XandersPactExileEffect extends OneShotEffect { + + XandersPactExileEffect() { + super(Outcome.Benefit); + staticText = "each opponent exiles the top card of their library. You may cast spells " + + "from among those cards this turn. If you cast a spell this way, " + + "pay life equal to that spell's mana value rather than pay its mana cost"; + } + + private XandersPactExileEffect(final XandersPactExileEffect effect) { + super(effect); + } + + @Override + public XandersPactExileEffect copy() { + return new XandersPactExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Set cards = game + .getOpponents(source.getControllerId()) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .map(Player::getLibrary) + .map(library -> library.getFromTop(game)) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + if (cards.isEmpty()) { + return false; + } + player.moveCards(cards, Zone.EXILED, source, game); + for (Card card : cards) { + game.addEffect(new XandersPactCastEffect(game, card), source); + } + return true; + } +} + +class XandersPactCastEffect extends CanPlayCardControllerEffect { + + XandersPactCastEffect(Game game, Card card) { + super(game, card.getMainCard().getId(), card.getZoneChangeCounter(game), Duration.EndOfTurn); + } + + private XandersPactCastEffect(final XandersPactCastEffect effect) { + super(effect); + } + + @Override + public XandersPactCastEffect copy() { + return new XandersPactCastEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + if (!super.applies(objectId, source, affectedControllerId, game)) { + return false; + } + Card cardToCheck = game.getCard(objectId); + if (cardToCheck.isLand(game)) { + return false; + } + Player controller = game.getPlayer(source.getControllerId()); + Costs newCosts = new CostsImpl<>(); + newCosts.add(new PayLifeCost(cardToCheck.getManaValue())); + newCosts.addAll(cardToCheck.getSpellAbility().getCosts()); + controller.setCastSourceIdWithAlternateMana(cardToCheck.getId(), null, newCosts); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/x/XathridDemon.java b/Mage.Sets/src/mage/cards/x/XathridDemon.java index 503eae7aa9c..bf58c988959 100644 --- a/Mage.Sets/src/mage/cards/x/XathridDemon.java +++ b/Mage.Sets/src/mage/cards/x/XathridDemon.java @@ -84,8 +84,8 @@ class XathridDemonEffect extends OneShotEffect { filter.add(AnotherPredicate.instance); Target target = new TargetControlledCreaturePermanent(1, 1, filter, true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - controller.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + if (target.canChoose(controller.getId(), source, game)) { + controller.choose(Outcome.Sacrifice, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { int amount = permanent.getPower().getValue(); diff --git a/Mage.Sets/src/mage/cards/x/XenagosTheReveler.java b/Mage.Sets/src/mage/cards/x/XenagosTheReveler.java index f78038fa4cf..80e57758801 100644 --- a/Mage.Sets/src/mage/cards/x/XenagosTheReveler.java +++ b/Mage.Sets/src/mage/cards/x/XenagosTheReveler.java @@ -3,7 +3,6 @@ package mage.cards.x; import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.hint.common.CreaturesYouControlHint; @@ -32,7 +31,7 @@ public final class XenagosTheReveler extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.XENAGOS); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Add X mana in any combination of {R} and/or {G}, where X is the number of creatures you control. this.addAbility(new LoyaltyAbility(new XenagosManaEffect(), +1) @@ -76,7 +75,7 @@ class XenagosManaEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - int x = game.getBattlefield().count(new FilterControlledCreaturePermanent(), source.getSourceId(), source.getControllerId(), game); + int x = game.getBattlefield().count(new FilterControlledCreaturePermanent(), source.getControllerId(), source, game); if (x == 0) { return false; } @@ -124,7 +123,7 @@ class XenagosExileEffect extends OneShotEffect { TargetCard target1 = new TargetCard(0, Integer.MAX_VALUE, Zone.EXILED, filter); target1.setNotTarget(true); if (!exiledCards.isEmpty() - && target1.canChoose(source.getSourceId(), source.getControllerId(), game) + && target1.canChoose(source.getControllerId(), source, game) && controller.choose(Outcome.PutCardInPlay, exiledCards, target1, game)) { controller.moveCards(new CardsImpl(target1.getTargets()), Zone.BATTLEFIELD, source, game); } diff --git a/Mage.Sets/src/mage/cards/y/YahenniUndyingPartisan.java b/Mage.Sets/src/mage/cards/y/YahenniUndyingPartisan.java index 11fb28c7604..d92b8d2815f 100644 --- a/Mage.Sets/src/mage/cards/y/YahenniUndyingPartisan.java +++ b/Mage.Sets/src/mage/cards/y/YahenniUndyingPartisan.java @@ -1,7 +1,5 @@ - package mage.cards.y; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -13,17 +11,16 @@ import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.StaticFilters; -import mage.filter.common.FilterOpponentsCreaturePermanent; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class YahenniUndyingPartisan extends CardImpl { @@ -41,14 +38,16 @@ public final class YahenniUndyingPartisan extends CardImpl { this.addAbility(HasteAbility.getInstance()); // Whenever a creature an opponent controls dies, put a +1/+1 counter on Yahenni, Undying Partisan. - this.addAbility(new DiesCreatureTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, new FilterOpponentsCreaturePermanent())); + this.addAbility(new DiesCreatureTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + false, StaticFilters.FILTER_OPPONENTS_PERMANENT_A_CREATURE + )); // Sacrifice another creature: Yahenni gains indestructible until end of turn. this.addAbility(new SimpleActivatedAbility( - Zone.BATTLEFIELD, new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn), - new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE))) - ); + new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE)) + )); } private YahenniUndyingPartisan(final YahenniUndyingPartisan card) { diff --git a/Mage.Sets/src/mage/cards/y/YahennisExpertise.java b/Mage.Sets/src/mage/cards/y/YahennisExpertise.java index 526e36f83d0..29fea75f30f 100644 --- a/Mage.Sets/src/mage/cards/y/YahennisExpertise.java +++ b/Mage.Sets/src/mage/cards/y/YahennisExpertise.java @@ -1,29 +1,36 @@ - - package mage.cards.y; -import java.util.UUID; import mage.abilities.effects.common.continuous.BoostAllEffect; -import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect; +import mage.abilities.effects.common.cost.CastFromHandForFreeEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.Duration; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; + +import java.util.UUID; /** * @author fireshoes */ public final class YahennisExpertise extends CardImpl { + private static final FilterCard filter = new FilterCard("a spell with mana value 3 or less"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); + } + public YahennisExpertise(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}{B}"); - // All creatures get -3/-3 until end of turn. this.getSpellAbility().addEffect(new BoostAllEffect(-3, -3, Duration.EndOfTurn)); // You may cast a card with converted mana cost 3 or less from your hand without paying its mana cost. - this.getSpellAbility().addEffect(new CastWithoutPayingManaCostEffect(3).concatBy("
")); + this.getSpellAbility().addEffect(new CastFromHandForFreeEffect(filter).concatBy("
")); } private YahennisExpertise(final YahennisExpertise card) { diff --git a/Mage.Sets/src/mage/cards/y/YannikScavengingSentinel.java b/Mage.Sets/src/mage/cards/y/YannikScavengingSentinel.java index c0f1d664a7e..f5140515d9d 100644 --- a/Mage.Sets/src/mage/cards/y/YannikScavengingSentinel.java +++ b/Mage.Sets/src/mage/cards/y/YannikScavengingSentinel.java @@ -91,12 +91,12 @@ class YannikScavengingSentinelEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (player == null || sourcePermanent == null - || game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) < 1) { + || game.getBattlefield().count(filter, source.getControllerId(), source, game) < 1) { return false; } TargetPermanent target = new TargetPermanent(filter); target.setNotTarget(true); - player.choose(outcome, target, source.getSourceId(), game); + player.choose(outcome, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent == null) { return false; diff --git a/Mage.Sets/src/mage/cards/y/YasharnImplacableEarth.java b/Mage.Sets/src/mage/cards/y/YasharnImplacableEarth.java index 14e22f0f5db..5b042531e79 100644 --- a/Mage.Sets/src/mage/cards/y/YasharnImplacableEarth.java +++ b/Mage.Sets/src/mage/cards/y/YasharnImplacableEarth.java @@ -135,7 +135,7 @@ class YasharnImplacableEarthEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "Players can't pay life or sacrifice nonland permanents to cast spells or activate abilities. (" + mageObject.getIdName() + ")."; } diff --git a/Mage.Sets/src/mage/cards/y/YasovaDragonclaw.java b/Mage.Sets/src/mage/cards/y/YasovaDragonclaw.java index 13fd40aa40d..8abb6bee7d2 100644 --- a/Mage.Sets/src/mage/cards/y/YasovaDragonclaw.java +++ b/Mage.Sets/src/mage/cards/y/YasovaDragonclaw.java @@ -75,7 +75,7 @@ class YasovaDragonclawPowerLessThanSourcePredicate implements ObjectSourcePlayer @Override public boolean apply(ObjectSourcePlayer input, Game game) { - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(input.getSourceId()); + Permanent sourcePermanent = input.getSource().getSourcePermanentOrLKI(game); return sourcePermanent != null && input.getObject().getPower().getValue() < sourcePermanent.getPower().getValue(); } diff --git a/Mage.Sets/src/mage/cards/y/YavimayaDryad.java b/Mage.Sets/src/mage/cards/y/YavimayaDryad.java index e125c1975c7..427b2bbf30a 100644 --- a/Mage.Sets/src/mage/cards/y/YavimayaDryad.java +++ b/Mage.Sets/src/mage/cards/y/YavimayaDryad.java @@ -60,7 +60,7 @@ class YavimayaDryadEffect extends SearchEffect { public YavimayaDryadEffect(TargetCardInLibrary target) { super(target, Outcome.PutLandInPlay); - staticText = "you may search your library for a Forest card and put it onto the battlefield tapped under target player's control. If you do, shuffle"; + staticText = "you may search your library for a Forest card, put it onto the battlefield tapped under target player's control, then shuffle"; } public YavimayaDryadEffect(final YavimayaDryadEffect effect) { diff --git a/Mage.Sets/src/mage/cards/y/YodaJediMaster.java b/Mage.Sets/src/mage/cards/y/YodaJediMaster.java index f1d3a4b06da..b8e80a18156 100644 --- a/Mage.Sets/src/mage/cards/y/YodaJediMaster.java +++ b/Mage.Sets/src/mage/cards/y/YodaJediMaster.java @@ -4,13 +4,12 @@ package mage.cards.y; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -19,8 +18,6 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Outcome; import mage.constants.TargetController; -import mage.constants.Zone; -import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; @@ -47,13 +44,10 @@ public final class YodaJediMaster extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.YODA); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + this.setStartingLoyalty(3); // +1: Look at the top two cards of your library. Put one on the bottom of your library. - Effect effect = new LookLibraryAndPickControllerEffect(StaticValue.get(2), false, StaticValue.get(1), - new FilterCard(), Zone.LIBRARY, true, false, false, Zone.LIBRARY, false, false, true); - effect.setText("Look at the top two cards of your library. Put one on the bottom of your library"); - this.addAbility(new LoyaltyAbility(effect, 1)); + this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect(2, 1, PutCards.BOTTOM_ANY, PutCards.TOP_ANY), 1)); // 0: Exile another target permanent you own. Return that card to the battlefield under your control at the beggining of your next end step. Ability ability = new LoyaltyAbility(new YodaJediMasterEffect(), 0); diff --git a/Mage.Sets/src/mage/cards/y/YokeOfTheDamned.java b/Mage.Sets/src/mage/cards/y/YokeOfTheDamned.java index 75a1a6dae9d..a6ebe276eca 100644 --- a/Mage.Sets/src/mage/cards/y/YokeOfTheDamned.java +++ b/Mage.Sets/src/mage/cards/y/YokeOfTheDamned.java @@ -1,8 +1,5 @@ - package mage.cards.y; -import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.DestroyAttachedToEffect; @@ -10,34 +7,34 @@ 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.filter.StaticFilters; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class YokeOfTheDamned extends CardImpl { - public YokeOfTheDamned(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); this.subtype.add(SubType.AURA); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); - Ability ability = new EnchantAbility(auraTarget.getTargetName()); - this.addAbility(ability); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); // When a creature dies, destroy enchanted creature. - this.addAbility(new DiesCreatureTriggeredAbility(new DestroyAttachedToEffect("enchanted creature"), false, StaticFilters.FILTER_PERMANENT_A_CREATURE)); - + this.addAbility(new DiesCreatureTriggeredAbility( + new DestroyAttachedToEffect("enchanted creature"), + false, StaticFilters.FILTER_PERMANENT_A_CREATURE + ).setTriggerPhrase("When a creature dies, ")); } private YokeOfTheDamned(final YokeOfTheDamned card) { diff --git a/Mage.Sets/src/mage/cards/y/YorionSkyNomad.java b/Mage.Sets/src/mage/cards/y/YorionSkyNomad.java index 66b3843287d..2683adb3849 100644 --- a/Mage.Sets/src/mage/cards/y/YorionSkyNomad.java +++ b/Mage.Sets/src/mage/cards/y/YorionSkyNomad.java @@ -111,7 +111,7 @@ class YorionSkyNomadEffect extends OneShotEffect { return false; } TargetPermanent target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); Set toExile = target.getTargets().stream().map(game::getPermanent).collect(Collectors.toSet()); UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); controller.moveCardsToExile(toExile, source, game, true, exileId, sourceObject.getIdName()); diff --git a/Mage.Sets/src/mage/cards/y/YoshimaruEverFaithful.java b/Mage.Sets/src/mage/cards/y/YoshimaruEverFaithful.java new file mode 100644 index 00000000000..1e971fb7e9a --- /dev/null +++ b/Mage.Sets/src/mage/cards/y/YoshimaruEverFaithful.java @@ -0,0 +1,56 @@ +package mage.cards.y; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.PartnerAbility; +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.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class YoshimaruEverFaithful extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent("another legendary permanent"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(SuperType.LEGENDARY.getPredicate()); + } + + public YoshimaruEverFaithful(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.DOG); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Whenever another legendary permanent enters the battlefield under your control, put a +1/+1 counter on Yoshimaru, Ever Faithful. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter + )); + + // Partner + this.addAbility(PartnerAbility.getInstance()); + } + + private YoshimaruEverFaithful(final YoshimaruEverFaithful card) { + super(card); + } + + @Override + public YoshimaruEverFaithful copy() { + return new YoshimaruEverFaithful(this); + } +} diff --git a/Mage.Sets/src/mage/cards/y/YouMeetInATavern.java b/Mage.Sets/src/mage/cards/y/YouMeetInATavern.java index fb4e0857a82..60ccfa10dad 100644 --- a/Mage.Sets/src/mage/cards/y/YouMeetInATavern.java +++ b/Mage.Sets/src/mage/cards/y/YouMeetInATavern.java @@ -1,21 +1,14 @@ package mage.cards.y; -import mage.abilities.Ability; import mage.abilities.Mode; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.players.Player; -import mage.target.common.TargetCardInLibrary; import java.util.UUID; @@ -29,7 +22,8 @@ public final class YouMeetInATavern extends CardImpl { // Choose one — // • Form a Party — Look at the top five cards of your library. You may reveal any number of creature cards from among them and put them into your hand. Put the rest on the bottom of your library in a random order. - this.getSpellAbility().addEffect(new YouMeetInATavernEffect()); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + 5, Integer.MAX_VALUE, StaticFilters.FILTER_CARD_CREATURES, PutCards.HAND, PutCards.BOTTOM_RANDOM)); this.getSpellAbility().withFirstModeFlavorWord("Form a Party"); // • Start a Brawl — Creatures you control get +2/+2 until end of turn. @@ -47,41 +41,3 @@ public final class YouMeetInATavern extends CardImpl { return new YouMeetInATavern(this); } } - -class YouMeetInATavernEffect extends OneShotEffect { - - YouMeetInATavernEffect() { - super(Outcome.Benefit); - staticText = "look at the top five cards of your library. You may reveal " + - "any number of creature cards from among them and put them into your hand. " + - "Put the rest on the bottom of your library in a random order"; - } - - private YouMeetInATavernEffect(final YouMeetInATavernEffect effect) { - super(effect); - } - - @Override - public YouMeetInATavernEffect copy() { - return new YouMeetInATavernEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 5)); - TargetCardInLibrary target = new TargetCardInLibrary( - 0, Integer.MAX_VALUE, StaticFilters.FILTER_CARD_CREATURE - ); - player.choose(outcome, cards, target, game); - Cards toHand = new CardsImpl(target.getTargets()); - cards.removeAll(toHand); - player.revealCards(source, toHand, game); - player.moveCards(toHand, Zone.HAND, source, game); - player.putCardsOnBottomOfLibrary(cards, game, source, false); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/z/ZadaHedronGrinder.java b/Mage.Sets/src/mage/cards/z/ZadaHedronGrinder.java index b83a15a650a..6f7c87ff550 100644 --- a/Mage.Sets/src/mage/cards/z/ZadaHedronGrinder.java +++ b/Mage.Sets/src/mage/cards/z/ZadaHedronGrinder.java @@ -140,7 +140,7 @@ class ZadaHedronGrinderCopySpellEffect extends CopySpellForEachItCouldTargetEffe return game.getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - player.getId(), source.getSourceId(), game + player.getId(), source, game ).stream() .filter(Objects::nonNull) .filter(p -> !p.equals(permanent)) diff --git a/Mage.Sets/src/mage/cards/z/ZagothTriome.java b/Mage.Sets/src/mage/cards/z/ZagothTriome.java index ba11f10e795..4c8d940d3a0 100644 --- a/Mage.Sets/src/mage/cards/z/ZagothTriome.java +++ b/Mage.Sets/src/mage/cards/z/ZagothTriome.java @@ -1,7 +1,7 @@ package mage.cards.z; import mage.abilities.common.EntersBattlefieldTappedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.keyword.CyclingAbility; import mage.abilities.mana.BlackManaAbility; import mage.abilities.mana.BlueManaAbility; @@ -34,7 +34,7 @@ public final class ZagothTriome extends CardImpl { this.addAbility(new EntersBattlefieldTappedAbility()); // Cycling {3} - this.addAbility(new CyclingAbility(new ManaCostsImpl("{3}"))); + this.addAbility(new CyclingAbility(new GenericManaCost(3))); } private ZagothTriome(final ZagothTriome card) { diff --git a/Mage.Sets/src/mage/cards/z/ZangiefTheRedCyclone.java b/Mage.Sets/src/mage/cards/z/ZangiefTheRedCyclone.java new file mode 100644 index 00000000000..de5330f1ead --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZangiefTheRedCyclone.java @@ -0,0 +1,143 @@ +package mage.cards.z; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToACreatureTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeEffect; +import mage.abilities.effects.common.combat.MustBeBlockedByAtLeastOneSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.events.DamagedEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ZangiefTheRedCyclone extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature"); + + static { + filter.add(ZangiefTheRedCycloneWatcher::checkPermanent); + } + + public ZangiefTheRedCyclone(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{R}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(7); + this.toughness = new MageInt(4); + + // Zangief, the Red Cyclone must be blocked if able. + this.addAbility(new SimpleStaticAbility(new MustBeBlockedByAtLeastOneSourceEffect(Duration.WhileOnBattlefield))); + + // Iron Muscle—As long as it's your turn, Zangief has indestructible. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(IndestructibleAbility.getInstance()), + MyTurnCondition.instance, "as long as it's your turn, {this} has indestructible" + )).withFlavorWord("Iron Muscle")); + + // Spinning Piledriver—Whenever Zangief deals damage to a creature, if that creature was dealt excess damage this turn, that creature's controller sacrifices a noncreature, nonland permanent. + this.addAbility(new DealsDamageToACreatureTriggeredAbility( + new ZangiefTheRedCycloneEffect(), false, false, true, filter + ).withFlavorWord("Spinning Piledriver"), new ZangiefTheRedCycloneWatcher()); + } + + private ZangiefTheRedCyclone(final ZangiefTheRedCyclone card) { + super(card); + } + + @Override + public ZangiefTheRedCyclone copy() { + return new ZangiefTheRedCyclone(this); + } +} + +class ZangiefTheRedCycloneEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterNonlandPermanent("noncreature, nonland permanent"); + + static { + filter.add(Predicates.not(CardType.CREATURE.getPredicate())); + } + + ZangiefTheRedCycloneEffect() { + super(Outcome.Benefit); + staticText = "if that creature was dealt excess damage this turn, " + + "that creature's controller sacrifices a noncreature, nonland permanent"; + } + + private ZangiefTheRedCycloneEffect(final ZangiefTheRedCycloneEffect effect) { + super(effect); + } + + @Override + public ZangiefTheRedCycloneEffect copy() { + return new ZangiefTheRedCycloneEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + return false; + } + return new SacrificeEffect(filter, 1, "") + .setTargetPointer(new FixedTarget(permanent.getControllerId(), game)) + .apply(game, source); + } +} + +class ZangiefTheRedCycloneWatcher extends Watcher { + + private final Set morSet = new HashSet<>(); + + ZangiefTheRedCycloneWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.DAMAGED_PERMANENT + && ((DamagedEvent) event).getExcess() >= 1) { + morSet.add(new MageObjectReference(event.getTargetId(), game)); + } + } + + @Override + public void reset() { + super.reset(); + morSet.clear(); + } + + static boolean checkPermanent(Permanent input, Game game) { + return game + .getState() + .getWatcher(ZangiefTheRedCycloneWatcher.class) + .morSet + .stream() + .anyMatch(mor -> mor.refersTo(input, game)); + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZaraRenegadeRecruiter.java b/Mage.Sets/src/mage/cards/z/ZaraRenegadeRecruiter.java index a8689d03d4e..f649003e831 100644 --- a/Mage.Sets/src/mage/cards/z/ZaraRenegadeRecruiter.java +++ b/Mage.Sets/src/mage/cards/z/ZaraRenegadeRecruiter.java @@ -101,7 +101,7 @@ class ZaraRenegadeRecruiterEffect extends OneShotEffect { UUID defenderId; if (game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_PERMANENT_PLANESWALKER, - source.getSourceId(), player.getId(), game + player.getId(), source, game ) < 1) { defenderId = player.getId(); } else { @@ -112,7 +112,7 @@ class ZaraRenegadeRecruiterEffect extends OneShotEffect { filter.getPermanentFilter().add(new ControllerIdPredicate(player.getId())); TargetPlayerOrPlaneswalker target = new TargetPlayerOrPlaneswalker(filter); target.setNotTarget(true); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); defenderId = target.getFirstTarget(); } game.getCombat().addAttackerToCombat(permanent.getId(), defenderId, game); diff --git a/Mage.Sets/src/mage/cards/z/ZarielArchdukeOfAvernus.java b/Mage.Sets/src/mage/cards/z/ZarielArchdukeOfAvernus.java index 8a36922cf41..4e78a8c2156 100644 --- a/Mage.Sets/src/mage/cards/z/ZarielArchdukeOfAvernus.java +++ b/Mage.Sets/src/mage/cards/z/ZarielArchdukeOfAvernus.java @@ -2,7 +2,6 @@ package mage.cards.z; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; @@ -30,7 +29,7 @@ public final class ZarielArchdukeOfAvernus extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ZARIEL); - this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + this.setStartingLoyalty(4); // +1: Creatures you control get +1/+0 and gain haste until end of turn. Ability ability = new LoyaltyAbility(new BoostControlledEffect( diff --git a/Mage.Sets/src/mage/cards/z/ZephyrSpirit.java b/Mage.Sets/src/mage/cards/z/ZephyrSpirit.java index ac88f4d9cfd..7e164047c20 100644 --- a/Mage.Sets/src/mage/cards/z/ZephyrSpirit.java +++ b/Mage.Sets/src/mage/cards/z/ZephyrSpirit.java @@ -24,10 +24,11 @@ public final class ZephyrSpirit extends CardImpl { this.toughness = new MageInt(6); // When Zephyr Spirit blocks, return it to its owner's hand. - this.addAbility(new BlocksSourceTriggeredAbility( - new ReturnToHandSourceEffect(true).setText("return it to its owner's hand"), - false, false, true - )); + this.addAbility( + new BlocksSourceTriggeredAbility( + new ReturnToHandSourceEffect(true).setText("return it to its owner's hand") + ).setTriggerPhrase("When {this} blocks, ") + ); } private ZephyrSpirit(final ZephyrSpirit card) { diff --git a/Mage.Sets/src/mage/cards/z/ZevlorElturelExile.java b/Mage.Sets/src/mage/cards/z/ZevlorElturelExile.java new file mode 100644 index 00000000000..a72e2b21fb7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZevlorElturelExile.java @@ -0,0 +1,200 @@ +package mage.cards.z; + +import mage.MageInt; +import mage.MageItem; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CopySpellForEachItCouldTargetEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.keyword.HasteAbility; +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.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.MageObjectReferencePredicate; +import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class ZevlorElturelExile extends CardImpl { + + public ZevlorElturelExile(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.TIEFLING); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // {2}, {T}: When you next cast an instant or sorcery spell that targets only a single opponent or a single permanent an opponent controls this turn, for each other opponent, choose that player or a permanent they control, copy that spell, and the copy targets the chosen permanent. + Ability ability = new SimpleActivatedAbility( + new CreateDelayedTriggeredAbilityEffect(new ZevlorElturelExileTriggeredAbility()), new GenericManaCost(2) + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private ZevlorElturelExile(final ZevlorElturelExile card) { + super(card); + } + + @Override + public ZevlorElturelExile copy() { + return new ZevlorElturelExile(this); + } +} + +class ZevlorElturelExileTriggeredAbility extends DelayedTriggeredAbility { + + ZevlorElturelExileTriggeredAbility() { + super(new ZevlorElturelExileEffect(), Duration.EndOfTurn, true, false); + } + + private ZevlorElturelExileTriggeredAbility(final ZevlorElturelExileTriggeredAbility ability) { + super(ability); + } + + @Override + public ZevlorElturelExileTriggeredAbility copy() { + return new ZevlorElturelExileTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!this.isControlledBy(event.getPlayerId())) { + return false; + } + Spell spell = game.getSpell(event.getTargetId()); + if (spell == null || !spell.isInstantOrSorcery(game)) { + return false; + } + Set targets = spell + .getSpellAbility() + .getTargets() + .stream() + .map(Target::getTargets) + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + targets.removeIf(uuid -> game.getPermanent(uuid) == null && game.getPlayer(uuid) == null); + if (targets.size() != 1) { + return false; + } + UUID targetId = targets.iterator().next(); + Set opponents = game.getOpponents(this.getControllerId()); + if (opponents.contains(targetId)) { + this.getEffects().setValue("targetId", targetId); + } else if (opponents.contains(game.getControllerId(targetId))) { + this.getEffects().setValue("targetId", game.getControllerId(targetId)); + } else { + return false; + } + this.getEffects().setValue("savedSpell", spell); + return true; + } + + @Override + public String getRule() { + return "When you next cast an instant or sorcery spell that targets only a single opponent or a single permanent an opponent controls this turn, for each other opponent, choose that player or a permanent they control, copy that spell, and the copy targets the chosen permanent."; + } +} + +class ZevlorElturelExileEffect extends CopySpellForEachItCouldTargetEffect { + + ZevlorElturelExileEffect() { + super(); + } + + @Override + protected StackObject getStackObject(Game game, Ability source) { + return (Spell) getValue("savedSpell"); + } + + @Override + protected Player getPlayer(Game game, Ability source) { + return game.getPlayer(source.getControllerId()); + } + + @Override + protected List prepareCopiesWithTargets(StackObject stackObject, Player player, Ability source, Game game) { + UUID targetId = (UUID) getValue("targetId"); + List predicates = new ArrayList<>(); + for (UUID opponentId : game.getOpponents(player.getId())) { + if (opponentId.equals(targetId)) { + continue; + } + Player opponent = game.getPlayer(opponentId); + if (opponent == null) { + continue; + } + boolean canTargetPlayer = stackObject.canTarget(game, opponentId); + Set targetAb = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_PERMANENT, + opponentId, source, game + ) + .stream() + .map(MageItem::getId) + .filter(uuid -> stackObject.canTarget(game, uuid)).collect(Collectors.toSet()); + if (!canTargetPlayer && targetAb.isEmpty()) { + continue; + } + if (canTargetPlayer && (targetAb.isEmpty() || player.chooseUse( + outcome, "Have the copy target " + opponent.getName() + " or a permanent they control?", + null, opponent.getName(), "A permanent they control", source, game + ))) { + predicates.add(new MageObjectReferencePredicate(new MageObjectReference(opponentId))); + } else if (!targetAb.isEmpty()) { + if (targetAb.size() == 1) { + predicates.add(new MageObjectReferencePredicate(targetAb.iterator().next(), game)); + continue; + } + FilterPermanent filter = new FilterPermanent("Permanent to target"); + filter.add(Predicates.or(targetAb.stream().map(PermanentIdPredicate::new).collect(Collectors.toSet()))); + TargetPermanent target = new TargetPermanent(filter); + target.setNotTarget(true); + player.choose(outcome, target, source, game); + predicates.add(new MageObjectReferencePredicate(target.getFirstTarget(), game)); + } + } + return predicates; + } + + private ZevlorElturelExileEffect(final ZevlorElturelExileEffect effect) { + super(effect); + } + + @Override + public ZevlorElturelExileEffect copy() { + return new ZevlorElturelExileEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZhaoZilongTigerGeneral.java b/Mage.Sets/src/mage/cards/z/ZhaoZilongTigerGeneral.java index d7939286090..9e6055a1f10 100644 --- a/Mage.Sets/src/mage/cards/z/ZhaoZilongTigerGeneral.java +++ b/Mage.Sets/src/mage/cards/z/ZhaoZilongTigerGeneral.java @@ -29,7 +29,7 @@ public final class ZhaoZilongTigerGeneral extends CardImpl { // Horsemanship this.addAbility(HorsemanshipAbility.getInstance()); // Whenever Zhao Zilong, Tiger General blocks, it gets +1/+1 until end of turn. - this.addAbility(new BlocksSourceTriggeredAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn), false)); + this.addAbility(new BlocksSourceTriggeredAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn, "it"))); } private ZhaoZilongTigerGeneral(final ZhaoZilongTigerGeneral card) { diff --git a/Mage.Sets/src/mage/cards/z/ZiatoraTheIncinerator.java b/Mage.Sets/src/mage/cards/z/ZiatoraTheIncinerator.java new file mode 100644 index 00000000000..1590eee30e3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZiatoraTheIncinerator.java @@ -0,0 +1,97 @@ +package mage.cards.z; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.TreasureToken; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ZiatoraTheIncinerator extends CardImpl { + + public ZiatoraTheIncinerator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{R}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.DEMON); + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // At the beginning of your end step, you may sacrifice another creature. When you do, Ziatora, the Incinerator deals damage equal to that creature's power to any target and you create three Treasure tokens. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new ZiatoraTheIncineratorEffect(), TargetController.YOU, false + )); + } + + private ZiatoraTheIncinerator(final ZiatoraTheIncinerator card) { + super(card); + } + + @Override + public ZiatoraTheIncinerator copy() { + return new ZiatoraTheIncinerator(this); + } +} + +class ZiatoraTheIncineratorEffect extends OneShotEffect { + + ZiatoraTheIncineratorEffect() { + super(Outcome.Benefit); + staticText = "you may sacrifice another creature. When you do, {this} deals damage " + + "equal to that creature's power to any target and you create three Treasure tokens"; + } + + private ZiatoraTheIncineratorEffect(final ZiatoraTheIncineratorEffect effect) { + super(effect); + } + + @Override + public ZiatoraTheIncineratorEffect copy() { + return new ZiatoraTheIncineratorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetPermanent target = new TargetControlledPermanent( + 0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, true + ); + player.choose(Outcome.Sacrifice, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null || !permanent.sacrifice(source, game)) { + return false; + } + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( + new DamageTargetEffect(permanent.getPower().getValue()), false + ); + ability.addEffect(new CreateTokenEffect(new TreasureToken(), 3).concatBy("and")); + ability.addTarget(new TargetAnyTarget()); + game.fireReflexiveTriggeredAbility(ability, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZiatorasEnvoy.java b/Mage.Sets/src/mage/cards/z/ZiatorasEnvoy.java new file mode 100644 index 00000000000..e146c3b6426 --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZiatorasEnvoy.java @@ -0,0 +1,138 @@ +package mage.cards.z; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.BlitzAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.*; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; +import mage.util.RandomUtil; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ZiatorasEnvoy extends CardImpl { + + public ZiatorasEnvoy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{R}{G}"); + + this.subtype.add(SubType.VIASHINO); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever Ziatora's Envoy deals combat damage to a player, look at the top card of your library. You may play a land from the top of your library or cast a spell with mana value less than or equal to the damage dealt from the top of your library without paying its mana cost. If you don't, put that card into your hand. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new ZiatorasEnvoyEffect(), false)); + + // Blitz {2}{B}{R}{G} + this.addAbility(new BlitzAbility(this, "{2}{B}{R}{G}")); + } + + private ZiatorasEnvoy(final ZiatorasEnvoy card) { + super(card); + } + + @Override + public ZiatorasEnvoy copy() { + return new ZiatorasEnvoy(this); + } +} + +class ZiatorasEnvoyEffect extends OneShotEffect { + + ZiatorasEnvoyEffect() { + super(Outcome.Benefit); + staticText = "look at the top card of your library. You may play a land from the top of your library " + + "or cast a spell with mana value less than or equal to the damage dealt from the top of your " + + "library without paying its mana cost. If you don't, put that card into your hand"; + } + + private ZiatorasEnvoyEffect(final ZiatorasEnvoyEffect effect) { + super(effect); + } + + @Override + public ZiatorasEnvoyEffect copy() { + return new ZiatorasEnvoyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Card card = player.getLibrary().getFromTop(game); + if (card == null) { + return false; + } + player.lookAtCards("Top of your library", card, game); + Cards cards = new CardsImpl(card); + // TODO: factor this out and reuse for other cards + if (player.canPlayLand()) { + Set landSet = new HashSet<>(); + if (card instanceof ModalDoubleFacesCard) { + ModalDoubleFacesCard mdfc = (ModalDoubleFacesCard) card; + if (mdfc.getLeftHalfCard().isLand(game)) { + landSet.add(mdfc.getLeftHalfCard()); + } + if (mdfc.getRightHalfCard().isLand(game)) { + landSet.add(mdfc.getRightHalfCard()); + } + } else if (card.isLand(game)) { + landSet.add(card); + } + Card land; + if (!landSet.isEmpty() && player.chooseUse( + Outcome.PutLandInPlay, "Play " + card.getName() + " as a land?", source, game + )) { + switch (landSet.size()) { + case 1: + land = RandomUtil.randomFromCollection(landSet); + break; + case 2: + Iterator iterator = landSet.iterator(); + Card land1 = iterator.next(); + Card land2 = iterator.next(); + land = player.chooseUse( + outcome, "Choose which land to play ", null, + land1.getName(), land2.getName(), source, game + ) ? land1 : land2; + break; + default: + land = null; + } + } else { + land = null; + } + if (land != null) { + player.playLand(land, game, true); + } + } + cards.retainZone(Zone.LIBRARY, game); + if (cards.isEmpty()) { + return true; + } + int damage = (Integer) this.getValue("damage"); + FilterCard filter = new FilterCard(); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, damage + 1)); + CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter); + cards.retainZone(Zone.LIBRARY, game); + return cards.isEmpty() || player.moveCards(cards, Zone.HAND, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZiatorasProvingGround.java b/Mage.Sets/src/mage/cards/z/ZiatorasProvingGround.java new file mode 100644 index 00000000000..f8700a160c5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZiatorasProvingGround.java @@ -0,0 +1,48 @@ +package mage.cards.z; + +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.keyword.CyclingAbility; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ZiatorasProvingGround extends CardImpl { + + public ZiatorasProvingGround(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + this.subtype.add(SubType.SWAMP); + this.subtype.add(SubType.MOUNTAIN); + this.subtype.add(SubType.FOREST); + + // ({T}: Add {B}, {R}, or {G}.) + this.addAbility(new BlackManaAbility()); + this.addAbility(new RedManaAbility()); + this.addAbility(new GreenManaAbility()); + + // Ziatora's Proving Ground enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // Cycling {3} + this.addAbility(new CyclingAbility(new GenericManaCost(3))); + } + + private ZiatorasProvingGround(final ZiatorasProvingGround card) { + super(card); + } + + @Override + public ZiatorasProvingGround copy() { + return new ZiatorasProvingGround(this); + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZndrspltsJudgment.java b/Mage.Sets/src/mage/cards/z/ZndrspltsJudgment.java index b68990b4ec7..c211e1ac14c 100644 --- a/Mage.Sets/src/mage/cards/z/ZndrspltsJudgment.java +++ b/Mage.Sets/src/mage/cards/z/ZndrspltsJudgment.java @@ -73,7 +73,7 @@ class ZndrspltsJudgmentEffect extends OneShotEffect { FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); filter.add(new ControllerIdPredicate(player.getId())); TargetCreaturePermanent target = new TargetCreaturePermanent(filter); - if (!player.choose(Outcome.Copy, target, source.getSourceId(), game)) { + if (!player.choose(Outcome.Copy, target, source, game)) { continue; } Effect effect = new CreateTokenCopyTargetEffect(player.getId()); @@ -84,7 +84,7 @@ class ZndrspltsJudgmentEffect extends OneShotEffect { FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); filter.add(new ControllerIdPredicate(player.getId())); TargetCreaturePermanent target = new TargetCreaturePermanent(filter); - if (!player.choose(Outcome.ReturnToHand, target, source.getSourceId(), game)) { + if (!player.choose(Outcome.ReturnToHand, target, source, game)) { continue; } Effect effect = new ReturnToHandTargetEffect(); diff --git a/Mage.Sets/src/mage/cards/z/ZoeticCavern.java b/Mage.Sets/src/mage/cards/z/ZoeticCavern.java index a762b1be5c7..aa92f91dce0 100644 --- a/Mage.Sets/src/mage/cards/z/ZoeticCavern.java +++ b/Mage.Sets/src/mage/cards/z/ZoeticCavern.java @@ -21,7 +21,7 @@ public final class ZoeticCavern extends CardImpl { // {T}: Add {C}. this.addAbility(new ColorlessManaAbility()); // Morph {2} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}"))); + this.addAbility(new MorphAbility(new ManaCostsImpl("{2}"))); } private ZoeticCavern(final ZoeticCavern card) { diff --git a/Mage.Sets/src/mage/cards/z/ZombieCutthroat.java b/Mage.Sets/src/mage/cards/z/ZombieCutthroat.java index 03e263e2b80..b78968b5c5e 100644 --- a/Mage.Sets/src/mage/cards/z/ZombieCutthroat.java +++ b/Mage.Sets/src/mage/cards/z/ZombieCutthroat.java @@ -23,7 +23,7 @@ public final class ZombieCutthroat extends CardImpl { this.toughness = new MageInt(4); // Morph-Pay 5 life. - this.addAbility(new MorphAbility(this, new PayLifeCost(5))); + this.addAbility(new MorphAbility(new PayLifeCost(5))); } private ZombieCutthroat(final ZombieCutthroat card) { diff --git a/Mage.Sets/src/mage/cards/z/ZurgoBellstriker.java b/Mage.Sets/src/mage/cards/z/ZurgoBellstriker.java index ec81deef69b..8a3303bdfcb 100644 --- a/Mage.Sets/src/mage/cards/z/ZurgoBellstriker.java +++ b/Mage.Sets/src/mage/cards/z/ZurgoBellstriker.java @@ -34,7 +34,7 @@ public final class ZurgoBellstriker extends CardImpl { // Zurgo Bellstriker can't block creatures with power 2 or greater. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBlockCreaturesSourceEffect(filter))); // Dash {1}{R} - this.addAbility(new DashAbility(this, "{1}{R}")); + this.addAbility(new DashAbility("{1}{R}")); } private ZurgoBellstriker(final ZurgoBellstriker card) { diff --git a/Mage.Sets/src/mage/sets/AlchemyInnistrad.java b/Mage.Sets/src/mage/sets/AlchemyInnistrad.java new file mode 100644 index 00000000000..9e4500ddfb2 --- /dev/null +++ b/Mage.Sets/src/mage/sets/AlchemyInnistrad.java @@ -0,0 +1,36 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class AlchemyInnistrad extends ExpansionSet { + + private static final AlchemyInnistrad instance = new AlchemyInnistrad(); + + public static AlchemyInnistrad getInstance() { + return instance; + } + + private AlchemyInnistrad() { + super("Alchemy: Innistrad", "Y22", ExpansionSet.buildDate(2021, 12, 9), SetType.MAGIC_ARENA); + this.blockName = "Alchemy"; + this.hasBoosters = false; + this.hasBasicLands = false; + + cards.add(new SetCardInfo("Citystalker Connoisseur", 27, Rarity.RARE, mage.cards.c.CitystalkerConnoisseur.class)); + cards.add(new SetCardInfo("Cursebound Witch", 24, Rarity.UNCOMMON, mage.cards.c.CurseboundWitch.class)); + cards.add(new SetCardInfo("Expedition Supplier", 6, Rarity.RARE, mage.cards.e.ExpeditionSupplier.class)); + cards.add(new SetCardInfo("Faithful Disciple", 7, Rarity.UNCOMMON, mage.cards.f.FaithfulDisciple.class)); + cards.add(new SetCardInfo("Ishkanah, Broodmother", 52, Rarity.MYTHIC, mage.cards.i.IshkanahBroodmother.class)); + cards.add(new SetCardInfo("Key to the Archive", 59, Rarity.RARE, mage.cards.k.KeyToTheArchive.class)); + cards.add(new SetCardInfo("Kindred Denial", 18, Rarity.UNCOMMON, mage.cards.k.KindredDenial.class)); + cards.add(new SetCardInfo("Obsessive Collector", 19, Rarity.RARE, mage.cards.o.ObsessiveCollector.class)); + cards.add(new SetCardInfo("Soulstealer Axe", 60, Rarity.UNCOMMON, mage.cards.s.SoulstealerAxe.class)); + cards.add(new SetCardInfo("Suntail Squadron", 11, Rarity.RARE, mage.cards.s.SuntailSquadron.class)); + cards.add(new SetCardInfo("Tireless Angler", 23, Rarity.RARE, mage.cards.t.TirelessAngler.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/AmonkhetRemastered.java b/Mage.Sets/src/mage/sets/AmonkhetRemastered.java index f827aca4a32..5f05893c39e 100644 --- a/Mage.Sets/src/mage/sets/AmonkhetRemastered.java +++ b/Mage.Sets/src/mage/sets/AmonkhetRemastered.java @@ -25,7 +25,6 @@ public class AmonkhetRemastered extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; - this.ratioBoosterSpecialLand = 1; // replace all basic lands cards.add(new SetCardInfo("Abandoned Sarcophagus", 268, Rarity.RARE, mage.cards.a.AbandonedSarcophagus.class)); cards.add(new SetCardInfo("Abrade", 136, Rarity.UNCOMMON, mage.cards.a.Abrade.class)); diff --git a/Mage.Sets/src/mage/sets/CommanderLegends.java b/Mage.Sets/src/mage/sets/CommanderLegends.java index 012a370df7c..fa2ce832a68 100644 --- a/Mage.Sets/src/mage/sets/CommanderLegends.java +++ b/Mage.Sets/src/mage/sets/CommanderLegends.java @@ -657,6 +657,8 @@ public final class CommanderLegends extends ExpansionSet { cards.add(new SetCardInfo("Tevesh Szat, Doom of Fools", 512, Rarity.MYTHIC, mage.cards.t.TeveshSzatDoomOfFools.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thalisse, Reverent Medium", 291, Rarity.UNCOMMON, mage.cards.t.ThalisseReverentMedium.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thalisse, Reverent Medium", 611, Rarity.UNCOMMON, mage.cards.t.ThalisseReverentMedium.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Prismatic Piper", 1, Rarity.COMMON, mage.cards.t.ThePrismaticPiper.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Prismatic Piper", 546, Rarity.COMMON, mage.cards.t.ThePrismaticPiper.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thirst for Knowledge", 103, Rarity.UNCOMMON, mage.cards.t.ThirstForKnowledge.class)); cards.add(new SetCardInfo("Thorn of the Black Rose", 154, Rarity.COMMON, mage.cards.t.ThornOfTheBlackRose.class)); cards.add(new SetCardInfo("Thornwood Falls", 498, Rarity.COMMON, mage.cards.t.ThornwoodFalls.class)); diff --git a/Mage.Sets/src/mage/sets/CommanderLegendsBattleForBaldursGate.java b/Mage.Sets/src/mage/sets/CommanderLegendsBattleForBaldursGate.java new file mode 100644 index 00000000000..4fea850afc5 --- /dev/null +++ b/Mage.Sets/src/mage/sets/CommanderLegendsBattleForBaldursGate.java @@ -0,0 +1,38 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class CommanderLegendsBattleForBaldursGate extends ExpansionSet { + + private static final CommanderLegendsBattleForBaldursGate instance = new CommanderLegendsBattleForBaldursGate(); + + public static CommanderLegendsBattleForBaldursGate getInstance() { + return instance; + } + + private CommanderLegendsBattleForBaldursGate() { + super("Commander Legends: Battle for Baldur's Gate", "CLB", ExpansionSet.buildDate(2022, 6, 10), SetType.SUPPLEMENTAL); + this.blockName = "Commander Legends"; + this.hasBasicLands = false; + this.hasBoosters = false; // temporary + + cards.add(new SetCardInfo("Ancient Brass Dragon", 111, Rarity.MYTHIC, mage.cards.a.AncientBrassDragon.class)); + cards.add(new SetCardInfo("Bountiful Promenade", 348, Rarity.RARE, mage.cards.b.BountifulPromenade.class)); + cards.add(new SetCardInfo("Elder Brain", 125, Rarity.RARE, mage.cards.e.ElderBrain.class)); + cards.add(new SetCardInfo("Fireball", 175, Rarity.UNCOMMON, mage.cards.f.Fireball.class)); + cards.add(new SetCardInfo("Lightning Bolt", 187, Rarity.COMMON, mage.cards.l.LightningBolt.class)); + cards.add(new SetCardInfo("Luxury Suite", 355, Rarity.RARE, mage.cards.l.LuxurySuite.class)); + cards.add(new SetCardInfo("Minsc & Boo, Timeless Heroes", 285, Rarity.MYTHIC, mage.cards.m.MinscBooTimelessHeroes.class)); + cards.add(new SetCardInfo("Morphic Pool", 357, Rarity.RARE, mage.cards.m.MorphicPool.class)); + cards.add(new SetCardInfo("Reflecting Pool", 358, Rarity.RARE, mage.cards.r.ReflectingPool.class)); + cards.add(new SetCardInfo("Sea of Clouds", 360, Rarity.RARE, mage.cards.s.SeaOfClouds.class)); + cards.add(new SetCardInfo("Spire Garden", 361, Rarity.RARE, mage.cards.s.SpireGarden.class)); + cards.add(new SetCardInfo("Wand of Wonder", 204, Rarity.RARE, mage.cards.w.WandOfWonder.class)); + cards.add(new SetCardInfo("Zevlor, Elturel Exile", 296, Rarity.RARE, mage.cards.z.ZevlorElturelExile.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/ConspiracyTakeTheCrown.java b/Mage.Sets/src/mage/sets/ConspiracyTakeTheCrown.java index 603c9bb55aa..21b01f34041 100644 --- a/Mage.Sets/src/mage/sets/ConspiracyTakeTheCrown.java +++ b/Mage.Sets/src/mage/sets/ConspiracyTakeTheCrown.java @@ -26,6 +26,7 @@ public final class ConspiracyTakeTheCrown extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; + this.maxCardNumberInBooster = 221; cards.add(new SetCardInfo("Absorb Vis", 126, Rarity.COMMON, mage.cards.a.AbsorbVis.class)); cards.add(new SetCardInfo("Adriana, Captain of the Guard", 73, Rarity.RARE, mage.cards.a.AdrianaCaptainOfTheGuard.class)); cards.add(new SetCardInfo("Affa Guard Hound", 81, Rarity.UNCOMMON, mage.cards.a.AffaGuardHound.class)); @@ -130,7 +131,8 @@ public final class ConspiracyTakeTheCrown extends ExpansionSet { cards.add(new SetCardInfo("Jeering Homunculus", 33, Rarity.COMMON, mage.cards.j.JeeringHomunculus.class)); cards.add(new SetCardInfo("Juniper Order Ranger", 204, Rarity.UNCOMMON, mage.cards.j.JuniperOrderRanger.class)); cards.add(new SetCardInfo("Kami of the Crescent Moon", 113, Rarity.RARE, mage.cards.k.KamiOfTheCrescentMoon.class)); - cards.add(new SetCardInfo("Kaya, Ghost Assassin", 75, Rarity.MYTHIC, mage.cards.k.KayaGhostAssassin.class)); + cards.add(new SetCardInfo("Kaya, Ghost Assassin", 75, Rarity.MYTHIC, mage.cards.k.KayaGhostAssassin.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kaya, Ghost Assassin", 222, Rarity.MYTHIC, mage.cards.k.KayaGhostAssassin.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Keeper of Keys", 34, Rarity.RARE, mage.cards.k.KeeperOfKeys.class)); cards.add(new SetCardInfo("Keepsake Gorgon", 141, Rarity.UNCOMMON, mage.cards.k.KeepsakeGorgon.class)); cards.add(new SetCardInfo("Kill Shot", 94, Rarity.COMMON, mage.cards.k.KillShot.class)); diff --git a/Mage.Sets/src/mage/sets/CrimsonVowCommander.java b/Mage.Sets/src/mage/sets/CrimsonVowCommander.java index b12fde7584c..1046a181864 100644 --- a/Mage.Sets/src/mage/sets/CrimsonVowCommander.java +++ b/Mage.Sets/src/mage/sets/CrimsonVowCommander.java @@ -25,7 +25,8 @@ public final class CrimsonVowCommander extends ExpansionSet { cards.add(new SetCardInfo("Anowon, the Ruin Sage", 118, Rarity.RARE, mage.cards.a.AnowonTheRuinSage.class)); cards.add(new SetCardInfo("Arcane Denial", 102, Rarity.COMMON, mage.cards.a.ArcaneDenial.class)); cards.add(new SetCardInfo("Arcane Signet", 159, Rarity.COMMON, mage.cards.a.ArcaneSignet.class)); - cards.add(new SetCardInfo("Arterial Alchemy", 23, Rarity.RARE, mage.cards.a.ArterialAlchemy.class)); + cards.add(new SetCardInfo("Arterial Alchemy", 23, Rarity.RARE, mage.cards.a.ArterialAlchemy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Arterial Alchemy", 61, Rarity.RARE, mage.cards.a.ArterialAlchemy.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Avacyn's Judgment", 142, Rarity.RARE, mage.cards.a.AvacynsJudgment.class)); cards.add(new SetCardInfo("Azorius Chancery", 171, Rarity.UNCOMMON, mage.cards.a.AzoriusChancery.class)); cards.add(new SetCardInfo("Azorius Locket", 160, Rarity.COMMON, mage.cards.a.AzoriusLocket.class)); @@ -38,8 +39,10 @@ public final class CrimsonVowCommander extends ExpansionSet { cards.add(new SetCardInfo("Bloodsworn Steward", 144, Rarity.RARE, mage.cards.b.BloodswornSteward.class)); cards.add(new SetCardInfo("Bloodtracker", 122, Rarity.RARE, mage.cards.b.Bloodtracker.class)); cards.add(new SetCardInfo("Boreas Charger", 79, Rarity.RARE, mage.cards.b.BoreasCharger.class)); - cards.add(new SetCardInfo("Breath of the Sleepless", 11, Rarity.RARE, mage.cards.b.BreathOfTheSleepless.class)); - cards.add(new SetCardInfo("Breathkeeper Seraph", 31, Rarity.RARE, mage.cards.b.BreathkeeperSeraph.class)); + cards.add(new SetCardInfo("Breath of the Sleepless", 11, Rarity.RARE, mage.cards.b.BreathOfTheSleepless.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Breath of the Sleepless", 49, Rarity.RARE, mage.cards.b.BreathOfTheSleepless.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Breathkeeper Seraph", 31, Rarity.RARE, mage.cards.b.BreathkeeperSeraph.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Breathkeeper Seraph", 69, Rarity.RARE, mage.cards.b.BreathkeeperSeraph.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Butcher of Malakir", 123, Rarity.RARE, mage.cards.b.ButcherOfMalakir.class)); cards.add(new SetCardInfo("Bygone Bishop", 80, Rarity.RARE, mage.cards.b.BygoneBishop.class)); cards.add(new SetCardInfo("Champion of Dusk", 124, Rarity.RARE, mage.cards.c.ChampionOfDusk.class)); @@ -48,22 +51,27 @@ public final class CrimsonVowCommander extends ExpansionSet { cards.add(new SetCardInfo("Commander's Sphere", 163, Rarity.COMMON, mage.cards.c.CommandersSphere.class)); cards.add(new SetCardInfo("Cordial Vampire", 125, Rarity.RARE, mage.cards.c.CordialVampire.class)); cards.add(new SetCardInfo("Crimson Honor Guard", 145, Rarity.RARE, mage.cards.c.CrimsonHonorGuard.class)); - cards.add(new SetCardInfo("Crossway Troublemakers", 17, Rarity.RARE, mage.cards.c.CrosswayTroublemakers.class)); + cards.add(new SetCardInfo("Crossway Troublemakers", 17, Rarity.RARE, mage.cards.c.CrosswayTroublemakers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Crossway Troublemakers", 55, Rarity.RARE, mage.cards.c.CrosswayTroublemakers.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Crush Contraband", 81, Rarity.UNCOMMON, mage.cards.c.CrushContraband.class)); cards.add(new SetCardInfo("Custodi Soulbinders", 82, Rarity.RARE, mage.cards.c.CustodiSoulbinders.class)); cards.add(new SetCardInfo("Custodi Squire", 83, Rarity.COMMON, mage.cards.c.CustodiSquire.class)); cards.add(new SetCardInfo("Damnable Pact", 126, Rarity.RARE, mage.cards.d.DamnablePact.class)); cards.add(new SetCardInfo("Dark Impostor", 127, Rarity.RARE, mage.cards.d.DarkImpostor.class)); cards.add(new SetCardInfo("Darksteel Mutation", 84, Rarity.UNCOMMON, mage.cards.d.DarksteelMutation.class)); - cards.add(new SetCardInfo("Disorder in the Court", 29, Rarity.RARE, mage.cards.d.DisorderInTheCourt.class)); + cards.add(new SetCardInfo("Disorder in the Court", 29, Rarity.RARE, mage.cards.d.DisorderInTheCourt.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Disorder in the Court", 67, Rarity.RARE, mage.cards.d.DisorderInTheCourt.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Distant Melody", 103, Rarity.COMMON, mage.cards.d.DistantMelody.class)); cards.add(new SetCardInfo("Donal, Herald of Wings", 3, Rarity.MYTHIC, mage.cards.d.DonalHeraldOfWings.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Donal, Herald of Wings", 41, Rarity.MYTHIC, mage.cards.d.DonalHeraldOfWings.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Doom Weaver", 34, Rarity.RARE, mage.cards.d.DoomWeaver.class)); + cards.add(new SetCardInfo("Doom Weaver", 34, Rarity.RARE, mage.cards.d.DoomWeaver.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Doom Weaver", 72, Rarity.RARE, mage.cards.d.DoomWeaver.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dovin, Grand Arbiter", 153, Rarity.MYTHIC, mage.cards.d.DovinGrandArbiter.class)); cards.add(new SetCardInfo("Drogskol Captain", 154, Rarity.UNCOMMON, mage.cards.d.DrogskolCaptain.class)); - cards.add(new SetCardInfo("Drogskol Reinforcements", 5, Rarity.RARE, mage.cards.d.DrogskolReinforcements.class)); - cards.add(new SetCardInfo("Ethereal Investigator", 12, Rarity.RARE, mage.cards.e.EtherealInvestigator.class)); + cards.add(new SetCardInfo("Drogskol Reinforcements", 43, Rarity.RARE, mage.cards.d.DrogskolReinforcements.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Drogskol Reinforcements", 5, Rarity.RARE, mage.cards.d.DrogskolReinforcements.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ethereal Investigator", 12, Rarity.RARE, mage.cards.e.EtherealInvestigator.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ethereal Investigator", 50, Rarity.RARE, mage.cards.e.EtherealInvestigator.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Exotic Orchard", 173, Rarity.RARE, mage.cards.e.ExoticOrchard.class)); cards.add(new SetCardInfo("Falkenrath Gorger", 146, Rarity.RARE, mage.cards.f.FalkenrathGorger.class)); cards.add(new SetCardInfo("Falkenrath Noble", 128, Rarity.UNCOMMON, mage.cards.f.FalkenrathNoble.class)); @@ -76,30 +84,42 @@ public final class CrimsonVowCommander extends ExpansionSet { cards.add(new SetCardInfo("Geist of Saint Traft", 155, Rarity.MYTHIC, mage.cards.g.GeistOfSaintTraft.class)); cards.add(new SetCardInfo("Ghostly Pilferer", 105, Rarity.RARE, mage.cards.g.GhostlyPilferer.class)); cards.add(new SetCardInfo("Ghostly Prison", 87, Rarity.UNCOMMON, mage.cards.g.GhostlyPrison.class)); - cards.add(new SetCardInfo("Glass-Cast Heart", 18, Rarity.RARE, mage.cards.g.GlassCastHeart.class)); + cards.add(new SetCardInfo("Glass-Cast Heart", 18, Rarity.RARE, mage.cards.g.GlassCastHeart.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Glass-Cast Heart", 56, Rarity.RARE, mage.cards.g.GlassCastHeart.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hallowed Spiritkeeper", 88, Rarity.RARE, mage.cards.h.HallowedSpiritkeeper.class)); cards.add(new SetCardInfo("Hanged Executioner", 89, Rarity.RARE, mage.cards.h.HangedExecutioner.class)); - cards.add(new SetCardInfo("Haunted Library", 6, Rarity.RARE, mage.cards.h.HauntedLibrary.class)); - cards.add(new SetCardInfo("Haunting Imitation", 13, Rarity.RARE, mage.cards.h.HauntingImitation.class)); - cards.add(new SetCardInfo("Hollowhenge Overlord", 36, Rarity.RARE, mage.cards.h.HollowhengeOverlord.class)); - cards.add(new SetCardInfo("Imperious Mindbreaker", 33, Rarity.RARE, mage.cards.i.ImperiousMindbreaker.class)); - cards.add(new SetCardInfo("Imposing Grandeur", 24, Rarity.RARE, mage.cards.i.ImposingGrandeur.class)); + cards.add(new SetCardInfo("Haunted Library", 44, Rarity.RARE, mage.cards.h.HauntedLibrary.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Haunted Library", 6, Rarity.RARE, mage.cards.h.HauntedLibrary.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Haunting Imitation", 13, Rarity.RARE, mage.cards.h.HauntingImitation.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Haunting Imitation", 51, Rarity.RARE, mage.cards.h.HauntingImitation.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hollowhenge Overlord", 36, Rarity.RARE, mage.cards.h.HollowhengeOverlord.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hollowhenge Overlord", 74, Rarity.RARE, mage.cards.h.HollowhengeOverlord.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Imperious Mindbreaker", 33, Rarity.RARE, mage.cards.i.ImperiousMindbreaker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Imperious Mindbreaker", 71, Rarity.RARE, mage.cards.i.ImperiousMindbreaker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Imposing Grandeur", 24, Rarity.RARE, mage.cards.i.ImposingGrandeur.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Imposing Grandeur", 62, Rarity.RARE, mage.cards.i.ImposingGrandeur.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Imprisoned in the Moon", 106, Rarity.RARE, mage.cards.i.ImprisonedInTheMoon.class)); cards.add(new SetCardInfo("Indulgent Aristocrat", 130, Rarity.UNCOMMON, mage.cards.i.IndulgentAristocrat.class)); - cards.add(new SetCardInfo("Kamber, the Plunderer", 19, Rarity.RARE, mage.cards.k.KamberThePlunderer.class)); + cards.add(new SetCardInfo("Kamber, the Plunderer", 19, Rarity.RARE, mage.cards.k.KamberThePlunderer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kamber, the Plunderer", 57, Rarity.RARE, mage.cards.k.KamberThePlunderer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kami of the Crescent Moon", 107, Rarity.RARE, mage.cards.k.KamiOfTheCrescentMoon.class)); cards.add(new SetCardInfo("Karmic Guide", 90, Rarity.RARE, mage.cards.k.KarmicGuide.class)); cards.add(new SetCardInfo("Kirtar's Wrath", 91, Rarity.RARE, mage.cards.k.KirtarsWrath.class)); cards.add(new SetCardInfo("Knight of the White Orchid", 92, Rarity.RARE, mage.cards.k.KnightOfTheWhiteOrchid.class)); - cards.add(new SetCardInfo("Laurine, the Diversion", 25, Rarity.RARE, mage.cards.l.LaurineTheDiversion.class)); + cards.add(new SetCardInfo("Laurine, the Diversion", 25, Rarity.RARE, mage.cards.l.LaurineTheDiversion.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Laurine, the Diversion", 63, Rarity.RARE, mage.cards.l.LaurineTheDiversion.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Malakir Bloodwitch", 131, Rarity.RARE, mage.cards.m.MalakirBloodwitch.class)); cards.add(new SetCardInfo("Marble Diamond", 165, Rarity.COMMON, mage.cards.m.MarbleDiamond.class)); - cards.add(new SetCardInfo("Markov Enforcer", 26, Rarity.RARE, mage.cards.m.MarkovEnforcer.class)); + cards.add(new SetCardInfo("Markov Enforcer", 26, Rarity.RARE, mage.cards.m.MarkovEnforcer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Markov Enforcer", 64, Rarity.RARE, mage.cards.m.MarkovEnforcer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mentor of the Meek", 93, Rarity.RARE, mage.cards.m.MentorOfTheMeek.class)); - cards.add(new SetCardInfo("Midnight Arsonist", 27, Rarity.RARE, mage.cards.m.MidnightArsonist.class)); + cards.add(new SetCardInfo("Midnight Arsonist", 27, Rarity.RARE, mage.cards.m.MidnightArsonist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Midnight Arsonist", 65, Rarity.RARE, mage.cards.m.MidnightArsonist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Midnight Clock", 108, Rarity.RARE, mage.cards.m.MidnightClock.class)); - cards.add(new SetCardInfo("Millicent, Restless Revenant", 1, Rarity.MYTHIC, mage.cards.m.MillicentRestlessRevenant.class)); - cards.add(new SetCardInfo("Mirage Phalanx", 35, Rarity.RARE, mage.cards.m.MiragePhalanx.class)); + cards.add(new SetCardInfo("Millicent, Restless Revenant", 1, Rarity.MYTHIC, mage.cards.m.MillicentRestlessRevenant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Millicent, Restless Revenant", 39, Rarity.MYTHIC, mage.cards.m.MillicentRestlessRevenant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mirage Phalanx", 35, Rarity.RARE, mage.cards.m.MiragePhalanx.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mirage Phalanx", 73, Rarity.RARE, mage.cards.m.MiragePhalanx.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mirror Entity", 94, Rarity.RARE, mage.cards.m.MirrorEntity.class)); cards.add(new SetCardInfo("Mob Rule", 147, Rarity.RARE, mage.cards.m.MobRule.class)); cards.add(new SetCardInfo("Molten Echoes", 148, Rarity.RARE, mage.cards.m.MoltenEchoes.class)); @@ -109,45 +129,57 @@ public final class CrimsonVowCommander extends ExpansionSet { cards.add(new SetCardInfo("Necropolis Regent", 132, Rarity.MYTHIC, mage.cards.n.NecropolisRegent.class)); cards.add(new SetCardInfo("Night's Whisper", 133, Rarity.COMMON, mage.cards.n.NightsWhisper.class)); cards.add(new SetCardInfo("Nirkana Revenant", 134, Rarity.MYTHIC, mage.cards.n.NirkanaRevenant.class)); - cards.add(new SetCardInfo("Occult Epiphany", 14, Rarity.RARE, mage.cards.o.OccultEpiphany.class)); - cards.add(new SetCardInfo("Olivia's Wrath", 20, Rarity.RARE, mage.cards.o.OliviasWrath.class)); + cards.add(new SetCardInfo("Occult Epiphany", 14, Rarity.RARE, mage.cards.o.OccultEpiphany.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Occult Epiphany", 52, Rarity.RARE, mage.cards.o.OccultEpiphany.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Olivia's Wrath", 20, Rarity.RARE, mage.cards.o.OliviasWrath.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Olivia's Wrath", 58, Rarity.RARE, mage.cards.o.OliviasWrath.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Oyobi, Who Split the Heavens", 95, Rarity.RARE, mage.cards.o.OyobiWhoSplitTheHeavens.class)); cards.add(new SetCardInfo("Path of Ancestry", 177, Rarity.COMMON, mage.cards.p.PathOfAncestry.class)); cards.add(new SetCardInfo("Patron of the Vein", 135, Rarity.RARE, mage.cards.p.PatronOfTheVein.class)); cards.add(new SetCardInfo("Port Town", 178, Rarity.RARE, mage.cards.p.PortTown.class)); cards.add(new SetCardInfo("Prairie Stream", 179, Rarity.RARE, mage.cards.p.PrairieStream.class)); - cards.add(new SetCardInfo("Predators' Hour", 21, Rarity.RARE, mage.cards.p.PredatorsHour.class)); - cards.add(new SetCardInfo("Priest of the Blessed Graf", 7, Rarity.RARE, mage.cards.p.PriestOfTheBlessedGraf.class)); + cards.add(new SetCardInfo("Predators' Hour", 21, Rarity.RARE, mage.cards.p.PredatorsHour.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Predators' Hour", 59, Rarity.RARE, mage.cards.p.PredatorsHour.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Priest of the Blessed Graf", 45, Rarity.RARE, mage.cards.p.PriestOfTheBlessedGraf.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Priest of the Blessed Graf", 7, Rarity.RARE, mage.cards.p.PriestOfTheBlessedGraf.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Promise of Bunrei", 96, Rarity.RARE, mage.cards.p.PromiseOfBunrei.class)); - cards.add(new SetCardInfo("Rakdos Carnarium", 180, Rarity.UNCOMMON, mage.cards.r.RakdosCarnarium.class)); + cards.add(new SetCardInfo("Rakdos Carnarium", 180, Rarity.COMMON, mage.cards.r.RakdosCarnarium.class)); cards.add(new SetCardInfo("Rakdos Charm", 156, Rarity.UNCOMMON, mage.cards.r.RakdosCharm.class)); cards.add(new SetCardInfo("Rakdos Signet", 166, Rarity.UNCOMMON, mage.cards.r.RakdosSignet.class)); cards.add(new SetCardInfo("Rakish Heir", 149, Rarity.UNCOMMON, mage.cards.r.RakishHeir.class)); cards.add(new SetCardInfo("Rattlechains", 110, Rarity.RARE, mage.cards.r.Rattlechains.class)); cards.add(new SetCardInfo("Reconnaissance Mission", 111, Rarity.UNCOMMON, mage.cards.r.ReconnaissanceMission.class)); cards.add(new SetCardInfo("Remorseful Cleric", 97, Rarity.RARE, mage.cards.r.RemorsefulCleric.class)); - cards.add(new SetCardInfo("Rhoda, Geist Avenger", 8, Rarity.RARE, mage.cards.r.RhodaGeistAvenger.class)); + cards.add(new SetCardInfo("Rhoda, Geist Avenger", 46, Rarity.RARE, mage.cards.r.RhodaGeistAvenger.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rhoda, Geist Avenger", 8, Rarity.RARE, mage.cards.r.RhodaGeistAvenger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sanctum Seeker", 136, Rarity.RARE, mage.cards.s.SanctumSeeker.class)); - cards.add(new SetCardInfo("Scion of Opulence", 28, Rarity.RARE, mage.cards.s.ScionOfOpulence.class)); + cards.add(new SetCardInfo("Scion of Opulence", 28, Rarity.RARE, mage.cards.s.ScionOfOpulence.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Scion of Opulence", 66, Rarity.RARE, mage.cards.s.ScionOfOpulence.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Shacklegeist", 112, Rarity.RARE, mage.cards.s.Shacklegeist.class)); cards.add(new SetCardInfo("Shadowblood Ridge", 181, Rarity.RARE, mage.cards.s.ShadowbloodRidge.class)); - cards.add(new SetCardInfo("Sinister Waltz", 30, Rarity.RARE, mage.cards.s.SinisterWaltz.class)); + cards.add(new SetCardInfo("Shadowgrange Archfiend", 22, Rarity.RARE, mage.cards.s.ShadowgrangeArchfiend.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Shadowgrange Archfiend", 60, Rarity.RARE, mage.cards.s.ShadowgrangeArchfiend.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sinister Waltz", 30, Rarity.RARE, mage.cards.s.SinisterWaltz.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sinister Waltz", 68, Rarity.RARE, mage.cards.s.SinisterWaltz.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sire of the Storm", 113, Rarity.UNCOMMON, mage.cards.s.SireOfTheStorm.class)); cards.add(new SetCardInfo("Sky Diamond", 167, Rarity.COMMON, mage.cards.s.SkyDiamond.class)); cards.add(new SetCardInfo("Skycloud Expanse", 182, Rarity.RARE, mage.cards.s.SkycloudExpanse.class)); cards.add(new SetCardInfo("Smoldering Marsh", 183, Rarity.RARE, mage.cards.s.SmolderingMarsh.class)); cards.add(new SetCardInfo("Sol Ring", 168, Rarity.UNCOMMON, mage.cards.s.SolRing.class)); + cards.add(new SetCardInfo("Spectral Arcanist", 15, Rarity.RARE, mage.cards.s.SpectralArcanist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spectral Arcanist", 53, Rarity.RARE, mage.cards.s.SpectralArcanist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Spectral Sailor", 114, Rarity.UNCOMMON, mage.cards.s.SpectralSailor.class)); cards.add(new SetCardInfo("Spectral Shepherd", 98, Rarity.UNCOMMON, mage.cards.s.SpectralShepherd.class)); cards.add(new SetCardInfo("Stensia Masquerade", 150, Rarity.UNCOMMON, mage.cards.s.StensiaMasquerade.class)); - cards.add(new SetCardInfo("Storm of Souls", 9, Rarity.RARE, mage.cards.s.StormOfSouls.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Storm of Souls", 47, Rarity.RARE, mage.cards.s.StormOfSouls.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Storm of Souls", 9, Rarity.RARE, mage.cards.s.StormOfSouls.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Strefan, Maurer Progenitor", 2, Rarity.MYTHIC, mage.cards.s.StrefanMaurerProgenitor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Strefan, Maurer Progenitor", 40, Rarity.MYTHIC, mage.cards.s.StrefanMaurerProgenitor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Stromkirk Captain", 157, Rarity.UNCOMMON, mage.cards.s.StromkirkCaptain.class)); cards.add(new SetCardInfo("Stromkirk Condemned", 137, Rarity.RARE, mage.cards.s.StromkirkCondemned.class)); cards.add(new SetCardInfo("Stromkirk Occultist", 151, Rarity.RARE, mage.cards.s.StromkirkOccultist.class)); - cards.add(new SetCardInfo("Sudden Salvation", 10, Rarity.RARE, mage.cards.s.SuddenSalvation.class)); + cards.add(new SetCardInfo("Sudden Salvation", 10, Rarity.RARE, mage.cards.s.SuddenSalvation.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sudden Salvation", 48, Rarity.RARE, mage.cards.s.SuddenSalvation.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Supreme Phantom", 115, Rarity.RARE, mage.cards.s.SupremePhantom.class)); cards.add(new SetCardInfo("Swiftfoot Boots", 169, Rarity.UNCOMMON, mage.cards.s.SwiftfootBoots.class)); cards.add(new SetCardInfo("Swords to Plowshares", 99, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); @@ -155,12 +187,15 @@ public final class CrimsonVowCommander extends ExpansionSet { cards.add(new SetCardInfo("Temple of Enlightenment", 185, Rarity.RARE, mage.cards.t.TempleOfEnlightenment.class)); cards.add(new SetCardInfo("Temple of Malice", 186, Rarity.RARE, mage.cards.t.TempleOfMalice.class)); cards.add(new SetCardInfo("Temple of the False God", 187, Rarity.UNCOMMON, mage.cards.t.TempleOfTheFalseGod.class)); - cards.add(new SetCardInfo("Thundering Mightmare", 37, Rarity.RARE, mage.cards.t.ThunderingMightmare.class)); - cards.add(new SetCardInfo("Timin, Youthful Geist", 16, Rarity.RARE, mage.cards.t.TiminYouthfulGeist.class)); + cards.add(new SetCardInfo("Thundering Mightmare", 37, Rarity.RARE, mage.cards.t.ThunderingMightmare.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Thundering Mightmare", 75, Rarity.RARE, mage.cards.t.ThunderingMightmare.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Timin, Youthful Geist", 16, Rarity.RARE, mage.cards.t.TiminYouthfulGeist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Timin, Youthful Geist", 54, Rarity.RARE, mage.cards.t.TiminYouthfulGeist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Timothar, Baron of Bats", 4, Rarity.MYTHIC, mage.cards.t.TimotharBaronOfBats.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Timothar, Baron of Bats", 42, Rarity.MYTHIC, mage.cards.t.TimotharBaronOfBats.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Twilight Drover", 100, Rarity.RARE, mage.cards.t.TwilightDrover.class)); - cards.add(new SetCardInfo("Umbris, Fear Manifest", 38, Rarity.MYTHIC, mage.cards.u.UmbrisFearManifest.class)); + cards.add(new SetCardInfo("Umbris, Fear Manifest", 38, Rarity.MYTHIC, mage.cards.u.UmbrisFearManifest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Umbris, Fear Manifest", 76, Rarity.MYTHIC, mage.cards.u.UmbrisFearManifest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Unclaimed Territory", 188, Rarity.UNCOMMON, mage.cards.u.UnclaimedTerritory.class)); cards.add(new SetCardInfo("Underworld Connections", 138, Rarity.RARE, mage.cards.u.UnderworldConnections.class)); cards.add(new SetCardInfo("Unstable Obelisk", 170, Rarity.UNCOMMON, mage.cards.u.UnstableObelisk.class)); @@ -169,7 +204,8 @@ public final class CrimsonVowCommander extends ExpansionSet { cards.add(new SetCardInfo("Vampiric Dragon", 158, Rarity.RARE, mage.cards.v.VampiricDragon.class)); cards.add(new SetCardInfo("Vandalblast", 152, Rarity.UNCOMMON, mage.cards.v.Vandalblast.class)); cards.add(new SetCardInfo("Verity Circle", 116, Rarity.RARE, mage.cards.v.VerityCircle.class)); - cards.add(new SetCardInfo("Wedding Ring", 32, Rarity.MYTHIC, mage.cards.w.WeddingRing.class)); + cards.add(new SetCardInfo("Wedding Ring", 32, Rarity.MYTHIC, mage.cards.w.WeddingRing.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wedding Ring", 70, Rarity.MYTHIC, mage.cards.w.WeddingRing.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Windborn Muse", 101, Rarity.RARE, mage.cards.w.WindbornMuse.class)); } } diff --git a/Mage.Sets/src/mage/sets/DoubleMasters.java b/Mage.Sets/src/mage/sets/DoubleMasters.java index c6d5a53ef21..a5d19747f80 100644 --- a/Mage.Sets/src/mage/sets/DoubleMasters.java +++ b/Mage.Sets/src/mage/sets/DoubleMasters.java @@ -437,18 +437,15 @@ class DoubleMastersCollator implements BoosterCollator { private final CardRun commonC = new CardRun(true, "18", "35", "4", "17", "2", "30", "12", "27", "3", "13", "33", "30", "18", "12", "35", "27", "4", "3", "17", "13", "2", "33", "12", "4", "13", "18", "27", "17", "33", "30", "35", "3", "2", "18", "35", "4", "17", "2", "30", "12", "27", "3", "13", "33", "30", "18", "12", "35", "27", "4", "3", "17", "13", "2", "33", "12", "4", "13", "18", "27", "17", "33", "30", "35", "3", "2", "18", "35", "4", "17", "2", "30", "12", "27", "3", "13", "33", "30", "18", "12", "35", "27", "4", "3", "17", "13", "2", "33", "12", "4", "13", "18", "27", "17", "33", "30", "35", "3", "2", "18", "35", "4", "17", "2", "30", "12", "27", "3", "13", "33", "30", "18", "12", "35", "27", "4", "3", "17", "13", "2", "33"); private final CardRun uncommonA = new CardRun(true, "315", "244", "73", "274", "208", "147", "202", "169", "290", "102", "65", "285", "220", "67", "186", "246", "112", "222", "22", "301", "86", "62", "228", "161", "101", "302", "54", "184", "220", "307", "73", "93", "15", "119", "202", "291", "169", "323", "102", "244", "201", "172", "312", "290", "37", "208", "246", "6", "65", "307", "86", "186", "67", "222", "141", "15", "315", "22", "274", "161", "37", "101", "285", "228", "184", "112", "147", "302", "172", "54", "220", "141", "301", "6", "93", "119", "169", "323", "291", "312", "201", "62", "244", "184", "102", "15", "222", "37", "290", "112", "147", "65", "285", "101", "315", "67", "202", "186", "274", "208", "323", "73", "307", "228", "86", "161", "119", "246", "312", "6", "22", "172", "301", "62", "302", "141", "93", "291", "54", "201"); private final CardRun uncommonB = new CardRun(true, "217", "23", "49", "245", "91", "194", "148", "71", "16", "125", "238", "198", "180", "36", "278", "99", "224", "38", "232", "123", "68", "258", "229", "310", "120", "242", "188", "25", "66", "267", "138", "178", "281", "199", "89", "194", "241", "23", "49", "91", "245", "166", "134", "238", "217", "148", "36", "265", "16", "125", "198", "232", "71", "100", "267", "229", "180", "68", "278", "123", "25", "99", "241", "38", "120", "258", "199", "188", "224", "281", "310", "49", "23", "66", "138", "178", "245", "217", "166", "134", "242", "89", "36", "265", "148", "100", "242", "198", "180", "25", "238", "16", "194", "38", "91", "71", "125", "278", "229", "310", "68", "232", "123", "178", "99", "258", "188", "120", "267", "199", "89", "224", "241", "66", "134", "166", "281", "138", "100", "265"); - private final CardRun rareA = new CardRun(false, "76", "231", "153", "77", "117", "118", "10", "43", "313", "158", "48", "85", "124", "252", "14", "167", "316", "318", "196", "127", "320", "130", "321", "97", "175", "271", "210", "272", "282", "26", "139", "103", "64", "325", "104", "179", "289", "32", "293", "326", "299", "327", "72", "109", "223", "225", "226", "75", "332", "113", "76", "231", "153", "77", "117", "118", "10", "43", "313", "158", "48", "85", "124", "252", "14", "167", "316", "318", "196", "127", "320", "130", "321", "97", "175", "271", "210", "272", "282", "26", "139", "103", "64", "325", "104", "179", "289", "32", "293", "326", "299", "327", "72", "109", "223", "225", "226", "75", "332", "113", "190", "8", "192", "240", "81", "314", "248", "164", "253", "51", "131", "204", "205", "20", "206", "136", "275", "214", "218", "303"); - private final CardRun rareB = new CardRun(false, "122", "82", "317", "55", "264", "174", "324", "24", "284", "215", "328"); - private final CardRun rareC = new CardRun(false, "189", "7", "311", "155", "236", "193", "11", "47", "249", "195", "128", "170", "260", "132", "203", "21", "268", "98", "57", "322", "209", "177", "279", "61", "212", "219", "292", "34", "183", "110", "149", "227", "306"); - private final CardRun rareD = new CardRun(false, "309", "191", "233", "9", "156", "243", "88", "251", "319", "53", "129", "200", "171", "19", "266", "207", "58", "211", "276", "213", "142", "286", "106", "31", "221", "182", "39"); - private final CardRun rareE = new CardRun(false, "5", "41", "152", "234", "235", "197", "94", "56", "1", "270", "107", "145", "295", "296", "297", "298", "300", "216", "185", "308"); + private final CardRun rareSlot1 = new CardRun(false, "76", "231", "153", "77", "117", "118", "10", "43", "313", "158", "48", "85", "124", "252", "14", "167", "316", "318", "196", "127", "320", "130", "321", "97", "175", "271", "210", "272", "282", "26", "139", "103", "64", "325", "104", "179", "289", "32", "293", "326", "299", "327", "72", "109", "223", "225", "226", "75", "332", "113", "76", "231", "153", "77", "117", "118", "10", "43", "313", "158", "48", "85", "124", "252", "14", "167", "316", "318", "196", "127", "320", "130", "321", "97", "175", "271", "210", "272", "282", "26", "139", "103", "64", "325", "104", "179", "289", "32", "293", "326", "299", "327", "72", "109", "223", "225", "226", "75", "332", "113", "190", "8", "192", "240", "81", "314", "248", "164", "253", "51", "131", "204", "205", "20", "206", "136", "275", "214", "218", "303", "122", "82", "317", "55", "264", "174", "324", "24", "284", "215", "328", "122", "82", "317", "55", "264", "174", "324", "24", "284", "215", "328"); + private final CardRun rareSlot2 = new CardRun(false, "189", "7", "311", "155", "236", "193", "11", "47", "249", "195", "128", "170", "260", "132", "203", "21", "268", "98", "57", "322", "209", "177", "279", "61", "212", "219", "292", "34", "183", "110", "149", "227", "306", "189", "7", "311", "155", "236", "193", "11", "47", "249", "195", "128", "170", "260", "132", "203", "21", "268", "98", "57", "322", "209", "177", "279", "61", "212", "219", "292", "34", "183", "110", "149", "227", "306", "309", "191", "233", "9", "156", "243", "88", "251", "319", "53", "129", "200", "171", "19", "266", "207", "58", "211", "276", "213", "142", "286", "106", "31", "221", "182", "39", "309", "191", "233", "9", "156", "243", "88", "251", "319", "53", "129", "200", "171", "19", "266", "207", "58", "211", "276", "213", "142", "286", "106", "31", "221", "182", "39", "5", "41", "152", "234", "235", "197", "94", "56", "1", "270", "107", "145", "295", "296", "297", "298", "300", "216", "185", "308"); private final CardRun foilCommonA = new CardRun(true, "126", "40", "28", "144", "69", "35", "114", "63", "4", "146", "74", "30", "143", "52", "33", "137", "60", "2", "121", "46", "269", "12", "135", "42", "29", "115", "59", "17", "140", "44", "18", "116", "70", "28", "133", "63", "13", "114", "52", "3", "150", "40", "27", "126", "50", "35", "135", "69", "4", "137", "269", "60", "30", "144", "74", "17", "18", "133", "44", "13", "150", "70", "29", "115", "59", "3", "116", "121", "45", "33", "146", "46", "12", "140", "42", "2", "143", "50", "144", "74", "12", "121", "50", "4", "269", "143", "63", "28", "17", "69", "35", "135", "45", "27", "126", "40", "30", "114", "52", "116", "60", "33", "137", "46", "2", "146", "42", "29", "133", "70", "13", "150", "44", "18", "140", "59", "3", "115", "45", "27"); private final CardRun foilCommonB = new CardRun(true, "95", "160", "168", "277", "80", "159", "230", "108", "157", "330", "78", "163", "287", "83", "173", "329", "108", "168", "247", "90", "154", "283", "80", "261", "262", "105", "187", "294", "79", "165", "331", "304", "84", "163", "162", "277", "111", "151", "330", "92", "157", "304", "96", "160", "230", "95", "181", "331", "78", "176", "287", "84", "159", "256", "87", "165", "261", "79", "330", "154", "294", "105", "173", "259", "83", "187", "329", "111", "168", "283", "92", "151", "262", "108", "162", "230", "80", "163", "247", "95", "157", "277", "90", "159", "331", "96", "176", "287", "78", "154", "259", "84", "160", "256", "105", "329", "181", "261", "79", "165", "304", "83", "151", "262", "111", "173", "283", "87", "187", "294", "92", "90", "162", "259", "96", "181", "247", "87", "176", "256"); private final CardRun foilCommonC = new CardRun(false, "237", "239", "250", "254", "255", "257", "263", "273", "280", "288", "305"); private final CardRun foilUncommonA = new CardRun(false, "6", "119", "312", "244", "161", "246", "315", "86", "93", "15", "169", "201", "54", "172", "202", "208", "22", "274", "323", "101", "102", "62", "141", "65", "285", "67", "220", "290", "291", "147", "222", "301", "302", "73", "184", "37", "112", "186", "228", "307"); private final CardRun foilUncommonB = new CardRun(false, "310", "232", "120", "238", "241", "242", "245", "194", "123", "89", "91", "166", "49", "16", "125", "198", "199", "258", "265", "134", "267", "99", "23", "278", "100", "25", "281", "138", "178", "66", "217", "68", "180", "71", "36", "148", "224", "38", "188", "229"); - private final CardRun foilRareA = new CardRun(false, "309", "231", "76", "189", "7", "153", "191", "233", "77", "9", "117", "311", "118", "155", "10", "236", "43", "193", "313", "156", "158", "243", "11", "122", "47", "82", "48", "85", "88", "124", "249", "251", "252", "14", "167", "195", "316", "317", "318", "196", "319", "127", "128", "53", "320", "170", "129", "260", "200", "171", "130", "321", "55", "132", "264", "203", "19", "266", "21", "174", "268", "207", "97", "98", "175", "57", "58", "271", "322", "209", "210", "211", "272", "276", "324", "177", "279", "24", "61", "282", "212", "26", "139", "284", "103", "64", "213", "142", "325", "104", "215", "286", "179", "219", "106", "289", "31", "32", "292", "293", "326", "221", "299", "34", "182", "327", "72", "109", "183", "223", "110", "149", "328", "225", "226", "227", "306", "75", "332", "113", "39"); - private final CardRun foilRareB = new CardRun(false, "5", "41", "190", "8", "152", "234", "235", "192", "240", "81", "314", "248", "164", "253", "51", "197", "94", "131", "56", "204", "1", "205", "20", "206", "270", "136", "275", "214", "218", "107", "145", "295", "296", "297", "298", "300", "216", "303", "185", "308"); + private final CardRun foilRare = new CardRun(false, "309", "231", "76", "189", "7", "153", "191", "233", "77", "9", "117", "311", "118", "155", "10", "236", "43", "193", "313", "156", "158", "243", "11", "122", "47", "82", "48", "85", "88", "124", "249", "251", "252", "14", "167", "195", "316", "317", "318", "196", "319", "127", "128", "53", "320", "170", "129", "260", "200", "171", "130", "321", "55", "132", "264", "203", "19", "266", "21", "174", "268", "207", "97", "98", "175", "57", "58", "271", "322", "209", "210", "211", "272", "276", "324", "177", "279", "24", "61", "282", "212", "26", "139", "284", "103", "64", "213", "142", "325", "104", "215", "286", "179", "219", "106", "289", "31", "32", "292", "293", "326", "221", "299", "34", "182", "327", "72", "109", "183", "223", "110", "149", "328", "225", "226", "227", "306", "75", "332", "113", "39"); + private final CardRun foilMythic = new CardRun(false, "5", "41", "190", "8", "152", "234", "235", "192", "240", "81", "314", "248", "164", "253", "51", "197", "94", "131", "56", "204", "1", "205", "20", "206", "270", "136", "275", "214", "218", "107", "145", "295", "296", "297", "298", "300", "216", "303", "185", "308"); private final BoosterStructure AAAABBBC = new BoosterStructure( commonA, commonA, commonA, commonA, @@ -465,34 +462,29 @@ class DoubleMastersCollator implements BoosterCollator { ); private final BoosterStructure AAB = new BoosterStructure(uncommonA, uncommonA, uncommonB); private final BoosterStructure ABB = new BoosterStructure(uncommonA, uncommonB, uncommonB); - private final BoosterStructure R1 = new BoosterStructure(rareA, rareC); - private final BoosterStructure R2 = new BoosterStructure(rareA, rareD); - private final BoosterStructure R3 = new BoosterStructure(rareA, rareE); - private final BoosterStructure R4 = new BoosterStructure(rareB, rareC); - private final BoosterStructure R5 = new BoosterStructure(rareB, rareD); - private final BoosterStructure R6 = new BoosterStructure(rareB, rareE); + private final BoosterStructure R1 = new BoosterStructure(rareSlot1, rareSlot2); private final BoosterStructure F01 = new BoosterStructure(foilCommonA, foilCommonB); private final BoosterStructure F02 = new BoosterStructure(foilCommonA, foilCommonC); private final BoosterStructure F03 = new BoosterStructure(foilCommonA, foilUncommonA); private final BoosterStructure F04 = new BoosterStructure(foilCommonA, foilUncommonB); - private final BoosterStructure F05 = new BoosterStructure(foilCommonA, foilRareA); - private final BoosterStructure F06 = new BoosterStructure(foilCommonA, foilRareB); + private final BoosterStructure F05 = new BoosterStructure(foilCommonA, foilRare); + private final BoosterStructure F06 = new BoosterStructure(foilCommonA, foilMythic); private final BoosterStructure F07 = new BoosterStructure(foilCommonB, foilCommonC); private final BoosterStructure F08 = new BoosterStructure(foilCommonB, foilUncommonA); private final BoosterStructure F09 = new BoosterStructure(foilCommonB, foilUncommonB); - private final BoosterStructure F10 = new BoosterStructure(foilCommonB, foilRareA); - private final BoosterStructure F11 = new BoosterStructure(foilCommonB, foilRareB); + private final BoosterStructure F10 = new BoosterStructure(foilCommonB, foilRare); + private final BoosterStructure F11 = new BoosterStructure(foilCommonB, foilMythic); private final BoosterStructure F12 = new BoosterStructure(foilCommonC, foilUncommonA); private final BoosterStructure F13 = new BoosterStructure(foilCommonC, foilUncommonB); - private final BoosterStructure F14 = new BoosterStructure(foilCommonC, foilRareA); - private final BoosterStructure F15 = new BoosterStructure(foilCommonC, foilRareB); + private final BoosterStructure F14 = new BoosterStructure(foilCommonC, foilRare); + private final BoosterStructure F15 = new BoosterStructure(foilCommonC, foilMythic); private final BoosterStructure F16 = new BoosterStructure(foilUncommonA, foilUncommonB); - private final BoosterStructure F17 = new BoosterStructure(foilUncommonA, foilRareA); - private final BoosterStructure F18 = new BoosterStructure(foilUncommonA, foilRareB); - private final BoosterStructure F19 = new BoosterStructure(foilUncommonB, foilRareA); - private final BoosterStructure F20 = new BoosterStructure(foilUncommonB, foilRareB); - private final BoosterStructure F21 = new BoosterStructure(foilRareA, foilRareB); + private final BoosterStructure F17 = new BoosterStructure(foilUncommonA, foilRare); + private final BoosterStructure F18 = new BoosterStructure(foilUncommonA, foilMythic); + private final BoosterStructure F19 = new BoosterStructure(foilUncommonB, foilRare); + private final BoosterStructure F20 = new BoosterStructure(foilUncommonB, foilMythic); + private final BoosterStructure F21 = new BoosterStructure(foilRare, foilMythic); // In order for equal numbers of each common to exist, the average booster must contain: // 3.52 A commons (320 / 91) @@ -509,13 +501,8 @@ class DoubleMastersCollator implements BoosterCollator { AAABBBBC, AAAABBBC, AAABBBBC, AAAABBBC, AAABBBBC, AAAABBBC, AAABBBBC, AAAABBBC, AAABBBBC, AAAABBBC, AAABBBBC, AAAABBBB, AAAABBBB, AAAABBBB ); - private final RarityConfiguration uncommonRuns = new RarityConfiguration( - AAB, ABB - ); - private final RarityConfiguration rareRuns = new RarityConfiguration( - R1, R2, R3, - R4, R5, R6 - ); + private final RarityConfiguration uncommonRuns = new RarityConfiguration(AAB, ABB); + private final RarityConfiguration rareRuns = new RarityConfiguration(R1); private final RarityConfiguration foilRuns = new RarityConfiguration( F01, F01, F01, F01, F01, F01, diff --git a/Mage.Sets/src/mage/sets/ForgottenRealmsCommander.java b/Mage.Sets/src/mage/sets/ForgottenRealmsCommander.java index 37b5b0b584f..88292da050b 100644 --- a/Mage.Sets/src/mage/sets/ForgottenRealmsCommander.java +++ b/Mage.Sets/src/mage/sets/ForgottenRealmsCommander.java @@ -25,15 +25,18 @@ public final class ForgottenRealmsCommander extends ExpansionSet { cards.add(new SetCardInfo("Angelic Gift", 64, Rarity.COMMON, mage.cards.a.AngelicGift.class)); cards.add(new SetCardInfo("Anger", 113, Rarity.UNCOMMON, mage.cards.a.Anger.class)); cards.add(new SetCardInfo("Apex of Power", 114, Rarity.MYTHIC, mage.cards.a.ApexOfPower.class)); - cards.add(new SetCardInfo("Arcane Endeavor", 14, Rarity.RARE, mage.cards.a.ArcaneEndeavor.class)); + cards.add(new SetCardInfo("Arcane Endeavor", 14, Rarity.RARE, mage.cards.a.ArcaneEndeavor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Arcane Endeavor", 283, Rarity.RARE, mage.cards.a.ArcaneEndeavor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arcane Sanctum", 223, Rarity.UNCOMMON, mage.cards.a.ArcaneSanctum.class)); cards.add(new SetCardInfo("Arcane Signet", 197, Rarity.COMMON, mage.cards.a.ArcaneSignet.class)); cards.add(new SetCardInfo("Argentum Armor", 198, Rarity.RARE, mage.cards.a.ArgentumArmor.class)); cards.add(new SetCardInfo("Ashen Rider", 175, Rarity.MYTHIC, mage.cards.a.AshenRider.class)); cards.add(new SetCardInfo("Atarka, World Render", 176, Rarity.RARE, mage.cards.a.AtarkaWorldRender.class)); cards.add(new SetCardInfo("Azorius Chancery", 224, Rarity.UNCOMMON, mage.cards.a.AzoriusChancery.class)); - cards.add(new SetCardInfo("Bag of Devouring", 21, Rarity.RARE, mage.cards.b.BagOfDevouring.class)); - cards.add(new SetCardInfo("Bag of Tricks", 37, Rarity.RARE, mage.cards.b.BagOfTricks.class)); + cards.add(new SetCardInfo("Bag of Devouring", 21, Rarity.RARE, mage.cards.b.BagOfDevouring.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Bag of Devouring", 290, Rarity.RARE, mage.cards.b.BagOfDevouring.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Bag of Tricks", 306, Rarity.RARE, mage.cards.b.BagOfTricks.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Bag of Tricks", 37, Rarity.RARE, mage.cards.b.BagOfTricks.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Baleful Strix", 177, Rarity.RARE, mage.cards.b.BalefulStrix.class)); cards.add(new SetCardInfo("Bant Charm", 178, Rarity.UNCOMMON, mage.cards.b.BantCharm.class)); cards.add(new SetCardInfo("Bant Panorama", 225, Rarity.COMMON, mage.cards.b.BantPanorama.class)); @@ -41,8 +44,10 @@ public final class ForgottenRealmsCommander extends ExpansionSet { cards.add(new SetCardInfo("Beast Within", 152, Rarity.UNCOMMON, mage.cards.b.BeastWithin.class)); cards.add(new SetCardInfo("Bedevil", 179, Rarity.RARE, mage.cards.b.Bedevil.class)); cards.add(new SetCardInfo("Behemoth Sledge", 180, Rarity.UNCOMMON, mage.cards.b.BehemothSledge.class)); - cards.add(new SetCardInfo("Belt of Giant Strength", 38, Rarity.RARE, mage.cards.b.BeltOfGiantStrength.class)); - cards.add(new SetCardInfo("Berserker's Frenzy", 29, Rarity.RARE, mage.cards.b.BerserkersFrenzy.class)); + cards.add(new SetCardInfo("Belt of Giant Strength", 307, Rarity.RARE, mage.cards.b.BeltOfGiantStrength.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Belt of Giant Strength", 38, Rarity.RARE, mage.cards.b.BeltOfGiantStrength.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Berserker's Frenzy", 29, Rarity.RARE, mage.cards.b.BerserkersFrenzy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Berserker's Frenzy", 298, Rarity.RARE, mage.cards.b.BerserkersFrenzy.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bituminous Blast", 181, Rarity.UNCOMMON, mage.cards.b.BituminousBlast.class)); cards.add(new SetCardInfo("Bogardan Hellkite", 115, Rarity.MYTHIC, mage.cards.b.BogardanHellkite.class)); cards.add(new SetCardInfo("Bojuka Bog", 226, Rarity.COMMON, mage.cards.b.BojukaBog.class)); @@ -51,11 +56,13 @@ public final class ForgottenRealmsCommander extends ExpansionSet { cards.add(new SetCardInfo("Burnished Hart", 200, Rarity.UNCOMMON, mage.cards.b.BurnishedHart.class)); cards.add(new SetCardInfo("Canopy Vista", 227, Rarity.RARE, mage.cards.c.CanopyVista.class)); cards.add(new SetCardInfo("Cataclysmic Gearhulk", 65, Rarity.MYTHIC, mage.cards.c.CataclysmicGearhulk.class)); - cards.add(new SetCardInfo("Catti-brie of Mithral Hall", 44, Rarity.RARE, mage.cards.c.CattiBrieOfMithralHall.class)); + cards.add(new SetCardInfo("Catti-brie of Mithral Hall", 313, Rarity.RARE, mage.cards.c.CattiBrieOfMithralHall.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Catti-brie of Mithral Hall", 44, Rarity.RARE, mage.cards.c.CattiBrieOfMithralHall.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Chain Reaction", 116, Rarity.RARE, mage.cards.c.ChainReaction.class)); cards.add(new SetCardInfo("Chameleon Colossus", 153, Rarity.RARE, mage.cards.c.ChameleonColossus.class)); cards.add(new SetCardInfo("Champion of Wits", 80, Rarity.RARE, mage.cards.c.ChampionOfWits.class)); - cards.add(new SetCardInfo("Chaos Dragon", 30, Rarity.RARE, mage.cards.c.ChaosDragon.class)); + cards.add(new SetCardInfo("Chaos Dragon", 299, Rarity.RARE, mage.cards.c.ChaosDragon.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Chaos Dragon", 30, Rarity.RARE, mage.cards.c.ChaosDragon.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Chaos Wand", 201, Rarity.RARE, mage.cards.c.ChaosWand.class)); cards.add(new SetCardInfo("Chaos Warp", 117, Rarity.RARE, mage.cards.c.ChaosWarp.class)); cards.add(new SetCardInfo("Chittering Witch", 95, Rarity.RARE, mage.cards.c.ChitteringWitch.class)); @@ -75,11 +82,13 @@ public final class ForgottenRealmsCommander extends ExpansionSet { cards.add(new SetCardInfo("Cultivate", 155, Rarity.UNCOMMON, mage.cards.c.Cultivate.class)); cards.add(new SetCardInfo("Curator of Mysteries", 81, Rarity.RARE, mage.cards.c.CuratorOfMysteries.class)); cards.add(new SetCardInfo("Curse of Verbosity", 82, Rarity.UNCOMMON, mage.cards.c.CurseOfVerbosity.class)); - cards.add(new SetCardInfo("Danse Macabre", 22, Rarity.RARE, mage.cards.d.DanseMacabre.class)); + cards.add(new SetCardInfo("Danse Macabre", 22, Rarity.RARE, mage.cards.d.DanseMacabre.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Danse Macabre", 291, Rarity.RARE, mage.cards.d.DanseMacabre.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dark-Dweller Oracle", 119, Rarity.RARE, mage.cards.d.DarkDwellerOracle.class)); cards.add(new SetCardInfo("Darkwater Catacombs", 232, Rarity.RARE, mage.cards.d.DarkwaterCatacombs.class)); cards.add(new SetCardInfo("Dead Man's Chest", 97, Rarity.RARE, mage.cards.d.DeadMansChest.class)); - cards.add(new SetCardInfo("Death Tyrant", 23, Rarity.RARE, mage.cards.d.DeathTyrant.class)); + cards.add(new SetCardInfo("Death Tyrant", 23, Rarity.RARE, mage.cards.d.DeathTyrant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Death Tyrant", 292, Rarity.RARE, mage.cards.d.DeathTyrant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Decree of Savagery", 156, Rarity.RARE, mage.cards.d.DecreeOfSavagery.class)); cards.add(new SetCardInfo("Demanding Dragon", 120, Rarity.RARE, mage.cards.d.DemandingDragon.class)); cards.add(new SetCardInfo("Desert", 233, Rarity.UNCOMMON, mage.cards.d.Desert.class)); @@ -87,15 +96,18 @@ public final class ForgottenRealmsCommander extends ExpansionSet { cards.add(new SetCardInfo("Dimir Aqueduct", 234, Rarity.UNCOMMON, mage.cards.d.DimirAqueduct.class)); cards.add(new SetCardInfo("Dire Fleet Daredevil", 121, Rarity.RARE, mage.cards.d.DireFleetDaredevil.class)); cards.add(new SetCardInfo("Disrupt Decorum", 122, Rarity.RARE, mage.cards.d.DisruptDecorum.class)); - cards.add(new SetCardInfo("Diviner's Portent", 15, Rarity.RARE, mage.cards.d.DivinersPortent.class)); + cards.add(new SetCardInfo("Diviner's Portent", 15, Rarity.RARE, mage.cards.d.DivinersPortent.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Diviner's Portent", 284, Rarity.RARE, mage.cards.d.DivinersPortent.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Doomed Necromancer", 98, Rarity.RARE, mage.cards.d.DoomedNecromancer.class)); cards.add(new SetCardInfo("Dragon's Hoard", 204, Rarity.RARE, mage.cards.d.DragonsHoard.class)); - cards.add(new SetCardInfo("Dragonborn Champion", 45, Rarity.RARE, mage.cards.d.DragonbornChampion.class)); + cards.add(new SetCardInfo("Dragonborn Champion", 314, Rarity.RARE, mage.cards.d.DragonbornChampion.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Dragonborn Champion", 45, Rarity.RARE, mage.cards.d.DragonbornChampion.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dragonlord's Servant", 123, Rarity.UNCOMMON, mage.cards.d.DragonlordsServant.class)); cards.add(new SetCardInfo("Dragonmaster Outcast", 124, Rarity.MYTHIC, mage.cards.d.DragonmasterOutcast.class)); cards.add(new SetCardInfo("Dragonspeaker Shaman", 330, Rarity.UNCOMMON, mage.cards.d.DragonspeakerShaman.class)); cards.add(new SetCardInfo("Dream Pillager", 125, Rarity.RARE, mage.cards.d.DreamPillager.class)); - cards.add(new SetCardInfo("Druid of Purification", 39, Rarity.RARE, mage.cards.d.DruidOfPurification.class)); + cards.add(new SetCardInfo("Druid of Purification", 308, Rarity.RARE, mage.cards.d.DruidOfPurification.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Druid of Purification", 39, Rarity.RARE, mage.cards.d.DruidOfPurification.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ebony Fly", 60, Rarity.UNCOMMON, mage.cards.e.EbonyFly.class)); cards.add(new SetCardInfo("Eel Umbra", 83, Rarity.COMMON, mage.cards.e.EelUmbra.class)); cards.add(new SetCardInfo("Esper Panorama", 235, Rarity.COMMON, mage.cards.e.EsperPanorama.class)); @@ -104,67 +116,89 @@ public final class ForgottenRealmsCommander extends ExpansionSet { cards.add(new SetCardInfo("Exotic Orchard", 236, Rarity.RARE, mage.cards.e.ExoticOrchard.class)); cards.add(new SetCardInfo("Explore", 157, Rarity.COMMON, mage.cards.e.Explore.class)); cards.add(new SetCardInfo("Explorer's Scope", 205, Rarity.COMMON, mage.cards.e.ExplorersScope.class)); + cards.add(new SetCardInfo("Extract Brain", 315, Rarity.RARE, mage.cards.e.ExtractBrain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Extract Brain", 46, Rarity.RARE, mage.cards.e.ExtractBrain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fellwar Stone", 206, Rarity.UNCOMMON, mage.cards.f.FellwarStone.class)); cards.add(new SetCardInfo("Fertile Ground", 158, Rarity.COMMON, mage.cards.f.FertileGround.class)); - cards.add(new SetCardInfo("Fey Steed", 5, Rarity.RARE, mage.cards.f.FeySteed.class)); + cards.add(new SetCardInfo("Fevered Suspicion", 316, Rarity.RARE, mage.cards.f.FeveredSuspicion.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fevered Suspicion", 47, Rarity.RARE, mage.cards.f.FeveredSuspicion.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fey Steed", 274, Rarity.RARE, mage.cards.f.FeySteed.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fey Steed", 5, Rarity.RARE, mage.cards.f.FeySteed.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fiend of the Shadows", 99, Rarity.RARE, mage.cards.f.FiendOfTheShadows.class)); - cards.add(new SetCardInfo("Fiendlash", 31, Rarity.RARE, mage.cards.f.Fiendlash.class)); + cards.add(new SetCardInfo("Fiendlash", 300, Rarity.RARE, mage.cards.f.Fiendlash.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fiendlash", 31, Rarity.RARE, mage.cards.f.Fiendlash.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fleecemane Lion", 185, Rarity.RARE, mage.cards.f.FleecemaneLion.class)); cards.add(new SetCardInfo("Flood Plain", 237, Rarity.UNCOMMON, mage.cards.f.FloodPlain.class)); cards.add(new SetCardInfo("Forbidden Alchemy", 84, Rarity.UNCOMMON, mage.cards.f.ForbiddenAlchemy.class)); cards.add(new SetCardInfo("Foreboding Ruins", 238, Rarity.RARE, mage.cards.f.ForebodingRuins.class)); cards.add(new SetCardInfo("Fortified Village", 239, Rarity.RARE, mage.cards.f.FortifiedVillage.class)); - cards.add(new SetCardInfo("Galea, Kindler of Hope", 1, Rarity.MYTHIC, mage.cards.g.GaleaKindlerOfHope.class)); + cards.add(new SetCardInfo("Galea, Kindler of Hope", 1, Rarity.MYTHIC, mage.cards.g.GaleaKindlerOfHope.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Galea, Kindler of Hope", 317, Rarity.MYTHIC, mage.cards.g.GaleaKindlerOfHope.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Game Trail", 240, Rarity.RARE, mage.cards.g.GameTrail.class)); cards.add(new SetCardInfo("Garruk's Uprising", 159, Rarity.UNCOMMON, mage.cards.g.GarruksUprising.class)); cards.add(new SetCardInfo("Geier Reach Sanitarium", 241, Rarity.RARE, mage.cards.g.GeierReachSanitarium.class)); cards.add(new SetCardInfo("Gonti, Lord of Luxury", 100, Rarity.RARE, mage.cards.g.GontiLordOfLuxury.class)); cards.add(new SetCardInfo("Grasslands", 242, Rarity.UNCOMMON, mage.cards.g.Grasslands.class)); cards.add(new SetCardInfo("Gratuitous Violence", 127, Rarity.RARE, mage.cards.g.GratuitousViolence.class)); - cards.add(new SetCardInfo("Grave Endeavor", 24, Rarity.RARE, mage.cards.g.GraveEndeavor.class)); + cards.add(new SetCardInfo("Grave Endeavor", 24, Rarity.RARE, mage.cards.g.GraveEndeavor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Grave Endeavor", 293, Rarity.RARE, mage.cards.g.GraveEndeavor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Greater Good", 160, Rarity.RARE, mage.cards.g.GreaterGood.class)); - cards.add(new SetCardInfo("Grim Hireling", 25, Rarity.RARE, mage.cards.g.GrimHireling.class)); - cards.add(new SetCardInfo("Gruul Signet", 207, Rarity.UNCOMMON, mage.cards.g.GruulSignet.class)); + cards.add(new SetCardInfo("Grim Hireling", 25, Rarity.RARE, mage.cards.g.GrimHireling.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Grim Hireling", 294, Rarity.RARE, mage.cards.g.GrimHireling.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gruul Signet", 207, Rarity.COMMON, mage.cards.g.GruulSignet.class)); cards.add(new SetCardInfo("Gruul Turf", 243, Rarity.UNCOMMON, mage.cards.g.GruulTurf.class)); cards.add(new SetCardInfo("Gryff's Boon", 67, Rarity.UNCOMMON, mage.cards.g.GryffsBoon.class)); cards.add(new SetCardInfo("Halimar Depths", 244, Rarity.COMMON, mage.cards.h.HalimarDepths.class)); cards.add(new SetCardInfo("Haven of the Spirit Dragon", 245, Rarity.RARE, mage.cards.h.HavenOfTheSpiritDragon.class)); cards.add(new SetCardInfo("Heirloom Blade", 208, Rarity.UNCOMMON, mage.cards.h.HeirloomBlade.class)); - cards.add(new SetCardInfo("Hellish Rebuke", 26, Rarity.RARE, mage.cards.h.HellishRebuke.class)); + cards.add(new SetCardInfo("Hellish Rebuke", 26, Rarity.RARE, mage.cards.h.HellishRebuke.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hellish Rebuke", 295, Rarity.RARE, mage.cards.h.HellishRebuke.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Heroic Intervention", 161, Rarity.RARE, mage.cards.h.HeroicIntervention.class)); cards.add(new SetCardInfo("Hex", 101, Rarity.RARE, mage.cards.h.Hex.class)); cards.add(new SetCardInfo("High Market", 246, Rarity.RARE, mage.cards.h.HighMarket.class)); cards.add(new SetCardInfo("Hoard-Smelter Dragon", 128, Rarity.RARE, mage.cards.h.HoardSmelterDragon.class)); - cards.add(new SetCardInfo("Holy Avenger", 6, Rarity.RARE, mage.cards.h.HolyAvenger.class)); + cards.add(new SetCardInfo("Holy Avenger", 275, Rarity.RARE, mage.cards.h.HolyAvenger.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Holy Avenger", 6, Rarity.RARE, mage.cards.h.HolyAvenger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hostage Taker", 186, Rarity.RARE, mage.cards.h.HostageTaker.class)); - cards.add(new SetCardInfo("Hurl Through Hell", 48, Rarity.RARE, mage.cards.h.HurlThroughHell.class)); + cards.add(new SetCardInfo("Hurl Through Hell", 318, Rarity.RARE, mage.cards.h.HurlThroughHell.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hurl Through Hell", 48, Rarity.RARE, mage.cards.h.HurlThroughHell.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ignite the Future", 129, Rarity.RARE, mage.cards.i.IgniteTheFuture.class)); - cards.add(new SetCardInfo("Immovable Rod", 7, Rarity.RARE, mage.cards.i.ImmovableRod.class)); + cards.add(new SetCardInfo("Immovable Rod", 276, Rarity.RARE, mage.cards.i.ImmovableRod.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Immovable Rod", 7, Rarity.RARE, mage.cards.i.ImmovableRod.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Imprisoned in the Moon", 85, Rarity.RARE, mage.cards.i.ImprisonedInTheMoon.class)); - cards.add(new SetCardInfo("Indomitable Might", 40, Rarity.RARE, mage.cards.i.IndomitableMight.class)); + cards.add(new SetCardInfo("Indomitable Might", 309, Rarity.RARE, mage.cards.i.IndomitableMight.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Indomitable Might", 40, Rarity.RARE, mage.cards.i.IndomitableMight.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Izzet Chemister", 130, Rarity.RARE, mage.cards.i.IzzetChemister.class)); - cards.add(new SetCardInfo("Karazikar, the Eye Tyrant", 49, Rarity.MYTHIC, mage.cards.k.KarazikarTheEyeTyrant.class)); + cards.add(new SetCardInfo("Karazikar, the Eye Tyrant", 319, Rarity.MYTHIC, mage.cards.k.KarazikarTheEyeTyrant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Karazikar, the Eye Tyrant", 49, Rarity.MYTHIC, mage.cards.k.KarazikarTheEyeTyrant.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Karmic Guide", 68, Rarity.RARE, mage.cards.k.KarmicGuide.class)); cards.add(new SetCardInfo("Kenrith's Transformation", 162, Rarity.UNCOMMON, mage.cards.k.KenrithsTransformation.class)); cards.add(new SetCardInfo("Kindred Summons", 163, Rarity.RARE, mage.cards.k.KindredSummons.class)); - cards.add(new SetCardInfo("Klauth's Will", 51, Rarity.RARE, mage.cards.k.KlauthsWill.class)); - cards.add(new SetCardInfo("Klauth, Unrivaled Ancient", 50, Rarity.MYTHIC, mage.cards.k.KlauthUnrivaledAncient.class)); + cards.add(new SetCardInfo("Klauth's Will", 321, Rarity.RARE, mage.cards.k.KlauthsWill.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Klauth's Will", 51, Rarity.RARE, mage.cards.k.KlauthsWill.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Klauth, Unrivaled Ancient", 320, Rarity.MYTHIC, mage.cards.k.KlauthUnrivaledAncient.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Klauth, Unrivaled Ancient", 50, Rarity.MYTHIC, mage.cards.k.KlauthUnrivaledAncient.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Knight of Autumn", 187, Rarity.RARE, mage.cards.k.KnightOfAutumn.class)); cards.add(new SetCardInfo("Light Up the Stage", 131, Rarity.UNCOMMON, mage.cards.l.LightUpTheStage.class)); cards.add(new SetCardInfo("Lightning Greaves", 331, Rarity.UNCOMMON, mage.cards.l.LightningGreaves.class)); - cards.add(new SetCardInfo("Lorcan, Warlock Collector", 27, Rarity.RARE, mage.cards.l.LorcanWarlockCollector.class)); + cards.add(new SetCardInfo("Lorcan, Warlock Collector", 27, Rarity.RARE, mage.cards.l.LorcanWarlockCollector.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lorcan, Warlock Collector", 296, Rarity.RARE, mage.cards.l.LorcanWarlockCollector.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Loyal Apprentice", 132, Rarity.UNCOMMON, mage.cards.l.LoyalApprentice.class)); cards.add(new SetCardInfo("Lumbering Falls", 247, Rarity.RARE, mage.cards.l.LumberingFalls.class)); - cards.add(new SetCardInfo("Maddening Hex", 32, Rarity.RARE, mage.cards.m.MaddeningHex.class)); + cards.add(new SetCardInfo("Maddening Hex", 301, Rarity.RARE, mage.cards.m.MaddeningHex.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Maddening Hex", 32, Rarity.RARE, mage.cards.m.MaddeningHex.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Magmaquake", 133, Rarity.RARE, mage.cards.m.Magmaquake.class)); - cards.add(new SetCardInfo("Mantle of the Ancients", 8, Rarity.RARE, mage.cards.m.MantleOfTheAncients.class)); + cards.add(new SetCardInfo("Mantle of the Ancients", 277, Rarity.RARE, mage.cards.m.MantleOfTheAncients.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mantle of the Ancients", 8, Rarity.RARE, mage.cards.m.MantleOfTheAncients.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Marionette Master", 102, Rarity.RARE, mage.cards.m.MarionetteMaster.class)); cards.add(new SetCardInfo("Masterwork of Ingenuity", 209, Rarity.RARE, mage.cards.m.MasterworkOfIngenuity.class)); cards.add(new SetCardInfo("Merfolk Looter", 86, Rarity.UNCOMMON, mage.cards.m.MerfolkLooter.class)); cards.add(new SetCardInfo("Meteor Golem", 210, Rarity.UNCOMMON, mage.cards.m.MeteorGolem.class)); - cards.add(new SetCardInfo("Midnight Pathlighter", 52, Rarity.RARE, mage.cards.m.MidnightPathlighter.class)); + cards.add(new SetCardInfo("Midnight Pathlighter", 322, Rarity.RARE, mage.cards.m.MidnightPathlighter.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Midnight Pathlighter", 52, Rarity.RARE, mage.cards.m.MidnightPathlighter.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mind Stone", 211, Rarity.UNCOMMON, mage.cards.m.MindStone.class)); - cards.add(new SetCardInfo("Minn, Wily Illusionist", 16, Rarity.RARE, mage.cards.m.MinnWilyIllusionist.class)); + cards.add(new SetCardInfo("Minn, Wily Illusionist", 16, Rarity.RARE, mage.cards.m.MinnWilyIllusionist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Minn, Wily Illusionist", 285, Rarity.RARE, mage.cards.m.MinnWilyIllusionist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mishra's Factory", 248, Rarity.UNCOMMON, mage.cards.m.MishrasFactory.class)); cards.add(new SetCardInfo("Moonsilver Spear", 212, Rarity.RARE, mage.cards.m.MoonsilverSpear.class)); cards.add(new SetCardInfo("Mortuary Mire", 249, Rarity.COMMON, mage.cards.m.MortuaryMire.class)); @@ -173,12 +207,14 @@ public final class ForgottenRealmsCommander extends ExpansionSet { cards.add(new SetCardInfo("Mulldrifter", 87, Rarity.UNCOMMON, mage.cards.m.Mulldrifter.class)); cards.add(new SetCardInfo("Murder of Crows", 88, Rarity.UNCOMMON, mage.cards.m.MurderOfCrows.class)); cards.add(new SetCardInfo("Nature's Lore", 164, Rarity.COMMON, mage.cards.n.NaturesLore.class)); - cards.add(new SetCardInfo("Netherese Puzzle-Ward", 17, Rarity.RARE, mage.cards.n.NetheresePuzzleWard.class)); - cards.add(new SetCardInfo("Reckless Endeavor", 33, Rarity.RARE, mage.cards.r.RecklessEndeavor.class)); cards.add(new SetCardInfo("Necromantic Selection", 103, Rarity.RARE, mage.cards.n.NecromanticSelection.class)); cards.add(new SetCardInfo("Necrotic Sliver", 188, Rarity.UNCOMMON, mage.cards.n.NecroticSliver.class)); - cards.add(new SetCardInfo("Neverwinter Hydra", 41, Rarity.RARE, mage.cards.n.NeverwinterHydra.class)); - cards.add(new SetCardInfo("Nihiloor", 53, Rarity.MYTHIC, mage.cards.n.Nihiloor.class)); + cards.add(new SetCardInfo("Netherese Puzzle-Ward", 17, Rarity.RARE, mage.cards.n.NetheresePuzzleWard.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Netherese Puzzle-Ward", 286, Rarity.RARE, mage.cards.n.NetheresePuzzleWard.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Neverwinter Hydra", 310, Rarity.RARE, mage.cards.n.NeverwinterHydra.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Neverwinter Hydra", 41, Rarity.RARE, mage.cards.n.NeverwinterHydra.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nihiloor", 323, Rarity.MYTHIC, mage.cards.n.Nihiloor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nihiloor", 53, Rarity.MYTHIC, mage.cards.n.Nihiloor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nimbus Maze", 252, Rarity.RARE, mage.cards.n.NimbusMaze.class)); cards.add(new SetCardInfo("Obsessive Stitcher", 189, Rarity.UNCOMMON, mage.cards.o.ObsessiveStitcher.class)); cards.add(new SetCardInfo("Ogre Slumlord", 104, Rarity.RARE, mage.cards.o.OgreSlumlord.class)); @@ -189,7 +225,8 @@ public final class ForgottenRealmsCommander extends ExpansionSet { cards.add(new SetCardInfo("Paradise Druid", 165, Rarity.UNCOMMON, mage.cards.p.ParadiseDruid.class)); cards.add(new SetCardInfo("Path of Ancestry", 254, Rarity.COMMON, mage.cards.p.PathOfAncestry.class)); cards.add(new SetCardInfo("Phantasmal Image", 89, Rarity.RARE, mage.cards.p.PhantasmalImage.class)); - cards.add(new SetCardInfo("Phantom Steed", 18, Rarity.RARE, mage.cards.p.PhantomSteed.class)); + cards.add(new SetCardInfo("Phantom Steed", 18, Rarity.RARE, mage.cards.p.PhantomSteed.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Phantom Steed", 287, Rarity.RARE, mage.cards.p.PhantomSteed.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Phthisis", 105, Rarity.UNCOMMON, mage.cards.p.Phthisis.class)); cards.add(new SetCardInfo("Piper of the Swarm", 106, Rarity.RARE, mage.cards.p.PiperOfTheSwarm.class)); cards.add(new SetCardInfo("Plaguecrafter", 107, Rarity.UNCOMMON, mage.cards.p.Plaguecrafter.class)); @@ -198,10 +235,12 @@ public final class ForgottenRealmsCommander extends ExpansionSet { cards.add(new SetCardInfo("Prairie Stream", 256, Rarity.RARE, mage.cards.p.PrairieStream.class)); cards.add(new SetCardInfo("Prognostic Sphinx", 90, Rarity.RARE, mage.cards.p.PrognosticSphinx.class)); cards.add(new SetCardInfo("Propaganda", 91, Rarity.UNCOMMON, mage.cards.p.Propaganda.class)); - cards.add(new SetCardInfo("Prosper, Tome-Bound", 2, Rarity.MYTHIC, mage.cards.p.ProsperTomeBound.class)); + cards.add(new SetCardInfo("Prosper, Tome-Bound", 2, Rarity.MYTHIC, mage.cards.p.ProsperTomeBound.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Prosper, Tome-Bound", 324, Rarity.MYTHIC, mage.cards.p.ProsperTomeBound.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Psychic Impetus", 92, Rarity.UNCOMMON, mage.cards.p.PsychicImpetus.class)); cards.add(new SetCardInfo("Puresteel Paladin", 69, Rarity.RARE, mage.cards.p.PuresteelPaladin.class)); - cards.add(new SetCardInfo("Radiant Solar", 9, Rarity.RARE, mage.cards.r.RadiantSolar.class)); + cards.add(new SetCardInfo("Radiant Solar", 278, Rarity.RARE, mage.cards.r.RadiantSolar.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Radiant Solar", 9, Rarity.RARE, mage.cards.r.RadiantSolar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Rakdos Carnarium", 257, Rarity.UNCOMMON, mage.cards.r.RakdosCarnarium.class)); cards.add(new SetCardInfo("Rakdos Charm", 190, Rarity.UNCOMMON, mage.cards.r.RakdosCharm.class)); cards.add(new SetCardInfo("Rakdos Signet", 214, Rarity.UNCOMMON, mage.cards.r.RakdosSignet.class)); @@ -209,22 +248,32 @@ public final class ForgottenRealmsCommander extends ExpansionSet { cards.add(new SetCardInfo("Rancor", 167, Rarity.UNCOMMON, mage.cards.r.Rancor.class)); cards.add(new SetCardInfo("Realm-Cloaked Giant", 70, Rarity.MYTHIC, mage.cards.r.RealmCloakedGiant.class)); cards.add(new SetCardInfo("Reassembling Skeleton", 109, Rarity.UNCOMMON, mage.cards.r.ReassemblingSkeleton.class)); + cards.add(new SetCardInfo("Reckless Endeavor", 302, Rarity.RARE, mage.cards.r.RecklessEndeavor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Reckless Endeavor", 33, Rarity.RARE, mage.cards.r.RecklessEndeavor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Return of the Wildspeaker", 168, Rarity.RARE, mage.cards.r.ReturnOfTheWildspeaker.class)); cards.add(new SetCardInfo("Return to Nature", 169, Rarity.COMMON, mage.cards.r.ReturnToNature.class)); - cards.add(new SetCardInfo("Revivify", 10, Rarity.RARE, mage.cards.r.Revivify.class)); - cards.add(new SetCardInfo("Ride the Avalanche", 54, Rarity.RARE, mage.cards.r.RideTheAvalanche.class)); + cards.add(new SetCardInfo("Revivify", 10, Rarity.RARE, mage.cards.r.Revivify.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Revivify", 279, Rarity.RARE, mage.cards.r.Revivify.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ride the Avalanche", 325, Rarity.RARE, mage.cards.r.RideTheAvalanche.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ride the Avalanche", 54, Rarity.RARE, mage.cards.r.RideTheAvalanche.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Rile", 136, Rarity.COMMON, mage.cards.r.Rile.class)); cards.add(new SetCardInfo("Rishkar's Expertise", 170, Rarity.RARE, mage.cards.r.RishkarsExpertise.class)); cards.add(new SetCardInfo("Riverwise Augur", 93, Rarity.UNCOMMON, mage.cards.r.RiverwiseAugur.class)); - cards.add(new SetCardInfo("Robe of Stars", 11, Rarity.RARE, mage.cards.r.RobeOfStars.class)); + cards.add(new SetCardInfo("Robe of Stars", 11, Rarity.RARE, mage.cards.r.RobeOfStars.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Robe of Stars", 280, Rarity.RARE, mage.cards.r.RobeOfStars.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rod of Absorption", 19, Rarity.RARE, mage.cards.r.RodOfAbsorption.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rod of Absorption", 288, Rarity.RARE, mage.cards.r.RodOfAbsorption.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ronom Unicorn", 71, Rarity.COMMON, mage.cards.r.RonomUnicorn.class)); cards.add(new SetCardInfo("Savage Ventmaw", 191, Rarity.UNCOMMON, mage.cards.s.SavageVentmaw.class)); - cards.add(new SetCardInfo("Scourge of Valkas", 137, Rarity.RARE, mage.cards.s.ScourgeOfValkas.class)); + cards.add(new SetCardInfo("Scourge of Valkas", 137, Rarity.MYTHIC, mage.cards.s.ScourgeOfValkas.class)); cards.add(new SetCardInfo("Seaside Citadel", 258, Rarity.UNCOMMON, mage.cards.s.SeasideCitadel.class)); - cards.add(new SetCardInfo("Sefris of the Hidden Ways", 3, Rarity.MYTHIC, mage.cards.s.SefrisOfTheHiddenWays.class)); + cards.add(new SetCardInfo("Sefris of the Hidden Ways", 3, Rarity.MYTHIC, mage.cards.s.SefrisOfTheHiddenWays.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sefris of the Hidden Ways", 326, Rarity.MYTHIC, mage.cards.s.SefrisOfTheHiddenWays.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Serum Visions", 94, Rarity.UNCOMMON, mage.cards.s.SerumVisions.class)); cards.add(new SetCardInfo("Shadowblood Ridge", 259, Rarity.RARE, mage.cards.s.ShadowbloodRidge.class)); cards.add(new SetCardInfo("Shamanic Revelation", 171, Rarity.RARE, mage.cards.s.ShamanicRevelation.class)); + cards.add(new SetCardInfo("Share the Spoils", 303, Rarity.RARE, mage.cards.s.ShareTheSpoils.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Share the Spoils", 34, Rarity.RARE, mage.cards.s.ShareTheSpoils.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Shielding Plax", 192, Rarity.COMMON, mage.cards.s.ShieldingPlax.class)); cards.add(new SetCardInfo("Shiny Impetus", 138, Rarity.UNCOMMON, mage.cards.s.ShinyImpetus.class)); cards.add(new SetCardInfo("Shivan Hellkite", 139, Rarity.RARE, mage.cards.s.ShivanHellkite.class)); @@ -236,11 +285,13 @@ public final class ForgottenRealmsCommander extends ExpansionSet { cards.add(new SetCardInfo("Smoldering Marsh", 262, Rarity.RARE, mage.cards.s.SmolderingMarsh.class)); cards.add(new SetCardInfo("Sol Ring", 215, Rarity.UNCOMMON, mage.cards.s.SolRing.class)); cards.add(new SetCardInfo("Solemn Simulacrum", 216, Rarity.RARE, mage.cards.s.SolemnSimulacrum.class)); - cards.add(new SetCardInfo("Song of Inspiration", 42, Rarity.RARE, mage.cards.s.SongOfInspiration.class)); + cards.add(new SetCardInfo("Song of Inspiration", 311, Rarity.RARE, mage.cards.s.SongOfInspiration.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Song of Inspiration", 42, Rarity.RARE, mage.cards.s.SongOfInspiration.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Spinerock Knoll", 263, Rarity.RARE, mage.cards.s.SpinerockKnoll.class)); cards.add(new SetCardInfo("Spit Flame", 142, Rarity.RARE, mage.cards.s.SpitFlame.class)); cards.add(new SetCardInfo("Sram, Senior Edificer", 72, Rarity.RARE, mage.cards.s.SramSeniorEdificer.class)); - cards.add(new SetCardInfo("Storvald, Frost Giant Jarl", 55, Rarity.MYTHIC, mage.cards.s.StorvaldFrostGiantJarl.class)); + cards.add(new SetCardInfo("Storvald, Frost Giant Jarl", 327, Rarity.MYTHIC, mage.cards.s.StorvaldFrostGiantJarl.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Storvald, Frost Giant Jarl", 55, Rarity.MYTHIC, mage.cards.s.StorvaldFrostGiantJarl.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sun Titan", 73, Rarity.MYTHIC, mage.cards.s.SunTitan.class)); cards.add(new SetCardInfo("Sunblast Angel", 74, Rarity.RARE, mage.cards.s.SunblastAngel.class)); cards.add(new SetCardInfo("Sungrass Prairie", 264, Rarity.RARE, mage.cards.s.SungrassPrairie.class)); @@ -257,7 +308,8 @@ public final class ForgottenRealmsCommander extends ExpansionSet { cards.add(new SetCardInfo("Terramorphic Expanse", 267, Rarity.COMMON, mage.cards.t.TerramorphicExpanse.class)); cards.add(new SetCardInfo("Terror of Mount Velus", 145, Rarity.RARE, mage.cards.t.TerrorOfMountVelus.class)); cards.add(new SetCardInfo("Theater of Horrors", 194, Rarity.RARE, mage.cards.t.TheaterOfHorrors.class)); - cards.add(new SetCardInfo("Thorough Investigation", 12, Rarity.RARE, mage.cards.t.ThoroughInvestigation.class)); + cards.add(new SetCardInfo("Thorough Investigation", 12, Rarity.RARE, mage.cards.t.ThoroughInvestigation.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Thorough Investigation", 281, Rarity.RARE, mage.cards.t.ThoroughInvestigation.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thriving Grove", 268, Rarity.COMMON, mage.cards.t.ThrivingGrove.class)); cards.add(new SetCardInfo("Thriving Heath", 269, Rarity.COMMON, mage.cards.t.ThrivingHeath.class)); cards.add(new SetCardInfo("Thriving Isle", 270, Rarity.COMMON, mage.cards.t.ThrivingIsle.class)); @@ -267,27 +319,36 @@ public final class ForgottenRealmsCommander extends ExpansionSet { cards.add(new SetCardInfo("Unburial Rites", 111, Rarity.UNCOMMON, mage.cards.u.UnburialRites.class)); cards.add(new SetCardInfo("Underdark Rift", 62, Rarity.UNCOMMON, mage.cards.u.UnderdarkRift.class)); cards.add(new SetCardInfo("Unstable Obelisk", 220, Rarity.UNCOMMON, mage.cards.u.UnstableObelisk.class)); - cards.add(new SetCardInfo("Utopia Sprawl", 172, Rarity.UNCOMMON, mage.cards.u.UtopiaSprawl.class)); + cards.add(new SetCardInfo("Utopia Sprawl", 172, Rarity.COMMON, mage.cards.u.UtopiaSprawl.class)); cards.add(new SetCardInfo("Utter End", 195, Rarity.RARE, mage.cards.u.UtterEnd.class)); - cards.add(new SetCardInfo("Valiant Endeavor", 13, Rarity.RARE, mage.cards.v.ValiantEndeavor.class)); + cards.add(new SetCardInfo("Valiant Endeavor", 13, Rarity.RARE, mage.cards.v.ValiantEndeavor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Valiant Endeavor", 282, Rarity.RARE, mage.cards.v.ValiantEndeavor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Valorous Stance", 76, Rarity.UNCOMMON, mage.cards.v.ValorousStance.class)); cards.add(new SetCardInfo("Vandalblast", 148, Rarity.UNCOMMON, mage.cards.v.Vandalblast.class)); cards.add(new SetCardInfo("Vanish into Memory", 196, Rarity.UNCOMMON, mage.cards.v.VanishIntoMemory.class)); + cards.add(new SetCardInfo("Vengeful Ancestor", 304, Rarity.RARE, mage.cards.v.VengefulAncestor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Vengeful Ancestor", 35, Rarity.RARE, mage.cards.v.VengefulAncestor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Verdant Embrace", 173, Rarity.RARE, mage.cards.v.VerdantEmbrace.class)); cards.add(new SetCardInfo("Victimize", 112, Rarity.UNCOMMON, mage.cards.v.Victimize.class)); cards.add(new SetCardInfo("Viridian Longbow", 221, Rarity.COMMON, mage.cards.v.ViridianLongbow.class)); cards.add(new SetCardInfo("Vitu-Ghazi, the City-Tree", 272, Rarity.UNCOMMON, mage.cards.v.VituGhaziTheCityTree.class)); - cards.add(new SetCardInfo("Vrondiss, Rage of Ancients", 4, Rarity.MYTHIC, mage.cards.v.VrondissRageOfAncients.class)); + cards.add(new SetCardInfo("Vrondiss, Rage of Ancients", 328, Rarity.MYTHIC, mage.cards.v.VrondissRageOfAncients.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Vrondiss, Rage of Ancients", 4, Rarity.MYTHIC, mage.cards.v.VrondissRageOfAncients.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wall of Omens", 77, Rarity.UNCOMMON, mage.cards.w.WallOfOmens.class)); - cards.add(new SetCardInfo("Wand of Orcus", 28, Rarity.RARE, mage.cards.w.WandOfOrcus.class)); + cards.add(new SetCardInfo("Wand of Orcus", 28, Rarity.RARE, mage.cards.w.WandOfOrcus.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wand of Orcus", 297, Rarity.RARE, mage.cards.w.WandOfOrcus.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Warstorm Surge", 149, Rarity.RARE, mage.cards.w.WarstormSurge.class)); cards.add(new SetCardInfo("Wayfarer's Bauble", 222, Rarity.COMMON, mage.cards.w.WayfarersBauble.class)); - cards.add(new SetCardInfo("Wild Endeavor", 43, Rarity.RARE, mage.cards.w.WildEndeavor.class)); + cards.add(new SetCardInfo("Wild Endeavor", 312, Rarity.RARE, mage.cards.w.WildEndeavor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wild Endeavor", 43, Rarity.RARE, mage.cards.w.WildEndeavor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Wild Growth", 174, Rarity.COMMON, mage.cards.w.WildGrowth.class)); - cards.add(new SetCardInfo("Wild-Magic Sorcerer", 36, Rarity.RARE, mage.cards.w.WildMagicSorcerer.class)); + cards.add(new SetCardInfo("Wild-Magic Sorcerer", 305, Rarity.RARE, mage.cards.w.WildMagicSorcerer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wild-Magic Sorcerer", 36, Rarity.RARE, mage.cards.w.WildMagicSorcerer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Winds of Rath", 78, Rarity.RARE, mage.cards.w.WindsOfRath.class)); - cards.add(new SetCardInfo("Winged Boots", 20, Rarity.RARE, mage.cards.w.WingedBoots.class)); - cards.add(new SetCardInfo("Wulfgar of Icewind Dale", 56, Rarity.RARE, mage.cards.w.WulfgarOfIcewindDale.class)); + cards.add(new SetCardInfo("Winged Boots", 20, Rarity.RARE, mage.cards.w.WingedBoots.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Winged Boots", 289, Rarity.RARE, mage.cards.w.WingedBoots.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wulfgar of Icewind Dale", 329, Rarity.RARE, mage.cards.w.WulfgarOfIcewindDale.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wulfgar of Icewind Dale", 56, Rarity.RARE, mage.cards.w.WulfgarOfIcewindDale.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Zhalfirin Void", 273, Rarity.UNCOMMON, mage.cards.z.ZhalfirinVoid.class)); } } diff --git a/Mage.Sets/src/mage/sets/IconicMasters.java b/Mage.Sets/src/mage/sets/IconicMasters.java index a211bac3865..0774344baa3 100644 --- a/Mage.Sets/src/mage/sets/IconicMasters.java +++ b/Mage.Sets/src/mage/sets/IconicMasters.java @@ -1,9 +1,16 @@ package mage.sets; import mage.cards.ExpansionSet; +import mage.collation.BoosterCollator; +import mage.collation.BoosterStructure; +import mage.collation.CardRun; +import mage.collation.RarityConfiguration; import mage.constants.Rarity; import mage.constants.SetType; +import java.util.ArrayList; +import java.util.List; + /** * @author MajorLazar */ @@ -276,4 +283,100 @@ public final class IconicMasters extends ExpansionSet { cards.add(new SetCardInfo("Wrench Mind", 115, Rarity.COMMON, mage.cards.w.WrenchMind.class)); cards.add(new SetCardInfo("Yosei, the Morning Star", 39, Rarity.RARE, mage.cards.y.YoseiTheMorningStar.class)); } + + @Override + public BoosterCollator createCollator() { + return new IconicMastersCollator(); + } +} + +// Booster collation info from https://www.lethe.xyz/mtg/collation/ima.html +// Using USA collation for common/uncommon, rare collation inferred from other sets +class IconicMastersCollator implements BoosterCollator { + private final CardRun commonA = new CardRun(true, "151", "16", "51", "126", "23", "50", "124", "19", "68", "150", "35", "76", "153", "12", "54", "119", "24", "41", "139", "34", "70", "137", "33", "66", "132", "16", "67", "135", "22", "51", "127", "32", "60", "124", "19", "41", "151", "35", "68", "150", "27", "72", "119", "23", "50", "126", "12", "66", "153", "24", "76", "139", "34", "70", "135", "33", "54", "137", "32", "60", "132", "22", "67", "127", "27", "72"); + private final CardRun commonB = new CardRun(true, "105", "165", "113", "167", "79", "176", "80", "170", "86", "187", "91", "185", "84", "173", "85", "182", "115", "178", "103", "161", "90", "191", "79", "167", "113", "170", "80", "165", "105", "176", "84", "185", "115", "187", "91", "173", "103", "182", "86", "161", "85", "178", "90", "167", "79", "191", "113", "165", "91", "176", "80", "187", "84", "185", "105", "161", "86", "170", "85", "173", "90", "182", "115", "178", "103", "191"); + private final CardRun commonC1 = new CardRun(true, "15", "146", "1", "71", "171", "102", "53", "123", "248", "219", "244", "160", "88", "57", "6", "141", "226", "92", "130", "29", "181", "216", "133", "15", "45", "1", "102", "177", "146", "229", "4", "114", "219", "53", "123", "171", "71", "226", "29", "88", "141", "248", "4", "229", "57", "177", "92", "6", "133", "216", "160", "130", "45", "114", "181"); + private final CardRun commonC2 = new CardRun(true, "190", "89", "61", "129", "222", "111", "25", "43", "158", "17", "214", "235", "13", "104", "154", "69", "117", "218", "25", "89", "61", "190", "214", "235", "104", "129", "43", "13", "158", "222", "111", "244", "117", "154", "25", "69", "17", "61", "214", "89", "111", "218", "190", "104", "43", "129", "235", "13", "222", "158", "154", "69", "218", "117", "17"); + private final CardRun uncommonA = new CardRun(true, "148", "247", "5", "202", "168", "107", "220", "192", "73", "217", "188", "121", "38", "93", "232", "77", "169", "2", "236", "206", "227", "125", "81", "44", "134", "243", "14", "204", "155", "112", "221", "202", "56", "220", "188", "131", "5", "97", "241", "52", "175", "38", "247", "211", "213", "121", "93", "77", "148", "232", "21", "206", "155", "81", "217", "192", "73", "221", "168", "125", "14", "107", "236", "44", "169", "2", "243", "204", "227", "134", "112", "52", "131", "241", "5", "202", "175", "97", "213", "211", "56", "220", "188", "148", "21", "93", "236", "73", "168", "14", "232", "206", "217", "121", "107", "77", "125", "247", "38", "192", "155", "81", "227", "204", "44", "213", "169", "131", "21", "112", "243", "56", "175", "2", "241", "211", "221", "134", "97", "52"); + private final CardRun uncommonB = new CardRun(true, "196", "156", "94", "225", "198", "46", "230", "166", "147", "7", "100", "245", "64", "186", "36", "234", "194", "224", "128", "109", "58", "143", "233", "3", "193", "162", "87", "231", "196", "40", "215", "156", "147", "37", "83", "249", "59", "180", "197", "239", "30", "225", "128", "100", "64", "142", "245", "36", "198", "230", "94", "166", "193", "58", "224", "186", "234", "3", "109", "147", "46", "156", "7", "239", "194", "231", "140", "87", "40", "143", "249", "30", "197", "162", "83", "225", "196", "64", "215", "166", "142", "36", "100", "233", "59", "180", "37", "245", "198", "230", "140", "94", "46", "128", "234", "7", "193", "186", "109", "231", "194", "58", "224", "162", "143", "3", "83", "233", "59", "180", "37", "249", "197", "215", "142", "87", "40", "140", "239", "30"); + private final CardRun rare = new CardRun(false, "9", "10", "20", "26", "28", "31", "39", "42", "48", "49", "55", "63", "74", "75", "78", "82", "95", "96", "99", "106", "110", "116", "118", "120", "122", "138", "144", "145", "159", "163", "164", "172", "174", "179", "184", "195", "199", "200", "201", "203", "205", "207", "208", "209", "210", "212", "223", "228", "237", "238", "240", "242", "246", "9", "10", "20", "26", "28", "31", "39", "42", "48", "49", "55", "63", "74", "75", "78", "82", "95", "96", "99", "106", "110", "116", "118", "120", "122", "138", "144", "145", "159", "163", "164", "172", "174", "179", "184", "195", "199", "200", "201", "203", "205", "207", "208", "209", "210", "212", "223", "228", "237", "238", "240", "242", "246", "8", "11", "18", "47", "62", "65", "98", "101", "108", "136", "149", "152", "157", "183", "189"); + private final CardRun foilCommon = new CardRun(true, "214", "66", "170", "85", "124", "34", "43", "92", "123", "160", "15", "219", "67", "171", "90", "126", "35", "53", "104", "129", "190", "12", "235", "68", "173", "103", "127", "6", "50", "102", "141", "158", "16", "229", "70", "176", "105", "132", "19", "51", "111", "117", "181", "17", "222", "57", "178", "113", "139", "32", "54", "79", "133", "191", "22", "244", "61", "182", "114", "150", "4", "60", "86", "146", "185", "23", "1", "71", "187", "115", "151", "25", "72", "91", "119", "161", "24", "216", "45", "154", "88", "153", "13", "76", "80", "135", "165", "27", "218", "69", "177", "89", "130", "29", "41", "84", "137", "167", "33", "248", "226"); + + private final BoosterStructure AABBC1C1C1C1C1C1 = new BoosterStructure( + commonA, commonA, + commonB, commonB, + commonC1, commonC1, commonC1, commonC1, commonC1, commonC1 + ); + private final BoosterStructure AAABBC1C1C1C1C1 = new BoosterStructure( + commonA, commonA, commonA, + commonB, commonB, + commonC1, commonC1, commonC1, commonC1, commonC1 + ); + private final BoosterStructure AAAABBC2C2C2C2 = new BoosterStructure( + commonA, commonA, commonA, commonA, + commonB, commonB, + commonC2, commonC2, commonC2, commonC2 + ); + private final BoosterStructure AAAABBBC2C2C2 = new BoosterStructure( + commonA, commonA, commonA, commonA, + commonB, commonB, commonB, + commonC2, commonC2, commonC2 + ); + private final BoosterStructure AAB = new BoosterStructure(uncommonA, uncommonA, uncommonB); + private final BoosterStructure ABB = new BoosterStructure(uncommonA, uncommonB, uncommonB); + private final BoosterStructure R1 = new BoosterStructure(rare); + private final BoosterStructure FC = new BoosterStructure(foilCommon); + private final BoosterStructure FUA = new BoosterStructure(uncommonA); + private final BoosterStructure FUB = new BoosterStructure(uncommonB); + + // In order for equal numbers of each common to exist, the average booster must contain: + // 3.27 A commons (36 / 11) + // 2.18 B commons (24 / 11) + // 2.73 C1 commons (30 / 11, or 60 / 11 in each C1 booster) + // 1.82 C2 commons (20 / 11, or 40 / 11 in each C2 booster) + // These numbers are the same for all sets with 101 commons in A/B/C1/C2 print runs + // and with 10 common slots per booster + private final RarityConfiguration commonRuns = new RarityConfiguration( + AABBC1C1C1C1C1C1, + AABBC1C1C1C1C1C1, + AABBC1C1C1C1C1C1, + AABBC1C1C1C1C1C1, + AABBC1C1C1C1C1C1, + AAABBC1C1C1C1C1, + AAABBC1C1C1C1C1, + AAABBC1C1C1C1C1, + AAABBC1C1C1C1C1, + AAABBC1C1C1C1C1, + AAABBC1C1C1C1C1, + + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBBC2C2C2, + AAAABBBC2C2C2, + AAAABBBC2C2C2, + AAAABBBC2C2C2 + ); + private final RarityConfiguration uncommonRuns = new RarityConfiguration(AAB, ABB); + private final RarityConfiguration rareRuns = new RarityConfiguration(R1); + private final RarityConfiguration foilRuns = new RarityConfiguration( + FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, + FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, + FUA, FUB, FUA, FUB, FUA, FUB, + R1, R1 + ); + + @Override + public List makeBooster() { + List booster = new ArrayList<>(); + booster.addAll(commonRuns.getNext().makeRun()); + booster.addAll(uncommonRuns.getNext().makeRun()); + booster.addAll(rareRuns.getNext().makeRun()); + booster.addAll(foilRuns.getNext().makeRun()); + return booster; + } } diff --git a/Mage.Sets/src/mage/sets/Judgment.java b/Mage.Sets/src/mage/sets/Judgment.java index 9a1bcdd8663..5ae5e9af369 100644 --- a/Mage.Sets/src/mage/sets/Judgment.java +++ b/Mage.Sets/src/mage/sets/Judgment.java @@ -85,6 +85,7 @@ public final class Judgment extends ExpansionSet { cards.add(new SetCardInfo("Glory", 11, Rarity.RARE, mage.cards.g.Glory.class)); cards.add(new SetCardInfo("Golden Wish", 12, Rarity.RARE, mage.cards.g.GoldenWish.class)); cards.add(new SetCardInfo("Goretusk Firebeast", 91, Rarity.COMMON, mage.cards.g.GoretuskFirebeast.class)); + cards.add(new SetCardInfo("Grave Consequences", 67, Rarity.UNCOMMON, mage.cards.g.GraveConsequences.class)); cards.add(new SetCardInfo("Grip of Amnesia", 41, Rarity.COMMON, mage.cards.g.GripOfAmnesia.class)); cards.add(new SetCardInfo("Grizzly Fate", 119, Rarity.UNCOMMON, mage.cards.g.GrizzlyFate.class)); cards.add(new SetCardInfo("Guided Strike", 13, Rarity.COMMON, mage.cards.g.GuidedStrike.class)); @@ -130,6 +131,7 @@ public final class Judgment extends ExpansionSet { cards.add(new SetCardInfo("Scalpelexis", 50, Rarity.RARE, mage.cards.s.Scalpelexis.class)); cards.add(new SetCardInfo("Seedtime", 130, Rarity.RARE, mage.cards.s.Seedtime.class)); cards.add(new SetCardInfo("Selfless Exorcist", 21, Rarity.RARE, mage.cards.s.SelflessExorcist.class)); + cards.add(new SetCardInfo("Serene Sunset", 131, Rarity.UNCOMMON, mage.cards.s.SereneSunset.class)); cards.add(new SetCardInfo("Shieldmage Advocate", 22, Rarity.COMMON, mage.cards.s.ShieldmageAdvocate.class)); cards.add(new SetCardInfo("Silver Seraph", 23, Rarity.RARE, mage.cards.s.SilverSeraph.class)); cards.add(new SetCardInfo("Solitary Confinement", 24, Rarity.RARE, mage.cards.s.SolitaryConfinement.class)); @@ -160,6 +162,7 @@ public final class Judgment extends ExpansionSet { cards.add(new SetCardInfo("Web of Inertia", 53, Rarity.UNCOMMON, mage.cards.w.WebOfInertia.class)); cards.add(new SetCardInfo("Wonder", 54, Rarity.UNCOMMON, mage.cards.w.Wonder.class)); cards.add(new SetCardInfo("Worldgorger Dragon", 103, Rarity.RARE, mage.cards.w.WorldgorgerDragon.class)); + cards.add(new SetCardInfo("Wormfang Behemoth", 55, Rarity.RARE, mage.cards.w.WormfangBehemoth.class)); cards.add(new SetCardInfo("Wormfang Drake", 57, Rarity.COMMON, mage.cards.w.WormfangDrake.class)); cards.add(new SetCardInfo("Wormfang Manta", 58, Rarity.RARE, mage.cards.w.WormfangManta.class)); cards.add(new SetCardInfo("Wormfang Newt", 59, Rarity.COMMON, mage.cards.w.WormfangNewt.class)); diff --git a/Mage.Sets/src/mage/sets/Kaldheim.java b/Mage.Sets/src/mage/sets/Kaldheim.java index dd96f68209c..0796d20113a 100644 --- a/Mage.Sets/src/mage/sets/Kaldheim.java +++ b/Mage.Sets/src/mage/sets/Kaldheim.java @@ -8,7 +8,6 @@ import mage.collation.CardRun; import mage.collation.RarityConfiguration; import mage.constants.Rarity; import mage.constants.SetType; -import mage.constants.SuperType; import java.util.ArrayList; import java.util.List; diff --git a/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java b/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java index 34e678fb148..a5da2ab9b15 100644 --- a/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java +++ b/Mage.Sets/src/mage/sets/KamigawaNeonDynasty.java @@ -1,10 +1,17 @@ package mage.sets; +import mage.cards.Card; import mage.cards.ExpansionSet; +import mage.cards.repository.CardInfo; +import mage.collation.BoosterCollator; +import mage.collation.BoosterStructure; +import mage.collation.CardRun; +import mage.collation.RarityConfiguration; import mage.constants.Rarity; import mage.constants.SetType; +import mage.util.RandomUtil; -import java.util.Arrays; +import java.util.ArrayList; import java.util.List; /** @@ -12,7 +19,6 @@ import java.util.List; */ public final class KamigawaNeonDynasty extends ExpansionSet { - private static final List unfinished = Arrays.asList("Acquisition Octopus", "Armguard Familiar", "Blade of the Oni", "Bronzeplate Boar", "Chainflail Centipede", "Cloudsteel Kirin", "Leech Gauntlet", "Lion Sash", "Lizard Blades", "Ogre-Head Helm", "Rabbit Battery", "Simian Sling", "The Reality Chip", "Webspinner Cuff"); private static final KamigawaNeonDynasty instance = new KamigawaNeonDynasty(); public static KamigawaNeonDynasty getInstance() { @@ -24,22 +30,39 @@ public final class KamigawaNeonDynasty extends ExpansionSet { this.blockName = "Kamigawa: Neon Dynasty"; this.hasBoosters = true; this.hasBasicLands = true; - this.numBoosterDoubleFaced = 1; // temporary test fix + this.numBoosterLands = 1; + this.numBoosterCommon = 9; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 7.4; + this.numBoosterDoubleFaced = 1; + this.maxCardNumberInBooster = 302; + this.ratioBoosterSpecialLand = 2; + this.ratioBoosterSpecialLandNumerator = 1; cards.add(new SetCardInfo("Acquisition Octopus", 44, Rarity.UNCOMMON, mage.cards.a.AcquisitionOctopus.class)); cards.add(new SetCardInfo("Akki Ember-Keeper", 130, Rarity.COMMON, mage.cards.a.AkkiEmberKeeper.class)); - cards.add(new SetCardInfo("Akki Ronin", 131, Rarity.COMMON, mage.cards.a.AkkiRonin.class)); + cards.add(new SetCardInfo("Akki Ronin", 131, Rarity.COMMON, mage.cards.a.AkkiRonin.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Akki Ronin", 319, Rarity.COMMON, mage.cards.a.AkkiRonin.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Akki War Paint", 132, Rarity.COMMON, mage.cards.a.AkkiWarPaint.class)); cards.add(new SetCardInfo("Ambitious Assault", 133, Rarity.COMMON, mage.cards.a.AmbitiousAssault.class)); cards.add(new SetCardInfo("Ancestral Katana", 1, Rarity.COMMON, mage.cards.a.AncestralKatana.class)); cards.add(new SetCardInfo("Anchor to Reality", 45, Rarity.UNCOMMON, mage.cards.a.AnchorToReality.class)); cards.add(new SetCardInfo("Animus of Night's Reach", 109, Rarity.UNCOMMON, mage.cards.a.AnimusOfNightsReach.class)); - cards.add(new SetCardInfo("Ao, the Dawn Sky", 2, Rarity.MYTHIC, mage.cards.a.AoTheDawnSky.class)); - cards.add(new SetCardInfo("Architect of Restoration", 34, Rarity.RARE, mage.cards.a.ArchitectOfRestoration.class)); + cards.add(new SetCardInfo("Ao, the Dawn Sky", 2, Rarity.MYTHIC, mage.cards.a.AoTheDawnSky.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ao, the Dawn Sky", 406, Rarity.MYTHIC, mage.cards.a.AoTheDawnSky.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ao, the Dawn Sky", 433, Rarity.MYTHIC, mage.cards.a.AoTheDawnSky.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Architect of Restoration", 34, Rarity.RARE, mage.cards.a.ArchitectOfRestoration.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Architect of Restoration", 354, Rarity.RARE, mage.cards.a.ArchitectOfRestoration.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Architect of Restoration", 442, Rarity.RARE, mage.cards.a.ArchitectOfRestoration.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Armguard Familiar", 46, Rarity.COMMON, mage.cards.a.ArmguardFamiliar.class)); - cards.add(new SetCardInfo("Asari Captain", 215, Rarity.UNCOMMON, mage.cards.a.AsariCaptain.class)); + cards.add(new SetCardInfo("Asari Captain", 215, Rarity.UNCOMMON, mage.cards.a.AsariCaptain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Asari Captain", 327, Rarity.UNCOMMON, mage.cards.a.AsariCaptain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Assassin's Ink", 87, Rarity.UNCOMMON, mage.cards.a.AssassinsInk.class)); - cards.add(new SetCardInfo("Atsushi, the Blazing Sky", 134, Rarity.MYTHIC, mage.cards.a.AtsushiTheBlazingSky.class)); + cards.add(new SetCardInfo("Atsushi, the Blazing Sky", 134, Rarity.MYTHIC, mage.cards.a.AtsushiTheBlazingSky.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Atsushi, the Blazing Sky", 410, Rarity.MYTHIC, mage.cards.a.AtsushiTheBlazingSky.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Atsushi, the Blazing Sky", 463, Rarity.MYTHIC, mage.cards.a.AtsushiTheBlazingSky.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Automated Artificer", 239, Rarity.COMMON, mage.cards.a.AutomatedArtificer.class)); cards.add(new SetCardInfo("Awakened Awareness", 47, Rarity.UNCOMMON, mage.cards.a.AwakenedAwareness.class)); cards.add(new SetCardInfo("Azusa's Many Journeys", 172, Rarity.UNCOMMON, mage.cards.a.AzusasManyJourneys.class)); cards.add(new SetCardInfo("Bamboo Grove Archer", 173, Rarity.COMMON, mage.cards.b.BambooGroveArcher.class)); @@ -47,15 +70,28 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("Bearer of Memory", 174, Rarity.COMMON, mage.cards.b.BearerOfMemory.class)); cards.add(new SetCardInfo("Befriending the Moths", 4, Rarity.COMMON, mage.cards.b.BefriendingTheMoths.class)); cards.add(new SetCardInfo("Behold the Unspeakable", 48, Rarity.UNCOMMON, mage.cards.b.BeholdTheUnspeakable.class)); - cards.add(new SetCardInfo("Biting-Palm Ninja", 88, Rarity.RARE, mage.cards.b.BitingPalmNinja.class)); - cards.add(new SetCardInfo("Blade-Blizzard Kitsune", 5, Rarity.UNCOMMON, mage.cards.b.BladeBlizzardKitsune.class)); + cards.add(new SetCardInfo("Biting-Palm Ninja", 338, Rarity.RARE, mage.cards.b.BitingPalmNinja.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Biting-Palm Ninja", 452, Rarity.RARE, mage.cards.b.BitingPalmNinja.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Biting-Palm Ninja", 88, Rarity.RARE, mage.cards.b.BitingPalmNinja.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Blade of the Oni", 377, Rarity.MYTHIC, mage.cards.b.BladeOfTheOni.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Blade of the Oni", 420, Rarity.MYTHIC, mage.cards.b.BladeOfTheOni.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Blade of the Oni", 453, Rarity.MYTHIC, mage.cards.b.BladeOfTheOni.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Blade of the Oni", 89, Rarity.MYTHIC, mage.cards.b.BladeOfTheOni.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Blade-Blizzard Kitsune", 331, Rarity.UNCOMMON, mage.cards.b.BladeBlizzardKitsune.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Blade-Blizzard Kitsune", 5, Rarity.UNCOMMON, mage.cards.b.BladeBlizzardKitsune.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bloodfell Caves", 264, Rarity.COMMON, mage.cards.b.BloodfellCaves.class)); + cards.add(new SetCardInfo("Blossom Prancer", 175, Rarity.UNCOMMON, mage.cards.b.BlossomPrancer.class)); cards.add(new SetCardInfo("Blossoming Sands", 265, Rarity.COMMON, mage.cards.b.BlossomingSands.class)); cards.add(new SetCardInfo("Boon of Boseiju", 176, Rarity.UNCOMMON, mage.cards.b.BoonOfBoseiju.class)); cards.add(new SetCardInfo("Born to Drive", 6, Rarity.UNCOMMON, mage.cards.b.BornToDrive.class)); cards.add(new SetCardInfo("Boseiju Reaches Skyward", 177, Rarity.UNCOMMON, mage.cards.b.BoseijuReachesSkyward.class)); + cards.add(new SetCardInfo("Boseiju, Who Endures", 266, Rarity.RARE, mage.cards.b.BoseijuWhoEndures.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Boseiju, Who Endures", 412, Rarity.RARE, mage.cards.b.BoseijuWhoEndures.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Boseiju, Who Endures", 501, Rarity.RARE, mage.cards.b.BoseijuWhoEndures.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Branch of Boseiju", 177, Rarity.UNCOMMON, mage.cards.b.BranchOfBoseiju.class)); - cards.add(new SetCardInfo("Brilliant Restoration", 7, Rarity.RARE, mage.cards.b.BrilliantRestoration.class)); + cards.add(new SetCardInfo("Brilliant Restoration", 363, Rarity.RARE, mage.cards.b.BrilliantRestoration.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Brilliant Restoration", 434, Rarity.RARE, mage.cards.b.BrilliantRestoration.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Brilliant Restoration", 7, Rarity.RARE, mage.cards.b.BrilliantRestoration.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Bronze Cudgels", 240, Rarity.UNCOMMON, mage.cards.b.BronzeCudgels.class)); cards.add(new SetCardInfo("Bronzeplate Boar", 135, Rarity.UNCOMMON, mage.cards.b.BronzeplateBoar.class)); cards.add(new SetCardInfo("Brute Suit", 241, Rarity.COMMON, mage.cards.b.BruteSuit.class)); @@ -63,39 +99,78 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("Chainflail Centipede", 90, Rarity.COMMON, mage.cards.c.ChainflailCentipede.class)); cards.add(new SetCardInfo("Circuit Mender", 242, Rarity.UNCOMMON, mage.cards.c.CircuitMender.class)); cards.add(new SetCardInfo("Clawing Torment", 91, Rarity.COMMON, mage.cards.c.ClawingTorment.class)); - cards.add(new SetCardInfo("Cloudsteel Kirin", 8, Rarity.RARE, mage.cards.c.CloudsteelKirin.class)); - cards.add(new SetCardInfo("Coiling Stalker", 179, Rarity.COMMON, mage.cards.c.CoilingStalker.class)); + cards.add(new SetCardInfo("Cloudsteel Kirin", 364, Rarity.RARE, mage.cards.c.CloudsteelKirin.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cloudsteel Kirin", 435, Rarity.RARE, mage.cards.c.CloudsteelKirin.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cloudsteel Kirin", 8, Rarity.RARE, mage.cards.c.CloudsteelKirin.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Coiling Stalker", 179, Rarity.COMMON, mage.cards.c.CoilingStalker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Coiling Stalker", 346, Rarity.COMMON, mage.cards.c.CoilingStalker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Colossal Skyturtle", 216, Rarity.UNCOMMON, mage.cards.c.ColossalSkyturtle.class)); cards.add(new SetCardInfo("Commune with Spirits", 180, Rarity.COMMON, mage.cards.c.CommuneWithSpirits.class)); - cards.add(new SetCardInfo("Covert Technician", 49, Rarity.UNCOMMON, mage.cards.c.CovertTechnician.class)); + cards.add(new SetCardInfo("Containment Construct", 243, Rarity.UNCOMMON, mage.cards.c.ContainmentConstruct.class)); + cards.add(new SetCardInfo("Covert Technician", 332, Rarity.UNCOMMON, mage.cards.c.CovertTechnician.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Covert Technician", 49, Rarity.UNCOMMON, mage.cards.c.CovertTechnician.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Crackling Emergence", 136, Rarity.COMMON, mage.cards.c.CracklingEmergence.class)); cards.add(new SetCardInfo("Debt to the Kami", 92, Rarity.COMMON, mage.cards.d.DebtToTheKami.class)); + cards.add(new SetCardInfo("Discover the Impossible", 50, Rarity.UNCOMMON, mage.cards.d.DiscoverTheImpossible.class)); cards.add(new SetCardInfo("Dismal Backwater", 267, Rarity.COMMON, mage.cards.d.DismalBackwater.class)); cards.add(new SetCardInfo("Disruption Protocol", 51, Rarity.COMMON, mage.cards.d.DisruptionProtocol.class)); cards.add(new SetCardInfo("Dockside Chef", 93, Rarity.UNCOMMON, mage.cards.d.DocksideChef.class)); - cards.add(new SetCardInfo("Dokuchi Shadow-Walker", 94, Rarity.COMMON, mage.cards.d.DokuchiShadowWalker.class)); - cards.add(new SetCardInfo("Dokuchi Silencer", 95, Rarity.UNCOMMON, mage.cards.d.DokuchiSilencer.class)); + cards.add(new SetCardInfo("Dokuchi Shadow-Walker", 339, Rarity.COMMON, mage.cards.d.DokuchiShadowWalker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Dokuchi Shadow-Walker", 94, Rarity.COMMON, mage.cards.d.DokuchiShadowWalker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Dokuchi Silencer", 340, Rarity.UNCOMMON, mage.cards.d.DokuchiSilencer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Dokuchi Silencer", 95, Rarity.UNCOMMON, mage.cards.d.DokuchiSilencer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Dragon-Kami's Egg", 181, Rarity.RARE, mage.cards.d.DragonKamisEgg.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Dragon-Kami's Egg", 358, Rarity.RARE, mage.cards.d.DragonKamisEgg.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Dragon-Kami's Egg", 473, Rarity.RARE, mage.cards.d.DragonKamisEgg.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dragonfly Suit", 9, Rarity.COMMON, mage.cards.d.DragonflySuit.class)); cards.add(new SetCardInfo("Dragonspark Reactor", 137, Rarity.UNCOMMON, mage.cards.d.DragonsparkReactor.class)); cards.add(new SetCardInfo("Dramatist's Puppet", 244, Rarity.COMMON, mage.cards.d.DramatistsPuppet.class)); - cards.add(new SetCardInfo("Echo of Death's Wail", 124, Rarity.RARE, mage.cards.e.EchoOfDeathsWail.class)); + cards.add(new SetCardInfo("Eater of Virtue", 245, Rarity.RARE, mage.cards.e.EaterOfVirtue.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Eater of Virtue", 401, Rarity.RARE, mage.cards.e.EaterOfVirtue.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Eater of Virtue", 496, Rarity.RARE, mage.cards.e.EaterOfVirtue.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Echo of Death's Wail", 124, Rarity.RARE, mage.cards.e.EchoOfDeathsWail.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Echo of Death's Wail", 356, Rarity.RARE, mage.cards.e.EchoOfDeathsWail.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Echo of Death's Wail", 462, Rarity.RARE, mage.cards.e.EchoOfDeathsWail.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ecologist's Terrarium", 246, Rarity.COMMON, mage.cards.e.EcologistsTerrarium.class)); - cards.add(new SetCardInfo("Eiganjo Exemplar", 10, Rarity.COMMON, mage.cards.e.EiganjoExemplar.class)); - cards.add(new SetCardInfo("Eiganjo Uprising", 217, Rarity.RARE, mage.cards.e.EiganjoUprising.class)); - cards.add(new SetCardInfo("Eiganjo, Seat of the Empire", 268, Rarity.RARE, mage.cards.e.EiganjoSeatOfTheEmpire.class)); + cards.add(new SetCardInfo("Eiganjo Exemplar", 10, Rarity.COMMON, mage.cards.e.EiganjoExemplar.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Eiganjo Exemplar", 309, Rarity.COMMON, mage.cards.e.EiganjoExemplar.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Eiganjo Uprising", 217, Rarity.RARE, mage.cards.e.EiganjoUprising.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Eiganjo Uprising", 396, Rarity.RARE, mage.cards.e.EiganjoUprising.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Eiganjo Uprising", 484, Rarity.RARE, mage.cards.e.EiganjoUprising.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Eiganjo, Seat of the Empire", 268, Rarity.RARE, mage.cards.e.EiganjoSeatOfTheEmpire.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Eiganjo, Seat of the Empire", 413, Rarity.RARE, mage.cards.e.EiganjoSeatOfTheEmpire.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Eiganjo, Seat of the Empire", 502, Rarity.RARE, mage.cards.e.EiganjoSeatOfTheEmpire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Enormous Energy Blade", 96, Rarity.UNCOMMON, mage.cards.e.EnormousEnergyBlade.class)); - cards.add(new SetCardInfo("Enthusiastic Mechanaut", 218, Rarity.UNCOMMON, mage.cards.e.EnthusiasticMechanaut.class)); + cards.add(new SetCardInfo("Enthusiastic Mechanaut", 218, Rarity.UNCOMMON, mage.cards.e.EnthusiasticMechanaut.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Enthusiastic Mechanaut", 509, Rarity.UNCOMMON, mage.cards.e.EnthusiasticMechanaut.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Era of Enlightenment", 11, Rarity.COMMON, mage.cards.e.EraOfEnlightenment.class)); cards.add(new SetCardInfo("Essence Capture", 52, Rarity.UNCOMMON, mage.cards.e.EssenceCapture.class)); + cards.add(new SetCardInfo("Etching of Kumano", 152, Rarity.UNCOMMON, mage.cards.e.EtchingOfKumano.class)); cards.add(new SetCardInfo("Experimental Synthesizer", 138, Rarity.COMMON, mage.cards.e.ExperimentalSynthesizer.class)); cards.add(new SetCardInfo("Explosive Entry", 139, Rarity.COMMON, mage.cards.e.ExplosiveEntry.class)); + cards.add(new SetCardInfo("Explosive Singularity", 140, Rarity.MYTHIC, mage.cards.e.ExplosiveSingularity.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Explosive Singularity", 383, Rarity.MYTHIC, mage.cards.e.ExplosiveSingularity.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Explosive Singularity", 422, Rarity.MYTHIC, mage.cards.e.ExplosiveSingularity.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Explosive Singularity", 464, Rarity.MYTHIC, mage.cards.e.ExplosiveSingularity.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fable of the Mirror-Breaker", 141, Rarity.RARE, mage.cards.f.FableOfTheMirrorBreaker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fable of the Mirror-Breaker", 357, Rarity.RARE, mage.cards.f.FableOfTheMirrorBreaker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fable of the Mirror-Breaker", 465, Rarity.RARE, mage.cards.f.FableOfTheMirrorBreaker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fade into Antiquity", 182, Rarity.COMMON, mage.cards.f.FadeIntoAntiquity.class)); - cards.add(new SetCardInfo("Fang of Shigeki", 183, Rarity.COMMON, mage.cards.f.FangOfShigeki.class)); - cards.add(new SetCardInfo("Farewell", 13, Rarity.RARE, mage.cards.f.Farewell.class)); + cards.add(new SetCardInfo("Fang of Shigeki", 183, Rarity.COMMON, mage.cards.f.FangOfShigeki.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fang of Shigeki", 347, Rarity.COMMON, mage.cards.f.FangOfShigeki.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Farewell", 13, Rarity.RARE, mage.cards.f.Farewell.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Farewell", 365, Rarity.RARE, mage.cards.f.Farewell.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Farewell", 417, Rarity.RARE, mage.cards.f.Farewell.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Farewell", 436, Rarity.RARE, mage.cards.f.Farewell.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Favor of Jukai", 184, Rarity.COMMON, mage.cards.f.FavorOfJukai.class)); cards.add(new SetCardInfo("Flame Discharge", 142, Rarity.UNCOMMON, mage.cards.f.FlameDischarge.class)); cards.add(new SetCardInfo("Forest", 291, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 292, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 301, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Forest", 302, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Fragment of Konda", 12, Rarity.UNCOMMON, mage.cards.f.FragmentOfKonda.class)); - cards.add(new SetCardInfo("Futurist Operative", 53, Rarity.UNCOMMON, mage.cards.f.FuturistOperative.class)); + cards.add(new SetCardInfo("Futurist Operative", 333, Rarity.UNCOMMON, mage.cards.f.FuturistOperative.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Futurist Operative", 53, Rarity.UNCOMMON, mage.cards.f.FuturistOperative.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Futurist Sentinel", 54, Rarity.COMMON, mage.cards.f.FuturistSentinel.class)); cards.add(new SetCardInfo("Generous Visitor", 185, Rarity.UNCOMMON, mage.cards.g.GenerousVisitor.class)); cards.add(new SetCardInfo("Geothermal Kami", 186, Rarity.COMMON, mage.cards.g.GeothermalKami.class)); @@ -107,180 +182,530 @@ public final class KamigawaNeonDynasty extends ExpansionSet { cards.add(new SetCardInfo("Go-Shintai of Lost Wisdom", 55, Rarity.UNCOMMON, mage.cards.g.GoShintaiOfLostWisdom.class)); cards.add(new SetCardInfo("Go-Shintai of Shared Purpose", 14, Rarity.UNCOMMON, mage.cards.g.GoShintaiOfSharedPurpose.class)); cards.add(new SetCardInfo("Golden-Tail Disciple", 15, Rarity.COMMON, mage.cards.g.GoldenTailDisciple.class)); - cards.add(new SetCardInfo("Goro-Goro, Disciple of Ryusei", 145, Rarity.RARE, mage.cards.g.GoroGoroDiscipleOfRyusei.class)); + cards.add(new SetCardInfo("Goro-Goro, Disciple of Ryusei", 145, Rarity.RARE, mage.cards.g.GoroGoroDiscipleOfRyusei.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Goro-Goro, Disciple of Ryusei", 320, Rarity.RARE, mage.cards.g.GoroGoroDiscipleOfRyusei.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Goro-Goro, Disciple of Ryusei", 466, Rarity.RARE, mage.cards.g.GoroGoroDiscipleOfRyusei.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Grafted Growth", 188, Rarity.COMMON, mage.cards.g.GraftedGrowth.class)); cards.add(new SetCardInfo("Gravelighter", 98, Rarity.UNCOMMON, mage.cards.g.Gravelighter.class)); - cards.add(new SetCardInfo("Greasefang, Okiba Boss", 220, Rarity.RARE, mage.cards.g.GreasefangOkibaBoss.class)); + cards.add(new SetCardInfo("Greasefang, Okiba Boss", 220, Rarity.RARE, mage.cards.g.GreasefangOkibaBoss.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Greasefang, Okiba Boss", 397, Rarity.RARE, mage.cards.g.GreasefangOkibaBoss.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Greasefang, Okiba Boss", 485, Rarity.RARE, mage.cards.g.GreasefangOkibaBoss.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Greater Tanuki", 189, Rarity.COMMON, mage.cards.g.GreaterTanuki.class)); - cards.add(new SetCardInfo("Guardians of Oboro", 56, Rarity.COMMON, mage.cards.g.GuardiansOfOboro.class)); + cards.add(new SetCardInfo("Guardians of Oboro", 317, Rarity.COMMON, mage.cards.g.GuardiansOfOboro.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Guardians of Oboro", 56, Rarity.COMMON, mage.cards.g.GuardiansOfOboro.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Hand of Enlightenment", 11, Rarity.COMMON, mage.cards.h.HandOfEnlightenment.class)); - cards.add(new SetCardInfo("Heiko Yamazaki, the General", 146, Rarity.UNCOMMON, mage.cards.h.HeikoYamazakiTheGeneral.class)); - cards.add(new SetCardInfo("Heir of the Ancient Fang", 191, Rarity.COMMON, mage.cards.h.HeirOfTheAncientFang.class)); - cards.add(new SetCardInfo("Hidetsugu, Devouring Chaos", 99, Rarity.RARE, mage.cards.h.HidetsuguDevouringChaos.class)); + cards.add(new SetCardInfo("Harmonious Emergence", 190, Rarity.COMMON, mage.cards.h.HarmoniousEmergence.class)); + cards.add(new SetCardInfo("Heiko Yamazaki, the General", 146, Rarity.UNCOMMON, mage.cards.h.HeikoYamazakiTheGeneral.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Heiko Yamazaki, the General", 321, Rarity.UNCOMMON, mage.cards.h.HeikoYamazakiTheGeneral.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Heir of the Ancient Fang", 191, Rarity.COMMON, mage.cards.h.HeirOfTheAncientFang.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Heir of the Ancient Fang", 325, Rarity.COMMON, mage.cards.h.HeirOfTheAncientFang.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hidetsugu Consumes All", 221, Rarity.MYTHIC, mage.cards.h.HidetsuguConsumesAll.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hidetsugu Consumes All", 361, Rarity.MYTHIC, mage.cards.h.HidetsuguConsumesAll.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hidetsugu Consumes All", 486, Rarity.MYTHIC, mage.cards.h.HidetsuguConsumesAll.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hidetsugu, Devouring Chaos", 378, Rarity.RARE, mage.cards.h.HidetsuguDevouringChaos.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hidetsugu, Devouring Chaos", 429, Rarity.RARE, mage.cards.h.HidetsuguDevouringChaos.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hidetsugu, Devouring Chaos", 430, Rarity.RARE, mage.cards.h.HidetsuguDevouringChaos.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hidetsugu, Devouring Chaos", 431, Rarity.RARE, mage.cards.h.HidetsuguDevouringChaos.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hidetsugu, Devouring Chaos", 432, Rarity.RARE, mage.cards.h.HidetsuguDevouringChaos.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hidetsugu, Devouring Chaos", 454, Rarity.RARE, mage.cards.h.HidetsuguDevouringChaos.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hidetsugu, Devouring Chaos", 99, Rarity.RARE, mage.cards.h.HidetsuguDevouringChaos.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("High-Speed Hoverbike", 247, Rarity.UNCOMMON, mage.cards.h.HighSpeedHoverbike.class)); - cards.add(new SetCardInfo("Hinata, Dawn-Crowned", 222, Rarity.RARE, mage.cards.h.HinataDawnCrowned.class)); + cards.add(new SetCardInfo("Hinata, Dawn-Crowned", 222, Rarity.RARE, mage.cards.h.HinataDawnCrowned.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hinata, Dawn-Crowned", 398, Rarity.RARE, mage.cards.h.HinataDawnCrowned.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hinata, Dawn-Crowned", 487, Rarity.RARE, mage.cards.h.HinataDawnCrowned.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Historian's Wisdom", 192, Rarity.UNCOMMON, mage.cards.h.HistoriansWisdom.class)); cards.add(new SetCardInfo("Hotshot Mechanic", 16, Rarity.UNCOMMON, mage.cards.h.HotshotMechanic.class)); cards.add(new SetCardInfo("Imperial Moth", 4, Rarity.COMMON, mage.cards.i.ImperialMoth.class)); cards.add(new SetCardInfo("Imperial Oath", 17, Rarity.COMMON, mage.cards.i.ImperialOath.class)); cards.add(new SetCardInfo("Imperial Recovery Unit", 18, Rarity.UNCOMMON, mage.cards.i.ImperialRecoveryUnit.class)); - cards.add(new SetCardInfo("Imperial Subduer", 19, Rarity.COMMON, mage.cards.i.ImperialSubduer.class)); - cards.add(new SetCardInfo("Inkrise Infiltrator", 100, Rarity.COMMON, mage.cards.i.InkriseInfiltrator.class)); + cards.add(new SetCardInfo("Imperial Subduer", 19, Rarity.COMMON, mage.cards.i.ImperialSubduer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Imperial Subduer", 310, Rarity.COMMON, mage.cards.i.ImperialSubduer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Inkrise Infiltrator", 100, Rarity.COMMON, mage.cards.i.InkriseInfiltrator.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Inkrise Infiltrator", 341, Rarity.COMMON, mage.cards.i.InkriseInfiltrator.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Intercessor's Arrest", 20, Rarity.COMMON, mage.cards.i.IntercessorsArrest.class)); - cards.add(new SetCardInfo("Inventive Iteration", 57, Rarity.RARE, mage.cards.i.InventiveIteration.class)); + cards.add(new SetCardInfo("Inventive Iteration", 355, Rarity.RARE, mage.cards.i.InventiveIteration.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Inventive Iteration", 443, Rarity.RARE, mage.cards.i.InventiveIteration.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Inventive Iteration", 57, Rarity.RARE, mage.cards.i.InventiveIteration.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Invigorating Hot Spring", 223, Rarity.UNCOMMON, mage.cards.i.InvigoratingHotSpring.class)); - cards.add(new SetCardInfo("Invoke Despair", 101, Rarity.RARE, mage.cards.i.InvokeDespair.class)); - cards.add(new SetCardInfo("Invoke the Ancients", 193, Rarity.RARE, mage.cards.i.InvokeTheAncients.class)); - cards.add(new SetCardInfo("Invoke the Winds", 58, Rarity.RARE, mage.cards.i.InvokeTheWinds.class)); + cards.add(new SetCardInfo("Invoke Calamity", 147, Rarity.RARE, mage.cards.i.InvokeCalamity.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Invoke Calamity", 384, Rarity.RARE, mage.cards.i.InvokeCalamity.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Invoke Calamity", 467, Rarity.RARE, mage.cards.i.InvokeCalamity.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Invoke Despair", 101, Rarity.RARE, mage.cards.i.InvokeDespair.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Invoke Despair", 379, Rarity.RARE, mage.cards.i.InvokeDespair.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Invoke Despair", 455, Rarity.RARE, mage.cards.i.InvokeDespair.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Invoke Despair", 506, Rarity.RARE, mage.cards.i.InvokeDespair.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Invoke Justice", 21, Rarity.RARE, mage.cards.i.InvokeJustice.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Invoke Justice", 366, Rarity.RARE, mage.cards.i.InvokeJustice.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Invoke Justice", 437, Rarity.RARE, mage.cards.i.InvokeJustice.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Invoke the Ancients", 193, Rarity.RARE, mage.cards.i.InvokeTheAncients.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Invoke the Ancients", 390, Rarity.RARE, mage.cards.i.InvokeTheAncients.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Invoke the Ancients", 474, Rarity.RARE, mage.cards.i.InvokeTheAncients.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Invoke the Winds", 370, Rarity.RARE, mage.cards.i.InvokeTheWinds.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Invoke the Winds", 444, Rarity.RARE, mage.cards.i.InvokeTheWinds.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Invoke the Winds", 58, Rarity.RARE, mage.cards.i.InvokeTheWinds.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Iron Apprentice", 248, Rarity.COMMON, mage.cards.i.IronApprentice.class)); cards.add(new SetCardInfo("Ironhoof Boar", 148, Rarity.COMMON, mage.cards.i.IronhoofBoar.class)); cards.add(new SetCardInfo("Island", 285, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Isshin, Two Heavens as One", 224, Rarity.RARE, mage.cards.i.IsshinTwoHeavensAsOne.class)); - cards.add(new SetCardInfo("Jukai Naturalist", 225, Rarity.UNCOMMON, mage.cards.j.JukaiNaturalist.class)); + cards.add(new SetCardInfo("Island", 286, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 295, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Island", 296, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Isshin, Two Heavens as One", 224, Rarity.RARE, mage.cards.i.IsshinTwoHeavensAsOne.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Isshin, Two Heavens as One", 328, Rarity.RARE, mage.cards.i.IsshinTwoHeavensAsOne.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Isshin, Two Heavens as One", 488, Rarity.RARE, mage.cards.i.IsshinTwoHeavensAsOne.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jin-Gitaxias, Progress Tyrant", 307, Rarity.MYTHIC, mage.cards.j.JinGitaxiasProgressTyrant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jin-Gitaxias, Progress Tyrant", 371, Rarity.MYTHIC, mage.cards.j.JinGitaxiasProgressTyrant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jin-Gitaxias, Progress Tyrant", 427, Rarity.MYTHIC, mage.cards.j.JinGitaxiasProgressTyrant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jin-Gitaxias, Progress Tyrant", 445, Rarity.MYTHIC, mage.cards.j.JinGitaxiasProgressTyrant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jin-Gitaxias, Progress Tyrant", 59, Rarity.MYTHIC, mage.cards.j.JinGitaxiasProgressTyrant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jugan Defends the Temple", 194, Rarity.MYTHIC, mage.cards.j.JuganDefendsTheTemple.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jugan Defends the Temple", 359, Rarity.MYTHIC, mage.cards.j.JuganDefendsTheTemple.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jugan Defends the Temple", 475, Rarity.MYTHIC, mage.cards.j.JuganDefendsTheTemple.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jukai Naturalist", 225, Rarity.UNCOMMON, mage.cards.j.JukaiNaturalist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jukai Naturalist", 510, Rarity.UNCOMMON, mage.cards.j.JukaiNaturalist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jukai Preserver", 195, Rarity.COMMON, mage.cards.j.JukaiPreserver.class)); - cards.add(new SetCardInfo("Jukai Trainee", 196, Rarity.COMMON, mage.cards.j.JukaiTrainee.class)); + cards.add(new SetCardInfo("Jukai Trainee", 196, Rarity.COMMON, mage.cards.j.JukaiTrainee.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jukai Trainee", 326, Rarity.COMMON, mage.cards.j.JukaiTrainee.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jungle Hollow", 269, Rarity.COMMON, mage.cards.j.JungleHollow.class)); - cards.add(new SetCardInfo("Junji, the Midnight Sky", 102, Rarity.MYTHIC, mage.cards.j.JunjiTheMidnightSky.class)); - cards.add(new SetCardInfo("Kairi, the Swirling Sky", 60, Rarity.MYTHIC, mage.cards.k.KairiTheSwirlingSky.class)); - cards.add(new SetCardInfo("Kaito Shizuki", 226, Rarity.MYTHIC, mage.cards.k.KaitoShizuki.class)); + cards.add(new SetCardInfo("Junji, the Midnight Sky", 102, Rarity.MYTHIC, mage.cards.j.JunjiTheMidnightSky.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Junji, the Midnight Sky", 409, Rarity.MYTHIC, mage.cards.j.JunjiTheMidnightSky.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Junji, the Midnight Sky", 456, Rarity.MYTHIC, mage.cards.j.JunjiTheMidnightSky.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kairi, the Swirling Sky", 408, Rarity.MYTHIC, mage.cards.k.KairiTheSwirlingSky.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kairi, the Swirling Sky", 446, Rarity.MYTHIC, mage.cards.k.KairiTheSwirlingSky.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kairi, the Swirling Sky", 60, Rarity.MYTHIC, mage.cards.k.KairiTheSwirlingSky.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kaito Shizuki", 226, Rarity.MYTHIC, mage.cards.k.KaitoShizuki.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kaito Shizuki", 305, Rarity.MYTHIC, mage.cards.k.KaitoShizuki.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kaito Shizuki", 350, Rarity.MYTHIC, mage.cards.k.KaitoShizuki.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kaito Shizuki", 424, Rarity.MYTHIC, mage.cards.k.KaitoShizuki.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kaito's Pursuit", 103, Rarity.COMMON, mage.cards.k.KaitosPursuit.class)); + cards.add(new SetCardInfo("Kami of Industry", 149, Rarity.COMMON, mage.cards.k.KamiOfIndustry.class)); cards.add(new SetCardInfo("Kami of Restless Shadows", 104, Rarity.COMMON, mage.cards.k.KamiOfRestlessShadows.class)); cards.add(new SetCardInfo("Kami of Terrible Secrets", 105, Rarity.COMMON, mage.cards.k.KamiOfTerribleSecrets.class)); - cards.add(new SetCardInfo("Kami of Transience", 197, Rarity.RARE, mage.cards.k.KamiOfTransience.class)); + cards.add(new SetCardInfo("Kami of Transience", 197, Rarity.RARE, mage.cards.k.KamiOfTransience.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kami of Transience", 391, Rarity.RARE, mage.cards.k.KamiOfTransience.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kami of Transience", 476, Rarity.RARE, mage.cards.k.KamiOfTransience.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kami's Flare", 150, Rarity.COMMON, mage.cards.k.KamisFlare.class)); - cards.add(new SetCardInfo("Kappa Tech-Wrecker", 198, Rarity.UNCOMMON, mage.cards.k.KappaTechWrecker.class)); + cards.add(new SetCardInfo("Kappa Tech-Wrecker", 198, Rarity.UNCOMMON, mage.cards.k.KappaTechWrecker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kappa Tech-Wrecker", 348, Rarity.UNCOMMON, mage.cards.k.KappaTechWrecker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kindled Fury", 151, Rarity.COMMON, mage.cards.k.KindledFury.class)); - cards.add(new SetCardInfo("Kirin-Touched Orochi", 212, Rarity.RARE, mage.cards.k.KirinTouchedOrochi.class)); + cards.add(new SetCardInfo("Kirin-Touched Orochi", 212, Rarity.RARE, mage.cards.k.KirinTouchedOrochi.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kirin-Touched Orochi", 360, Rarity.RARE, mage.cards.k.KirinTouchedOrochi.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kirin-Touched Orochi", 482, Rarity.RARE, mage.cards.k.KirinTouchedOrochi.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Kitsune Ace", 22, Rarity.COMMON, mage.cards.k.KitsuneAce.class)); - cards.add(new SetCardInfo("Kodama of the West Tree", 199, Rarity.MYTHIC, mage.cards.k.KodamaOfTheWestTree.class)); - cards.add(new SetCardInfo("Kura, the Boundless Sky", 200, Rarity.MYTHIC, mage.cards.k.KuraTheBoundlessSky.class)); - cards.add(new SetCardInfo("Kyodai, Soul of Kamigawa", 23, Rarity.RARE, mage.cards.k.KyodaiSoulOfKamigawa.class)); + cards.add(new SetCardInfo("Kodama of the West Tree", 199, Rarity.MYTHIC, mage.cards.k.KodamaOfTheWestTree.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kodama of the West Tree", 392, Rarity.MYTHIC, mage.cards.k.KodamaOfTheWestTree.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kodama of the West Tree", 423, Rarity.MYTHIC, mage.cards.k.KodamaOfTheWestTree.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kodama of the West Tree", 477, Rarity.MYTHIC, mage.cards.k.KodamaOfTheWestTree.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kotose, the Silent Spider", 228, Rarity.RARE, mage.cards.k.KotoseTheSilentSpider.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kotose, the Silent Spider", 351, Rarity.RARE, mage.cards.k.KotoseTheSilentSpider.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kotose, the Silent Spider", 490, Rarity.RARE, mage.cards.k.KotoseTheSilentSpider.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kumano Faces Kakkazan", 152, Rarity.UNCOMMON, mage.cards.k.KumanoFacesKakkazan.class)); + cards.add(new SetCardInfo("Kura, the Boundless Sky", 200, Rarity.MYTHIC, mage.cards.k.KuraTheBoundlessSky.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kura, the Boundless Sky", 411, Rarity.MYTHIC, mage.cards.k.KuraTheBoundlessSky.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kura, the Boundless Sky", 478, Rarity.MYTHIC, mage.cards.k.KuraTheBoundlessSky.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kyodai, Soul of Kamigawa", 23, Rarity.RARE, mage.cards.k.KyodaiSoulOfKamigawa.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kyodai, Soul of Kamigawa", 407, Rarity.RARE, mage.cards.k.KyodaiSoulOfKamigawa.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kyodai, Soul of Kamigawa", 438, Rarity.RARE, mage.cards.k.KyodaiSoulOfKamigawa.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Leech Gauntlet", 106, Rarity.UNCOMMON, mage.cards.l.LeechGauntlet.class)); + cards.add(new SetCardInfo("Lethal Exploit", 107, Rarity.COMMON, mage.cards.l.LethalExploit.class)); cards.add(new SetCardInfo("Life of Toshiro Umezawa", 108, Rarity.UNCOMMON, mage.cards.l.LifeOfToshiroUmezawa.class)); cards.add(new SetCardInfo("Light the Way", 24, Rarity.COMMON, mage.cards.l.LightTheWay.class)); + cards.add(new SetCardInfo("Light-Paws, Emperor's Voice", 25, Rarity.RARE, mage.cards.l.LightPawsEmperorsVoice.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Light-Paws, Emperor's Voice", 367, Rarity.RARE, mage.cards.l.LightPawsEmperorsVoice.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Light-Paws, Emperor's Voice", 439, Rarity.RARE, mage.cards.l.LightPawsEmperorsVoice.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Likeness of the Seeker", 172, Rarity.UNCOMMON, mage.cards.l.LikenessOfTheSeeker.class)); - cards.add(new SetCardInfo("Lion Sash", 26, Rarity.RARE, mage.cards.l.LionSash.class)); - cards.add(new SetCardInfo("Living Breakthrough", 57, Rarity.RARE, mage.cards.l.LivingBreakthrough.class)); - cards.add(new SetCardInfo("Lizard Blades", 153, Rarity.RARE, mage.cards.l.LizardBlades.class)); + cards.add(new SetCardInfo("Lion Sash", 26, Rarity.RARE, mage.cards.l.LionSash.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lion Sash", 368, Rarity.RARE, mage.cards.l.LionSash.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lion Sash", 440, Rarity.RARE, mage.cards.l.LionSash.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Living Breakthrough", 355, Rarity.RARE, mage.cards.l.LivingBreakthrough.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Living Breakthrough", 443, Rarity.RARE, mage.cards.l.LivingBreakthrough.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Living Breakthrough", 57, Rarity.RARE, mage.cards.l.LivingBreakthrough.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lizard Blades", 153, Rarity.RARE, mage.cards.l.LizardBlades.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lizard Blades", 385, Rarity.RARE, mage.cards.l.LizardBlades.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lizard Blades", 468, Rarity.RARE, mage.cards.l.LizardBlades.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lucky Offering", 27, Rarity.COMMON, mage.cards.l.LuckyOffering.class)); cards.add(new SetCardInfo("Malicious Malfunction", 110, Rarity.UNCOMMON, mage.cards.m.MaliciousMalfunction.class)); + cards.add(new SetCardInfo("March of Burgeoning Life", 201, Rarity.RARE, mage.cards.m.MarchOfBurgeoningLife.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("March of Burgeoning Life", 393, Rarity.RARE, mage.cards.m.MarchOfBurgeoningLife.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("March of Burgeoning Life", 479, Rarity.RARE, mage.cards.m.MarchOfBurgeoningLife.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("March of Otherworldly Light", 28, Rarity.RARE, mage.cards.m.MarchOfOtherworldlyLight.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("March of Otherworldly Light", 369, Rarity.RARE, mage.cards.m.MarchOfOtherworldlyLight.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("March of Otherworldly Light", 441, Rarity.RARE, mage.cards.m.MarchOfOtherworldlyLight.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("March of Reckless Joy", 154, Rarity.RARE, mage.cards.m.MarchOfRecklessJoy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("March of Reckless Joy", 386, Rarity.RARE, mage.cards.m.MarchOfRecklessJoy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("March of Reckless Joy", 469, Rarity.RARE, mage.cards.m.MarchOfRecklessJoy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("March of Swirling Mist", 372, Rarity.RARE, mage.cards.m.MarchOfSwirlingMist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("March of Swirling Mist", 447, Rarity.RARE, mage.cards.m.MarchOfSwirlingMist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("March of Swirling Mist", 61, Rarity.RARE, mage.cards.m.MarchOfSwirlingMist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("March of Wretched Sorrow", 111, Rarity.RARE, mage.cards.m.MarchOfWretchedSorrow.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("March of Wretched Sorrow", 380, Rarity.RARE, mage.cards.m.MarchOfWretchedSorrow.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("March of Wretched Sorrow", 457, Rarity.RARE, mage.cards.m.MarchOfWretchedSorrow.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Master's Rebuke", 202, Rarity.COMMON, mage.cards.m.MastersRebuke.class)); cards.add(new SetCardInfo("Mech Hangar", 270, Rarity.UNCOMMON, mage.cards.m.MechHangar.class)); + cards.add(new SetCardInfo("Mechtitan Core", 249, Rarity.RARE, mage.cards.m.MechtitanCore.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mechtitan Core", 402, Rarity.RARE, mage.cards.m.MechtitanCore.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mechtitan Core", 497, Rarity.RARE, mage.cards.m.MechtitanCore.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Memory of Toshiro", 108, Rarity.UNCOMMON, mage.cards.m.MemoryOfToshiro.class)); cards.add(new SetCardInfo("Michiko's Reign of Truth", 29, Rarity.UNCOMMON, mage.cards.m.MichikosReignOfTruth.class)); + cards.add(new SetCardInfo("Mindlink Mech", 373, Rarity.RARE, mage.cards.m.MindlinkMech.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mindlink Mech", 448, Rarity.RARE, mage.cards.m.MindlinkMech.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mindlink Mech", 62, Rarity.RARE, mage.cards.m.MindlinkMech.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mirror Box", 250, Rarity.RARE, mage.cards.m.MirrorBox.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mirror Box", 403, Rarity.RARE, mage.cards.m.MirrorBox.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mirror Box", 498, Rarity.RARE, mage.cards.m.MirrorBox.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mirrorshell Crab", 63, Rarity.COMMON, mage.cards.m.MirrorshellCrab.class)); cards.add(new SetCardInfo("Mnemonic Sphere", 64, Rarity.COMMON, mage.cards.m.MnemonicSphere.class)); cards.add(new SetCardInfo("Mobilizer Mech", 65, Rarity.UNCOMMON, mage.cards.m.MobilizerMech.class)); - cards.add(new SetCardInfo("Moon-Circuit Hacker", 67, Rarity.COMMON, mage.cards.m.MoonCircuitHacker.class)); + cards.add(new SetCardInfo("Moon-Circuit Hacker", 334, Rarity.COMMON, mage.cards.m.MoonCircuitHacker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Moon-Circuit Hacker", 67, Rarity.COMMON, mage.cards.m.MoonCircuitHacker.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Moonfolk Puzzlemaker", 68, Rarity.COMMON, mage.cards.m.MoonfolkPuzzlemaker.class)); cards.add(new SetCardInfo("Moonsnare Prototype", 69, Rarity.COMMON, mage.cards.m.MoonsnarePrototype.class)); - cards.add(new SetCardInfo("Moonsnare Specialist", 70, Rarity.COMMON, mage.cards.m.MoonsnareSpecialist.class)); + cards.add(new SetCardInfo("Moonsnare Specialist", 335, Rarity.COMMON, mage.cards.m.MoonsnareSpecialist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Moonsnare Specialist", 70, Rarity.COMMON, mage.cards.m.MoonsnareSpecialist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mothrider Patrol", 30, Rarity.COMMON, mage.cards.m.MothriderPatrol.class)); cards.add(new SetCardInfo("Mountain", 289, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mukotai Ambusher", 112, Rarity.COMMON, mage.cards.m.MukotaiAmbusher.class)); - cards.add(new SetCardInfo("Mukotai Soulripper", 113, Rarity.RARE, mage.cards.m.MukotaiSoulripper.class)); + cards.add(new SetCardInfo("Mountain", 290, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 299, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 300, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mukotai Ambusher", 112, Rarity.COMMON, mage.cards.m.MukotaiAmbusher.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mukotai Ambusher", 342, Rarity.COMMON, mage.cards.m.MukotaiAmbusher.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mukotai Soulripper", 113, Rarity.RARE, mage.cards.m.MukotaiSoulripper.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mukotai Soulripper", 381, Rarity.RARE, mage.cards.m.MukotaiSoulripper.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mukotai Soulripper", 458, Rarity.RARE, mage.cards.m.MukotaiSoulripper.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nameless Conqueror", 162, Rarity.COMMON, mage.cards.n.NamelessConqueror.class)); cards.add(new SetCardInfo("Naomi, Pillar of Order", 229, Rarity.UNCOMMON, mage.cards.n.NaomiPillarOfOrder.class)); + cards.add(new SetCardInfo("Nashi, Moon Sage's Scion", 114, Rarity.MYTHIC, mage.cards.n.NashiMoonSagesScion.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nashi, Moon Sage's Scion", 343, Rarity.MYTHIC, mage.cards.n.NashiMoonSagesScion.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nashi, Moon Sage's Scion", 421, Rarity.MYTHIC, mage.cards.n.NashiMoonSagesScion.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nashi, Moon Sage's Scion", 459, Rarity.MYTHIC, mage.cards.n.NashiMoonSagesScion.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Network Disruptor", 71, Rarity.COMMON, mage.cards.n.NetworkDisruptor.class)); cards.add(new SetCardInfo("Network Terminal", 251, Rarity.COMMON, mage.cards.n.NetworkTerminal.class)); - cards.add(new SetCardInfo("Nezumi Bladeblesser", 115, Rarity.COMMON, mage.cards.n.NezumiBladeblesser.class)); - cards.add(new SetCardInfo("Nezumi Prowler", 116, Rarity.UNCOMMON, mage.cards.n.NezumiProwler.class)); + cards.add(new SetCardInfo("Nezumi Bladeblesser", 115, Rarity.COMMON, mage.cards.n.NezumiBladeblesser.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nezumi Bladeblesser", 318, Rarity.COMMON, mage.cards.n.NezumiBladeblesser.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nezumi Prowler", 116, Rarity.UNCOMMON, mage.cards.n.NezumiProwler.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nezumi Prowler", 344, Rarity.UNCOMMON, mage.cards.n.NezumiProwler.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Nezumi Road Captain", 117, Rarity.COMMON, mage.cards.n.NezumiRoadCaptain.class)); cards.add(new SetCardInfo("Ninja's Kunai", 252, Rarity.COMMON, mage.cards.n.NinjasKunai.class)); - cards.add(new SetCardInfo("Norika Yamazaki, the Poet", 31, Rarity.UNCOMMON, mage.cards.n.NorikaYamazakiThePoet.class)); - cards.add(new SetCardInfo("Ogre-Head Helm", 155, Rarity.RARE, mage.cards.o.OgreHeadHelm.class)); + cards.add(new SetCardInfo("Norika Yamazaki, the Poet", 31, Rarity.UNCOMMON, mage.cards.n.NorikaYamazakiThePoet.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Norika Yamazaki, the Poet", 311, Rarity.UNCOMMON, mage.cards.n.NorikaYamazakiThePoet.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("O-Kagachi Made Manifest", 227, Rarity.MYTHIC, mage.cards.o.OKagachiMadeManifest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("O-Kagachi Made Manifest", 362, Rarity.MYTHIC, mage.cards.o.OKagachiMadeManifest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("O-Kagachi Made Manifest", 489, Rarity.MYTHIC, mage.cards.o.OKagachiMadeManifest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ogre-Head Helm", 155, Rarity.RARE, mage.cards.o.OgreHeadHelm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ogre-Head Helm", 387, Rarity.RARE, mage.cards.o.OgreHeadHelm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ogre-Head Helm", 470, Rarity.RARE, mage.cards.o.OgreHeadHelm.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Okiba Reckoner Raid", 117, Rarity.COMMON, mage.cards.o.OkibaReckonerRaid.class)); + cards.add(new SetCardInfo("Okiba Salvage", 118, Rarity.UNCOMMON, mage.cards.o.OkibaSalvage.class)); cards.add(new SetCardInfo("Oni-Cult Anvil", 230, Rarity.UNCOMMON, mage.cards.o.OniCultAnvil.class)); cards.add(new SetCardInfo("Orochi Merge-Keeper", 203, Rarity.UNCOMMON, mage.cards.o.OrochiMergeKeeper.class)); - cards.add(new SetCardInfo("Otawara, Soaring City", 271, Rarity.RARE, mage.cards.o.OtawaraSoaringCity.class)); + cards.add(new SetCardInfo("Otawara, Soaring City", 271, Rarity.RARE, mage.cards.o.OtawaraSoaringCity.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Otawara, Soaring City", 414, Rarity.RARE, mage.cards.o.OtawaraSoaringCity.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Otawara, Soaring City", 503, Rarity.RARE, mage.cards.o.OtawaraSoaringCity.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Papercraft Decoy", 253, Rarity.COMMON, mage.cards.p.PapercraftDecoy.class)); cards.add(new SetCardInfo("Patchwork Automaton", 254, Rarity.UNCOMMON, mage.cards.p.PatchworkAutomaton.class)); - cards.add(new SetCardInfo("Peerless Samurai", 156, Rarity.COMMON, mage.cards.p.PeerlessSamurai.class)); + cards.add(new SetCardInfo("Peerless Samurai", 156, Rarity.COMMON, mage.cards.p.PeerlessSamurai.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Peerless Samurai", 322, Rarity.COMMON, mage.cards.p.PeerlessSamurai.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 283, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 284, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 293, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Plains", 294, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Planar Incision", 72, Rarity.COMMON, mage.cards.p.PlanarIncision.class)); cards.add(new SetCardInfo("Portrait of Michiko", 29, Rarity.UNCOMMON, mage.cards.p.PortraitOfMichiko.class)); cards.add(new SetCardInfo("Prodigy's Prototype", 231, Rarity.UNCOMMON, mage.cards.p.ProdigysPrototype.class)); - cards.add(new SetCardInfo("Prosperous Thief", 73, Rarity.UNCOMMON, mage.cards.p.ProsperousThief.class)); + cards.add(new SetCardInfo("Prosperous Thief", 336, Rarity.UNCOMMON, mage.cards.p.ProsperousThief.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Prosperous Thief", 73, Rarity.UNCOMMON, mage.cards.p.ProsperousThief.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Rabbit Battery", 157, Rarity.UNCOMMON, mage.cards.r.RabbitBattery.class)); - cards.add(new SetCardInfo("Raiyuu, Storm's Edge", 232, Rarity.RARE, mage.cards.r.RaiyuuStormsEdge.class)); + cards.add(new SetCardInfo("Raiyuu, Storm's Edge", 232, Rarity.RARE, mage.cards.r.RaiyuuStormsEdge.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Raiyuu, Storm's Edge", 329, Rarity.RARE, mage.cards.r.RaiyuuStormsEdge.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Raiyuu, Storm's Edge", 491, Rarity.RARE, mage.cards.r.RaiyuuStormsEdge.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Reality Heist", 75, Rarity.UNCOMMON, mage.cards.r.RealityHeist.class)); - cards.add(new SetCardInfo("Reckoner Bankbuster", 255, Rarity.RARE, mage.cards.r.ReckonerBankbuster.class)); + cards.add(new SetCardInfo("Reckoner Bankbuster", 255, Rarity.RARE, mage.cards.r.ReckonerBankbuster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Reckoner Bankbuster", 404, Rarity.RARE, mage.cards.r.ReckonerBankbuster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Reckoner Bankbuster", 499, Rarity.RARE, mage.cards.r.ReckonerBankbuster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Reckoner Shakedown", 119, Rarity.COMMON, mage.cards.r.ReckonerShakedown.class)); + cards.add(new SetCardInfo("Reckoner's Bargain", 120, Rarity.COMMON, mage.cards.r.ReckonersBargain.class)); + cards.add(new SetCardInfo("Reflection of Kiki-Jiki", 141, Rarity.RARE, mage.cards.r.ReflectionOfKikiJiki.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Reflection of Kiki-Jiki", 357, Rarity.RARE, mage.cards.r.ReflectionOfKikiJiki.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Reflection of Kiki-Jiki", 465, Rarity.RARE, mage.cards.r.ReflectionOfKikiJiki.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Regent's Authority", 32, Rarity.COMMON, mage.cards.r.RegentsAuthority.class)); - cards.add(new SetCardInfo("Reinforced Ronin", 158, Rarity.UNCOMMON, mage.cards.r.ReinforcedRonin.class)); + cards.add(new SetCardInfo("Reinforced Ronin", 158, Rarity.UNCOMMON, mage.cards.r.ReinforcedRonin.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Reinforced Ronin", 323, Rarity.UNCOMMON, mage.cards.r.ReinforcedRonin.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Reito Sentinel", 256, Rarity.UNCOMMON, mage.cards.r.ReitoSentinel.class)); + cards.add(new SetCardInfo("Remnant of the Rising Star", 194, Rarity.MYTHIC, mage.cards.r.RemnantOfTheRisingStar.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Remnant of the Rising Star", 359, Rarity.MYTHIC, mage.cards.r.RemnantOfTheRisingStar.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Remnant of the Rising Star", 475, Rarity.MYTHIC, mage.cards.r.RemnantOfTheRisingStar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Repel the Vile", 33, Rarity.COMMON, mage.cards.r.RepelTheVile.class)); cards.add(new SetCardInfo("Replication Specialist", 76, Rarity.UNCOMMON, mage.cards.r.ReplicationSpecialist.class)); cards.add(new SetCardInfo("Return to Action", 121, Rarity.COMMON, mage.cards.r.ReturnToAction.class)); - cards.add(new SetCardInfo("Risona, Asari Commander", 233, Rarity.RARE, mage.cards.r.RisonaAsariCommander.class)); + cards.add(new SetCardInfo("Risona, Asari Commander", 233, Rarity.RARE, mage.cards.r.RisonaAsariCommander.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Risona, Asari Commander", 330, Rarity.RARE, mage.cards.r.RisonaAsariCommander.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Risona, Asari Commander", 425, Rarity.RARE, mage.cards.r.RisonaAsariCommander.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Risona, Asari Commander", 492, Rarity.RARE, mage.cards.r.RisonaAsariCommander.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Roadside Reliquary", 272, Rarity.UNCOMMON, mage.cards.r.RoadsideReliquary.class)); cards.add(new SetCardInfo("Roaring Earth", 204, Rarity.UNCOMMON, mage.cards.r.RoaringEarth.class)); cards.add(new SetCardInfo("Rugged Highlands", 273, Rarity.COMMON, mage.cards.r.RuggedHighlands.class)); cards.add(new SetCardInfo("Runaway Trash-Bot", 257, Rarity.UNCOMMON, mage.cards.r.RunawayTrashBot.class)); cards.add(new SetCardInfo("Saiba Trespassers", 77, Rarity.COMMON, mage.cards.s.SaibaTrespassers.class)); - cards.add(new SetCardInfo("Satoru Umezawa", 234, Rarity.RARE, mage.cards.s.SatoruUmezawa.class)); - cards.add(new SetCardInfo("Satsuki, the Living Lore", 235, Rarity.RARE, mage.cards.s.SatsukiTheLivingLore.class)); + cards.add(new SetCardInfo("Satoru Umezawa", 234, Rarity.RARE, mage.cards.s.SatoruUmezawa.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Satoru Umezawa", 352, Rarity.RARE, mage.cards.s.SatoruUmezawa.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Satoru Umezawa", 426, Rarity.RARE, mage.cards.s.SatoruUmezawa.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Satoru Umezawa", 493, Rarity.RARE, mage.cards.s.SatoruUmezawa.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Satoru Umezawa", 507, Rarity.RARE, mage.cards.s.SatoruUmezawa.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Satsuki, the Living Lore", 235, Rarity.RARE, mage.cards.s.SatsukiTheLivingLore.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Satsuki, the Living Lore", 399, Rarity.RARE, mage.cards.s.SatsukiTheLivingLore.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Satsuki, the Living Lore", 494, Rarity.RARE, mage.cards.s.SatsukiTheLivingLore.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Scoured Barrens", 274, Rarity.COMMON, mage.cards.s.ScouredBarrens.class)); - cards.add(new SetCardInfo("Scrap Welder", 159, Rarity.RARE, mage.cards.s.ScrapWelder.class)); + cards.add(new SetCardInfo("Scrap Welder", 159, Rarity.RARE, mage.cards.s.ScrapWelder.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Scrap Welder", 388, Rarity.RARE, mage.cards.s.ScrapWelder.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Scrap Welder", 471, Rarity.RARE, mage.cards.s.ScrapWelder.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Scrapyard Steelbreaker", 160, Rarity.COMMON, mage.cards.s.ScrapyardSteelbreaker.class)); cards.add(new SetCardInfo("Searchlight Companion", 258, Rarity.COMMON, mage.cards.s.SearchlightCompanion.class)); cards.add(new SetCardInfo("Season of Renewal", 205, Rarity.COMMON, mage.cards.s.SeasonOfRenewal.class)); + cards.add(new SetCardInfo("Secluded Courtyard", 275, Rarity.UNCOMMON, mage.cards.s.SecludedCourtyard.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Secluded Courtyard", 512, Rarity.UNCOMMON, mage.cards.s.SecludedCourtyard.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Seismic Wave", 161, Rarity.UNCOMMON, mage.cards.s.SeismicWave.class)); - cards.add(new SetCardInfo("Selfless Samurai", 35, Rarity.UNCOMMON, mage.cards.s.SelflessSamurai.class)); + cards.add(new SetCardInfo("Selfless Samurai", 312, Rarity.UNCOMMON, mage.cards.s.SelflessSamurai.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Selfless Samurai", 35, Rarity.UNCOMMON, mage.cards.s.SelflessSamurai.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Seshiro's Living Legacy", 210, Rarity.COMMON, mage.cards.s.SeshirosLivingLegacy.class)); - cards.add(new SetCardInfo("Seven-Tail Mentor", 36, Rarity.COMMON, mage.cards.s.SevenTailMentor.class)); + cards.add(new SetCardInfo("Seven-Tail Mentor", 313, Rarity.COMMON, mage.cards.s.SevenTailMentor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Seven-Tail Mentor", 36, Rarity.COMMON, mage.cards.s.SevenTailMentor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Shigeki, Jukai Visionary", 206, Rarity.RARE, mage.cards.s.ShigekiJukaiVisionary.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Shigeki, Jukai Visionary", 394, Rarity.RARE, mage.cards.s.ShigekiJukaiVisionary.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Shigeki, Jukai Visionary", 480, Rarity.RARE, mage.cards.s.ShigekiJukaiVisionary.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Short Circuit", 78, Rarity.COMMON, mage.cards.s.ShortCircuit.class)); cards.add(new SetCardInfo("Shrine Steward", 259, Rarity.COMMON, mage.cards.s.ShrineSteward.class)); - cards.add(new SetCardInfo("Silver-Fur Master", 236, Rarity.UNCOMMON, mage.cards.s.SilverFurMaster.class)); + cards.add(new SetCardInfo("Silver-Fur Master", 236, Rarity.UNCOMMON, mage.cards.s.SilverFurMaster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Silver-Fur Master", 353, Rarity.UNCOMMON, mage.cards.s.SilverFurMaster.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Silver-Fur Master", 511, Rarity.UNCOMMON, mage.cards.s.SilverFurMaster.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Simian Sling", 163, Rarity.COMMON, mage.cards.s.SimianSling.class)); - cards.add(new SetCardInfo("Sky-Blessed Samurai", 37, Rarity.UNCOMMON, mage.cards.s.SkyBlessedSamurai.class)); + cards.add(new SetCardInfo("Sky-Blessed Samurai", 314, Rarity.UNCOMMON, mage.cards.s.SkyBlessedSamurai.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sky-Blessed Samurai", 37, Rarity.UNCOMMON, mage.cards.s.SkyBlessedSamurai.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Skyswimmer Koi", 79, Rarity.COMMON, mage.cards.s.SkyswimmerKoi.class)); cards.add(new SetCardInfo("Sokenzan Smelter", 164, Rarity.UNCOMMON, mage.cards.s.SokenzanSmelter.class)); - cards.add(new SetCardInfo("Sokenzan, Crucible of Defiance", 276, Rarity.RARE, mage.cards.s.SokenzanCrucibleOfDefiance.class)); - cards.add(new SetCardInfo("Soul Transfer", 122, Rarity.RARE, mage.cards.s.SoulTransfer.class)); + cards.add(new SetCardInfo("Sokenzan, Crucible of Defiance", 276, Rarity.RARE, mage.cards.s.SokenzanCrucibleOfDefiance.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sokenzan, Crucible of Defiance", 415, Rarity.RARE, mage.cards.s.SokenzanCrucibleOfDefiance.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sokenzan, Crucible of Defiance", 504, Rarity.RARE, mage.cards.s.SokenzanCrucibleOfDefiance.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soul Transfer", 122, Rarity.RARE, mage.cards.s.SoulTransfer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soul Transfer", 382, Rarity.RARE, mage.cards.s.SoulTransfer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soul Transfer", 460, Rarity.RARE, mage.cards.s.SoulTransfer.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Spell Pierce", 80, Rarity.COMMON, mage.cards.s.SpellPierce.class)); - cards.add(new SetCardInfo("Spirit-Sister's Call", 237, Rarity.MYTHIC, mage.cards.s.SpiritSistersCall.class)); - cards.add(new SetCardInfo("Spirited Companion", 38, Rarity.COMMON, mage.cards.s.SpiritedCompanion.class)); - cards.add(new SetCardInfo("Spring-Leaf Avenger", 208, Rarity.RARE, mage.cards.s.SpringLeafAvenger.class)); - cards.add(new SetCardInfo("Sunblade Samurai", 39, Rarity.COMMON, mage.cards.s.SunbladeSamurai.class)); - cards.add(new SetCardInfo("Surgehacker Mech", 260, Rarity.RARE, mage.cards.s.SurgehackerMech.class)); + cards.add(new SetCardInfo("Spinning Wheel Kick", 207, Rarity.UNCOMMON, mage.cards.s.SpinningWheelKick.class)); + cards.add(new SetCardInfo("Spirit-Sister's Call", 237, Rarity.MYTHIC, mage.cards.s.SpiritSistersCall.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spirit-Sister's Call", 400, Rarity.MYTHIC, mage.cards.s.SpiritSistersCall.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spirit-Sister's Call", 495, Rarity.MYTHIC, mage.cards.s.SpiritSistersCall.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spirited Companion", 38, Rarity.COMMON, mage.cards.s.SpiritedCompanion.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spirited Companion", 508, Rarity.COMMON, mage.cards.s.SpiritedCompanion.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spring-Leaf Avenger", 208, Rarity.RARE, mage.cards.s.SpringLeafAvenger.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spring-Leaf Avenger", 349, Rarity.RARE, mage.cards.s.SpringLeafAvenger.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spring-Leaf Avenger", 481, Rarity.RARE, mage.cards.s.SpringLeafAvenger.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Storyweave", 209, Rarity.UNCOMMON, mage.cards.s.Storyweave.class)); + cards.add(new SetCardInfo("Suit Up", 81, Rarity.COMMON, mage.cards.s.SuitUp.class)); + cards.add(new SetCardInfo("Sunblade Samurai", 315, Rarity.COMMON, mage.cards.s.SunbladeSamurai.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sunblade Samurai", 39, Rarity.COMMON, mage.cards.s.SunbladeSamurai.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Surgehacker Mech", 260, Rarity.RARE, mage.cards.s.SurgehackerMech.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Surgehacker Mech", 405, Rarity.RARE, mage.cards.s.SurgehackerMech.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Surgehacker Mech", 500, Rarity.RARE, mage.cards.s.SurgehackerMech.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 287, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 288, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 297, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 298, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Swiftwater Cliffs", 277, Rarity.COMMON, mage.cards.s.SwiftwaterCliffs.class)); - cards.add(new SetCardInfo("Takenuma, Abandoned Mire", 278, Rarity.RARE, mage.cards.t.TakenumaAbandonedMire.class)); + cards.add(new SetCardInfo("Takenuma, Abandoned Mire", 278, Rarity.RARE, mage.cards.t.TakenumaAbandonedMire.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Takenuma, Abandoned Mire", 416, Rarity.RARE, mage.cards.t.TakenumaAbandonedMire.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Takenuma, Abandoned Mire", 505, Rarity.RARE, mage.cards.t.TakenumaAbandonedMire.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tales of Master Seshiro", 210, Rarity.COMMON, mage.cards.t.TalesOfMasterSeshiro.class)); + cards.add(new SetCardInfo("Tameshi, Reality Architect", 375, Rarity.RARE, mage.cards.t.TameshiRealityArchitect.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tameshi, Reality Architect", 450, Rarity.RARE, mage.cards.t.TameshiRealityArchitect.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tameshi, Reality Architect", 82, Rarity.RARE, mage.cards.t.TameshiRealityArchitect.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tamiyo's Compleation", 83, Rarity.COMMON, mage.cards.t.TamiyosCompleation.class)); - cards.add(new SetCardInfo("Teachings of the Kirin", 212, Rarity.RARE, mage.cards.t.TeachingsOfTheKirin.class)); + cards.add(new SetCardInfo("Tamiyo's Safekeeping", 211, Rarity.COMMON, mage.cards.t.TamiyosSafekeeping.class)); + cards.add(new SetCardInfo("Tamiyo, Compleated Sage", 238, Rarity.MYTHIC, mage.cards.t.TamiyoCompleatedSage.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tamiyo, Compleated Sage", 306, Rarity.MYTHIC, mage.cards.t.TamiyoCompleatedSage.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tamiyo, Compleated Sage", 308, Rarity.MYTHIC, mage.cards.t.TamiyoCompleatedSage.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tamiyo, Compleated Sage", 428, Rarity.MYTHIC, mage.cards.t.TamiyoCompleatedSage.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tatsunari, Toad Rider", 123, Rarity.RARE, mage.cards.t.TatsunariToadRider.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tatsunari, Toad Rider", 345, Rarity.RARE, mage.cards.t.TatsunariToadRider.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tatsunari, Toad Rider", 461, Rarity.RARE, mage.cards.t.TatsunariToadRider.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Teachings of the Kirin", 212, Rarity.RARE, mage.cards.t.TeachingsOfTheKirin.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Teachings of the Kirin", 360, Rarity.RARE, mage.cards.t.TeachingsOfTheKirin.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Teachings of the Kirin", 482, Rarity.RARE, mage.cards.t.TeachingsOfTheKirin.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tempered in Solitude", 165, Rarity.UNCOMMON, mage.cards.t.TemperedInSolitude.class)); + cards.add(new SetCardInfo("Tezzeret, Betrayer of Flesh", 304, Rarity.MYTHIC, mage.cards.t.TezzeretBetrayerOfFlesh.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tezzeret, Betrayer of Flesh", 376, Rarity.MYTHIC, mage.cards.t.TezzeretBetrayerOfFlesh.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tezzeret, Betrayer of Flesh", 419, Rarity.MYTHIC, mage.cards.t.TezzeretBetrayerOfFlesh.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tezzeret, Betrayer of Flesh", 84, Rarity.MYTHIC, mage.cards.t.TezzeretBetrayerOfFlesh.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Dragon-Kami Reborn", 181, Rarity.RARE, mage.cards.t.TheDragonKamiReborn.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Dragon-Kami Reborn", 358, Rarity.RARE, mage.cards.t.TheDragonKamiReborn.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Dragon-Kami Reborn", 473, Rarity.RARE, mage.cards.t.TheDragonKamiReborn.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Fall of Lord Konda", 12, Rarity.UNCOMMON, mage.cards.t.TheFallOfLordKonda.class)); + cards.add(new SetCardInfo("The Kami War", 227, Rarity.MYTHIC, mage.cards.t.TheKamiWar.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Kami War", 362, Rarity.MYTHIC, mage.cards.t.TheKamiWar.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Kami War", 489, Rarity.MYTHIC, mage.cards.t.TheKamiWar.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Long Reach of Night", 109, Rarity.UNCOMMON, mage.cards.t.TheLongReachOfNight.class)); cards.add(new SetCardInfo("The Modern Age", 66, Rarity.COMMON, mage.cards.t.TheModernAge.class)); - cards.add(new SetCardInfo("The Restoration of Eiganjo", 34, Rarity.RARE, mage.cards.t.TheRestorationOfEiganjo.class)); + cards.add(new SetCardInfo("The Reality Chip", 374, Rarity.RARE, mage.cards.t.TheRealityChip.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Reality Chip", 449, Rarity.RARE, mage.cards.t.TheRealityChip.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Reality Chip", 74, Rarity.RARE, mage.cards.t.TheRealityChip.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Restoration of Eiganjo", 34, Rarity.RARE, mage.cards.t.TheRestorationOfEiganjo.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Restoration of Eiganjo", 354, Rarity.RARE, mage.cards.t.TheRestorationOfEiganjo.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Restoration of Eiganjo", 442, Rarity.RARE, mage.cards.t.TheRestorationOfEiganjo.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Shattered States Era", 162, Rarity.COMMON, mage.cards.t.TheShatteredStatesEra.class)); - cards.add(new SetCardInfo("The Wandering Emperor", 42, Rarity.MYTHIC, mage.cards.t.TheWanderingEmperor.class)); + cards.add(new SetCardInfo("The Wandering Emperor", 303, Rarity.MYTHIC, mage.cards.t.TheWanderingEmperor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Wandering Emperor", 316, Rarity.MYTHIC, mage.cards.t.TheWanderingEmperor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Wandering Emperor", 418, Rarity.MYTHIC, mage.cards.t.TheWanderingEmperor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Wandering Emperor", 42, Rarity.MYTHIC, mage.cards.t.TheWanderingEmperor.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thirst for Knowledge", 85, Rarity.UNCOMMON, mage.cards.t.ThirstForKnowledge.class)); cards.add(new SetCardInfo("Thornwood Falls", 279, Rarity.COMMON, mage.cards.t.ThornwoodFalls.class)); - cards.add(new SetCardInfo("Thousand-Faced Shadow", 86, Rarity.RARE, mage.cards.t.ThousandFacedShadow.class)); + cards.add(new SetCardInfo("Thousand-Faced Shadow", 337, Rarity.RARE, mage.cards.t.ThousandFacedShadow.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Thousand-Faced Shadow", 451, Rarity.RARE, mage.cards.t.ThousandFacedShadow.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Thousand-Faced Shadow", 86, Rarity.RARE, mage.cards.t.ThousandFacedShadow.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Thundering Raiju", 166, Rarity.RARE, mage.cards.t.ThunderingRaiju.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Thundering Raiju", 389, Rarity.RARE, mage.cards.t.ThunderingRaiju.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Thundering Raiju", 472, Rarity.RARE, mage.cards.t.ThunderingRaiju.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Thundersteel Colossus", 261, Rarity.COMMON, mage.cards.t.ThundersteelColossus.class)); cards.add(new SetCardInfo("Touch the Spirit Realm", 40, Rarity.UNCOMMON, mage.cards.t.TouchTheSpiritRealm.class)); cards.add(new SetCardInfo("Towashi Guide-Bot", 262, Rarity.UNCOMMON, mage.cards.t.TowashiGuideBot.class)); cards.add(new SetCardInfo("Towashi Songshaper", 167, Rarity.COMMON, mage.cards.t.TowashiSongshaper.class)); cards.add(new SetCardInfo("Tranquil Cove", 280, Rarity.COMMON, mage.cards.t.TranquilCove.class)); - cards.add(new SetCardInfo("Tribute to Horobi", 124, Rarity.RARE, mage.cards.t.TributeToHorobi.class)); + cards.add(new SetCardInfo("Tribute to Horobi", 124, Rarity.RARE, mage.cards.t.TributeToHorobi.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tribute to Horobi", 356, Rarity.RARE, mage.cards.t.TributeToHorobi.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tribute to Horobi", 462, Rarity.RARE, mage.cards.t.TributeToHorobi.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Twinshot Sniper", 168, Rarity.UNCOMMON, mage.cards.t.TwinshotSniper.class)); cards.add(new SetCardInfo("Twisted Embrace", 125, Rarity.COMMON, mage.cards.t.TwistedEmbrace.class)); cards.add(new SetCardInfo("Uncharted Haven", 281, Rarity.COMMON, mage.cards.u.UnchartedHaven.class)); cards.add(new SetCardInfo("Undercity Scrounger", 126, Rarity.COMMON, mage.cards.u.UndercityScrounger.class)); cards.add(new SetCardInfo("Unforgiving One", 127, Rarity.UNCOMMON, mage.cards.u.UnforgivingOne.class)); cards.add(new SetCardInfo("Unstoppable Ogre", 169, Rarity.COMMON, mage.cards.u.UnstoppableOgre.class)); - cards.add(new SetCardInfo("Upriser Renegade", 170, Rarity.UNCOMMON, mage.cards.u.UpriserRenegade.class)); + cards.add(new SetCardInfo("Upriser Renegade", 170, Rarity.UNCOMMON, mage.cards.u.UpriserRenegade.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Upriser Renegade", 324, Rarity.UNCOMMON, mage.cards.u.UpriserRenegade.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Vector Glider", 66, Rarity.COMMON, mage.cards.v.VectorGlider.class)); + cards.add(new SetCardInfo("Vessel of the All-Consuming", 221, Rarity.MYTHIC, mage.cards.v.VesselOfTheAllConsuming.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Vessel of the All-Consuming", 361, Rarity.MYTHIC, mage.cards.v.VesselOfTheAllConsuming.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Vessel of the All-Consuming", 486, Rarity.MYTHIC, mage.cards.v.VesselOfTheAllConsuming.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Virus Beetle", 128, Rarity.COMMON, mage.cards.v.VirusBeetle.class)); cards.add(new SetCardInfo("Vision of the Unspeakable", 48, Rarity.UNCOMMON, mage.cards.v.VisionOfTheUnspeakable.class)); + cards.add(new SetCardInfo("Voltage Surge", 171, Rarity.COMMON, mage.cards.v.VoltageSurge.class)); cards.add(new SetCardInfo("Walking Skyscraper", 263, Rarity.UNCOMMON, mage.cards.w.WalkingSkyscraper.class)); cards.add(new SetCardInfo("Wanderer's Intervention", 41, Rarity.COMMON, mage.cards.w.WanderersIntervention.class)); - cards.add(new SetCardInfo("Weaver of Harmony", 213, Rarity.RARE, mage.cards.w.WeaverOfHarmony.class)); + cards.add(new SetCardInfo("Weaver of Harmony", 213, Rarity.RARE, mage.cards.w.WeaverOfHarmony.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Weaver of Harmony", 395, Rarity.RARE, mage.cards.w.WeaverOfHarmony.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Weaver of Harmony", 483, Rarity.RARE, mage.cards.w.WeaverOfHarmony.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Webspinner Cuff", 214, Rarity.UNCOMMON, mage.cards.w.WebspinnerCuff.class)); cards.add(new SetCardInfo("When We Were Young", 43, Rarity.UNCOMMON, mage.cards.w.WhenWeWereYoung.class)); cards.add(new SetCardInfo("Wind-Scarred Crag", 282, Rarity.COMMON, mage.cards.w.WindScarredCrag.class)); cards.add(new SetCardInfo("You Are Already Dead", 129, Rarity.COMMON, mage.cards.y.YouAreAlreadyDead.class)); + } - cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); // remove when mechanic is fully implemented + // add common or uncommon double faced card to booster + @Override + protected void addDoubleFace(List booster) { + Rarity rarity; + for (int i = 0; i < numBoosterDoubleFaced; i++) { + // relative frequency of common to uncommon DFCs differs between printings + // using Japanese ratio as it's closest to the ratio of non-DFC commons to uncommons + if (RandomUtil.nextInt(102) < 54) { + rarity = Rarity.COMMON; + } else { + rarity = Rarity.UNCOMMON; + } + addToBooster(booster, getSpecialCardsByRarity(rarity)); + } + } + + @Override + protected List findSpecialCardsByRarity(Rarity rarity) { + // rare and mythic DFCs are normal rares + if (rarity == Rarity.RARE || rarity == Rarity.MYTHIC) { + return new ArrayList(); + } + List cardInfos = super.findSpecialCardsByRarity(rarity); + if (rarity == Rarity.LAND) { + // Uncharted Haven is a normal common + cardInfos.removeIf(cardInfo -> "Uncharted Haven".equals(cardInfo.getName())); + } + return cardInfos; + } + + @Override + public BoosterCollator createCollator() { + return new KamigawaNeonDynastyCollator(); + } +} + +// Booster collation info from https://www.lethe.xyz/mtg/collation/neo.html +// Using Japanese collation for common/uncommon, rare collation inferred from other sets +class KamigawaNeonDynastyCollator implements BoosterCollator { + private final CardRun commonA = new CardRun(true, "36", "112", "17", "317", "9", "183", "30", "131", "315", "179", "27", "115", "15", "325", "33", "67", "1", "196", "10", "100", "32", "70", "22", "346", "41", "56", "30", "115", "9", "191", "310", "156", "10", "347", "39", "94", "36", "326", "15", "1", "100", "17", "70", "32", "112", "27", "334", "22", "131", "33", "196", "41", "115", "30", "179", "309", "94", "15", "183", "9", "100", "19", "33", "335", "27", "156", "22", "342", "32", "56", "36", "319", "1", "191", "17", "67", "39", "196", "19", "318", "41", "179", "15", "94", "10", "70", "30", "341", "9", "27", "183", "33", "156", "17", "112", "313", "191", "22", "56", "39", "131", "32", "339", "41", "67", "19", "1", "322"); + private final CardRun commonB = new CardRun(true, "78", "244", "188", "54", "259", "174", "80", "258", "186", "81", "132", "178", "46", "239", "205", "51", "261", "180", "71", "24", "173", "63", "202", "149", "77", "184", "248", "72", "190", "69", "136", "211", "78", "182", "54", "103", "174", "83", "259", "188", "46", "244", "189", "80", "261", "186", "64", "132", "205", "81", "239", "178", "51", "136", "173", "77", "24", "180", "63", "184", "149", "71", "190", "258", "72", "202", "78", "248", "188", "83", "174", "69", "103", "182", "64", "244", "211", "54", "239", "186", "80", "259", "178", "81", "149", "205", "46", "261", "189", "51", "258", "173", "71", "132", "184", "63", "180", "24", "77", "202", "136", "72", "182", "69", "248", "211", "83", "190", "64", "103", "189"); + private final CardRun commonC = new CardRun(true, "90", "252", "169", "107", "163", "20", "121", "167", "125", "253", "138", "104", "151", "68", "120", "160", "38", "129", "150", "241", "126", "130", "105", "251", "143", "91", "246", "148", "92", "281", "171", "128", "151", "79", "125", "139", "253", "104", "163", "252", "107", "133", "241", "90", "167", "119", "20", "160", "121", "195", "169", "126", "68", "138", "120", "171", "251", "91", "148", "281", "105", "130", "38", "128", "139", "79", "92", "150", "119", "246", "143", "129", "20", "133", "107", "169", "253", "90", "163", "195", "121", "151", "125", "252", "160", "104", "167", "38", "120", "138", "68", "129", "130", "91", "241", "150", "126", "246", "171", "92", "251", "148", "105", "281", "143", "128", "79", "139", "119", "195", "133"); + private final CardRun commonDFC = new CardRun(true, "4", "210", "48", "11", "109", "162", "108", "12", "66", "172", "152", "117", "177", "4", "210", "11", "108", "162", "29", "48", "117", "66", "4", "177", "11", "210", "162", "172", "12", "117", "48", "108", "4", "109", "210", "162", "29", "66", "172", "11", "152", "12", "108", "177", "109", "66", "29", "210", "4", "162", "117", "11", "152", "66", "117", "162", "4", "48", "210", "12", "172", "152", "11", "117", "162", "109", "66", "4", "108", "177", "29", "162", "11", "66", "109", "210", "117", "177", "4", "48", "11", "108", "152", "12", "172", "29", "210", "4", "117", "66", "109", "48", "12", "162", "11", "210", "152", "172", "66", "29", "177", "117"); + private final CardRun uncommonA = new CardRun(true, "170", "40", "158", "76", "340", "18", "215", "3", "146", "231", "314", "161", "31", "219", "53", "198", "236", "175", "49", "168", "344", "185", "73", "40", "95", "142", "35", "76", "215", "87", "5", "229", "324", "18", "158", "219", "53", "3", "116", "168", "37", "198", "146", "231", "332", "161", "311", "175", "236", "142", "312", "87", "170", "185", "5", "229", "73", "40", "95", "76", "327", "18", "158", "219", "321", "231", "49", "168", "53", "3", "353", "161", "116", "198", "37", "175", "31", "142", "336", "229", "35", "76", "5", "185", "170", "87", "323", "40", "215", "18", "95", "3", "146", "348", "236", "175", "49", "219", "37", "231", "31", "168", "333", "161", "116", "185", "35", "142", "331", "229", "73", "87"); + private final CardRun uncommonB = new CardRun(true, "144", "262", "207", "270", "137", "214", "96", "47", "240", "14", "93", "187", "164", "50", "223", "257", "157", "209", "247", "225", "43", "75", "118", "263", "203", "45", "165", "16", "110", "243", "65", "6", "192", "98", "55", "242", "204", "97", "272", "256", "85", "127", "176", "230", "52", "135", "254", "218", "106", "275", "216", "96", "214", "144", "270", "44", "262", "187", "93", "240", "207", "47", "137", "14", "257", "209", "43", "164", "225", "263", "75", "223", "203", "247", "50", "157", "118", "16", "192", "45", "6", "110", "204", "55", "165", "242", "98", "65", "243", "97", "85", "254", "272", "52", "216", "106", "135", "256", "218", "176", "127", "230", "275", "44"); + private final CardRun rare = new CardRun(false, "7", "8", "13", "21", "23", "25", "26", "28", "34", "57", "58", "61", "62", "74", "82", "86", "88", "99", "101", "111", "113", "122", "123", "124", "141", "145", "147", "153", "154", "155", "159", "166", "181", "193", "197", "201", "206", "208", "212", "213", "217", "220", "222", "224", "228", "232", "233", "234", "235", "245", "249", "250", "255", "260", "266", "268", "271", "276", "278", "7", "8", "13", "21", "23", "25", "26", "28", "34", "57", "58", "61", "62", "74", "82", "86", "88", "99", "101", "111", "113", "122", "123", "124", "141", "145", "147", "153", "154", "155", "159", "166", "181", "193", "197", "201", "206", "208", "212", "213", "217", "220", "222", "224", "228", "232", "233", "234", "235", "245", "249", "250", "255", "260", "266", "268", "271", "276", "278", "2", "42", "59", "60", "84", "89", "102", "114", "134", "140", "194", "199", "200", "221", "226", "227", "237", "238"); + private final CardRun land = new CardRun(true, "265", "274", "282", "279", "264", "285", "277", "283", "273", "267", "280", "274", "300", "295", "282", "287", "290", "292", "284", "298", "279", "296", "297", "277", "293", "269", "282", "289", "267", "273", "279", "286", "302", "274", "294", "280", "277", "295", "291", "299", "265", "282", "269", "264", "279", "297", "280", "300", "274", "285", "265", "273", "296", "293", "302", "287", "269", "294", "279", "298", "267", "301", "283", "295", "277", "273", "280", "299", "269", "274", "302", "267", "298", "264", "290", "286", "282", "293", "297", "300", "265", "296", "277", "284", "301", "273", "264", "292", "274", "289", "294", "267", "282", "288", "279", "280", "269", "265", "291", "298", "299", "264", "301", "267", "293", "300", "280", "273", "265", "269", "277", "294", "297", "301", "264", "299", "295", "302", "288", "296"); + + private final BoosterStructure AABBBCCCC = new BoosterStructure( + commonA, commonA, + commonB, commonB, commonB, + commonC, commonC, commonC, commonC + ); + + private final BoosterStructure AABBBBCCC = new BoosterStructure( + commonA, commonA, + commonB, commonB, commonB, commonB, + commonC, commonC, commonC + ); + + private final BoosterStructure AAABBBCCC = new BoosterStructure( + commonA, commonA, commonA, + commonB, commonB, commonB, + commonC, commonC, commonC + ); + + private final BoosterStructure AAB = new BoosterStructure(uncommonA, uncommonA, uncommonB); + private final BoosterStructure ABB = new BoosterStructure(uncommonA, uncommonB, uncommonB); + + private final BoosterStructure D1 = new BoosterStructure(commonDFC); + private final BoosterStructure R1 = new BoosterStructure(rare); + private final BoosterStructure L1 = new BoosterStructure(land); + + // In order for equal numbers of each common to exist, the average booster must contain: + // 2.41 A commons (243 / 101) + // 3.30 B commons (333 / 101) + // 3.30 C commons (333 / 101) + private final RarityConfiguration commonRuns = new RarityConfiguration( + AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, + AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, + AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, + AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, AABBBCCCC, + AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, + AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, + AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, + AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, AABBBBCCC, + AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, + AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, + AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, + AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, + AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, AAABBBCCC, + AAABBBCCC + ); + + private final RarityConfiguration uncommonRuns = new RarityConfiguration( + AAB, ABB, ABB, ABB, ABB, ABB, ABB, ABB, ABB, ABB, + ABB, ABB, ABB, ABB, ABB, ABB, ABB, ABB, ABB, ABB + ); + + private final RarityConfiguration dfcRuns = new RarityConfiguration(D1); + private final RarityConfiguration rareRuns = new RarityConfiguration(R1); + private final RarityConfiguration landRuns = new RarityConfiguration(L1); + + @Override + public List makeBooster() { + List booster = new ArrayList<>(); + booster.addAll(commonRuns.getNext().makeRun()); + booster.addAll(dfcRuns.getNext().makeRun()); + booster.addAll(uncommonRuns.getNext().makeRun()); + booster.addAll(rareRuns.getNext().makeRun()); + booster.addAll(landRuns.getNext().makeRun()); + return booster; } } diff --git a/Mage.Sets/src/mage/sets/Masters25.java b/Mage.Sets/src/mage/sets/Masters25.java index 3f97e60eeff..8ef6e048850 100644 --- a/Mage.Sets/src/mage/sets/Masters25.java +++ b/Mage.Sets/src/mage/sets/Masters25.java @@ -1,9 +1,16 @@ package mage.sets; import mage.cards.ExpansionSet; +import mage.collation.BoosterCollator; +import mage.collation.BoosterStructure; +import mage.collation.CardRun; +import mage.collation.RarityConfiguration; import mage.constants.Rarity; import mage.constants.SetType; +import java.util.ArrayList; +import java.util.List; + /** * @author JayDi85 */ @@ -276,4 +283,100 @@ public final class Masters25 extends ExpansionSet { cards.add(new SetCardInfo("Twilight Mire", 248, Rarity.RARE, mage.cards.t.TwilightMire.class)); cards.add(new SetCardInfo("Zoetic Cavern", 249, Rarity.UNCOMMON, mage.cards.z.ZoeticCavern.class)); } + + @Override + public BoosterCollator createCollator() { + return new Masters25Collator(); + } +} + +// Booster collation info from https://www.lethe.xyz/mtg/collation/a25.html +// Using USA collation for common/uncommon, rare collation inferred from other sets +class Masters25Collator implements BoosterCollator { + private final CardRun commonA = new CardRun(true, "107", "154", "7", "90", "134", "19", "93", "145", "1", "86", "118", "33", "89", "153", "31", "106", "120", "6", "109", "151", "22", "114", "125", "16", "85", "126", "34", "99", "127", "33", "89", "143", "24", "93", "154", "39", "113", "134", "7", "90", "153", "31", "109", "118", "6", "107", "125", "1", "85", "145", "19", "86", "120", "16", "113", "126", "24", "106", "151", "22", "114", "143", "39", "99", "127", "34"); + private final CardRun commonB = new CardRun(true, "167", "41", "184", "46", "157", "67", "190", "69", "172", "49", "165", "61", "158", "40", "169", "71", "183", "48", "167", "46", "166", "54", "190", "49", "172", "67", "184", "72", "157", "61", "175", "41", "183", "71", "165", "69", "169", "48", "190", "40", "158", "54", "166", "72", "184", "67", "157", "46", "167", "41", "169", "71", "175", "49", "172", "61", "158", "69", "183", "40", "165", "72", "166", "48", "175", "54"); + private final CardRun commonC1 = new CardRun(true, "98", "74", "17", "182", "80", "155", "50", "226", "160", "140", "10", "105", "170", "13", "195", "111", "139", "73", "228", "193", "150", "28", "100", "60", "12", "180", "98", "155", "74", "231", "160", "124", "226", "80", "50", "17", "182", "105", "140", "73", "228", "195", "139", "13", "100", "60", "10", "193", "111", "124", "12", "231", "170", "150", "28"); + private final CardRun commonC2 = new CardRun(true, "15", "56", "87", "163", "144", "51", "25", "84", "131", "194", "64", "29", "229", "82", "163", "149", "56", "15", "221", "131", "240", "45", "25", "64", "87", "194", "144", "56", "229", "82", "29", "180", "51", "25", "221", "84", "163", "149", "45", "15", "87", "144", "240", "64", "29", "229", "82", "194", "131", "51", "221", "84", "149", "240", "45"); + private final CardRun uncommonA = new CardRun(true, "152", "21", "52", "218", "227", "94", "187", "133", "20", "75", "198", "242", "79", "159", "156", "38", "55", "218", "234", "108", "162", "147", "4", "43", "198", "225", "83", "178", "129", "8", "63", "197", "249", "116", "162", "148", "14", "53", "213", "227", "112", "177", "152", "21", "52", "218", "234", "94", "187", "133", "38", "75", "220", "242", "79", "188", "156", "4", "55", "108", "178", "147", "20", "43", "197", "227", "112", "159", "152", "8", "63", "213", "225", "83", "177", "148", "14", "53", "198", "249", "94", "162", "129", "21", "55", "220", "242", "116", "187", "133", "38", "75", "79", "188", "156", "20", "52", "108", "178", "147", "4", "53", "197", "234", "83", "159", "129", "8", "63", "220", "249", "116", "177", "148", "14", "43", "213", "225", "112", "188"); + private final CardRun uncommonB = new CardRun(true, "59", "235", "199", "97", "192", "141", "30", "78", "201", "245", "115", "186", "132", "27", "66", "207", "236", "91", "173", "123", "26", "58", "215", "230", "37", "171", "146", "81", "47", "217", "243", "104", "176", "137", "18", "59", "117", "174", "135", "26", "65", "199", "235", "97", "186", "123", "35", "78", "201", "245", "91", "171", "141", "30", "58", "207", "236", "115", "173", "132", "27", "47", "217", "243", "81", "174", "137", "37", "59", "104", "192", "146", "18", "66", "26", "115", "186", "135", "37", "65", "215", "230", "97", "176", "141", "30", "47", "201", "245", "91", "173", "132", "236", "66", "199", "35", "117", "192", "123", "26", "78", "217", "235", "81", "171", "146", "27", "58", "207", "243", "104", "176", "137", "18", "65", "215", "230", "117", "174", "135", "35"); + private final CardRun rare = new CardRun(false, "3", "9", "11", "23", "32", "36", "42", "44", "57", "68", "70", "77", "92", "95", "96", "102", "103", "110", "121", "122", "128", "130", "138", "142", "161", "164", "168", "179", "185", "189", "200", "202", "203", "205", "206", "208", "209", "210", "211", "212", "216", "219", "223", "232", "233", "237", "238", "239", "241", "244", "246", "247", "248", "3", "9", "11", "23", "32", "36", "42", "44", "57", "68", "70", "77", "92", "95", "96", "102", "103", "110", "121", "122", "128", "130", "138", "142", "161", "164", "168", "179", "185", "189", "200", "202", "203", "205", "206", "208", "209", "210", "211", "212", "216", "219", "223", "232", "233", "237", "238", "239", "241", "244", "246", "247", "248", "2", "5", "62", "76", "88", "101", "119", "136", "181", "191", "196", "204", "214", "222", "224"); + private final CardRun foilCommon = new CardRun(true, "7", "153", "40", "158", "22", "87", "170", "126", "228", "50", "29", "82", "134", "31", "175", "54", "98", "226", "127", "195", "51", "33", "105", "140", "71", "182", "6", "90", "194", "144", "89", "73", "10", "107", "149", "39", "183", "74", "85", "221", "139", "160", "56", "15", "109", "124", "67", "184", "28", "86", "165", "145", "12", "41", "13", "106", "143", "24", "190", "45", "80", "231", "151", "180", "46", "16", "113", "150", "60", "167", "1", "84", "193", "154", "72", "34", "48", "114", "118", "240", "169", "61", "100", "19", "155", "157", "69", "25", "93", "120", "64", "172", "229", "111", "163", "131", "17", "166", "49", "99", "125"); + + private final BoosterStructure AABBC1C1C1C1C1C1 = new BoosterStructure( + commonA, commonA, + commonB, commonB, + commonC1, commonC1, commonC1, commonC1, commonC1, commonC1 + ); + private final BoosterStructure AAABBC1C1C1C1C1 = new BoosterStructure( + commonA, commonA, commonA, + commonB, commonB, + commonC1, commonC1, commonC1, commonC1, commonC1 + ); + private final BoosterStructure AAAABBC2C2C2C2 = new BoosterStructure( + commonA, commonA, commonA, commonA, + commonB, commonB, + commonC2, commonC2, commonC2, commonC2 + ); + private final BoosterStructure AAAABBBC2C2C2 = new BoosterStructure( + commonA, commonA, commonA, commonA, + commonB, commonB, commonB, + commonC2, commonC2, commonC2 + ); + private final BoosterStructure AAB = new BoosterStructure(uncommonA, uncommonA, uncommonB); + private final BoosterStructure ABB = new BoosterStructure(uncommonA, uncommonB, uncommonB); + private final BoosterStructure R1 = new BoosterStructure(rare); + private final BoosterStructure FC = new BoosterStructure(foilCommon); + private final BoosterStructure FUA = new BoosterStructure(uncommonA); + private final BoosterStructure FUB = new BoosterStructure(uncommonB); + + // In order for equal numbers of each common to exist, the average booster must contain: + // 3.27 A commons (36 / 11) + // 2.18 B commons (24 / 11) + // 2.73 C1 commons (30 / 11, or 60 / 11 in each C1 booster) + // 1.82 C2 commons (20 / 11, or 40 / 11 in each C2 booster) + // These numbers are the same for all sets with 101 commons in A/B/C1/C2 print runs + // and with 10 common slots per booster + private final RarityConfiguration commonRuns = new RarityConfiguration( + AABBC1C1C1C1C1C1, + AABBC1C1C1C1C1C1, + AABBC1C1C1C1C1C1, + AABBC1C1C1C1C1C1, + AABBC1C1C1C1C1C1, + AAABBC1C1C1C1C1, + AAABBC1C1C1C1C1, + AAABBC1C1C1C1C1, + AAABBC1C1C1C1C1, + AAABBC1C1C1C1C1, + AAABBC1C1C1C1C1, + + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBBC2C2C2, + AAAABBBC2C2C2, + AAAABBBC2C2C2, + AAAABBBC2C2C2 + ); + private final RarityConfiguration uncommonRuns = new RarityConfiguration(AAB, ABB); + private final RarityConfiguration rareRuns = new RarityConfiguration(R1); + private final RarityConfiguration foilRuns = new RarityConfiguration( + FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, + FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, + FUA, FUB, FUA, FUB, FUA, FUB, + R1, R1 + ); + + @Override + public List makeBooster() { + List booster = new ArrayList<>(); + booster.addAll(commonRuns.getNext().makeRun()); + booster.addAll(uncommonRuns.getNext().makeRun()); + booster.addAll(rareRuns.getNext().makeRun()); + booster.addAll(foilRuns.getNext().makeRun()); + return booster; + } } diff --git a/Mage.Sets/src/mage/sets/ModernMasters2017.java b/Mage.Sets/src/mage/sets/ModernMasters2017.java index 8137d6771d8..7a364a114c4 100644 --- a/Mage.Sets/src/mage/sets/ModernMasters2017.java +++ b/Mage.Sets/src/mage/sets/ModernMasters2017.java @@ -1,9 +1,16 @@ package mage.sets; import mage.cards.ExpansionSet; +import mage.collation.BoosterCollator; +import mage.collation.BoosterStructure; +import mage.collation.CardRun; +import mage.collation.RarityConfiguration; import mage.constants.Rarity; import mage.constants.SetType; +import java.util.ArrayList; +import java.util.List; + /** * @author fireshoes */ @@ -276,4 +283,99 @@ public final class ModernMasters2017 extends ExpansionSet { cards.add(new SetCardInfo("Zur the Enchanter", 204, Rarity.RARE, mage.cards.z.ZurTheEnchanter.class)); } + @Override + public BoosterCollator createCollator() { + return new ModernMasters2017Collator(); + } +} + +// Booster collation info from https://www.lethe.xyz/mtg/collation/mm3.html +// Using USA collation for common/uncommon, rare collation inferred from other sets +class ModernMasters2017Collator implements BoosterCollator { + private final CardRun commonA = new CardRun(true, "154", "234", "160", "184", "73", "248", "131", "192", "11", "236", "43", "151", "159", "119", "241", "156", "188", "86", "246", "205", "207", "100", "154", "172", "70", "230", "169", "166", "118", "248", "150", "38", "92", "7", "178", "156", "236", "73", "192", "131", "184", "160", "234", "151", "11", "159", "43", "241", "205", "188", "118", "172", "86", "246", "100", "150", "166", "70", "207", "7", "230", "119", "38", "169", "178", "92"); + private final CardRun commonB = new CardRun(true, "140", "74", "138", "67", "124", "71", "137", "82", "135", "78", "123", "62", "136", "65", "125", "60", "126", "80", "129", "79", "133", "71", "138", "82", "123", "78", "124", "81", "126", "62", "137", "65", "140", "74", "135", "60", "129", "67", "125", "80", "136", "79", "133", "71", "138", "65", "123", "78", "124", "60", "137", "81", "140", "74", "126", "62", "136", "82", "135", "67", "129", "80", "125", "79", "133", "81"); + private final CardRun commonC1 = new CardRun(true, "14", "48", "168", "247", "97", "16", "34", "157", "53", "93", "29", "41", "242", "208", "104", "10", "47", "237", "211", "111", "18", "30", "231", "209", "89", "1", "48", "235", "168", "97", "14", "34", "94", "242", "111", "29", "41", "157", "231", "93", "16", "53", "209", "247", "94", "1", "47", "211", "235", "104", "18", "30", "208", "237", "89"); + private final CardRun commonC2 = new CardRun(true, "109", "8", "51", "113", "24", "44", "102", "28", "58", "110", "23", "39", "114", "21", "52", "99", "5", "42", "109", "24", "51", "102", "8", "44", "113", "23", "58", "99", "21", "39", "110", "28", "52", "114", "5", "51", "109", "23", "42", "102", "10", "44", "110", "24", "39", "113", "8", "52", "114", "21", "58", "99", "5", "42", "28"); + private final CardRun uncommonA = new CardRun(true, "75", "174", "225", "49", "155", "224", "149", "238", "212", "215", "9", "228", "37", "222", "167", "245", "165", "223", "183", "226", "195", "88", "201", "217", "2", "198", "227", "103", "181", "219", "149", "220", "193", "130", "152", "224", "49", "210", "225", "27", "202", "233", "199", "215", "174", "75", "171", "9", "222", "212", "226", "37", "165", "223", "167", "219", "201", "2", "181", "217", "103", "195", "227", "183", "228", "155", "88", "198", "215", "199", "238", "171", "27", "210", "220", "130", "202", "245", "149", "223", "152", "49", "174", "233", "212", "225", "193", "37", "155", "9", "224", "165", "217", "75", "181", "228", "167", "222", "198", "88", "171", "238", "183", "227", "210", "2", "195", "226", "103", "201", "219", "27", "202", "245", "199", "220", "152", "130", "233", "193"); + private final CardRun uncommonB = new CardRun(true, "142", "173", "15", "95", "145", "170", "61", "180", "31", "12", "213", "127", "6", "186", "59", "17", "56", "197", "112", "128", "85", "179", "120", "107", "33", "203", "106", "189", "57", "117", "185", "95", "243", "173", "115", "45", "15", "170", "61", "191", "145", "12", "196", "17", "68", "194", "56", "87", "120", "197", "6", "83", "31", "179", "142", "186", "106", "127", "213", "45", "112", "203", "59", "180", "33", "128", "185", "107", "85", "189", "68", "170", "145", "87", "196", "117", "31", "173", "243", "95", "61", "186", "115", "179", "57", "83", "142", "191", "56", "12", "213", "127", "33", "194", "59", "180", "6", "107", "185", "128", "85", "197", "120", "17", "112", "203", "68", "117", "196", "45", "15", "189", "115", "191", "243", "87", "57", "194", "106", "83"); + private final CardRun rare = new CardRun(false, "3", "19", "20", "22", "25", "26", "32", "35", "36", "40", "46", "55", "63", "64", "66", "69", "77", "84", "90", "96", "98", "101", "108", "116", "121", "132", "134", "139", "143", "144", "146", "147", "148", "153", "158", "162", "163", "164", "175", "176", "182", "190", "204", "206", "214", "216", "218", "221", "229", "239", "240", "244", "249", "3", "19", "20", "22", "25", "26", "32", "35", "36", "40", "46", "55", "63", "64", "66", "69", "77", "84", "90", "96", "98", "101", "108", "116", "121", "132", "134", "139", "143", "144", "146", "147", "148", "153", "158", "162", "163", "164", "175", "176", "182", "190", "204", "206", "214", "216", "218", "221", "229", "239", "240", "244", "249", "4", "13", "50", "54", "72", "76", "91", "105", "122", "141", "161", "177", "187", "200", "232"); + private final CardRun foilCommon = new CardRun(true, "123", "11", "126", "39", "151", "58", "178", "81", "231", "125", "140", "124", "14", "129", "41", "154", "60", "184", "82", "234", "104", "150", "99", "16", "131", "42", "156", "62", "188", "86", "235", "109", "78", "100", "18", "133", "43", "157", "65", "192", "89", "236", "110", "79", "102", "21", "135", "44", "159", "67", "205", "92", "237", "111", "80", "1", "23", "136", "47", "160", "70", "207", "93", "241", "113", "52", "5", "24", "137", "48", "166", "71", "208", "94", "242", "114", "53", "7", "28", "138", "51", "168", "73", "209", "97", "246", "118", "34", "8", "29", "230", "248", "169", "74", "211", "172", "247", "119", "38", "10", "30"); + + private final BoosterStructure AABBC1C1C1C1C1C1 = new BoosterStructure( + commonA, commonA, + commonB, commonB, + commonC1, commonC1, commonC1, commonC1, commonC1, commonC1 + ); + private final BoosterStructure AAABBC1C1C1C1C1 = new BoosterStructure( + commonA, commonA, commonA, + commonB, commonB, + commonC1, commonC1, commonC1, commonC1, commonC1 + ); + private final BoosterStructure AAAABBC2C2C2C2 = new BoosterStructure( + commonA, commonA, commonA, commonA, + commonB, commonB, + commonC2, commonC2, commonC2, commonC2 + ); + private final BoosterStructure AAAABBBC2C2C2 = new BoosterStructure( + commonA, commonA, commonA, commonA, + commonB, commonB, commonB, + commonC2, commonC2, commonC2 + ); + private final BoosterStructure AAB = new BoosterStructure(uncommonA, uncommonA, uncommonB); + private final BoosterStructure ABB = new BoosterStructure(uncommonA, uncommonB, uncommonB); + private final BoosterStructure R1 = new BoosterStructure(rare); + private final BoosterStructure FC = new BoosterStructure(foilCommon); + private final BoosterStructure FUA = new BoosterStructure(uncommonA); + private final BoosterStructure FUB = new BoosterStructure(uncommonB); + + // In order for equal numbers of each common to exist, the average booster must contain: + // 3.27 A commons (36 / 11) + // 2.18 B commons (24 / 11) + // 2.73 C1 commons (30 / 11, or 60 / 11 in each C1 booster) + // 1.82 C2 commons (20 / 11, or 40 / 11 in each C2 booster) + // These numbers are the same for all sets with 101 commons in A/B/C1/C2 print runs + // and with 10 common slots per booster + private final RarityConfiguration commonRuns = new RarityConfiguration( + AABBC1C1C1C1C1C1, + AABBC1C1C1C1C1C1, + AABBC1C1C1C1C1C1, + AABBC1C1C1C1C1C1, + AABBC1C1C1C1C1C1, + AAABBC1C1C1C1C1, + AAABBC1C1C1C1C1, + AAABBC1C1C1C1C1, + AAABBC1C1C1C1C1, + AAABBC1C1C1C1C1, + AAABBC1C1C1C1C1, + + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBC2C2C2C2, + AAAABBBC2C2C2, + AAAABBBC2C2C2, + AAAABBBC2C2C2, + AAAABBBC2C2C2 + ); + private final RarityConfiguration uncommonRuns = new RarityConfiguration(AAB, ABB); + private final RarityConfiguration rareRuns = new RarityConfiguration(R1); + private final RarityConfiguration foilRuns = new RarityConfiguration( + FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, + FC, FC, FC, FC, FC, FC, FC, FC, FC, FC, + FUA, FUB, FUA, FUB, FUA, FUB, + R1, R1 + ); + + @Override + public List makeBooster() { + List booster = new ArrayList<>(); + booster.addAll(commonRuns.getNext().makeRun()); + booster.addAll(uncommonRuns.getNext().makeRun()); + booster.addAll(rareRuns.getNext().makeRun()); + booster.addAll(foilRuns.getNext().makeRun()); + return booster; + } } diff --git a/Mage.Sets/src/mage/sets/NeonDynastyCommander.java b/Mage.Sets/src/mage/sets/NeonDynastyCommander.java index 3f6daf4e068..55a441a1d25 100644 --- a/Mage.Sets/src/mage/sets/NeonDynastyCommander.java +++ b/Mage.Sets/src/mage/sets/NeonDynastyCommander.java @@ -19,10 +19,185 @@ public final class NeonDynastyCommander extends ExpansionSet { super("Neon Dynasty Commander", "NEC", ExpansionSet.buildDate(2022, 2, 18), SetType.SUPPLEMENTAL); this.hasBasicLands = false; - cards.add(new SetCardInfo("Chishiro, the Shattered Blade", 1, Rarity.MYTHIC, mage.cards.c.ChishiroTheShatteredBlade.class)); - cards.add(new SetCardInfo("Kotori, Pilot Prodigy", 2, Rarity.MYTHIC, mage.cards.k.KotoriPilotProdigy.class)); - cards.add(new SetCardInfo("Myojin of Blooming Dawn", 31, Rarity.RARE, mage.cards.m.MyojinOfBloomingDawn.class)); - cards.add(new SetCardInfo("Myojin of Roaring Blades", 36, Rarity.RARE, mage.cards.m.MyojinOfRoaringBlades.class)); - cards.add(new SetCardInfo("Myojin of Towering Might", 38, Rarity.RARE, mage.cards.m.MyojinOfToweringMight.class)); + cards.add(new SetCardInfo("Access Denied", 11, Rarity.RARE, mage.cards.a.AccessDenied.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Access Denied", 47, Rarity.RARE, mage.cards.a.AccessDenied.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Acidic Slime", 112, Rarity.UNCOMMON, mage.cards.a.AcidicSlime.class)); + cards.add(new SetCardInfo("Aerial Surveyor", 39, Rarity.RARE, mage.cards.a.AerialSurveyor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Aerial Surveyor", 5, Rarity.RARE, mage.cards.a.AerialSurveyor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Aeronaut Admiral", 79, Rarity.UNCOMMON, mage.cards.a.AeronautAdmiral.class)); + cards.add(new SetCardInfo("Agitator Ant", 102, Rarity.RARE, mage.cards.a.AgitatorAnt.class)); + cards.add(new SetCardInfo("Akki Battle Squad", 18, Rarity.RARE, mage.cards.a.AkkiBattleSquad.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Akki Battle Squad", 57, Rarity.RARE, mage.cards.a.AkkiBattleSquad.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Arcane Signet", 144, Rarity.COMMON, mage.cards.a.ArcaneSignet.class)); + cards.add(new SetCardInfo("Arcanist's Owl", 135, Rarity.UNCOMMON, mage.cards.a.ArcanistsOwl.class)); + cards.add(new SetCardInfo("Armed and Armored", 80, Rarity.UNCOMMON, mage.cards.a.ArmedAndArmored.class)); + cards.add(new SetCardInfo("Ascendant Acolyte", 24, Rarity.RARE, mage.cards.a.AscendantAcolyte.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ascendant Acolyte", 64, Rarity.RARE, mage.cards.a.AscendantAcolyte.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Azorius Signet", 145, Rarity.UNCOMMON, mage.cards.a.AzoriusSignet.class)); + cards.add(new SetCardInfo("Bear Umbra", 113, Rarity.RARE, mage.cards.b.BearUmbra.class)); + cards.add(new SetCardInfo("Beast Within", 114, Rarity.UNCOMMON, mage.cards.b.BeastWithin.class)); + cards.add(new SetCardInfo("Blackblade Reforged", 146, Rarity.RARE, mage.cards.b.BlackbladeReforged.class)); + cards.add(new SetCardInfo("Bonehoard", 147, Rarity.RARE, mage.cards.b.Bonehoard.class)); + cards.add(new SetCardInfo("Cataclysmic Gearhulk", 81, Rarity.MYTHIC, mage.cards.c.CataclysmicGearhulk.class)); + cards.add(new SetCardInfo("Chain Reaction", 103, Rarity.RARE, mage.cards.c.ChainReaction.class)); + cards.add(new SetCardInfo("Champion of Lambholt", 115, Rarity.RARE, mage.cards.c.ChampionOfLambholt.class)); + cards.add(new SetCardInfo("Chaos Warp", 104, Rarity.RARE, mage.cards.c.ChaosWarp.class)); + cards.add(new SetCardInfo("Chishiro, the Shattered Blade", 1, Rarity.MYTHIC, mage.cards.c.ChishiroTheShatteredBlade.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Chishiro, the Shattered Blade", 73, Rarity.MYTHIC, mage.cards.c.ChishiroTheShatteredBlade.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Chishiro, the Shattered Blade", 77, Rarity.MYTHIC, mage.cards.c.ChishiroTheShatteredBlade.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cinder Glade", 166, Rarity.RARE, mage.cards.c.CinderGlade.class)); + cards.add(new SetCardInfo("Collision of Realms", 19, Rarity.RARE, mage.cards.c.CollisionOfRealms.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Collision of Realms", 58, Rarity.RARE, mage.cards.c.CollisionOfRealms.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Colossal Plow", 148, Rarity.UNCOMMON, mage.cards.c.ColossalPlow.class)); + cards.add(new SetCardInfo("Command Tower", 167, Rarity.COMMON, mage.cards.c.CommandTower.class)); + cards.add(new SetCardInfo("Concord with the Kami", 25, Rarity.RARE, mage.cards.c.ConcordWithTheKami.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Concord with the Kami", 65, Rarity.RARE, mage.cards.c.ConcordWithTheKami.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Crush Contraband", 82, Rarity.UNCOMMON, mage.cards.c.CrushContraband.class)); + cards.add(new SetCardInfo("Cultivator's Caravan", 149, Rarity.RARE, mage.cards.c.CultivatorsCaravan.class)); + cards.add(new SetCardInfo("Cyberdrive Awakener", 12, Rarity.RARE, mage.cards.c.CyberdriveAwakener.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cyberdrive Awakener", 48, Rarity.RARE, mage.cards.c.CyberdriveAwakener.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Dance of the Manse", 136, Rarity.RARE, mage.cards.d.DanceOfTheManse.class)); + cards.add(new SetCardInfo("Decimate", 137, Rarity.RARE, mage.cards.d.Decimate.class)); + cards.add(new SetCardInfo("Dispatch", 83, Rarity.UNCOMMON, mage.cards.d.Dispatch.class)); + cards.add(new SetCardInfo("Drumbellower", 40, Rarity.RARE, mage.cards.d.Drumbellower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Drumbellower", 6, Rarity.RARE, mage.cards.d.Drumbellower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Elemental Mastery", 105, Rarity.RARE, mage.cards.e.ElementalMastery.class)); + cards.add(new SetCardInfo("Emry, Lurker of the Loch", 91, Rarity.RARE, mage.cards.e.EmryLurkerOfTheLoch.class)); + cards.add(new SetCardInfo("Etherium Sculptor", 92, Rarity.COMMON, mage.cards.e.EtheriumSculptor.class)); + cards.add(new SetCardInfo("Exotic Orchard", 168, Rarity.RARE, mage.cards.e.ExoticOrchard.class)); + cards.add(new SetCardInfo("Fellwar Stone", 150, Rarity.UNCOMMON, mage.cards.f.FellwarStone.class)); + cards.add(new SetCardInfo("Fertilid", 116, Rarity.COMMON, mage.cards.f.Fertilid.class)); + cards.add(new SetCardInfo("Fireshrieker", 151, Rarity.UNCOMMON, mage.cards.f.Fireshrieker.class)); + cards.add(new SetCardInfo("Forgotten Ancient", 117, Rarity.RARE, mage.cards.f.ForgottenAncient.class)); + cards.add(new SetCardInfo("Foundry Inspector", 152, Rarity.COMMON, mage.cards.f.FoundryInspector.class)); + cards.add(new SetCardInfo("Game Trail", 169, Rarity.RARE, mage.cards.g.GameTrail.class)); + cards.add(new SetCardInfo("Generous Gift", 84, Rarity.UNCOMMON, mage.cards.g.GenerousGift.class)); + cards.add(new SetCardInfo("Genesis Hydra", 118, Rarity.RARE, mage.cards.g.GenesisHydra.class)); + cards.add(new SetCardInfo("Go-Shintai of Life's Origin", 37, Rarity.MYTHIC, mage.cards.g.GoShintaiOfLifesOrigin.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Go-Shintai of Life's Origin", 66, Rarity.MYTHIC, mage.cards.g.GoShintaiOfLifesOrigin.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Goblin Razerunners", 106, Rarity.RARE, mage.cards.g.GoblinRazerunners.class)); + cards.add(new SetCardInfo("Gold Myr", 153, Rarity.COMMON, mage.cards.g.GoldMyr.class)); + cards.add(new SetCardInfo("Grumgully, the Generous", 138, Rarity.UNCOMMON, mage.cards.g.GrumgullyTheGenerous.class)); + cards.add(new SetCardInfo("Gruul Turf", 170, Rarity.UNCOMMON, mage.cards.g.GruulTurf.class)); + cards.add(new SetCardInfo("Hanna, Ship's Navigator", 139, Rarity.RARE, mage.cards.h.HannaShipsNavigator.class)); + cards.add(new SetCardInfo("Hunter's Insight", 119, Rarity.UNCOMMON, mage.cards.h.HuntersInsight.class)); + cards.add(new SetCardInfo("Imposter Mech", 13, Rarity.RARE, mage.cards.i.ImposterMech.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Imposter Mech", 49, Rarity.RARE, mage.cards.i.ImposterMech.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Indomitable Archangel", 85, Rarity.MYTHIC, mage.cards.i.IndomitableArchangel.class)); + cards.add(new SetCardInfo("Ironsoul Enforcer", 41, Rarity.RARE, mage.cards.i.IronsoulEnforcer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ironsoul Enforcer", 7, Rarity.RARE, mage.cards.i.IronsoulEnforcer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jace, Architect of Thought", 93, Rarity.MYTHIC, mage.cards.j.JaceArchitectOfThought.class)); + cards.add(new SetCardInfo("Kaima, the Fractured Calm", 3, Rarity.MYTHIC, mage.cards.k.KaimaTheFracturedCalm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kaima, the Fractured Calm", 74, Rarity.MYTHIC, mage.cards.k.KaimaTheFracturedCalm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kami of Celebration", 20, Rarity.RARE, mage.cards.k.KamiOfCelebration.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kami of Celebration", 59, Rarity.RARE, mage.cards.k.KamiOfCelebration.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kappa Cannoneer", 14, Rarity.RARE, mage.cards.k.KappaCannoneer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kappa Cannoneer", 50, Rarity.RARE, mage.cards.k.KappaCannoneer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Katsumasa, the Animator", 15, Rarity.RARE, mage.cards.k.KatsumasaTheAnimator.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Katsumasa, the Animator", 51, Rarity.RARE, mage.cards.k.KatsumasaTheAnimator.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kodama's Reach", 120, Rarity.COMMON, mage.cards.k.KodamasReach.class)); + cards.add(new SetCardInfo("Komainu Battle Armor", 21, Rarity.RARE, mage.cards.k.KomainuBattleArmor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Komainu Battle Armor", 60, Rarity.RARE, mage.cards.k.KomainuBattleArmor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kosei, Penitent Warlord", 26, Rarity.RARE, mage.cards.k.KoseiPenitentWarlord.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kosei, Penitent Warlord", 67, Rarity.RARE, mage.cards.k.KoseiPenitentWarlord.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kotori, Pilot Prodigy", 2, Rarity.MYTHIC, mage.cards.k.KotoriPilotProdigy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kotori, Pilot Prodigy", 75, Rarity.MYTHIC, mage.cards.k.KotoriPilotProdigy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kotori, Pilot Prodigy", 78, Rarity.MYTHIC, mage.cards.k.KotoriPilotProdigy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Krenko, Tin Street Kingpin", 107, Rarity.RARE, mage.cards.k.KrenkoTinStreetKingpin.class)); + cards.add(new SetCardInfo("Loyal Guardian", 121, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class)); + cards.add(new SetCardInfo("Mage Slayer", 140, Rarity.UNCOMMON, mage.cards.m.MageSlayer.class)); + cards.add(new SetCardInfo("Master of Etherium", 94, Rarity.RARE, mage.cards.m.MasterOfEtherium.class)); + cards.add(new SetCardInfo("Mirage Mirror", 154, Rarity.RARE, mage.cards.m.MirageMirror.class)); + cards.add(new SetCardInfo("Mossfire Valley", 171, Rarity.RARE, mage.cards.m.MossfireValley.class)); + cards.add(new SetCardInfo("Myojin of Blooming Dawn", 31, Rarity.RARE, mage.cards.m.MyojinOfBloomingDawn.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Myojin of Blooming Dawn", 42, Rarity.RARE, mage.cards.m.MyojinOfBloomingDawn.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Myojin of Cryptic Dreams", 33, Rarity.RARE, mage.cards.m.MyojinOfCrypticDreams.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Myojin of Cryptic Dreams", 52, Rarity.RARE, mage.cards.m.MyojinOfCrypticDreams.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Myojin of Grim Betrayal", 34, Rarity.RARE, mage.cards.m.MyojinOfGrimBetrayal.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Myojin of Grim Betrayal", 55, Rarity.RARE, mage.cards.m.MyojinOfGrimBetrayal.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Myojin of Roaring Blades", 36, Rarity.RARE, mage.cards.m.MyojinOfRoaringBlades.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Myojin of Roaring Blades", 61, Rarity.RARE, mage.cards.m.MyojinOfRoaringBlades.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Myojin of Towering Might", 38, Rarity.RARE, mage.cards.m.MyojinOfToweringMight.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Myojin of Towering Might", 68, Rarity.RARE, mage.cards.m.MyojinOfToweringMight.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Myrsmith", 86, Rarity.UNCOMMON, mage.cards.m.Myrsmith.class)); + cards.add(new SetCardInfo("Nissa, Voice of Zendikar", 122, Rarity.MYTHIC, mage.cards.n.NissaVoiceOfZendikar.class)); + cards.add(new SetCardInfo("One with the Kami", 27, Rarity.RARE, mage.cards.o.OneWithTheKami.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("One with the Kami", 69, Rarity.RARE, mage.cards.o.OneWithTheKami.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Opal Palace", 172, Rarity.COMMON, mage.cards.o.OpalPalace.class)); + cards.add(new SetCardInfo("Oran-Rief, the Vastwood", 173, Rarity.RARE, mage.cards.o.OranRiefTheVastwood.class)); + cards.add(new SetCardInfo("Ordeal of Nylea", 123, Rarity.UNCOMMON, mage.cards.o.OrdealOfNylea.class)); + cards.add(new SetCardInfo("Organic Extinction", 43, Rarity.RARE, mage.cards.o.OrganicExtinction.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Organic Extinction", 8, Rarity.RARE, mage.cards.o.OrganicExtinction.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ox of Agonas", 108, Rarity.MYTHIC, mage.cards.o.OxOfAgonas.class)); + cards.add(new SetCardInfo("Parhelion II", 87, Rarity.RARE, mage.cards.p.ParhelionII.class)); + cards.add(new SetCardInfo("Peacewalker Colossus", 155, Rarity.RARE, mage.cards.p.PeacewalkerColossus.class)); + cards.add(new SetCardInfo("Port Town", 174, Rarity.RARE, mage.cards.p.PortTown.class)); + cards.add(new SetCardInfo("Prairie Stream", 175, Rarity.RARE, mage.cards.p.PrairieStream.class)); + cards.add(new SetCardInfo("Primeval Protector", 124, Rarity.RARE, mage.cards.p.PrimevalProtector.class)); + cards.add(new SetCardInfo("Raff Capashen, Ship's Mage", 141, Rarity.UNCOMMON, mage.cards.r.RaffCapashenShipsMage.class)); + cards.add(new SetCardInfo("Raging Ravine", 176, Rarity.RARE, mage.cards.r.RagingRavine.class)); + cards.add(new SetCardInfo("Raiders' Karve", 156, Rarity.COMMON, mage.cards.r.RaidersKarve.class)); + cards.add(new SetCardInfo("Rampant Growth", 125, Rarity.COMMON, mage.cards.r.RampantGrowth.class)); + cards.add(new SetCardInfo("Rampant Rejuvenator", 28, Rarity.RARE, mage.cards.r.RampantRejuvenator.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rampant Rejuvenator", 70, Rarity.RARE, mage.cards.r.RampantRejuvenator.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Reality Shift", 95, Rarity.UNCOMMON, mage.cards.r.RealityShift.class)); + cards.add(new SetCardInfo("Release to Memory", 44, Rarity.RARE, mage.cards.r.ReleaseToMemory.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Release to Memory", 9, Rarity.RARE, mage.cards.r.ReleaseToMemory.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Research Thief", 16, Rarity.RARE, mage.cards.r.ResearchThief.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Research Thief", 53, Rarity.RARE, mage.cards.r.ResearchThief.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rhythm of the Wild", 142, Rarity.UNCOMMON, mage.cards.r.RhythmOfTheWild.class)); + cards.add(new SetCardInfo("Riddlesmith", 96, Rarity.UNCOMMON, mage.cards.r.Riddlesmith.class)); + cards.add(new SetCardInfo("Rishkar's Expertise", 127, Rarity.RARE, mage.cards.r.RishkarsExpertise.class)); + cards.add(new SetCardInfo("Rishkar, Peema Renegade", 126, Rarity.RARE, mage.cards.r.RishkarPeemaRenegade.class)); + cards.add(new SetCardInfo("Ruthless Technomancer", 35, Rarity.RARE, mage.cards.r.RuthlessTechnomancer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ruthless Technomancer", 56, Rarity.RARE, mage.cards.r.RuthlessTechnomancer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sai, Master Thopterist", 97, Rarity.RARE, mage.cards.s.SaiMasterThopterist.class)); + cards.add(new SetCardInfo("Sakura-Tribe Elder", 128, Rarity.COMMON, mage.cards.s.SakuraTribeElder.class)); + cards.add(new SetCardInfo("Shamanic Revelation", 129, Rarity.RARE, mage.cards.s.ShamanicRevelation.class)); + cards.add(new SetCardInfo("Shifting Shadow", 109, Rarity.RARE, mage.cards.s.ShiftingShadow.class)); + cards.add(new SetCardInfo("Shimmer Myr", 157, Rarity.UNCOMMON, mage.cards.s.ShimmerMyr.class)); + cards.add(new SetCardInfo("Shorikai, Genesis Engine", 4, Rarity.MYTHIC, mage.cards.s.ShorikaiGenesisEngine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Shorikai, Genesis Engine", 76, Rarity.MYTHIC, mage.cards.s.ShorikaiGenesisEngine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Silkguard", 29, Rarity.RARE, mage.cards.s.Silkguard.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Silkguard", 71, Rarity.RARE, mage.cards.s.Silkguard.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Silver Myr", 158, Rarity.COMMON, mage.cards.s.SilverMyr.class)); + cards.add(new SetCardInfo("Skycloud Expanse", 177, Rarity.RARE, mage.cards.s.SkycloudExpanse.class)); + cards.add(new SetCardInfo("Skysovereign, Consul Flagship", 159, Rarity.MYTHIC, mage.cards.s.SkysovereignConsulFlagship.class)); + cards.add(new SetCardInfo("Smoke Spirits' Aid", 22, Rarity.RARE, mage.cards.s.SmokeSpiritsAid.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Smoke Spirits' Aid", 62, Rarity.RARE, mage.cards.s.SmokeSpiritsAid.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Smuggler's Copter", 160, Rarity.RARE, mage.cards.s.SmugglersCopter.class)); + cards.add(new SetCardInfo("Snake Umbra", 130, Rarity.UNCOMMON, mage.cards.s.SnakeUmbra.class)); + cards.add(new SetCardInfo("Sol Ring", 161, Rarity.UNCOMMON, mage.cards.s.SolRing.class)); + cards.add(new SetCardInfo("Solemn Simulacrum", 162, Rarity.RARE, mage.cards.s.SolemnSimulacrum.class)); + cards.add(new SetCardInfo("Soul's Majesty", 131, Rarity.RARE, mage.cards.s.SoulsMajesty.class)); + cards.add(new SetCardInfo("Spearbreaker Behemoth", 132, Rarity.RARE, mage.cards.s.SpearbreakerBehemoth.class)); + cards.add(new SetCardInfo("Spire of Industry", 178, Rarity.RARE, mage.cards.s.SpireOfIndustry.class)); + cards.add(new SetCardInfo("Sram, Senior Edificer", 88, Rarity.RARE, mage.cards.s.SramSeniorEdificer.class)); + cards.add(new SetCardInfo("Starstorm", 110, Rarity.RARE, mage.cards.s.Starstorm.class)); + cards.add(new SetCardInfo("Swift Reconfiguration", 10, Rarity.RARE, mage.cards.s.SwiftReconfiguration.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swift Reconfiguration", 45, Rarity.RARE, mage.cards.s.SwiftReconfiguration.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swiftfoot Boots", 163, Rarity.UNCOMMON, mage.cards.s.SwiftfootBoots.class)); + cards.add(new SetCardInfo("Sword of Vengeance", 164, Rarity.RARE, mage.cards.s.SwordOfVengeance.class)); + cards.add(new SetCardInfo("Swords to Plowshares", 89, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); + cards.add(new SetCardInfo("Tanuki Transplanter", 30, Rarity.RARE, mage.cards.t.TanukiTransplanter.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tanuki Transplanter", 72, Rarity.RARE, mage.cards.t.TanukiTransplanter.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Taurean Mauler", 111, Rarity.RARE, mage.cards.t.TaureanMauler.class)); + cards.add(new SetCardInfo("Temple of Abandon", 179, Rarity.RARE, mage.cards.t.TempleOfAbandon.class)); + cards.add(new SetCardInfo("Temple of Enlightenment", 180, Rarity.RARE, mage.cards.t.TempleOfEnlightenment.class)); + cards.add(new SetCardInfo("Teshar, Ancestor's Apostle", 90, Rarity.RARE, mage.cards.t.TesharAncestorsApostle.class)); + cards.add(new SetCardInfo("Thopter Spy Network", 98, Rarity.RARE, mage.cards.t.ThopterSpyNetwork.class)); + cards.add(new SetCardInfo("Thoughtcast", 99, Rarity.COMMON, mage.cards.t.Thoughtcast.class)); + cards.add(new SetCardInfo("Ulasht, the Hate Seed", 143, Rarity.RARE, mage.cards.u.UlashtTheHateSeed.class)); + cards.add(new SetCardInfo("Universal Surveillance", 17, Rarity.RARE, mage.cards.u.UniversalSurveillance.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Universal Surveillance", 54, Rarity.RARE, mage.cards.u.UniversalSurveillance.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Unquenchable Fury", 23, Rarity.RARE, mage.cards.u.UnquenchableFury.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Unquenchable Fury", 63, Rarity.RARE, mage.cards.u.UnquenchableFury.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Vastwood Surge", 133, Rarity.UNCOMMON, mage.cards.v.VastwoodSurge.class)); + cards.add(new SetCardInfo("Vedalken Engineer", 100, Rarity.COMMON, mage.cards.v.VedalkenEngineer.class)); + cards.add(new SetCardInfo("Weatherlight", 165, Rarity.MYTHIC, mage.cards.w.Weatherlight.class)); + cards.add(new SetCardInfo("Whiptongue Hydra", 134, Rarity.RARE, mage.cards.w.WhiptongueHydra.class)); + cards.add(new SetCardInfo("Whirler Rogue", 101, Rarity.UNCOMMON, mage.cards.w.WhirlerRogue.class)); + cards.add(new SetCardInfo("Yoshimaru, Ever Faithful", 32, Rarity.MYTHIC, mage.cards.y.YoshimaruEverFaithful.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Yoshimaru, Ever Faithful", 46, Rarity.MYTHIC, mage.cards.y.YoshimaruEverFaithful.class, NON_FULL_USE_VARIOUS)); } } diff --git a/Mage.Sets/src/mage/sets/NewCapennaCommander.java b/Mage.Sets/src/mage/sets/NewCapennaCommander.java new file mode 100644 index 00000000000..8a8215c71cb --- /dev/null +++ b/Mage.Sets/src/mage/sets/NewCapennaCommander.java @@ -0,0 +1,331 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class NewCapennaCommander extends ExpansionSet { + + private static final NewCapennaCommander instance = new NewCapennaCommander(); + + public static NewCapennaCommander getInstance() { + return instance; + } + + private NewCapennaCommander() { + super("New Capenna Commander", "NCC", ExpansionSet.buildDate(2022, 4, 29), SetType.SUPPLEMENTAL); + this.hasBasicLands = false; + + cards.add(new SetCardInfo("Aether Snap", 241, Rarity.RARE, mage.cards.a.AetherSnap.class)); + cards.add(new SetCardInfo("Agitator Ant", 263, Rarity.RARE, mage.cards.a.AgitatorAnt.class)); + cards.add(new SetCardInfo("Ajani Unyielding", 324, Rarity.MYTHIC, mage.cards.a.AjaniUnyielding.class)); + cards.add(new SetCardInfo("Alela, Artful Provocateur", 325, Rarity.MYTHIC, mage.cards.a.AlelaArtfulProvocateur.class)); + cards.add(new SetCardInfo("Angelic Sleuth", 12, Rarity.RARE, mage.cards.a.AngelicSleuth.class)); + cards.add(new SetCardInfo("Arasta of the Endless Web", 279, Rarity.RARE, mage.cards.a.ArastaOfTheEndlessWeb.class)); + cards.add(new SetCardInfo("Arcane Sanctum", 385, Rarity.UNCOMMON, mage.cards.a.ArcaneSanctum.class)); + cards.add(new SetCardInfo("Arcane Signet", 360, Rarity.COMMON, mage.cards.a.ArcaneSignet.class)); + cards.add(new SetCardInfo("Archon of Coronation", 192, Rarity.MYTHIC, mage.cards.a.ArchonOfCoronation.class)); + cards.add(new SetCardInfo("Army of the Damned", 242, Rarity.MYTHIC, mage.cards.a.ArmyOfTheDamned.class)); + cards.add(new SetCardInfo("Artifact Mutation", 326, Rarity.RARE, mage.cards.a.ArtifactMutation.class)); + cards.add(new SetCardInfo("Artisan of Kozilek", 191, Rarity.UNCOMMON, mage.cards.a.ArtisanOfKozilek.class)); + cards.add(new SetCardInfo("Ash Barrens", 386, Rarity.UNCOMMON, mage.cards.a.AshBarrens.class)); + cards.add(new SetCardInfo("Assemble the Legion", 327, Rarity.RARE, mage.cards.a.AssembleTheLegion.class)); + cards.add(new SetCardInfo("Audacious Swap", 44, Rarity.RARE, mage.cards.a.AudaciousSwap.class)); + cards.add(new SetCardInfo("Aura Mutation", 328, Rarity.RARE, mage.cards.a.AuraMutation.class)); + cards.add(new SetCardInfo("Austere Command", 193, Rarity.RARE, mage.cards.a.AustereCommand.class)); + cards.add(new SetCardInfo("Aven Courier", 22, Rarity.RARE, mage.cards.a.AvenCourier.class)); + cards.add(new SetCardInfo("Aven Mimeomancer", 329, Rarity.RARE, mage.cards.a.AvenMimeomancer.class)); + cards.add(new SetCardInfo("Avenger of Zendikar", 280, Rarity.MYTHIC, mage.cards.a.AvengerOfZendikar.class)); + cards.add(new SetCardInfo("Avenging Huntbonder", 194, Rarity.RARE, mage.cards.a.AvengingHuntbonder.class)); + cards.add(new SetCardInfo("Awakening Zone", 281, Rarity.RARE, mage.cards.a.AwakeningZone.class)); + cards.add(new SetCardInfo("Azorius Signet", 361, Rarity.UNCOMMON, mage.cards.a.AzoriusSignet.class)); + cards.add(new SetCardInfo("Bant Charm", 330, Rarity.UNCOMMON, mage.cards.b.BantCharm.class)); + cards.add(new SetCardInfo("Bant Panorama", 387, Rarity.COMMON, mage.cards.b.BantPanorama.class)); + cards.add(new SetCardInfo("Beast Within", 282, Rarity.UNCOMMON, mage.cards.b.BeastWithin.class)); + cards.add(new SetCardInfo("Beastmaster Ascension", 283, Rarity.RARE, mage.cards.b.BeastmasterAscension.class)); + cards.add(new SetCardInfo("Bedevil", 331, Rarity.RARE, mage.cards.b.Bedevil.class)); + cards.add(new SetCardInfo("Bennie Bracks, Zoologist", 86, Rarity.MYTHIC, mage.cards.b.BennieBracksZoologist.class)); + cards.add(new SetCardInfo("Blasphemous Act", 264, Rarity.RARE, mage.cards.b.BlasphemousAct.class)); + cards.add(new SetCardInfo("Blighted Woodland", 388, Rarity.UNCOMMON, mage.cards.b.BlightedWoodland.class)); + cards.add(new SetCardInfo("Bloodsoaked Champion", 243, Rarity.RARE, mage.cards.b.BloodsoakedChampion.class)); + cards.add(new SetCardInfo("Bloodthirsty Blade", 362, Rarity.UNCOMMON, mage.cards.b.BloodthirstyBlade.class)); + cards.add(new SetCardInfo("Body Count", 34, Rarity.RARE, mage.cards.b.BodyCount.class)); + cards.add(new SetCardInfo("Boros Charm", 332, Rarity.UNCOMMON, mage.cards.b.BorosCharm.class)); + cards.add(new SetCardInfo("Boss's Chauffeur", 13, Rarity.RARE, mage.cards.b.BosssChauffeur.class)); + cards.add(new SetCardInfo("Boxing Ring", 91, Rarity.RARE, mage.cards.b.BoxingRing.class)); + cards.add(new SetCardInfo("Bribe Taker", 55, Rarity.RARE, mage.cards.b.BribeTaker.class)); + cards.add(new SetCardInfo("Brokers Confluence", 68, Rarity.RARE, mage.cards.b.BrokersConfluence.class)); + cards.add(new SetCardInfo("Cabaretti Confluence", 69, Rarity.RARE, mage.cards.c.CabarettiConfluence.class)); + cards.add(new SetCardInfo("Caldaia Guardian", 56, Rarity.RARE, mage.cards.c.CaldaiaGuardian.class)); + cards.add(new SetCardInfo("Call the Coppercoats", 195, Rarity.RARE, mage.cards.c.CallTheCoppercoats.class)); + cards.add(new SetCardInfo("Call the Skybreaker", 333, Rarity.RARE, mage.cards.c.CallTheSkybreaker.class)); + cards.add(new SetCardInfo("Camaraderie", 334, Rarity.RARE, mage.cards.c.Camaraderie.class)); + cards.add(new SetCardInfo("Canopy Vista", 389, Rarity.RARE, mage.cards.c.CanopyVista.class)); + cards.add(new SetCardInfo("Cascade Bluffs", 390, Rarity.RARE, mage.cards.c.CascadeBluffs.class)); + cards.add(new SetCardInfo("Castle Ardenvale", 391, Rarity.RARE, mage.cards.c.CastleArdenvale.class)); + cards.add(new SetCardInfo("Castle Embereth", 392, Rarity.RARE, mage.cards.c.CastleEmbereth.class)); + cards.add(new SetCardInfo("Cephalid Facetaker", 23, Rarity.RARE, mage.cards.c.CephalidFacetaker.class)); + cards.add(new SetCardInfo("Chain Reaction", 265, Rarity.RARE, mage.cards.c.ChainReaction.class)); + cards.add(new SetCardInfo("Champion of Lambholt", 284, Rarity.RARE, mage.cards.c.ChampionOfLambholt.class)); + cards.add(new SetCardInfo("Champion of Wits", 213, Rarity.RARE, mage.cards.c.ChampionOfWits.class)); + cards.add(new SetCardInfo("Change of Plans", 24, Rarity.RARE, mage.cards.c.ChangeOfPlans.class)); + cards.add(new SetCardInfo("Chaos Warp", 266, Rarity.RARE, mage.cards.c.ChaosWarp.class)); + cards.add(new SetCardInfo("Chasm Skulker", 214, Rarity.RARE, mage.cards.c.ChasmSkulker.class)); + cards.add(new SetCardInfo("Choked Estuary", 393, Rarity.RARE, mage.cards.c.ChokedEstuary.class)); + cards.add(new SetCardInfo("Cinder Glade", 394, Rarity.RARE, mage.cards.c.CinderGlade.class)); + cards.add(new SetCardInfo("Clone Legion", 215, Rarity.MYTHIC, mage.cards.c.CloneLegion.class)); + cards.add(new SetCardInfo("Command Tower", 395, Rarity.COMMON, mage.cards.c.CommandTower.class)); + cards.add(new SetCardInfo("Commander's Sphere", 363, Rarity.COMMON, mage.cards.c.CommandersSphere.class)); + cards.add(new SetCardInfo("Commit // Memory", 216, Rarity.RARE, mage.cards.c.CommitMemory.class)); + cards.add(new SetCardInfo("Crash the Party", 57, Rarity.RARE, mage.cards.c.CrashTheParty.class)); + cards.add(new SetCardInfo("Creeping Tar Pit", 396, Rarity.RARE, mage.cards.c.CreepingTarPit.class)); + cards.add(new SetCardInfo("Crumbling Necropolis", 397, Rarity.UNCOMMON, mage.cards.c.CrumblingNecropolis.class)); + cards.add(new SetCardInfo("Crystalline Giant", 364, Rarity.RARE, mage.cards.c.CrystallineGiant.class)); + cards.add(new SetCardInfo("Cultivate", 285, Rarity.UNCOMMON, mage.cards.c.Cultivate.class)); + cards.add(new SetCardInfo("Currency Converter", 81, Rarity.RARE, mage.cards.c.CurrencyConverter.class)); + cards.add(new SetCardInfo("Custodi Lich", 244, Rarity.RARE, mage.cards.c.CustodiLich.class)); + cards.add(new SetCardInfo("Damnable Pact", 245, Rarity.RARE, mage.cards.d.DamnablePact.class)); + cards.add(new SetCardInfo("Damning Verdict", 15, Rarity.RARE, mage.cards.d.DamningVerdict.class)); + cards.add(new SetCardInfo("Daring Saboteur", 217, Rarity.UNCOMMON, mage.cards.d.DaringSaboteur.class)); + cards.add(new SetCardInfo("Darkwater Catacombs", 398, Rarity.RARE, mage.cards.d.DarkwaterCatacombs.class)); + cards.add(new SetCardInfo("Daxos of Meletis", 335, Rarity.RARE, mage.cards.d.DaxosOfMeletis.class)); + cards.add(new SetCardInfo("Deathbringer Regent", 246, Rarity.RARE, mage.cards.d.DeathbringerRegent.class)); + cards.add(new SetCardInfo("Deathreap Ritual", 336, Rarity.UNCOMMON, mage.cards.d.DeathreapRitual.class)); + cards.add(new SetCardInfo("Declaration in Stone", 196, Rarity.RARE, mage.cards.d.DeclarationInStone.class)); + cards.add(new SetCardInfo("Deep Analysis", 218, Rarity.COMMON, mage.cards.d.DeepAnalysis.class)); + cards.add(new SetCardInfo("Determined Iteration", 45, Rarity.RARE, mage.cards.d.DeterminedIteration.class)); + cards.add(new SetCardInfo("Devoted Druid", 286, Rarity.UNCOMMON, mage.cards.d.DevotedDruid.class)); + cards.add(new SetCardInfo("Dig Through Time", 219, Rarity.RARE, mage.cards.d.DigThroughTime.class)); + cards.add(new SetCardInfo("Dimir Signet", 365, Rarity.COMMON, mage.cards.d.DimirSignet.class)); + cards.add(new SetCardInfo("Disciple of Bolas", 247, Rarity.RARE, mage.cards.d.DiscipleOfBolas.class)); + cards.add(new SetCardInfo("Dodgy Jalopy", 58, Rarity.RARE, mage.cards.d.DodgyJalopy.class)); + cards.add(new SetCardInfo("Double Vision", 267, Rarity.RARE, mage.cards.d.DoubleVision.class)); + cards.add(new SetCardInfo("Dragonlord Ojutai", 337, Rarity.MYTHIC, mage.cards.d.DragonlordOjutai.class)); + cards.add(new SetCardInfo("Drana, Liberator of Malakir", 248, Rarity.MYTHIC, mage.cards.d.DranaLiberatorOfMalakir.class)); + cards.add(new SetCardInfo("Drawn from Dreams", 220, Rarity.RARE, mage.cards.d.DrawnFromDreams.class)); + cards.add(new SetCardInfo("Dread Summons", 249, Rarity.RARE, mage.cards.d.DreadSummons.class)); + cards.add(new SetCardInfo("Duelist's Heritage", 197, Rarity.RARE, mage.cards.d.DuelistsHeritage.class)); + cards.add(new SetCardInfo("Dusk // Dawn", 198, Rarity.RARE, mage.cards.d.DuskDawn.class)); + cards.add(new SetCardInfo("Esper Panorama", 399, Rarity.COMMON, mage.cards.e.EsperPanorama.class)); + cards.add(new SetCardInfo("Etali, Primal Storm", 268, Rarity.RARE, mage.cards.e.EtaliPrimalStorm.class)); + cards.add(new SetCardInfo("Everflowing Chalice", 366, Rarity.COMMON, mage.cards.e.EverflowingChalice.class)); + cards.add(new SetCardInfo("Evolution Sage", 287, Rarity.UNCOMMON, mage.cards.e.EvolutionSage.class)); + cards.add(new SetCardInfo("Evolutionary Leap", 288, Rarity.RARE, mage.cards.e.EvolutionaryLeap.class)); + cards.add(new SetCardInfo("Exotic Orchard", 400, Rarity.RARE, mage.cards.e.ExoticOrchard.class)); + cards.add(new SetCardInfo("Explore", 289, Rarity.COMMON, mage.cards.e.Explore.class)); + cards.add(new SetCardInfo("Extravagant Replication", 25, Rarity.RARE, mage.cards.e.ExtravagantReplication.class)); + cards.add(new SetCardInfo("Fact or Fiction", 221, Rarity.UNCOMMON, mage.cards.f.FactOrFiction.class)); + cards.add(new SetCardInfo("Fallen Shinobi", 338, Rarity.RARE, mage.cards.f.FallenShinobi.class)); + cards.add(new SetCardInfo("False Floor", 82, Rarity.RARE, mage.cards.f.FalseFloor.class)); + cards.add(new SetCardInfo("Farseek", 290, Rarity.COMMON, mage.cards.f.Farseek.class)); + cards.add(new SetCardInfo("Fathom Mage", 339, Rarity.RARE, mage.cards.f.FathomMage.class)); + cards.add(new SetCardInfo("Feed the Swarm", 250, Rarity.COMMON, mage.cards.f.FeedTheSwarm.class)); + cards.add(new SetCardInfo("Felidar Retreat", 199, Rarity.RARE, mage.cards.f.FelidarRetreat.class)); + cards.add(new SetCardInfo("Fell the Mighty", 200, Rarity.RARE, mage.cards.f.FellTheMighty.class)); + cards.add(new SetCardInfo("Fellwar Stone", 367, Rarity.UNCOMMON, mage.cards.f.FellwarStone.class)); + cards.add(new SetCardInfo("Fetid Heath", 401, Rarity.RARE, mage.cards.f.FetidHeath.class)); + cards.add(new SetCardInfo("First Responder", 60, Rarity.RARE, mage.cards.f.FirstResponder.class)); + cards.add(new SetCardInfo("Flawless Forgery", 26, Rarity.RARE, mage.cards.f.FlawlessForgery.class)); + cards.add(new SetCardInfo("Flooded Grove", 402, Rarity.RARE, mage.cards.f.FloodedGrove.class)); + cards.add(new SetCardInfo("Foreboding Ruins", 403, Rarity.RARE, mage.cards.f.ForebodingRuins.class)); + cards.add(new SetCardInfo("Forgotten Ancient", 291, Rarity.RARE, mage.cards.f.ForgottenAncient.class)); + cards.add(new SetCardInfo("Fortified Village", 404, Rarity.RARE, mage.cards.f.FortifiedVillage.class)); + cards.add(new SetCardInfo("Frantic Search", 222, Rarity.COMMON, mage.cards.f.FranticSearch.class)); + cards.add(new SetCardInfo("Gahiji, Honored One", 340, Rarity.MYTHIC, mage.cards.g.GahijiHonoredOne.class)); + cards.add(new SetCardInfo("Game Trail", 405, Rarity.RARE, mage.cards.g.GameTrail.class)); + cards.add(new SetCardInfo("Garruk's Uprising", 292, Rarity.UNCOMMON, mage.cards.g.GarruksUprising.class)); + cards.add(new SetCardInfo("Gavel of the Righteous", 83, Rarity.RARE, mage.cards.g.GavelOfTheRighteous.class)); + cards.add(new SetCardInfo("Gavony Township", 406, Rarity.RARE, mage.cards.g.GavonyTownship.class)); + cards.add(new SetCardInfo("Generous Gift", 201, Rarity.UNCOMMON, mage.cards.g.GenerousGift.class)); + cards.add(new SetCardInfo("Ghostly Pilferer", 223, Rarity.RARE, mage.cards.g.GhostlyPilferer.class)); + cards.add(new SetCardInfo("Giant Adephage", 293, Rarity.MYTHIC, mage.cards.g.GiantAdephage.class)); + cards.add(new SetCardInfo("Goblin Electromancer", 341, Rarity.COMMON, mage.cards.g.GoblinElectromancer.class)); + cards.add(new SetCardInfo("Grand Crescendo", 16, Rarity.RARE, mage.cards.g.GrandCrescendo.class)); + cards.add(new SetCardInfo("Grateful Apparition", 202, Rarity.UNCOMMON, mage.cards.g.GratefulApparition.class)); + cards.add(new SetCardInfo("Graveblade Marauder", 251, Rarity.RARE, mage.cards.g.GravebladeMarauder.class)); + cards.add(new SetCardInfo("Greenwarden of Murasa", 294, Rarity.MYTHIC, mage.cards.g.GreenwardenOfMurasa.class)); + cards.add(new SetCardInfo("Grime Gorger", 72, Rarity.RARE, mage.cards.g.GrimeGorger.class)); + cards.add(new SetCardInfo("Grixis Panorama", 407, Rarity.COMMON, mage.cards.g.GrixisPanorama.class)); + cards.add(new SetCardInfo("Harmonize", 295, Rarity.UNCOMMON, mage.cards.h.Harmonize.class)); + cards.add(new SetCardInfo("Hex", 252, Rarity.RARE, mage.cards.h.Hex.class)); + cards.add(new SetCardInfo("Hoofprints of the Stag", 203, Rarity.RARE, mage.cards.h.HoofprintsOfTheStag.class)); + cards.add(new SetCardInfo("Identity Thief", 224, Rarity.RARE, mage.cards.i.IdentityThief.class)); + cards.add(new SetCardInfo("Idol of Oblivion", 368, Rarity.RARE, mage.cards.i.IdolOfOblivion.class)); + cards.add(new SetCardInfo("In Too Deep", 27, Rarity.RARE, mage.cards.i.InTooDeep.class)); + cards.add(new SetCardInfo("Incubation Druid", 296, Rarity.RARE, mage.cards.i.IncubationDruid.class)); + cards.add(new SetCardInfo("Indrik Stomphowler", 297, Rarity.UNCOMMON, mage.cards.i.IndrikStomphowler.class)); + cards.add(new SetCardInfo("Indulge // Excess", 46, Rarity.RARE, mage.cards.i.IndulgeExcess.class)); + cards.add(new SetCardInfo("Industrial Advancement", 47, Rarity.RARE, mage.cards.i.IndustrialAdvancement.class)); + cards.add(new SetCardInfo("Inferno Titan", 269, Rarity.MYTHIC, mage.cards.i.InfernoTitan.class)); + cards.add(new SetCardInfo("Inkfathom Witch", 342, Rarity.UNCOMMON, mage.cards.i.InkfathomWitch.class)); + cards.add(new SetCardInfo("Intangible Virtue", 204, Rarity.UNCOMMON, mage.cards.i.IntangibleVirtue.class)); + cards.add(new SetCardInfo("Izzet Signet", 369, Rarity.UNCOMMON, mage.cards.i.IzzetSignet.class)); + cards.add(new SetCardInfo("Jenara, Asura of War", 343, Rarity.MYTHIC, mage.cards.j.JenaraAsuraOfWar.class)); + cards.add(new SetCardInfo("Jund Panorama", 408, Rarity.COMMON, mage.cards.j.JundPanorama.class)); + cards.add(new SetCardInfo("Jungle Shrine", 409, Rarity.UNCOMMON, mage.cards.j.JungleShrine.class)); + cards.add(new SetCardInfo("Karn's Bastion", 410, Rarity.RARE, mage.cards.k.KarnsBastion.class)); + cards.add(new SetCardInfo("Kazuul, Tyrant of the Cliffs", 270, Rarity.RARE, mage.cards.k.KazuulTyrantOfTheCliffs.class)); + cards.add(new SetCardInfo("Kess, Dissident Mage", 344, Rarity.MYTHIC, mage.cards.k.KessDissidentMage.class)); + cards.add(new SetCardInfo("Kessig Wolf Run", 411, Rarity.RARE, mage.cards.k.KessigWolfRun.class)); + cards.add(new SetCardInfo("Killer Service", 61, Rarity.RARE, mage.cards.k.KillerService.class)); + cards.add(new SetCardInfo("Kitt Kanto, Mayhem Diva", 4, Rarity.MYTHIC, mage.cards.k.KittKantoMayhemDiva.class)); + cards.add(new SetCardInfo("Kodama's Reach", 298, Rarity.COMMON, mage.cards.k.KodamasReach.class)); + cards.add(new SetCardInfo("Kresh the Bloodbraided", 345, Rarity.MYTHIC, mage.cards.k.KreshTheBloodbraided.class)); + cards.add(new SetCardInfo("Leafkin Druid", 299, Rarity.COMMON, mage.cards.l.LeafkinDruid.class)); + cards.add(new SetCardInfo("Life Insurance", 74, Rarity.RARE, mage.cards.l.LifeInsurance.class)); + cards.add(new SetCardInfo("Life of the Party", 48, Rarity.RARE, mage.cards.l.LifeOfTheParty.class)); + cards.add(new SetCardInfo("Life's Legacy", 300, Rarity.RARE, mage.cards.l.LifesLegacy.class)); + cards.add(new SetCardInfo("Lifecrafter's Bestiary", 370, Rarity.RARE, mage.cards.l.LifecraftersBestiary.class)); + cards.add(new SetCardInfo("Lightning Greaves", 371, Rarity.UNCOMMON, mage.cards.l.LightningGreaves.class)); + cards.add(new SetCardInfo("Littjara Mirrorlake", 412, Rarity.UNCOMMON, mage.cards.l.LittjaraMirrorlake.class)); + cards.add(new SetCardInfo("Llanowar Reborn", 413, Rarity.UNCOMMON, mage.cards.l.LlanowarReborn.class)); + cards.add(new SetCardInfo("Looter il-Kor", 225, Rarity.COMMON, mage.cards.l.LooterIlKor.class)); + cards.add(new SetCardInfo("Luminarch Aspirant", 205, Rarity.RARE, mage.cards.l.LuminarchAspirant.class)); + cards.add(new SetCardInfo("Maestros Confluence", 75, Rarity.RARE, mage.cards.m.MaestrosConfluence.class)); + cards.add(new SetCardInfo("Magus of the Wheel", 271, Rarity.RARE, mage.cards.m.MagusOfTheWheel.class)); + cards.add(new SetCardInfo("March of the Multitudes", 346, Rarity.MYTHIC, mage.cards.m.MarchOfTheMultitudes.class)); + cards.add(new SetCardInfo("Martial Coup", 206, Rarity.RARE, mage.cards.m.MartialCoup.class)); + cards.add(new SetCardInfo("Mask of Riddles", 347, Rarity.UNCOMMON, mage.cards.m.MaskOfRiddles.class)); + cards.add(new SetCardInfo("Mask of the Schemer", 28, Rarity.RARE, mage.cards.m.MaskOfTheSchemer.class)); + cards.add(new SetCardInfo("Mezzio Mugger", 49, Rarity.RARE, mage.cards.m.MezzioMugger.class)); + cards.add(new SetCardInfo("Midnight Clock", 226, Rarity.RARE, mage.cards.m.MidnightClock.class)); + cards.add(new SetCardInfo("Migration Path", 301, Rarity.UNCOMMON, mage.cards.m.MigrationPath.class)); + cards.add(new SetCardInfo("Mimic Vat", 372, Rarity.RARE, mage.cards.m.MimicVat.class)); + cards.add(new SetCardInfo("Mitotic Slime", 302, Rarity.RARE, mage.cards.m.MitoticSlime.class)); + cards.add(new SetCardInfo("Mossfire Valley", 414, Rarity.RARE, mage.cards.m.MossfireValley.class)); + cards.add(new SetCardInfo("Mosswort Bridge", 415, Rarity.RARE, mage.cards.m.MosswortBridge.class)); + cards.add(new SetCardInfo("Myriad Landscape", 416, Rarity.UNCOMMON, mage.cards.m.MyriadLandscape.class)); + cards.add(new SetCardInfo("Mystic Confluence", 227, Rarity.RARE, mage.cards.m.MysticConfluence.class)); + cards.add(new SetCardInfo("Nadir Kraken", 228, Rarity.RARE, mage.cards.n.NadirKraken.class)); + cards.add(new SetCardInfo("Naya Panorama", 417, Rarity.COMMON, mage.cards.n.NayaPanorama.class)); + cards.add(new SetCardInfo("Nesting Grounds", 418, Rarity.RARE, mage.cards.n.NestingGrounds.class)); + cards.add(new SetCardInfo("Nightmare Unmaking", 253, Rarity.RARE, mage.cards.n.NightmareUnmaking.class)); + cards.add(new SetCardInfo("Noxious Gearhulk", 254, Rarity.MYTHIC, mage.cards.n.NoxiousGearhulk.class)); + cards.add(new SetCardInfo("Oblivion Stone", 373, Rarity.RARE, mage.cards.o.OblivionStone.class)); + cards.add(new SetCardInfo("Obscura Confluence", 76, Rarity.RARE, mage.cards.o.ObscuraConfluence.class)); + cards.add(new SetCardInfo("Oracle's Vault", 374, Rarity.RARE, mage.cards.o.OraclesVault.class)); + cards.add(new SetCardInfo("Orzhov Advokist", 207, Rarity.UNCOMMON, mage.cards.o.OrzhovAdvokist.class)); + cards.add(new SetCardInfo("Orzhov Signet", 375, Rarity.UNCOMMON, mage.cards.o.OrzhovSignet.class)); + cards.add(new SetCardInfo("Outpost Siege", 272, Rarity.RARE, mage.cards.o.OutpostSiege.class)); + cards.add(new SetCardInfo("Overgrown Battlement", 303, Rarity.UNCOMMON, mage.cards.o.OvergrownBattlement.class)); + cards.add(new SetCardInfo("Painful Truths", 255, Rarity.RARE, mage.cards.p.PainfulTruths.class)); + cards.add(new SetCardInfo("Park Heights Maverick", 63, Rarity.RARE, mage.cards.p.ParkHeightsMaverick.class)); + cards.add(new SetCardInfo("Path of Ancestry", 419, Rarity.COMMON, mage.cards.p.PathOfAncestry.class)); + cards.add(new SetCardInfo("Path to Exile", 208, Rarity.UNCOMMON, mage.cards.p.PathToExile.class)); + cards.add(new SetCardInfo("Perrie, the Pulverizer", 5, Rarity.MYTHIC, mage.cards.p.PerrieThePulverizer.class)); + cards.add(new SetCardInfo("Planar Outburst", 209, Rarity.RARE, mage.cards.p.PlanarOutburst.class)); + cards.add(new SetCardInfo("Ponder", 229, Rarity.COMMON, mage.cards.p.Ponder.class)); + cards.add(new SetCardInfo("Port Town", 420, Rarity.RARE, mage.cards.p.PortTown.class)); + cards.add(new SetCardInfo("Power Conduit", 376, Rarity.UNCOMMON, mage.cards.p.PowerConduit.class)); + cards.add(new SetCardInfo("Prairie Stream", 421, Rarity.RARE, mage.cards.p.PrairieStream.class)); + cards.add(new SetCardInfo("Preordain", 230, Rarity.COMMON, mage.cards.p.Preordain.class)); + cards.add(new SetCardInfo("Primal Empathy", 348, Rarity.UNCOMMON, mage.cards.p.PrimalEmpathy.class)); + cards.add(new SetCardInfo("Profane Command", 256, Rarity.RARE, mage.cards.p.ProfaneCommand.class)); + cards.add(new SetCardInfo("Prosperous Partnership", 78, Rarity.RARE, mage.cards.p.ProsperousPartnership.class)); + cards.add(new SetCardInfo("Protection Racket", 39, Rarity.RARE, mage.cards.p.ProtectionRacket.class)); + cards.add(new SetCardInfo("Puppeteer Clique", 257, Rarity.RARE, mage.cards.p.PuppeteerClique.class)); + cards.add(new SetCardInfo("Quietus Spike", 377, Rarity.RARE, mage.cards.q.QuietusSpike.class)); + cards.add(new SetCardInfo("Rakdos Signet", 378, Rarity.UNCOMMON, mage.cards.r.RakdosSignet.class)); + cards.add(new SetCardInfo("Rampant Growth", 304, Rarity.COMMON, mage.cards.r.RampantGrowth.class)); + cards.add(new SetCardInfo("Reign of the Pit", 258, Rarity.RARE, mage.cards.r.ReignOfThePit.class)); + cards.add(new SetCardInfo("Rekindling Phoenix", 273, Rarity.MYTHIC, mage.cards.r.RekindlingPhoenix.class)); + cards.add(new SetCardInfo("Rishkar's Expertise", 306, Rarity.RARE, mage.cards.r.RishkarsExpertise.class)); + cards.add(new SetCardInfo("Rishkar, Peema Renegade", 305, Rarity.RARE, mage.cards.r.RishkarPeemaRenegade.class)); + cards.add(new SetCardInfo("Rite of the Raging Storm", 274, Rarity.UNCOMMON, mage.cards.r.RiteOfTheRagingStorm.class)); + cards.add(new SetCardInfo("River's Rebuke", 231, Rarity.RARE, mage.cards.r.RiversRebuke.class)); + cards.add(new SetCardInfo("Roalesk, Apex Hybrid", 349, Rarity.MYTHIC, mage.cards.r.RoaleskApexHybrid.class)); + cards.add(new SetCardInfo("Rogue's Passage", 422, Rarity.UNCOMMON, mage.cards.r.RoguesPassage.class)); + cards.add(new SetCardInfo("Rose Room Treasurer", 51, Rarity.RARE, mage.cards.r.RoseRoomTreasurer.class)); + cards.add(new SetCardInfo("Rugged Prairie", 423, Rarity.RARE, mage.cards.r.RuggedPrairie.class)); + cards.add(new SetCardInfo("Sakura-Tribe Elder", 307, Rarity.COMMON, mage.cards.s.SakuraTribeElder.class)); + cards.add(new SetCardInfo("Sandwurm Convergence", 308, Rarity.RARE, mage.cards.s.SandwurmConvergence.class)); + cards.add(new SetCardInfo("Savage Lands", 424, Rarity.UNCOMMON, mage.cards.s.SavageLands.class)); + cards.add(new SetCardInfo("Scavenging Ooze", 309, Rarity.RARE, mage.cards.s.ScavengingOoze.class)); + cards.add(new SetCardInfo("Scepter of Celebration", 64, Rarity.RARE, mage.cards.s.ScepterOfCelebration.class)); + cards.add(new SetCardInfo("Scute Swarm", 310, Rarity.RARE, mage.cards.s.ScuteSwarm.class)); + cards.add(new SetCardInfo("Seaside Citadel", 425, Rarity.UNCOMMON, mage.cards.s.SeasideCitadel.class)); + cards.add(new SetCardInfo("Seize the Spotlight", 52, Rarity.RARE, mage.cards.s.SeizeTheSpotlight.class)); + cards.add(new SetCardInfo("Selvala, Explorer Returned", 350, Rarity.RARE, mage.cards.s.SelvalaExplorerReturned.class)); + cards.add(new SetCardInfo("Sever the Bloodline", 259, Rarity.RARE, mage.cards.s.SeverTheBloodline.class)); + cards.add(new SetCardInfo("Shadowblood Ridge", 426, Rarity.RARE, mage.cards.s.ShadowbloodRidge.class)); + cards.add(new SetCardInfo("Shadowmage Infiltrator", 351, Rarity.UNCOMMON, mage.cards.s.ShadowmageInfiltrator.class)); + cards.add(new SetCardInfo("Shamanic Revelation", 311, Rarity.RARE, mage.cards.s.ShamanicRevelation.class)); + cards.add(new SetCardInfo("Silent-Blade Oni", 352, Rarity.RARE, mage.cards.s.SilentBladeOni.class)); + cards.add(new SetCardInfo("Skyclave Shade", 260, Rarity.RARE, mage.cards.s.SkyclaveShade.class)); + cards.add(new SetCardInfo("Skycloud Expanse", 427, Rarity.RARE, mage.cards.s.SkycloudExpanse.class)); + cards.add(new SetCardInfo("Skyship Plunderer", 232, Rarity.UNCOMMON, mage.cards.s.SkyshipPlunderer.class)); + cards.add(new SetCardInfo("Slippery Bogbonder", 312, Rarity.RARE, mage.cards.s.SlipperyBogbonder.class)); + cards.add(new SetCardInfo("Smoldering Marsh", 428, Rarity.RARE, mage.cards.s.SmolderingMarsh.class)); + cards.add(new SetCardInfo("Sol Ring", 379, Rarity.UNCOMMON, mage.cards.s.SolRing.class)); + cards.add(new SetCardInfo("Solemn Simulacrum", 380, Rarity.RARE, mage.cards.s.SolemnSimulacrum.class)); + cards.add(new SetCardInfo("Spellbinding Soprano", 53, Rarity.RARE, mage.cards.s.SpellbindingSoprano.class)); + cards.add(new SetCardInfo("Spinerock Knoll", 429, Rarity.RARE, mage.cards.s.SpinerockKnoll.class)); + cards.add(new SetCardInfo("Spiteful Repossession", 90, Rarity.RARE, mage.cards.s.SpitefulRepossession.class)); + cards.add(new SetCardInfo("Squee, the Immortal", 275, Rarity.RARE, mage.cards.s.SqueeTheImmortal.class)); + cards.add(new SetCardInfo("Stalking Vengeance", 276, Rarity.RARE, mage.cards.s.StalkingVengeance.class)); + cards.add(new SetCardInfo("Steelbane Hydra", 313, Rarity.RARE, mage.cards.s.SteelbaneHydra.class)); + cards.add(new SetCardInfo("Stolen Identity", 233, Rarity.RARE, mage.cards.s.StolenIdentity.class)); + cards.add(new SetCardInfo("Storm of Forms", 32, Rarity.RARE, mage.cards.s.StormOfForms.class)); + cards.add(new SetCardInfo("Strionic Resonator", 381, Rarity.RARE, mage.cards.s.StrionicResonator.class)); + cards.add(new SetCardInfo("Sun Titan", 210, Rarity.MYTHIC, mage.cards.s.SunTitan.class)); + cards.add(new SetCardInfo("Sungrass Prairie", 430, Rarity.RARE, mage.cards.s.SungrassPrairie.class)); + cards.add(new SetCardInfo("Sunken Hollow", 431, Rarity.RARE, mage.cards.s.SunkenHollow.class)); + cards.add(new SetCardInfo("Swiftfoot Boots", 382, Rarity.UNCOMMON, mage.cards.s.SwiftfootBoots.class)); + cards.add(new SetCardInfo("Swords to Plowshares", 211, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); + cards.add(new SetCardInfo("Sylvan Offering", 314, Rarity.RARE, mage.cards.s.SylvanOffering.class)); + cards.add(new SetCardInfo("Talrand's Invocation", 234, Rarity.UNCOMMON, mage.cards.t.TalrandsInvocation.class)); + cards.add(new SetCardInfo("Temple of Epiphany", 432, Rarity.RARE, mage.cards.t.TempleOfEpiphany.class)); + cards.add(new SetCardInfo("Temple of Malady", 433, Rarity.RARE, mage.cards.t.TempleOfMalady.class)); + cards.add(new SetCardInfo("Temple of Mystery", 434, Rarity.RARE, mage.cards.t.TempleOfMystery.class)); + cards.add(new SetCardInfo("Temple of Silence", 435, Rarity.RARE, mage.cards.t.TempleOfSilence.class)); + cards.add(new SetCardInfo("Temple of Triumph", 437, Rarity.RARE, mage.cards.t.TempleOfTriumph.class)); + cards.add(new SetCardInfo("Temple of the False God", 436, Rarity.UNCOMMON, mage.cards.t.TempleOfTheFalseGod.class)); + cards.add(new SetCardInfo("Temur Sabertooth", 315, Rarity.UNCOMMON, mage.cards.t.TemurSabertooth.class)); + cards.add(new SetCardInfo("Terminate", 353, Rarity.UNCOMMON, mage.cards.t.Terminate.class)); + cards.add(new SetCardInfo("Tezzeret's Gambit", 235, Rarity.RARE, mage.cards.t.TezzeretsGambit.class)); + cards.add(new SetCardInfo("Thief of Sanity", 354, Rarity.RARE, mage.cards.t.ThiefOfSanity.class)); + cards.add(new SetCardInfo("Thragtusk", 316, Rarity.RARE, mage.cards.t.Thragtusk.class)); + cards.add(new SetCardInfo("Thriving Bluff", 438, Rarity.COMMON, mage.cards.t.ThrivingBluff.class)); + cards.add(new SetCardInfo("Thriving Grove", 439, Rarity.COMMON, mage.cards.t.ThrivingGrove.class)); + cards.add(new SetCardInfo("Thriving Heath", 440, Rarity.COMMON, mage.cards.t.ThrivingHeath.class)); + cards.add(new SetCardInfo("Thriving Isle", 441, Rarity.COMMON, mage.cards.t.ThrivingIsle.class)); + cards.add(new SetCardInfo("Thriving Moor", 442, Rarity.COMMON, mage.cards.t.ThrivingMoor.class)); + cards.add(new SetCardInfo("Thrummingbird", 236, Rarity.UNCOMMON, mage.cards.t.Thrummingbird.class)); + cards.add(new SetCardInfo("Thunderfoot Baloth", 317, Rarity.RARE, mage.cards.t.ThunderfootBaloth.class)); + cards.add(new SetCardInfo("Tivit, Seller of Secrets", 10, Rarity.MYTHIC, mage.cards.t.TivitSellerOfSecrets.class)); + cards.add(new SetCardInfo("Together Forever", 212, Rarity.RARE, mage.cards.t.TogetherForever.class)); + cards.add(new SetCardInfo("Treasure Cruise", 237, Rarity.COMMON, mage.cards.t.TreasureCruise.class)); + cards.add(new SetCardInfo("Treeshaker Chimera", 318, Rarity.RARE, mage.cards.t.TreeshakerChimera.class)); + cards.add(new SetCardInfo("Twilight Mire", 443, Rarity.RARE, mage.cards.t.TwilightMire.class)); + cards.add(new SetCardInfo("Twinning Staff", 383, Rarity.RARE, mage.cards.t.TwinningStaff.class)); + cards.add(new SetCardInfo("Urban Evolution", 355, Rarity.UNCOMMON, mage.cards.u.UrbanEvolution.class)); + cards.add(new SetCardInfo("Utter End", 356, Rarity.RARE, mage.cards.u.UtterEnd.class)); + cards.add(new SetCardInfo("Victimize", 261, Rarity.UNCOMMON, mage.cards.v.Victimize.class)); + cards.add(new SetCardInfo("Vivid Creek", 444, Rarity.UNCOMMON, mage.cards.v.VividCreek.class)); + cards.add(new SetCardInfo("Vivid Grove", 445, Rarity.UNCOMMON, mage.cards.v.VividGrove.class)); + cards.add(new SetCardInfo("Vivid Meadow", 446, Rarity.UNCOMMON, mage.cards.v.VividMeadow.class)); + cards.add(new SetCardInfo("Vivien's Stampede", 65, Rarity.RARE, mage.cards.v.ViviensStampede.class)); + cards.add(new SetCardInfo("Vorel of the Hull Clade", 357, Rarity.RARE, mage.cards.v.VorelOfTheHullClade.class)); + cards.add(new SetCardInfo("Wall of Roots", 319, Rarity.COMMON, mage.cards.w.WallOfRoots.class)); + cards.add(new SetCardInfo("Warstorm Surge", 277, Rarity.RARE, mage.cards.w.WarstormSurge.class)); + cards.add(new SetCardInfo("Waste Management", 40, Rarity.RARE, mage.cards.w.WasteManagement.class)); + cards.add(new SetCardInfo("Wayfarer's Bauble", 384, Rarity.COMMON, mage.cards.w.WayfarersBauble.class)); + cards.add(new SetCardInfo("Whirler Rogue", 238, Rarity.UNCOMMON, mage.cards.w.WhirlerRogue.class)); + cards.add(new SetCardInfo("Wickerbough Elder", 320, Rarity.COMMON, mage.cards.w.WickerboughElder.class)); + cards.add(new SetCardInfo("Windbrisk Heights", 447, Rarity.RARE, mage.cards.w.WindbriskHeights.class)); + cards.add(new SetCardInfo("Windgrace's Judgment", 358, Rarity.RARE, mage.cards.w.WindgracesJudgment.class)); + cards.add(new SetCardInfo("Wingspan Mentor", 239, Rarity.UNCOMMON, mage.cards.w.WingspanMentor.class)); + cards.add(new SetCardInfo("Woe Strider", 262, Rarity.RARE, mage.cards.w.WoeStrider.class)); + cards.add(new SetCardInfo("Wood Elves", 321, Rarity.COMMON, mage.cards.w.WoodElves.class)); + cards.add(new SetCardInfo("Woodfall Primus", 322, Rarity.RARE, mage.cards.w.WoodfallPrimus.class)); + cards.add(new SetCardInfo("World Shaper", 323, Rarity.RARE, mage.cards.w.WorldShaper.class)); + cards.add(new SetCardInfo("Wrexial, the Risen Deep", 359, Rarity.MYTHIC, mage.cards.w.WrexialTheRisenDeep.class)); + cards.add(new SetCardInfo("Writ of Return", 42, Rarity.RARE, mage.cards.w.WritOfReturn.class)); + cards.add(new SetCardInfo("Xander's Pact", 43, Rarity.RARE, mage.cards.x.XandersPact.class)); + cards.add(new SetCardInfo("Zndrsplt's Judgment", 240, Rarity.RARE, mage.cards.z.ZndrspltsJudgment.class)); + cards.add(new SetCardInfo("Zurzoth, Chaos Rider", 278, Rarity.RARE, mage.cards.z.ZurzothChaosRider.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/Onslaught.java b/Mage.Sets/src/mage/sets/Onslaught.java index 381eeb145fc..01391ae58c3 100644 --- a/Mage.Sets/src/mage/sets/Onslaught.java +++ b/Mage.Sets/src/mage/sets/Onslaught.java @@ -169,6 +169,7 @@ public final class Onslaught extends ExpansionSet { cards.add(new SetCardInfo("Gratuitous Violence", 212, Rarity.RARE, mage.cards.g.GratuitousViolence.class)); cards.add(new SetCardInfo("Gravel Slinger", 33, Rarity.COMMON, mage.cards.g.GravelSlinger.class)); cards.add(new SetCardInfo("Gravespawn Sovereign", 152, Rarity.RARE, mage.cards.g.GravespawnSovereign.class)); + cards.add(new SetCardInfo("Graxiplon", 86, Rarity.UNCOMMON, mage.cards.g.Graxiplon.class)); cards.add(new SetCardInfo("Grinning Demon", 153, Rarity.RARE, mage.cards.g.GrinningDemon.class)); cards.add(new SetCardInfo("Gustcloak Harrier", 34, Rarity.COMMON, mage.cards.g.GustcloakHarrier.class)); cards.add(new SetCardInfo("Gustcloak Runner", 35, Rarity.COMMON, mage.cards.g.GustcloakRunner.class)); diff --git a/Mage.Sets/src/mage/sets/Planechase2012Edition.java b/Mage.Sets/src/mage/sets/Planechase2012Edition.java index 3b456a8d7f7..98b81c6bef7 100644 --- a/Mage.Sets/src/mage/sets/Planechase2012Edition.java +++ b/Mage.Sets/src/mage/sets/Planechase2012Edition.java @@ -69,6 +69,7 @@ public final class Planechase2012Edition extends ExpansionSet { cards.add(new SetCardInfo("Forest", 154, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 155, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 156, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fractured Powerstone", 111, Rarity.COMMON, mage.cards.f.FracturedPowerstone.class)); cards.add(new SetCardInfo("Fusion Elemental", 93, Rarity.UNCOMMON, mage.cards.f.FusionElemental.class)); cards.add(new SetCardInfo("Ghostly Prison", 7, Rarity.UNCOMMON, mage.cards.g.GhostlyPrison.class)); cards.add(new SetCardInfo("Glen Elendra Liege", 94, Rarity.RARE, mage.cards.g.GlenElendraLiege.class)); diff --git a/Mage.Sets/src/mage/sets/SecretLairDrop.java b/Mage.Sets/src/mage/sets/SecretLairDrop.java index 7563a3c49d1..e37cbc60c42 100644 --- a/Mage.Sets/src/mage/sets/SecretLairDrop.java +++ b/Mage.Sets/src/mage/sets/SecretLairDrop.java @@ -20,6 +20,11 @@ public class SecretLairDrop extends ExpansionSet { this.hasBoosters = false; this.hasBasicLands = true; + cards.add(new SetCardInfo("Demonlord Belzenlok", "159*", Rarity.MYTHIC, mage.cards.d.DemonlordBelzenlok.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Griselbrand", "160*", Rarity.MYTHIC, mage.cards.g.Griselbrand.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kothophed, Soul Hoarder", "162*", Rarity.RARE, mage.cards.k.KothophedSoulHoarder.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Liliana's Contract", "161*", Rarity.RARE, mage.cards.l.LilianasContract.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Razaketh, the Foulblooded", "163*", Rarity.MYTHIC, mage.cards.r.RazakethTheFoulblooded.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Snow-Covered Plains", 1, Rarity.LAND, mage.cards.s.SnowCoveredPlains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Snow-Covered Island", 2, Rarity.LAND, mage.cards.s.SnowCoveredIsland.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Snow-Covered Swamp", 3, Rarity.LAND, mage.cards.s.SnowCoveredSwamp.class, NON_FULL_USE_VARIOUS)); @@ -125,7 +130,7 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Glen Elendra Archmage", 115, Rarity.RARE, mage.cards.g.GlenElendraArchmage.class)); cards.add(new SetCardInfo("Mistbind Clique", 116, Rarity.RARE, mage.cards.m.MistbindClique.class)); cards.add(new SetCardInfo("Spellstutter Sprite", 117, Rarity.RARE, mage.cards.s.SpellstutterSprite.class)); - cards.add(new SetCardInfo("Vendilion Clique", 118, Rarity.RARE, mage.cards.v.VendilionClique.class)); + cards.add(new SetCardInfo("Vendilion Clique", 118, Rarity.MYTHIC, mage.cards.v.VendilionClique.class)); cards.add(new SetCardInfo("Swamp", 119, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Sower of Temptation", 120, Rarity.RARE, mage.cards.s.SowerOfTemptation.class)); cards.add(new SetCardInfo("Damnation", 121, Rarity.RARE, mage.cards.d.Damnation.class)); @@ -149,7 +154,7 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Assassin's Trophy", 139, Rarity.RARE, mage.cards.a.AssassinsTrophy.class)); cards.add(new SetCardInfo("Decimate", 140, Rarity.RARE, mage.cards.d.Decimate.class)); cards.add(new SetCardInfo("Dreadbore", 141, Rarity.RARE, mage.cards.d.Dreadbore.class)); - cards.add(new SetCardInfo("Thraximundar", 142, Rarity.RARE, mage.cards.t.Thraximundar.class)); + cards.add(new SetCardInfo("Thraximundar", 142, Rarity.MYTHIC, mage.cards.t.Thraximundar.class)); cards.add(new SetCardInfo("Rick, Steadfast Leader", 143, Rarity.MYTHIC, mage.cards.r.RickSteadfastLeader.class)); cards.add(new SetCardInfo("Daryl, Hunter of Walkers", 144, Rarity.MYTHIC, mage.cards.d.DarylHunterOfWalkers.class)); cards.add(new SetCardInfo("Glenn, the Voice of Calm", 145, Rarity.MYTHIC, mage.cards.g.GlennTheVoiceOfCalm.class)); @@ -160,11 +165,11 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Zulaport Cutthroat", 156, Rarity.RARE, mage.cards.z.ZulaportCutthroat.class)); cards.add(new SetCardInfo("Warren Instigator", 157, Rarity.MYTHIC, mage.cards.w.WarrenInstigator.class)); cards.add(new SetCardInfo("Avenger of Zendikar", 158, Rarity.MYTHIC, mage.cards.a.AvengerOfZendikar.class)); - cards.add(new SetCardInfo("Demonlord Belzenlok", 159, Rarity.MYTHIC, mage.cards.d.DemonlordBelzenlok.class)); - cards.add(new SetCardInfo("Griselbrand", 160, Rarity.MYTHIC, mage.cards.g.Griselbrand.class)); - cards.add(new SetCardInfo("Liliana's Contract", 161, Rarity.RARE, mage.cards.l.LilianasContract.class)); - cards.add(new SetCardInfo("Kothophed, Soul Hoarder", 162, Rarity.RARE, mage.cards.k.KothophedSoulHoarder.class)); - cards.add(new SetCardInfo("Razaketh, the Foulblooded", 163, Rarity.MYTHIC, mage.cards.r.RazakethTheFoulblooded.class)); + cards.add(new SetCardInfo("Demonlord Belzenlok", 159, Rarity.MYTHIC, mage.cards.d.DemonlordBelzenlok.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Griselbrand", 160, Rarity.MYTHIC, mage.cards.g.Griselbrand.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Liliana's Contract", 161, Rarity.RARE, mage.cards.l.LilianasContract.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kothophed, Soul Hoarder", 162, Rarity.RARE, mage.cards.k.KothophedSoulHoarder.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Razaketh, the Foulblooded", 163, Rarity.MYTHIC, mage.cards.r.RazakethTheFoulblooded.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Teferi's Protection", 164, Rarity.RARE, mage.cards.t.TeferisProtection.class)); cards.add(new SetCardInfo("Consecrated Sphinx", 165, Rarity.RARE, mage.cards.c.ConsecratedSphinx.class)); cards.add(new SetCardInfo("Collected Company", 166, Rarity.RARE, mage.cards.c.CollectedCompany.class)); @@ -218,7 +223,7 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Well of Lost Dreams", 227, Rarity.RARE, mage.cards.w.WellOfLostDreams.class)); cards.add(new SetCardInfo("Frantic Search", 228, Rarity.RARE, mage.cards.f.FranticSearch.class)); cards.add(new SetCardInfo("Intruder Alarm", 229, Rarity.RARE, mage.cards.i.IntruderAlarm.class)); - cards.add(new SetCardInfo("Shelldock Isle", 230, Rarity.RARE, mage.cards.s.ShelldockIsle.class)); + cards.add(new SetCardInfo("Shelldock Isle", 230, Rarity.RARE, mage.cards.s.ShelldockIsle.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Gravecrawler", 231, Rarity.RARE, mage.cards.g.Gravecrawler.class)); cards.add(new SetCardInfo("Liliana, Death's Majesty", 232, Rarity.MYTHIC, mage.cards.l.LilianaDeathsMajesty.class)); cards.add(new SetCardInfo("Rise of the Dark Realms", 233, Rarity.MYTHIC, mage.cards.r.RiseOfTheDarkRealms.class)); @@ -261,10 +266,10 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Ob Nixilis Reignited", 274, Rarity.MYTHIC, mage.cards.o.ObNixilisReignited.class)); cards.add(new SetCardInfo("Sire of Insanity", 275, Rarity.RARE, mage.cards.s.SireOfInsanity.class)); cards.add(new SetCardInfo("Sliver Hivelord", 276, Rarity.MYTHIC, mage.cards.s.SliverHivelord.class)); - cards.add(new SetCardInfo("Spellskite", 277, Rarity.RARE, mage.cards.s.Spellskite.class)); + cards.add(new SetCardInfo("Spellskite", 277, Rarity.RARE, mage.cards.s.Spellskite.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sanctum Prelate", 278, Rarity.MYTHIC, mage.cards.s.SanctumPrelate.class)); cards.add(new SetCardInfo("Carpet of Flowers", 279, Rarity.RARE, mage.cards.c.CarpetOfFlowers.class)); - cards.add(new SetCardInfo("Sphere of Safety", 280, Rarity.RARE, mage.cards.s.SphereOfSafety.class)); + cards.add(new SetCardInfo("Sphere of Safety", 280, Rarity.RARE, mage.cards.s.SphereOfSafety.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Karmic Guide", 281, Rarity.RARE, mage.cards.k.KarmicGuide.class)); cards.add(new SetCardInfo("Mesa Enchantress", 282, Rarity.RARE, mage.cards.m.MesaEnchantress.class)); cards.add(new SetCardInfo("Archaeomancer", 283, Rarity.RARE, mage.cards.a.Archaeomancer.class)); @@ -319,14 +324,14 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Fabricate", 332, Rarity.RARE, mage.cards.f.Fabricate.class)); cards.add(new SetCardInfo("Fact or Fiction", 333, Rarity.RARE, mage.cards.f.FactOrFiction.class)); cards.add(new SetCardInfo("Mystical Tutor", 334, Rarity.RARE, mage.cards.m.MysticalTutor.class)); - cards.add(new SetCardInfo("Mind Flayer, the Shadow", 340, Rarity.MYTHIC, mage.cards.m.MindFlayerTheShadow.class)); - cards.add(new SetCardInfo("Chief Jim Hopper", 341, Rarity.RARE, mage.cards.c.ChiefJimHopper.class)); - cards.add(new SetCardInfo("Dustin, Gadget Genius", 342, Rarity.RARE, mage.cards.d.DustinGadgetGenius.class)); - cards.add(new SetCardInfo("Eleven, the Mage", 343, Rarity.RARE, mage.cards.e.ElevenTheMage.class)); - cards.add(new SetCardInfo("Lucas, the Sharpshooter", 344, Rarity.RARE, mage.cards.l.LucasTheSharpshooter.class)); - cards.add(new SetCardInfo("Max, the Daredevil", 345, Rarity.RARE, mage.cards.m.MaxTheDaredevil.class)); - cards.add(new SetCardInfo("Mike, the Dungeon Master", 346, Rarity.RARE, mage.cards.m.MikeTheDungeonMaster.class)); - cards.add(new SetCardInfo("Will the Wise", 347, Rarity.RARE, mage.cards.w.WillTheWise.class)); + cards.add(new SetCardInfo("Arvinox, the Mind Flail", 340, Rarity.MYTHIC, mage.cards.a.ArvinoxTheMindFlail.class)); + cards.add(new SetCardInfo("Sophina, Spearsage Deserter", 341, Rarity.RARE, mage.cards.s.SophinaSpearsageDeserter.class)); + cards.add(new SetCardInfo("Hargilde, Kindly Runechanter", 342, Rarity.RARE, mage.cards.h.HargildeKindlyRunechanter.class)); + cards.add(new SetCardInfo("Cecily, Haunted Mage", 343, Rarity.RARE, mage.cards.c.CecilyHauntedMage.class)); + cards.add(new SetCardInfo("Bjorna, Nightfall Alchemist", 344, Rarity.RARE, mage.cards.b.BjornaNightfallAlchemist.class)); + cards.add(new SetCardInfo("Elmar, Ulvenwald Informant", 345, Rarity.RARE, mage.cards.e.ElmarUlvenwaldInformant.class)); + cards.add(new SetCardInfo("Othelm, Sigardian Outcast", 346, Rarity.RARE, mage.cards.o.OthelmSigardianOutcast.class)); + cards.add(new SetCardInfo("Wernog, Rider's Chaplain", 347, Rarity.RARE, mage.cards.w.WernogRidersChaplain.class)); cards.add(new SetCardInfo("Moorland Haunt", 349, Rarity.RARE, mage.cards.m.MoorlandHaunt.class)); cards.add(new SetCardInfo("Vault of the Archangel", 350, Rarity.RARE, mage.cards.v.VaultOfTheArchangel.class)); cards.add(new SetCardInfo("Nephalia Drownyard", 351, Rarity.RARE, mage.cards.n.NephaliaDrownyard.class)); @@ -367,8 +372,71 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Stitch in Time", "382b", Rarity.RARE, mage.cards.s.StitchInTime.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Krark's Thumb", 383, Rarity.RARE, mage.cards.k.KrarksThumb.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Krark's Thumb", "383b", Rarity.RARE, mage.cards.k.KrarksThumb.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 384, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Island", 385, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Island", 386, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 387, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Tamiyo, the Moon Sage", 396, Rarity.MYTHIC, mage.cards.t.TamiyoTheMoonSage.class)); + cards.add(new SetCardInfo("Ajani, Mentor of Heroes", 397, Rarity.MYTHIC, mage.cards.a.AjaniMentorOfHeroes.class)); + cards.add(new SetCardInfo("Angrath, the Flame-Chained", 398, Rarity.MYTHIC, mage.cards.a.AngrathTheFlameChained.class)); + cards.add(new SetCardInfo("Ashiok, Dream Render", 399, Rarity.RARE, mage.cards.a.AshiokDreamRender.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sorin, Grim Nemesis", 400, Rarity.MYTHIC, mage.cards.s.SorinGrimNemesis.class)); + cards.add(new SetCardInfo("Brain Freeze", 410, Rarity.RARE, mage.cards.b.BrainFreeze.class)); + cards.add(new SetCardInfo("Bribery", 411, Rarity.RARE, mage.cards.b.Bribery.class)); + cards.add(new SetCardInfo("Snap", 412, Rarity.RARE, mage.cards.s.Snap.class)); + cards.add(new SetCardInfo("Unmask", 413, Rarity.RARE, mage.cards.u.Unmask.class)); + cards.add(new SetCardInfo("Shadow of Doubt", 414, Rarity.RARE, mage.cards.s.ShadowOfDoubt.class)); + cards.add(new SetCardInfo("Plains", 415, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Island", 416, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 417, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 418, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Forest", 419, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Hokori, Dust Drinker", 420, Rarity.RARE, mage.cards.h.HokoriDustDrinker.class)); + cards.add(new SetCardInfo("Kira, Great Glass-Spinner", 421, Rarity.RARE, mage.cards.k.KiraGreatGlassSpinner.class)); + cards.add(new SetCardInfo("Eidolon of the Great Revel", 422, Rarity.RARE, mage.cards.e.EidolonOfTheGreatRevel.class)); + cards.add(new SetCardInfo("Elvish Spirit Guide", 423, Rarity.RARE, mage.cards.e.ElvishSpiritGuide.class)); + cards.add(new SetCardInfo("Ghostly Prison", 424, Rarity.RARE, mage.cards.g.GhostlyPrison.class)); + cards.add(new SetCardInfo("Freed from the Real", 425, Rarity.RARE, mage.cards.f.FreedFromTheReal.class)); + cards.add(new SetCardInfo("Boseiju, Who Shelters All", 426, Rarity.RARE, mage.cards.b.BoseijuWhoSheltersAll.class)); + cards.add(new SetCardInfo("Hall of the Bandit Lord", 427, Rarity.RARE, mage.cards.h.HallOfTheBanditLord.class)); + cards.add(new SetCardInfo("E. Honda, Sumo Champion", 428, Rarity.RARE, mage.cards.e.EHondaSumoChampion.class)); + cards.add(new SetCardInfo("Ryu, World Warrior", 429, Rarity.RARE, mage.cards.r.RyuWorldWarrior.class)); + cards.add(new SetCardInfo("Ken, Burning Brawler", 430, Rarity.RARE, mage.cards.k.KenBurningBrawler.class)); + cards.add(new SetCardInfo("Blanka, Ferocious Friend", 431, Rarity.RARE, mage.cards.b.BlankaFerociousFriend.class)); + cards.add(new SetCardInfo("Chun-Li, Countless Kicks", 432, Rarity.RARE, mage.cards.c.ChunLiCountlessKicks.class)); + cards.add(new SetCardInfo("Dhalsim, Pliable Pacifist", 433, Rarity.RARE, mage.cards.d.DhalsimPliablePacifist.class)); + cards.add(new SetCardInfo("Guile, Sonic Soldier", 434, Rarity.RARE, mage.cards.g.GuileSonicSoldier.class)); + cards.add(new SetCardInfo("Zangief, the Red Cyclone", 435, Rarity.RARE, mage.cards.z.ZangiefTheRedCyclone.class)); + cards.add(new SetCardInfo("Windbrisk Heights", 436, Rarity.RARE, mage.cards.w.WindbriskHeights.class)); + cards.add(new SetCardInfo("Shelldock Isle", 437, Rarity.RARE, mage.cards.s.ShelldockIsle.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Howltooth Hollow", 438, Rarity.RARE, mage.cards.h.HowltoothHollow.class)); + cards.add(new SetCardInfo("Spinerock Knoll", 439, Rarity.RARE, mage.cards.s.SpinerockKnoll.class)); + cards.add(new SetCardInfo("Mosswort Bridge", 440, Rarity.RARE, mage.cards.m.MosswortBridge.class)); + cards.add(new SetCardInfo("Atraxa, Praetors' Voice", 453, Rarity.MYTHIC, mage.cards.a.AtraxaPraetorsVoice.class)); + cards.add(new SetCardInfo("Breya, Etherium Shaper", 454, Rarity.MYTHIC, mage.cards.b.BreyaEtheriumShaper.class)); + cards.add(new SetCardInfo("Yidris, Maelstrom Wielder", 455, Rarity.MYTHIC, mage.cards.y.YidrisMaelstromWielder.class)); + cards.add(new SetCardInfo("Glacial Fortress", 456, Rarity.RARE, mage.cards.g.GlacialFortress.class)); + cards.add(new SetCardInfo("Drowned Catacomb", 457, Rarity.RARE, mage.cards.d.DrownedCatacomb.class)); + cards.add(new SetCardInfo("Dragonskull Summit", 458, Rarity.RARE, mage.cards.d.DragonskullSummit.class)); + cards.add(new SetCardInfo("Rootbound Crag", 459, Rarity.RARE, mage.cards.r.RootboundCrag.class)); + cards.add(new SetCardInfo("Sunpetal Grove", 460, Rarity.RARE, mage.cards.s.SunpetalGrove.class)); + cards.add(new SetCardInfo("Sram, Senior Edificer", 461, Rarity.RARE, mage.cards.s.SramSeniorEdificer.class)); + cards.add(new SetCardInfo("Balthor the Defiled", 462, Rarity.RARE, mage.cards.b.BalthorTheDefiled.class)); + cards.add(new SetCardInfo("Torbran, Thane of Red Fell", 463, Rarity.RARE, mage.cards.t.TorbranThaneOfRedFell.class)); + cards.add(new SetCardInfo("Depala, Pilot Exemplar", 464, Rarity.RARE, mage.cards.d.DepalaPilotExemplar.class)); + cards.add(new SetCardInfo("Nomad Outpost", 465, Rarity.RARE, mage.cards.n.NomadOutpost.class)); + cards.add(new SetCardInfo("Island", 466, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Concordant Crossroads", 467, Rarity.RARE, mage.cards.c.ConcordantCrossroads.class)); + cards.add(new SetCardInfo("Ghost Quarter", 468, Rarity.RARE, mage.cards.g.GhostQuarter.class)); + cards.add(new SetCardInfo("Mother of Runes", 473, Rarity.RARE, mage.cards.m.MotherOfRunes.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Death's Shadow", 474, Rarity.RARE, mage.cards.d.DeathsShadow.class)); + cards.add(new SetCardInfo("Elvish Mystic", 475, Rarity.RARE, mage.cards.e.ElvishMystic.class)); + cards.add(new SetCardInfo("Forest", 476, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Path to Exile", 477, Rarity.RARE, mage.cards.p.PathToExile.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Rhystic Study", 478, Rarity.RARE, mage.cards.r.RhysticStudy.class)); + cards.add(new SetCardInfo("Duress", 479, Rarity.RARE, mage.cards.d.Duress.class)); + cards.add(new SetCardInfo("Seize the Day", 480, Rarity.RARE, mage.cards.s.SeizeTheDay.class)); + cards.add(new SetCardInfo("Krosan Grip", 481, Rarity.RARE, mage.cards.k.KrosanGrip.class)); cards.add(new SetCardInfo("Counterflux", 482, Rarity.RARE, mage.cards.c.Counterflux.class)); cards.add(new SetCardInfo("Thran Dynamo", 483, Rarity.RARE, mage.cards.t.ThranDynamo.class)); cards.add(new SetCardInfo("Plains", 484, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); @@ -403,7 +471,7 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Tamiyo, Collector of Tales", 525, Rarity.RARE, mage.cards.t.TamiyoCollectorOfTales.class)); cards.add(new SetCardInfo("Teferi, Time Raveler", 526, Rarity.RARE, mage.cards.t.TeferiTimeRaveler.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Angrath, Captain of Chaos", 527, Rarity.UNCOMMON, mage.cards.a.AngrathCaptainOfChaos.class)); - cards.add(new SetCardInfo("Ashiok, Dream Render", 528, Rarity.UNCOMMON, mage.cards.a.AshiokDreamRender.class)); + cards.add(new SetCardInfo("Ashiok, Dream Render", 528, Rarity.UNCOMMON, mage.cards.a.AshiokDreamRender.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dovin, Hand of Control", 529, Rarity.UNCOMMON, mage.cards.d.DovinHandOfControl.class)); cards.add(new SetCardInfo("Huatli, the Sun's Heart", 530, Rarity.UNCOMMON, mage.cards.h.HuatliTheSunsHeart.class)); cards.add(new SetCardInfo("Kaya, Bane of the Dead", 531, Rarity.UNCOMMON, mage.cards.k.KayaBaneOfTheDead.class)); @@ -415,32 +483,86 @@ public class SecretLairDrop extends ExpansionSet { cards.add(new SetCardInfo("Tibalt, the Fiend-Blooded", 537, Rarity.MYTHIC, mage.cards.t.TibaltTheFiendBlooded.class)); cards.add(new SetCardInfo("Evolving Wilds", 538, Rarity.RARE, mage.cards.e.EvolvingWilds.class)); cards.add(new SetCardInfo("Swamp", 539, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Plains", 540, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 541, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 542, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 543, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 544, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 545, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 546, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 547, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 548, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 549, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 550, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 551, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 552, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 553, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 554, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 555, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 556, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 557, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 558, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 559, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 560, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 561, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 562, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 563, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 564, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 565, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 566, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 567, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 568, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 569, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 570, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 571, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 572, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 573, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 574, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 575, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 576, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 577, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 578, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 579, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lucille", 581, Rarity.MYTHIC, mage.cards.l.Lucille.class)); cards.add(new SetCardInfo("Brainstorm", 582, Rarity.RARE, mage.cards.b.Brainstorm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fblthp, the Lost", 583, Rarity.RARE, mage.cards.f.FblthpTheLost.class)); + cards.add(new SetCardInfo("Wrexial, the Risen Deep", 584, Rarity.MYTHIC, mage.cards.w.WrexialTheRisenDeep.class)); cards.add(new SetCardInfo("Terramorphic Expanse", 585, Rarity.RARE, mage.cards.t.TerramorphicExpanse.class)); + cards.add(new SetCardInfo("Spellskite", 587, Rarity.RARE, mage.cards.s.Spellskite.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sphere of Safety", 588, Rarity.RARE, mage.cards.s.SphereOfSafety.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Arcane Signet", 589, Rarity.RARE, mage.cards.a.ArcaneSignet.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Crash Through", 591, Rarity.RARE, mage.cards.c.CrashThrough.class)); + cards.add(new SetCardInfo("Persistent Petitioners", 596, Rarity.RARE, mage.cards.p.PersistentPetitioners.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Persistent Petitioners", 597, Rarity.RARE, mage.cards.p.PersistentPetitioners.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Persistent Petitioners", 598, Rarity.RARE, mage.cards.p.PersistentPetitioners.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Eldrazi Monument", 603, Rarity.MYTHIC, mage.cards.e.EldraziMonument.class)); cards.add(new SetCardInfo("Ornithopter", 604, Rarity.RARE, mage.cards.o.Ornithopter.class)); cards.add(new SetCardInfo("Panharmonicon", 605, Rarity.RARE, mage.cards.p.Panharmonicon.class)); cards.add(new SetCardInfo("Swiftfoot Boots", 606, Rarity.RARE, mage.cards.s.SwiftfootBoots.class)); cards.add(new SetCardInfo("Rogue's Passage", 607, Rarity.RARE, mage.cards.r.RoguesPassage.class)); - cards.add(new SetCardInfo("Hawkins National Laboratory", 609, Rarity.RARE, mage.cards.h.HawkinsNationalLaboratory.class)); - cards.add(new SetCardInfo("The Upside Down", 609, Rarity.RARE, mage.cards.t.TheUpsideDown.class)); + cards.add(new SetCardInfo("Darksteel Citadel", 608, Rarity.RARE, mage.cards.d.DarksteelCitadel.class)); + cards.add(new SetCardInfo("Havengul Laboratory", 609, Rarity.RARE, mage.cards.h.HavengulLaboratory.class)); + cards.add(new SetCardInfo("Havengul Mystery", 609, Rarity.RARE, mage.cards.h.HavengulMystery.class)); + cards.add(new SetCardInfo("Battlefield Forge", 669, Rarity.RARE, mage.cards.b.BattlefieldForge.class)); + cards.add(new SetCardInfo("Plains", 670, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Questing Phelddagrif", 671, Rarity.RARE, mage.cards.q.QuestingPhelddagrif.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Questing Phelddagrif", 672, Rarity.RARE, mage.cards.q.QuestingPhelddagrif.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lightning Bolt", 675, Rarity.RARE, mage.cards.l.LightningBolt.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spore Frog", 696, Rarity.RARE, mage.cards.s.SporeFrog.class)); + cards.add(new SetCardInfo("Command Tower", 697, Rarity.RARE, mage.cards.c.CommandTower.class)); + cards.add(new SetCardInfo("Idyllic Tutor", 1020, Rarity.RARE, mage.cards.i.IdyllicTutor.class)); + cards.add(new SetCardInfo("Swords to Plowshares", 1021, Rarity.RARE, mage.cards.s.SwordsToPlowshares.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Solve the Equation", 1022, Rarity.RARE, mage.cards.s.SolveTheEquation.class)); + cards.add(new SetCardInfo("Praetor's Grasp", 1023, Rarity.RARE, mage.cards.p.PraetorsGrasp.class)); + cards.add(new SetCardInfo("Veil of Summer", 1024, Rarity.RARE, mage.cards.v.VeilOfSummer.class)); + cards.add(new SetCardInfo("Void Winnower", 1075, Rarity.MYTHIC, mage.cards.v.VoidWinnower.class)); + cards.add(new SetCardInfo("Goblin Settler", 1076, Rarity.RARE, mage.cards.g.GoblinSettler.class)); + cards.add(new SetCardInfo("Collector Ouphe", 1077, Rarity.RARE, mage.cards.c.CollectorOuphe.class)); + cards.add(new SetCardInfo("Vengevine", 1078, Rarity.MYTHIC, mage.cards.v.Vengevine.class)); + cards.add(new SetCardInfo("Garruk, Caller of Beasts", 9995, Rarity.MYTHIC, mage.cards.g.GarrukCallerOfBeasts.class)); + cards.add(new SetCardInfo("Rograkh, Son of Rohgahh", 9996, Rarity.RARE, mage.cards.r.RograkhSonOfRohgahh.class)); + cards.add(new SetCardInfo("Geralf's Messenger", 9997, Rarity.RARE, mage.cards.g.GeralfsMessenger.class)); + cards.add(new SetCardInfo("Empress Galina", 9998, Rarity.RARE, mage.cards.e.EmpressGalina.class)); + cards.add(new SetCardInfo("Sisay, Weatherlight Captain", 9999, Rarity.RARE, mage.cards.s.SisayWeatherlightCaptain.class)); } } diff --git a/Mage.Sets/src/mage/sets/StarWars.java b/Mage.Sets/src/mage/sets/StarWars.java index 2c540af1387..1df06d8e5f2 100644 --- a/Mage.Sets/src/mage/sets/StarWars.java +++ b/Mage.Sets/src/mage/sets/StarWars.java @@ -271,7 +271,7 @@ public final class StarWars extends ExpansionSet { cards.add(new SetCardInfo("Repurpose", 85, Rarity.COMMON, mage.cards.r.Repurpose.class)); cards.add(new SetCardInfo("Resistance", 310, Rarity.UNCOMMON, mage.cards.r.Resistance.class)); cards.add(new SetCardInfo("Resistance Bomber", 515, Rarity.UNCOMMON, mage.cards.r.ResistanceBomber.class)); - cards.add(new SetCardInfo("Revenge", 117, Rarity.COMMON, mage.cards.r.RevengeStarWars.class)); + cards.add(new SetCardInfo("Revenge (Star Wars)", 117, Rarity.COMMON, mage.cards.r.RevengeStarWars.class)); cards.add(new SetCardInfo("Rey", 410, Rarity.RARE, mage.cards.r.Rey.class)); cards.add(new SetCardInfo("Riding Ronto", 28, Rarity.UNCOMMON, mage.cards.r.RidingRonto.class)); cards.add(new SetCardInfo("Riot Trooper", 411, Rarity.COMMON, mage.cards.r.RiotTrooper.class)); diff --git a/Mage.Sets/src/mage/sets/StreetsOfNewCapenna.java b/Mage.Sets/src/mage/sets/StreetsOfNewCapenna.java new file mode 100644 index 00000000000..c7ba1260180 --- /dev/null +++ b/Mage.Sets/src/mage/sets/StreetsOfNewCapenna.java @@ -0,0 +1,498 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class StreetsOfNewCapenna extends ExpansionSet { + + private static final StreetsOfNewCapenna instance = new StreetsOfNewCapenna(); + + public static StreetsOfNewCapenna getInstance() { + return instance; + } + + private StreetsOfNewCapenna() { + super("Streets of New Capenna", "SNC", ExpansionSet.buildDate(2022, 4, 29), SetType.EXPANSION); + this.blockName = "Streets of New Capenna"; + this.hasBoosters = true; + this.hasBasicLands = true; + this.numBoosterLands = 1; + this.numBoosterCommon = 10; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 7; + this.maxCardNumberInBooster = 281; + + cards.add(new SetCardInfo("A Little Chat", 47, Rarity.UNCOMMON, mage.cards.a.ALittleChat.class)); + cards.add(new SetCardInfo("All-Seeing Arbiter", 286, Rarity.MYTHIC, mage.cards.a.AllSeeingArbiter.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("All-Seeing Arbiter", 34, Rarity.MYTHIC, mage.cards.a.AllSeeingArbiter.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("An Offer You Can't Refuse", 464, Rarity.UNCOMMON, mage.cards.a.AnOfferYouCantRefuse.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("An Offer You Can't Refuse", 51, Rarity.UNCOMMON, mage.cards.a.AnOfferYouCantRefuse.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Angel of Suffering", 416, Rarity.MYTHIC, mage.cards.a.AngelOfSuffering.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Angel of Suffering", 67, Rarity.MYTHIC, mage.cards.a.AngelOfSuffering.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Angelic Observer", 1, Rarity.UNCOMMON, mage.cards.a.AngelicObserver.class)); + cards.add(new SetCardInfo("Antagonize", 100, Rarity.COMMON, mage.cards.a.Antagonize.class)); + cards.add(new SetCardInfo("Arc Spitter", 233, Rarity.UNCOMMON, mage.cards.a.ArcSpitter.class)); + cards.add(new SetCardInfo("Arcane Bombardment", 101, Rarity.MYTHIC, mage.cards.a.ArcaneBombardment.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Arcane Bombardment", 422, Rarity.MYTHIC, mage.cards.a.ArcaneBombardment.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Attended Socialite", 133, Rarity.COMMON, mage.cards.a.AttendedSocialite.class)); + cards.add(new SetCardInfo("Aven Heartstabber", 166, Rarity.RARE, mage.cards.a.AvenHeartstabber.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Aven Heartstabber", 433, Rarity.RARE, mage.cards.a.AvenHeartstabber.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Backstreet Bruiser", 35, Rarity.COMMON, mage.cards.b.BackstreetBruiser.class)); + cards.add(new SetCardInfo("Backup Agent", 2, Rarity.COMMON, mage.cards.b.BackupAgent.class)); + cards.add(new SetCardInfo("Ballroom Brawlers", 3, Rarity.UNCOMMON, mage.cards.b.BallroomBrawlers.class)); + cards.add(new SetCardInfo("Big Score", 102, Rarity.COMMON, mage.cards.b.BigScore.class)); + cards.add(new SetCardInfo("Black Market Tycoon", 167, Rarity.RARE, mage.cards.b.BlackMarketTycoon.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Black Market Tycoon", 434, Rarity.RARE, mage.cards.b.BlackMarketTycoon.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Body Dropper", 168, Rarity.COMMON, mage.cards.b.BodyDropper.class)); + cards.add(new SetCardInfo("Body Launderer", 417, Rarity.MYTHIC, mage.cards.b.BodyLaunderer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Body Launderer", 68, Rarity.MYTHIC, mage.cards.b.BodyLaunderer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Boon of Safety", 4, Rarity.COMMON, mage.cards.b.BoonOfSafety.class)); + cards.add(new SetCardInfo("Bootleggers' Stash", 134, Rarity.MYTHIC, mage.cards.b.BootleggersStash.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Bootleggers' Stash", 288, Rarity.MYTHIC, mage.cards.b.BootleggersStash.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Botanical Plaza", 247, Rarity.COMMON, mage.cards.b.BotanicalPlaza.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Botanical Plaza", 350, Rarity.COMMON, mage.cards.b.BotanicalPlaza.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Bouncer's Beatdown", 135, Rarity.UNCOMMON, mage.cards.b.BouncersBeatdown.class)); + cards.add(new SetCardInfo("Brass Knuckles", 234, Rarity.UNCOMMON, mage.cards.b.BrassKnuckles.class)); + cards.add(new SetCardInfo("Brazen Upstart", 169, Rarity.UNCOMMON, mage.cards.b.BrazenUpstart.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Brazen Upstart", 296, Rarity.UNCOMMON, mage.cards.b.BrazenUpstart.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Brazen Upstart", 361, Rarity.UNCOMMON, mage.cards.b.BrazenUpstart.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Broken Wings", 136, Rarity.COMMON, mage.cards.b.BrokenWings.class)); + cards.add(new SetCardInfo("Brokers Ascendancy", 170, Rarity.RARE, mage.cards.b.BrokersAscendancy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Brokers Ascendancy", 297, Rarity.RARE, mage.cards.b.BrokersAscendancy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Brokers Ascendancy", 362, Rarity.RARE, mage.cards.b.BrokersAscendancy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Brokers Charm", 171, Rarity.UNCOMMON, mage.cards.b.BrokersCharm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Brokers Charm", 298, Rarity.UNCOMMON, mage.cards.b.BrokersCharm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Brokers Charm", 363, Rarity.UNCOMMON, mage.cards.b.BrokersCharm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Brokers Hideout", 248, Rarity.COMMON, mage.cards.b.BrokersHideout.class)); + cards.add(new SetCardInfo("Brokers Initiate", 5, Rarity.COMMON, mage.cards.b.BrokersInitiate.class)); + cards.add(new SetCardInfo("Brokers Veteran", 36, Rarity.COMMON, mage.cards.b.BrokersVeteran.class)); + cards.add(new SetCardInfo("Buy Your Silence", 6, Rarity.COMMON, mage.cards.b.BuyYourSilence.class)); + cards.add(new SetCardInfo("Cabaretti Ascendancy", 172, Rarity.RARE, mage.cards.c.CabarettiAscendancy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cabaretti Ascendancy", 299, Rarity.RARE, mage.cards.c.CabarettiAscendancy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cabaretti Ascendancy", 364, Rarity.RARE, mage.cards.c.CabarettiAscendancy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cabaretti Charm", 173, Rarity.UNCOMMON, mage.cards.c.CabarettiCharm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cabaretti Charm", 300, Rarity.UNCOMMON, mage.cards.c.CabarettiCharm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cabaretti Charm", 365, Rarity.UNCOMMON, mage.cards.c.CabarettiCharm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cabaretti Courtyard", 249, Rarity.COMMON, mage.cards.c.CabarettiCourtyard.class)); + cards.add(new SetCardInfo("Cabaretti Initiate", 137, Rarity.COMMON, mage.cards.c.CabarettiInitiate.class)); + cards.add(new SetCardInfo("Caldaia Strongarm", 138, Rarity.COMMON, mage.cards.c.CaldaiaStrongarm.class)); + cards.add(new SetCardInfo("Call In a Professional", 103, Rarity.UNCOMMON, mage.cards.c.CallInAProfessional.class)); + cards.add(new SetCardInfo("Capenna Express", 139, Rarity.COMMON, mage.cards.c.CapennaExpress.class)); + cards.add(new SetCardInfo("Case the Joint", 37, Rarity.COMMON, mage.cards.c.CaseTheJoint.class)); + cards.add(new SetCardInfo("Celebrity Fencer", 7, Rarity.COMMON, mage.cards.c.CelebrityFencer.class)); + cards.add(new SetCardInfo("Celestial Regulator", 174, Rarity.COMMON, mage.cards.c.CelestialRegulator.class)); + cards.add(new SetCardInfo("Cement Shoes", 235, Rarity.UNCOMMON, mage.cards.c.CementShoes.class)); + cards.add(new SetCardInfo("Cemetery Tampering", 418, Rarity.RARE, mage.cards.c.CemeteryTampering.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cemetery Tampering", 69, Rarity.RARE, mage.cards.c.CemeteryTampering.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ceremonial Groundbreaker", 175, Rarity.UNCOMMON, mage.cards.c.CeremonialGroundbreaker.class)); + cards.add(new SetCardInfo("Chrome Cat", 236, Rarity.COMMON, mage.cards.c.ChromeCat.class)); + cards.add(new SetCardInfo("Citizen's Crowbar", 8, Rarity.UNCOMMON, mage.cards.c.CitizensCrowbar.class)); + cards.add(new SetCardInfo("Civic Gardener", 140, Rarity.COMMON, mage.cards.c.CivicGardener.class)); + cards.add(new SetCardInfo("Civil Servant", 176, Rarity.COMMON, mage.cards.c.CivilServant.class)); + cards.add(new SetCardInfo("Cleanup Crew", 141, Rarity.UNCOMMON, mage.cards.c.CleanupCrew.class)); + cards.add(new SetCardInfo("Cormela, Glamour Thief", 177, Rarity.UNCOMMON, mage.cards.c.CormelaGlamourThief.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cormela, Glamour Thief", 301, Rarity.UNCOMMON, mage.cards.c.CormelaGlamourThief.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cormela, Glamour Thief", 366, Rarity.UNCOMMON, mage.cards.c.CormelaGlamourThief.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Corpse Appraiser", 178, Rarity.UNCOMMON, mage.cards.c.CorpseAppraiser.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Corpse Appraiser", 302, Rarity.UNCOMMON, mage.cards.c.CorpseAppraiser.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Corpse Appraiser", 367, Rarity.UNCOMMON, mage.cards.c.CorpseAppraiser.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Corpse Explosion", 179, Rarity.RARE, mage.cards.c.CorpseExplosion.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Corpse Explosion", 435, Rarity.RARE, mage.cards.c.CorpseExplosion.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Corrupt Court Official", 70, Rarity.COMMON, mage.cards.c.CorruptCourtOfficial.class)); + cards.add(new SetCardInfo("Courier's Briefcase", 142, Rarity.UNCOMMON, mage.cards.c.CouriersBriefcase.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Courier's Briefcase", 467, Rarity.UNCOMMON, mage.cards.c.CouriersBriefcase.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Crew Captain", 180, Rarity.UNCOMMON, mage.cards.c.CrewCaptain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Crew Captain", 303, Rarity.UNCOMMON, mage.cards.c.CrewCaptain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Crew Captain", 368, Rarity.UNCOMMON, mage.cards.c.CrewCaptain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Crooked Custodian", 71, Rarity.COMMON, mage.cards.c.CrookedCustodian.class)); + cards.add(new SetCardInfo("Cut Your Losses", 38, Rarity.RARE, mage.cards.c.CutYourLosses.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cut Your Losses", 410, Rarity.RARE, mage.cards.c.CutYourLosses.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cut of the Profits", 419, Rarity.RARE, mage.cards.c.CutOfTheProfits.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cut of the Profits", 72, Rarity.RARE, mage.cards.c.CutOfTheProfits.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Cutthroat Contender", 73, Rarity.COMMON, mage.cards.c.CutthroatContender.class)); + cards.add(new SetCardInfo("Dapper Shieldmate", 9, Rarity.COMMON, mage.cards.d.DapperShieldmate.class)); + cards.add(new SetCardInfo("Daring Escape", 104, Rarity.COMMON, mage.cards.d.DaringEscape.class)); + cards.add(new SetCardInfo("Darling of the Masses", 181, Rarity.UNCOMMON, mage.cards.d.DarlingOfTheMasses.class)); + cards.add(new SetCardInfo("Deal Gone Bad", 74, Rarity.COMMON, mage.cards.d.DealGoneBad.class)); + cards.add(new SetCardInfo("Demon's Due", 75, Rarity.COMMON, mage.cards.d.DemonsDue.class)); + cards.add(new SetCardInfo("Depopulate", 10, Rarity.RARE, mage.cards.d.Depopulate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Depopulate", 406, Rarity.RARE, mage.cards.d.Depopulate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Devilish Valet", 105, Rarity.RARE, mage.cards.d.DevilishValet.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Devilish Valet", 423, Rarity.RARE, mage.cards.d.DevilishValet.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Dig Up the Body", 76, Rarity.COMMON, mage.cards.d.DigUpTheBody.class)); + cards.add(new SetCardInfo("Disciplined Duelist", 182, Rarity.UNCOMMON, mage.cards.d.DisciplinedDuelist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Disciplined Duelist", 304, Rarity.UNCOMMON, mage.cards.d.DisciplinedDuelist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Disciplined Duelist", 369, Rarity.UNCOMMON, mage.cards.d.DisciplinedDuelist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Disdainful Stroke", 39, Rarity.COMMON, mage.cards.d.DisdainfulStroke.class)); + cards.add(new SetCardInfo("Dusk Mangler", 77, Rarity.UNCOMMON, mage.cards.d.DuskMangler.class)); + cards.add(new SetCardInfo("Echo Inspector", 40, Rarity.COMMON, mage.cards.e.EchoInspector.class)); + cards.add(new SetCardInfo("Elegant Entourage", 143, Rarity.UNCOMMON, mage.cards.e.ElegantEntourage.class)); + cards.add(new SetCardInfo("Elspeth Resplendent", 11, Rarity.MYTHIC, mage.cards.e.ElspethResplendent.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Elspeth Resplendent", 282, Rarity.MYTHIC, mage.cards.e.ElspethResplendent.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Elspeth Resplendent", 341, Rarity.MYTHIC, mage.cards.e.ElspethResplendent.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Elspeth Resplendent", 441, Rarity.MYTHIC, mage.cards.e.ElspethResplendent.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Endless Detour", 183, Rarity.RARE, mage.cards.e.EndlessDetour.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Endless Detour", 305, Rarity.RARE, mage.cards.e.EndlessDetour.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Endless Detour", 370, Rarity.RARE, mage.cards.e.EndlessDetour.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Errant, Street Artist", 344, Rarity.RARE, mage.cards.e.ErrantStreetArtist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Errant, Street Artist", 41, Rarity.RARE, mage.cards.e.ErrantStreetArtist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Errant, Street Artist", 444, Rarity.RARE, mage.cards.e.ErrantStreetArtist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Evelyn, the Covetous", 184, Rarity.RARE, mage.cards.e.EvelynTheCovetous.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Evelyn, the Covetous", 306, Rarity.RARE, mage.cards.e.EvelynTheCovetous.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Evelyn, the Covetous", 371, Rarity.RARE, mage.cards.e.EvelynTheCovetous.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Even the Score", 411, Rarity.MYTHIC, mage.cards.e.EvenTheScore.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Even the Score", 42, Rarity.MYTHIC, mage.cards.e.EvenTheScore.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Evolving Door", 144, Rarity.RARE, mage.cards.e.EvolvingDoor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Evolving Door", 429, Rarity.RARE, mage.cards.e.EvolvingDoor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Exhibition Magician", 106, Rarity.COMMON, mage.cards.e.ExhibitionMagician.class)); + cards.add(new SetCardInfo("Exotic Pets", 185, Rarity.UNCOMMON, mage.cards.e.ExoticPets.class)); + cards.add(new SetCardInfo("Expendable Lackey", 43, Rarity.COMMON, mage.cards.e.ExpendableLackey.class)); + cards.add(new SetCardInfo("Extract the Truth", 78, Rarity.COMMON, mage.cards.e.ExtractTheTruth.class)); + cards.add(new SetCardInfo("Extraction Specialist", 12, Rarity.RARE, mage.cards.e.ExtractionSpecialist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Extraction Specialist", 407, Rarity.RARE, mage.cards.e.ExtractionSpecialist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Faerie Vandal", 44, Rarity.UNCOMMON, mage.cards.f.FaerieVandal.class)); + cards.add(new SetCardInfo("Fake Your Own Death", 79, Rarity.COMMON, mage.cards.f.FakeYourOwnDeath.class)); + cards.add(new SetCardInfo("Falco Spara, Pactweaver", 186, Rarity.MYTHIC, mage.cards.f.FalcoSparaPactweaver.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Falco Spara, Pactweaver", 307, Rarity.MYTHIC, mage.cards.f.FalcoSparaPactweaver.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Falco Spara, Pactweaver", 372, Rarity.MYTHIC, mage.cards.f.FalcoSparaPactweaver.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fatal Grudge", 187, Rarity.UNCOMMON, mage.cards.f.FatalGrudge.class)); + cards.add(new SetCardInfo("Fight Rigging", 145, Rarity.RARE, mage.cards.f.FightRigging.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fight Rigging", 430, Rarity.RARE, mage.cards.f.FightRigging.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fleetfoot Dancer", 188, Rarity.RARE, mage.cards.f.FleetfootDancer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fleetfoot Dancer", 308, Rarity.RARE, mage.cards.f.FleetfootDancer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fleetfoot Dancer", 373, Rarity.RARE, mage.cards.f.FleetfootDancer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("For the Family", 146, Rarity.COMMON, mage.cards.f.ForTheFamily.class)); + cards.add(new SetCardInfo("Forest", 270, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 271, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 280, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Forest", 281, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Forge Boss", 189, Rarity.UNCOMMON, mage.cards.f.ForgeBoss.class)); + cards.add(new SetCardInfo("Freelance Muscle", 147, Rarity.UNCOMMON, mage.cards.f.FreelanceMuscle.class)); + cards.add(new SetCardInfo("Gala Greeters", 148, Rarity.RARE, mage.cards.g.GalaGreeters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gala Greeters", 431, Rarity.RARE, mage.cards.g.GalaGreeters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gala Greeters", 450, Rarity.RARE, mage.cards.g.GalaGreeters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gala Greeters", 451, Rarity.RARE, mage.cards.g.GalaGreeters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gala Greeters", 452, Rarity.RARE, mage.cards.g.GalaGreeters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gala Greeters", 453, Rarity.RARE, mage.cards.g.GalaGreeters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gala Greeters", 454, Rarity.RARE, mage.cards.g.GalaGreeters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gala Greeters", 455, Rarity.RARE, mage.cards.g.GalaGreeters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gala Greeters", 456, Rarity.RARE, mage.cards.g.GalaGreeters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gala Greeters", 457, Rarity.RARE, mage.cards.g.GalaGreeters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gala Greeters", 458, Rarity.RARE, mage.cards.g.GalaGreeters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gala Greeters", 459, Rarity.RARE, mage.cards.g.GalaGreeters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gala Greeters", 460, Rarity.RARE, mage.cards.g.GalaGreeters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gathering Throng", 13, Rarity.COMMON, mage.cards.g.GatheringThrong.class)); + cards.add(new SetCardInfo("Getaway Car", 237, Rarity.RARE, mage.cards.g.GetawayCar.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Getaway Car", 438, Rarity.RARE, mage.cards.g.GetawayCar.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Giada, Font of Hope", 14, Rarity.RARE, mage.cards.g.GiadaFontOfHope.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Giada, Font of Hope", 342, Rarity.RARE, mage.cards.g.GiadaFontOfHope.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Giada, Font of Hope", 442, Rarity.RARE, mage.cards.g.GiadaFontOfHope.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gilded Pinions", 238, Rarity.COMMON, mage.cards.g.GildedPinions.class)); + cards.add(new SetCardInfo("Girder Goons", 80, Rarity.COMMON, mage.cards.g.GirderGoons.class)); + cards.add(new SetCardInfo("Glamorous Outlaw", 190, Rarity.COMMON, mage.cards.g.GlamorousOutlaw.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Glamorous Outlaw", 309, Rarity.COMMON, mage.cards.g.GlamorousOutlaw.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Glamorous Outlaw", 374, Rarity.COMMON, mage.cards.g.GlamorousOutlaw.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Glittering Stockpile", 107, Rarity.UNCOMMON, mage.cards.g.GlitteringStockpile.class)); + cards.add(new SetCardInfo("Glittermonger", 149, Rarity.COMMON, mage.cards.g.Glittermonger.class)); + cards.add(new SetCardInfo("Goldhound", 108, Rarity.COMMON, mage.cards.g.Goldhound.class)); + cards.add(new SetCardInfo("Graveyard Shift", 81, Rarity.UNCOMMON, mage.cards.g.GraveyardShift.class)); + cards.add(new SetCardInfo("Grisly Sigil", 82, Rarity.UNCOMMON, mage.cards.g.GrislySigil.class)); + cards.add(new SetCardInfo("Halo Fountain", 15, Rarity.MYTHIC, mage.cards.h.HaloFountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Halo Fountain", 285, Rarity.MYTHIC, mage.cards.h.HaloFountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Halo Scarab", 239, Rarity.COMMON, mage.cards.h.HaloScarab.class)); + cards.add(new SetCardInfo("High-Rise Sawjack", 150, Rarity.COMMON, mage.cards.h.HighRiseSawjack.class)); + cards.add(new SetCardInfo("Hoard Hauler", 109, Rarity.RARE, mage.cards.h.HoardHauler.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hoard Hauler", 424, Rarity.RARE, mage.cards.h.HoardHauler.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hold for Ransom", 16, Rarity.COMMON, mage.cards.h.HoldForRansom.class)); + cards.add(new SetCardInfo("Hostile Takeover", 191, Rarity.RARE, mage.cards.h.HostileTakeover.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hostile Takeover", 310, Rarity.RARE, mage.cards.h.HostileTakeover.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hostile Takeover", 375, Rarity.RARE, mage.cards.h.HostileTakeover.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Hypnotic Grifter", 45, Rarity.UNCOMMON, mage.cards.h.HypnoticGrifter.class)); + cards.add(new SetCardInfo("Illicit Shipment", 83, Rarity.UNCOMMON, mage.cards.i.IllicitShipment.class)); + cards.add(new SetCardInfo("Illuminator Virtuoso", 17, Rarity.UNCOMMON, mage.cards.i.IlluminatorVirtuoso.class)); + cards.add(new SetCardInfo("Incandescent Aria", 192, Rarity.RARE, mage.cards.i.IncandescentAria.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Incandescent Aria", 311, Rarity.RARE, mage.cards.i.IncandescentAria.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Incandescent Aria", 376, Rarity.RARE, mage.cards.i.IncandescentAria.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Incriminate", 465, Rarity.COMMON, mage.cards.i.Incriminate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Incriminate", 84, Rarity.COMMON, mage.cards.i.Incriminate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Inspiring Overseer", 18, Rarity.COMMON, mage.cards.i.InspiringOverseer.class)); + cards.add(new SetCardInfo("Involuntary Employment", 110, Rarity.UNCOMMON, mage.cards.i.InvoluntaryEmployment.class)); + cards.add(new SetCardInfo("Island", 264, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 265, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 274, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Island", 275, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Jackhammer", 111, Rarity.COMMON, mage.cards.j.Jackhammer.class)); + cards.add(new SetCardInfo("Jaxis, the Troublemaker", 112, Rarity.RARE, mage.cards.j.JaxisTheTroublemaker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jaxis, the Troublemaker", 425, Rarity.RARE, mage.cards.j.JaxisTheTroublemaker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jaxis, the Troublemaker", 461, Rarity.RARE, mage.cards.j.JaxisTheTroublemaker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jetmir's Fixer", 194, Rarity.COMMON, mage.cards.j.JetmirsFixer.class)); + cards.add(new SetCardInfo("Jetmir's Garden", 250, Rarity.RARE, mage.cards.j.JetmirsGarden.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jetmir's Garden", 291, Rarity.RARE, mage.cards.j.JetmirsGarden.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jetmir's Garden", 351, Rarity.RARE, mage.cards.j.JetmirsGarden.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jetmir, Nexus of Revels", 193, Rarity.MYTHIC, mage.cards.j.JetmirNexusOfRevels.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jetmir, Nexus of Revels", 312, Rarity.MYTHIC, mage.cards.j.JetmirNexusOfRevels.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jetmir, Nexus of Revels", 377, Rarity.MYTHIC, mage.cards.j.JetmirNexusOfRevels.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jewel Thief", 151, Rarity.COMMON, mage.cards.j.JewelThief.class)); + cards.add(new SetCardInfo("Jinnie Fay, Jetmir's Second", 195, Rarity.RARE, mage.cards.j.JinnieFayJetmirsSecond.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jinnie Fay, Jetmir's Second", 313, Rarity.RARE, mage.cards.j.JinnieFayJetmirsSecond.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jinnie Fay, Jetmir's Second", 378, Rarity.RARE, mage.cards.j.JinnieFayJetmirsSecond.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Join the Maestros", 85, Rarity.COMMON, mage.cards.j.JoinTheMaestros.class)); + cards.add(new SetCardInfo("Kill Shot", 19, Rarity.COMMON, mage.cards.k.KillShot.class)); + cards.add(new SetCardInfo("Knockout Blow", 20, Rarity.UNCOMMON, mage.cards.k.KnockoutBlow.class)); + cards.add(new SetCardInfo("Lagrella, the Magpie", 196, Rarity.UNCOMMON, mage.cards.l.LagrellaTheMagpie.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lagrella, the Magpie", 314, Rarity.UNCOMMON, mage.cards.l.LagrellaTheMagpie.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lagrella, the Magpie", 379, Rarity.UNCOMMON, mage.cards.l.LagrellaTheMagpie.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ledger Shredder", 412, Rarity.RARE, mage.cards.l.LedgerShredder.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ledger Shredder", 46, Rarity.RARE, mage.cards.l.LedgerShredder.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Light 'Em Up", 113, Rarity.COMMON, mage.cards.l.LightEmUp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Light 'Em Up", 466, Rarity.COMMON, mage.cards.l.LightEmUp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lord Xander, the Collector", 197, Rarity.MYTHIC, mage.cards.l.LordXanderTheCollector.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lord Xander, the Collector", 315, Rarity.MYTHIC, mage.cards.l.LordXanderTheCollector.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lord Xander, the Collector", 380, Rarity.MYTHIC, mage.cards.l.LordXanderTheCollector.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Luxior, Giada's Gift", 240, Rarity.MYTHIC, mage.cards.l.LuxiorGiadasGift.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Luxior, Giada's Gift", 439, Rarity.MYTHIC, mage.cards.l.LuxiorGiadasGift.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Luxurious Libation", 152, Rarity.UNCOMMON, mage.cards.l.LuxuriousLibation.class)); + cards.add(new SetCardInfo("Maestros Ascendancy", 198, Rarity.RARE, mage.cards.m.MaestrosAscendancy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Maestros Ascendancy", 316, Rarity.RARE, mage.cards.m.MaestrosAscendancy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Maestros Ascendancy", 381, Rarity.RARE, mage.cards.m.MaestrosAscendancy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Maestros Charm", 199, Rarity.UNCOMMON, mage.cards.m.MaestrosCharm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Maestros Charm", 317, Rarity.UNCOMMON, mage.cards.m.MaestrosCharm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Maestros Charm", 382, Rarity.UNCOMMON, mage.cards.m.MaestrosCharm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Maestros Diabolist", 200, Rarity.RARE, mage.cards.m.MaestrosDiabolist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Maestros Diabolist", 318, Rarity.RARE, mage.cards.m.MaestrosDiabolist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Maestros Diabolist", 383, Rarity.RARE, mage.cards.m.MaestrosDiabolist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Maestros Initiate", 86, Rarity.COMMON, mage.cards.m.MaestrosInitiate.class)); + cards.add(new SetCardInfo("Maestros Theater", 251, Rarity.COMMON, mage.cards.m.MaestrosTheater.class)); + cards.add(new SetCardInfo("Mage's Attendant", 21, Rarity.UNCOMMON, mage.cards.m.MagesAttendant.class)); + cards.add(new SetCardInfo("Majestic Metamorphosis", 48, Rarity.COMMON, mage.cards.m.MajesticMetamorphosis.class)); + cards.add(new SetCardInfo("Make Disappear", 49, Rarity.COMMON, mage.cards.m.MakeDisappear.class)); + cards.add(new SetCardInfo("Masked Bandits", 201, Rarity.COMMON, mage.cards.m.MaskedBandits.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Masked Bandits", 319, Rarity.COMMON, mage.cards.m.MaskedBandits.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Masked Bandits", 384, Rarity.COMMON, mage.cards.m.MaskedBandits.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mayhem Patrol", 114, Rarity.COMMON, mage.cards.m.MayhemPatrol.class)); + cards.add(new SetCardInfo("Meeting of the Five", 202, Rarity.MYTHIC, mage.cards.m.MeetingOfTheFive.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Meeting of the Five", 436, Rarity.MYTHIC, mage.cards.m.MeetingOfTheFive.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Metropolis Angel", 203, Rarity.UNCOMMON, mage.cards.m.MetropolisAngel.class)); + cards.add(new SetCardInfo("Midnight Assassin", 87, Rarity.COMMON, mage.cards.m.MidnightAssassin.class)); + cards.add(new SetCardInfo("Most Wanted", 153, Rarity.COMMON, mage.cards.m.MostWanted.class)); + cards.add(new SetCardInfo("Mountain", 268, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 269, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 278, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 279, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Mr. Orfeo, the Boulder", 204, Rarity.UNCOMMON, mage.cards.m.MrOrfeoTheBoulder.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mr. Orfeo, the Boulder", 320, Rarity.UNCOMMON, mage.cards.m.MrOrfeoTheBoulder.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mr. Orfeo, the Boulder", 385, Rarity.UNCOMMON, mage.cards.m.MrOrfeoTheBoulder.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Murder", 88, Rarity.COMMON, mage.cards.m.Murder.class)); + cards.add(new SetCardInfo("Mysterious Limousine", 22, Rarity.RARE, mage.cards.m.MysteriousLimousine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mysterious Limousine", 408, Rarity.RARE, mage.cards.m.MysteriousLimousine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mysterious Limousine", 462, Rarity.RARE, mage.cards.m.MysteriousLimousine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Night Clubber", 89, Rarity.UNCOMMON, mage.cards.n.NightClubber.class)); + cards.add(new SetCardInfo("Nimble Larcenist", 205, Rarity.UNCOMMON, mage.cards.n.NimbleLarcenist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nimble Larcenist", 321, Rarity.UNCOMMON, mage.cards.n.NimbleLarcenist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nimble Larcenist", 386, Rarity.UNCOMMON, mage.cards.n.NimbleLarcenist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ob Nixilis, the Adversary", 206, Rarity.MYTHIC, mage.cards.o.ObNixilisTheAdversary.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ob Nixilis, the Adversary", 284, Rarity.MYTHIC, mage.cards.o.ObNixilisTheAdversary.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ob Nixilis, the Adversary", 348, Rarity.MYTHIC, mage.cards.o.ObNixilisTheAdversary.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ob Nixilis, the Adversary", 448, Rarity.MYTHIC, mage.cards.o.ObNixilisTheAdversary.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Obscura Ascendancy", 207, Rarity.RARE, mage.cards.o.ObscuraAscendancy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Obscura Ascendancy", 322, Rarity.RARE, mage.cards.o.ObscuraAscendancy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Obscura Ascendancy", 387, Rarity.RARE, mage.cards.o.ObscuraAscendancy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Obscura Charm", 208, Rarity.UNCOMMON, mage.cards.o.ObscuraCharm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Obscura Charm", 323, Rarity.UNCOMMON, mage.cards.o.ObscuraCharm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Obscura Charm", 388, Rarity.UNCOMMON, mage.cards.o.ObscuraCharm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Obscura Initiate", 50, Rarity.COMMON, mage.cards.o.ObscuraInitiate.class)); + cards.add(new SetCardInfo("Obscura Interceptor", 209, Rarity.RARE, mage.cards.o.ObscuraInterceptor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Obscura Interceptor", 324, Rarity.RARE, mage.cards.o.ObscuraInterceptor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Obscura Interceptor", 389, Rarity.RARE, mage.cards.o.ObscuraInterceptor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Obscura Storefront", 252, Rarity.COMMON, mage.cards.o.ObscuraStorefront.class)); + cards.add(new SetCardInfo("Ognis, the Dragon's Lash", 210, Rarity.RARE, mage.cards.o.OgnisTheDragonsLash.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ognis, the Dragon's Lash", 325, Rarity.RARE, mage.cards.o.OgnisTheDragonsLash.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ognis, the Dragon's Lash", 390, Rarity.RARE, mage.cards.o.OgnisTheDragonsLash.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ominous Parcel", 241, Rarity.COMMON, mage.cards.o.OminousParcel.class)); + cards.add(new SetCardInfo("Out of the Way", 52, Rarity.UNCOMMON, mage.cards.o.OutOfTheWay.class)); + cards.add(new SetCardInfo("Paragon of Modernity", 242, Rarity.COMMON, mage.cards.p.ParagonOfModernity.class)); + cards.add(new SetCardInfo("Park Heights Pegasus", 211, Rarity.RARE, mage.cards.p.ParkHeightsPegasus.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Park Heights Pegasus", 437, Rarity.RARE, mage.cards.p.ParkHeightsPegasus.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Patch Up", 23, Rarity.UNCOMMON, mage.cards.p.PatchUp.class)); + cards.add(new SetCardInfo("Plains", 262, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 263, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 272, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Plains", 273, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Plasma Jockey", 115, Rarity.COMMON, mage.cards.p.PlasmaJockey.class)); + cards.add(new SetCardInfo("Prizefight", 154, Rarity.COMMON, mage.cards.p.Prizefight.class)); + cards.add(new SetCardInfo("Professional Face-Breaker", 116, Rarity.RARE, mage.cards.p.ProfessionalFaceBreaker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Professional Face-Breaker", 426, Rarity.RARE, mage.cards.p.ProfessionalFaceBreaker.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Psionic Snoop", 53, Rarity.COMMON, mage.cards.p.PsionicSnoop.class)); + cards.add(new SetCardInfo("Psychic Pickpocket", 54, Rarity.UNCOMMON, mage.cards.p.PsychicPickpocket.class)); + cards.add(new SetCardInfo("Public Enemy", 55, Rarity.UNCOMMON, mage.cards.p.PublicEnemy.class)); + cards.add(new SetCardInfo("Pugnacious Pugilist", 117, Rarity.UNCOMMON, mage.cards.p.PugnaciousPugilist.class)); + cards.add(new SetCardInfo("Pyre-Sledge Arsonist", 118, Rarity.UNCOMMON, mage.cards.p.PyreSledgeArsonist.class)); + cards.add(new SetCardInfo("Queza, Augur of Agonies", 212, Rarity.UNCOMMON, mage.cards.q.QuezaAugurOfAgonies.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Queza, Augur of Agonies", 326, Rarity.UNCOMMON, mage.cards.q.QuezaAugurOfAgonies.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Queza, Augur of Agonies", 391, Rarity.UNCOMMON, mage.cards.q.QuezaAugurOfAgonies.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Quick-Draw Dagger", 243, Rarity.COMMON, mage.cards.q.QuickDrawDagger.class)); + cards.add(new SetCardInfo("Rabble Rousing", 24, Rarity.RARE, mage.cards.r.RabbleRousing.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rabble Rousing", 409, Rarity.RARE, mage.cards.r.RabbleRousing.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Racers' Ring", 253, Rarity.COMMON, mage.cards.r.RacersRing.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Racers' Ring", 352, Rarity.COMMON, mage.cards.r.RacersRing.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Raffine's Guidance", 25, Rarity.COMMON, mage.cards.r.RaffinesGuidance.class)); + cards.add(new SetCardInfo("Raffine's Informant", 26, Rarity.COMMON, mage.cards.r.RaffinesInformant.class)); + cards.add(new SetCardInfo("Raffine's Silencer", 90, Rarity.UNCOMMON, mage.cards.r.RaffinesSilencer.class)); + cards.add(new SetCardInfo("Raffine's Tower", 254, Rarity.RARE, mage.cards.r.RaffinesTower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Raffine's Tower", 292, Rarity.RARE, mage.cards.r.RaffinesTower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Raffine's Tower", 353, Rarity.RARE, mage.cards.r.RaffinesTower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Raffine, Scheming Seer", 213, Rarity.MYTHIC, mage.cards.r.RaffineSchemingSeer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Raffine, Scheming Seer", 327, Rarity.MYTHIC, mage.cards.r.RaffineSchemingSeer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Raffine, Scheming Seer", 392, Rarity.MYTHIC, mage.cards.r.RaffineSchemingSeer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rakish Revelers", 214, Rarity.COMMON, mage.cards.r.RakishRevelers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rakish Revelers", 328, Rarity.COMMON, mage.cards.r.RakishRevelers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rakish Revelers", 393, Rarity.COMMON, mage.cards.r.RakishRevelers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ready to Rumble", 119, Rarity.COMMON, mage.cards.r.ReadyToRumble.class)); + cards.add(new SetCardInfo("Refuse to Yield", 27, Rarity.UNCOMMON, mage.cards.r.RefuseToYield.class)); + cards.add(new SetCardInfo("Reservoir Kraken", 413, Rarity.RARE, mage.cards.r.ReservoirKraken.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Reservoir Kraken", 56, Rarity.RARE, mage.cards.r.ReservoirKraken.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Revel Ruiner", 91, Rarity.COMMON, mage.cards.r.RevelRuiner.class)); + cards.add(new SetCardInfo("Revelation of Power", 28, Rarity.COMMON, mage.cards.r.RevelationOfPower.class)); + cards.add(new SetCardInfo("Rhox Pummeler", 155, Rarity.COMMON, mage.cards.r.RhoxPummeler.class)); + cards.add(new SetCardInfo("Rigo, Streetwise Mentor", 215, Rarity.RARE, mage.cards.r.RigoStreetwiseMentor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rigo, Streetwise Mentor", 329, Rarity.RARE, mage.cards.r.RigoStreetwiseMentor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rigo, Streetwise Mentor", 394, Rarity.RARE, mage.cards.r.RigoStreetwiseMentor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Riveteers Ascendancy", 216, Rarity.RARE, mage.cards.r.RiveteersAscendancy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Riveteers Ascendancy", 330, Rarity.RARE, mage.cards.r.RiveteersAscendancy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Riveteers Ascendancy", 395, Rarity.RARE, mage.cards.r.RiveteersAscendancy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Riveteers Charm", 217, Rarity.UNCOMMON, mage.cards.r.RiveteersCharm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Riveteers Charm", 331, Rarity.UNCOMMON, mage.cards.r.RiveteersCharm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Riveteers Charm", 396, Rarity.UNCOMMON, mage.cards.r.RiveteersCharm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Riveteers Decoy", 156, Rarity.UNCOMMON, mage.cards.r.RiveteersDecoy.class)); + cards.add(new SetCardInfo("Riveteers Initiate", 120, Rarity.COMMON, mage.cards.r.RiveteersInitiate.class)); + cards.add(new SetCardInfo("Riveteers Overlook", 255, Rarity.COMMON, mage.cards.r.RiveteersOverlook.class)); + cards.add(new SetCardInfo("Riveteers Requisitioner", 121, Rarity.UNCOMMON, mage.cards.r.RiveteersRequisitioner.class)); + cards.add(new SetCardInfo("Rob the Archives", 122, Rarity.UNCOMMON, mage.cards.r.RobTheArchives.class)); + cards.add(new SetCardInfo("Rocco, Cabaretti Caterer", 218, Rarity.UNCOMMON, mage.cards.r.RoccoCabarettiCaterer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rocco, Cabaretti Caterer", 332, Rarity.UNCOMMON, mage.cards.r.RoccoCabarettiCaterer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rocco, Cabaretti Caterer", 397, Rarity.UNCOMMON, mage.cards.r.RoccoCabarettiCaterer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rogues' Gallery", 92, Rarity.UNCOMMON, mage.cards.r.RoguesGallery.class)); + cards.add(new SetCardInfo("Rooftop Nuisance", 57, Rarity.COMMON, mage.cards.r.RooftopNuisance.class)); + cards.add(new SetCardInfo("Rumor Gatherer", 29, Rarity.UNCOMMON, mage.cards.r.RumorGatherer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rumor Gatherer", 463, Rarity.UNCOMMON, mage.cards.r.RumorGatherer.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Run Out of Town", 58, Rarity.COMMON, mage.cards.r.RunOutOfTown.class)); + cards.add(new SetCardInfo("Sanctuary Warden", 30, Rarity.MYTHIC, mage.cards.s.SanctuaryWarden.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sanctuary Warden", 343, Rarity.MYTHIC, mage.cards.s.SanctuaryWarden.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sanctuary Warden", 443, Rarity.MYTHIC, mage.cards.s.SanctuaryWarden.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sanguine Spy", 420, Rarity.RARE, mage.cards.s.SanguineSpy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sanguine Spy", 93, Rarity.RARE, mage.cards.s.SanguineSpy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Scheming Fence", 219, Rarity.RARE, mage.cards.s.SchemingFence.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Scheming Fence", 349, Rarity.RARE, mage.cards.s.SchemingFence.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Scheming Fence", 449, Rarity.RARE, mage.cards.s.SchemingFence.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Scuttling Butler", 244, Rarity.UNCOMMON, mage.cards.s.ScuttlingButler.class)); + cards.add(new SetCardInfo("Security Bypass", 59, Rarity.COMMON, mage.cards.s.SecurityBypass.class)); + cards.add(new SetCardInfo("Security Rhox", 220, Rarity.UNCOMMON, mage.cards.s.SecurityRhox.class)); + cards.add(new SetCardInfo("Sewer Crocodile", 60, Rarity.COMMON, mage.cards.s.SewerCrocodile.class)); + cards.add(new SetCardInfo("Shadow of Mortality", 287, Rarity.RARE, mage.cards.s.ShadowOfMortality.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Shadow of Mortality", 94, Rarity.RARE, mage.cards.s.ShadowOfMortality.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Shakedown Heavy", 421, Rarity.RARE, mage.cards.s.ShakedownHeavy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Shakedown Heavy", 95, Rarity.RARE, mage.cards.s.ShakedownHeavy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Shattered Seraph", 221, Rarity.COMMON, mage.cards.s.ShatteredSeraph.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Shattered Seraph", 333, Rarity.COMMON, mage.cards.s.ShatteredSeraph.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Shattered Seraph", 398, Rarity.COMMON, mage.cards.s.ShatteredSeraph.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sizzling Soloist", 123, Rarity.UNCOMMON, mage.cards.s.SizzlingSoloist.class)); + cards.add(new SetCardInfo("Sky Crier", 31, Rarity.COMMON, mage.cards.s.SkyCrier.class)); + cards.add(new SetCardInfo("Skybridge Towers", 256, Rarity.COMMON, mage.cards.s.SkybridgeTowers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Skybridge Towers", 354, Rarity.COMMON, mage.cards.s.SkybridgeTowers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sleep with the Fishes", 61, Rarity.UNCOMMON, mage.cards.s.SleepWithTheFishes.class)); + cards.add(new SetCardInfo("Slip Out the Back", 62, Rarity.UNCOMMON, mage.cards.s.SlipOutTheBack.class)); + cards.add(new SetCardInfo("Snooping Newsie", 222, Rarity.COMMON, mage.cards.s.SnoopingNewsie.class)); + cards.add(new SetCardInfo("Social Climber", 157, Rarity.COMMON, mage.cards.s.SocialClimber.class)); + cards.add(new SetCardInfo("Soul of Emancipation", 223, Rarity.RARE, mage.cards.s.SoulOfEmancipation.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soul of Emancipation", 334, Rarity.RARE, mage.cards.s.SoulOfEmancipation.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soul of Emancipation", 399, Rarity.RARE, mage.cards.s.SoulOfEmancipation.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spara's Adjudicators", 224, Rarity.COMMON, mage.cards.s.SparasAdjudicators.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spara's Adjudicators", 335, Rarity.COMMON, mage.cards.s.SparasAdjudicators.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spara's Adjudicators", 400, Rarity.COMMON, mage.cards.s.SparasAdjudicators.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spara's Headquarters", 257, Rarity.RARE, mage.cards.s.SparasHeadquarters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spara's Headquarters", 293, Rarity.RARE, mage.cards.s.SparasHeadquarters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Spara's Headquarters", 355, Rarity.RARE, mage.cards.s.SparasHeadquarters.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Speakeasy Server", 32, Rarity.COMMON, mage.cards.s.SpeakeasyServer.class)); + cards.add(new SetCardInfo("Sticky Fingers", 124, Rarity.COMMON, mage.cards.s.StickyFingers.class)); + cards.add(new SetCardInfo("Stimulus Package", 225, Rarity.UNCOMMON, mage.cards.s.StimulusPackage.class)); + cards.add(new SetCardInfo("Strangle", 125, Rarity.COMMON, mage.cards.s.Strangle.class)); + cards.add(new SetCardInfo("Structural Assault", 126, Rarity.RARE, mage.cards.s.StructuralAssault.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Structural Assault", 427, Rarity.RARE, mage.cards.s.StructuralAssault.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Suspicious Bookcase", 245, Rarity.UNCOMMON, mage.cards.s.SuspiciousBookcase.class)); + cards.add(new SetCardInfo("Swamp", 266, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 267, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 276, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 277, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); + cards.add(new SetCardInfo("Swooping Protector", 33, Rarity.UNCOMMON, mage.cards.s.SwoopingProtector.class)); + cards.add(new SetCardInfo("Syndicate Infiltrator", 226, Rarity.UNCOMMON, mage.cards.s.SyndicateInfiltrator.class)); + cards.add(new SetCardInfo("Tainted Indulgence", 227, Rarity.UNCOMMON, mage.cards.t.TaintedIndulgence.class)); + cards.add(new SetCardInfo("Take to the Streets", 158, Rarity.UNCOMMON, mage.cards.t.TakeToTheStreets.class)); + cards.add(new SetCardInfo("Tavern Swindler", 96, Rarity.UNCOMMON, mage.cards.t.TavernSwindler.class)); + cards.add(new SetCardInfo("Tenacious Underdog", 345, Rarity.RARE, mage.cards.t.TenaciousUnderdog.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tenacious Underdog", 445, Rarity.RARE, mage.cards.t.TenaciousUnderdog.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tenacious Underdog", 97, Rarity.RARE, mage.cards.t.TenaciousUnderdog.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Titan of Industry", 159, Rarity.MYTHIC, mage.cards.t.TitanOfIndustry.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Titan of Industry", 289, Rarity.MYTHIC, mage.cards.t.TitanOfIndustry.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Toluz, Clever Conductor", 228, Rarity.RARE, mage.cards.t.ToluzCleverConductor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Toluz, Clever Conductor", 336, Rarity.RARE, mage.cards.t.ToluzCleverConductor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Toluz, Clever Conductor", 401, Rarity.RARE, mage.cards.t.ToluzCleverConductor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Topiary Stomper", 160, Rarity.RARE, mage.cards.t.TopiaryStomper.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Topiary Stomper", 290, Rarity.RARE, mage.cards.t.TopiaryStomper.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Torch Breath", 127, Rarity.UNCOMMON, mage.cards.t.TorchBreath.class)); + cards.add(new SetCardInfo("Tramway Station", 258, Rarity.COMMON, mage.cards.t.TramwayStation.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tramway Station", 356, Rarity.COMMON, mage.cards.t.TramwayStation.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Undercover Operative", 414, Rarity.RARE, mage.cards.u.UndercoverOperative.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Undercover Operative", 63, Rarity.RARE, mage.cards.u.UndercoverOperative.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Unleash the Inferno", 229, Rarity.RARE, mage.cards.u.UnleashTheInferno.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Unleash the Inferno", 337, Rarity.RARE, mage.cards.u.UnleashTheInferno.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Unleash the Inferno", 402, Rarity.RARE, mage.cards.u.UnleashTheInferno.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Unlicensed Hearse", 246, Rarity.RARE, mage.cards.u.UnlicensedHearse.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Unlicensed Hearse", 440, Rarity.RARE, mage.cards.u.UnlicensedHearse.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Unlucky Witness", 128, Rarity.UNCOMMON, mage.cards.u.UnluckyWitness.class)); + cards.add(new SetCardInfo("Urabrask, Heretic Praetor", 129, Rarity.MYTHIC, mage.cards.u.UrabraskHereticPraetor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urabrask, Heretic Praetor", 346, Rarity.MYTHIC, mage.cards.u.UrabraskHereticPraetor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urabrask, Heretic Praetor", 360, Rarity.MYTHIC, mage.cards.u.UrabraskHereticPraetor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urabrask, Heretic Praetor", 446, Rarity.MYTHIC, mage.cards.u.UrabraskHereticPraetor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Vampire Scrivener", 98, Rarity.UNCOMMON, mage.cards.v.VampireScrivener.class)); + cards.add(new SetCardInfo("Venom Connoisseur", 161, Rarity.UNCOMMON, mage.cards.v.VenomConnoisseur.class)); + cards.add(new SetCardInfo("Vivien on the Hunt", 162, Rarity.MYTHIC, mage.cards.v.VivienOnTheHunt.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Vivien on the Hunt", 283, Rarity.MYTHIC, mage.cards.v.VivienOnTheHunt.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Vivien on the Hunt", 347, Rarity.MYTHIC, mage.cards.v.VivienOnTheHunt.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Vivien on the Hunt", 447, Rarity.MYTHIC, mage.cards.v.VivienOnTheHunt.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Voice of the Vermin", 163, Rarity.UNCOMMON, mage.cards.v.VoiceOfTheVermin.class)); + cards.add(new SetCardInfo("Void Rend", 230, Rarity.RARE, mage.cards.v.VoidRend.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Void Rend", 338, Rarity.RARE, mage.cards.v.VoidRend.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Void Rend", 403, Rarity.RARE, mage.cards.v.VoidRend.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Warm Welcome", 164, Rarity.COMMON, mage.cards.w.WarmWelcome.class)); + cards.add(new SetCardInfo("Waterfront District", 259, Rarity.COMMON, mage.cards.w.WaterfrontDistrict.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Waterfront District", 357, Rarity.COMMON, mage.cards.w.WaterfrontDistrict.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Whack", 99, Rarity.UNCOMMON, mage.cards.w.Whack.class)); + cards.add(new SetCardInfo("Widespread Thieving", 130, Rarity.RARE, mage.cards.w.WidespreadThieving.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Widespread Thieving", 428, Rarity.RARE, mage.cards.w.WidespreadThieving.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wingshield Agent", 64, Rarity.UNCOMMON, mage.cards.w.WingshieldAgent.class)); + cards.add(new SetCardInfo("Wiretapping", 415, Rarity.RARE, mage.cards.w.Wiretapping.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wiretapping", 65, Rarity.RARE, mage.cards.w.Wiretapping.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Witness Protection", 66, Rarity.COMMON, mage.cards.w.WitnessProtection.class)); + cards.add(new SetCardInfo("Witty Roastmaster", 131, Rarity.COMMON, mage.cards.w.WittyRoastmaster.class)); + cards.add(new SetCardInfo("Workshop Warchief", 165, Rarity.RARE, mage.cards.w.WorkshopWarchief.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Workshop Warchief", 432, Rarity.RARE, mage.cards.w.WorkshopWarchief.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wrecking Crew", 132, Rarity.COMMON, mage.cards.w.WreckingCrew.class)); + cards.add(new SetCardInfo("Xander's Lounge", 260, Rarity.RARE, mage.cards.x.XandersLounge.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Xander's Lounge", 294, Rarity.RARE, mage.cards.x.XandersLounge.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Xander's Lounge", 358, Rarity.RARE, mage.cards.x.XandersLounge.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ziatora's Envoy", 232, Rarity.RARE, mage.cards.z.ZiatorasEnvoy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ziatora's Envoy", 340, Rarity.RARE, mage.cards.z.ZiatorasEnvoy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ziatora's Envoy", 405, Rarity.RARE, mage.cards.z.ZiatorasEnvoy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ziatora's Proving Ground", 261, Rarity.RARE, mage.cards.z.ZiatorasProvingGround.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ziatora's Proving Ground", 295, Rarity.RARE, mage.cards.z.ZiatorasProvingGround.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ziatora's Proving Ground", 359, Rarity.RARE, mage.cards.z.ZiatorasProvingGround.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ziatora, the Incinerator", 231, Rarity.MYTHIC, mage.cards.z.ZiatoraTheIncinerator.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ziatora, the Incinerator", 339, Rarity.MYTHIC, mage.cards.z.ZiatoraTheIncinerator.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ziatora, the Incinerator", 404, Rarity.MYTHIC, mage.cards.z.ZiatoraTheIncinerator.class, NON_FULL_USE_VARIOUS)); + } +} diff --git a/Mage.Sets/src/mage/sets/UniversesWithin.java b/Mage.Sets/src/mage/sets/UniversesWithin.java new file mode 100644 index 00000000000..7d919c69dfb --- /dev/null +++ b/Mage.Sets/src/mage/sets/UniversesWithin.java @@ -0,0 +1,35 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class UniversesWithin extends ExpansionSet { + + private static final UniversesWithin instance = new UniversesWithin(); + + public static UniversesWithin getInstance() { + return instance; + } + + private UniversesWithin() { + // The set name is a placeholder and will likely change + super("Universes Within", "SLX", ExpansionSet.buildDate(2022, 3, 3), SetType.SUPPLEMENTAL); + this.hasBasicLands = false; + this.hasBoosters = false; + + cards.add(new SetCardInfo("Arvinox, the Mind Flail", 1, Rarity.MYTHIC, mage.cards.a.ArvinoxTheMindFlail.class)); + cards.add(new SetCardInfo("Bjorna, Nightfall Alchemist", 2, Rarity.RARE, mage.cards.b.BjornaNightfallAlchemist.class)); + cards.add(new SetCardInfo("Cecily, Haunted Mage", 3, Rarity.RARE, mage.cards.c.CecilyHauntedMage.class)); + cards.add(new SetCardInfo("Elmar, Ulvenwald Informant", 4, Rarity.RARE, mage.cards.e.ElmarUlvenwaldInformant.class)); + cards.add(new SetCardInfo("Hargilde, Kindly Runechanter", 5, Rarity.RARE, mage.cards.h.HargildeKindlyRunechanter.class)); + cards.add(new SetCardInfo("Havengul Laboratory", 9, Rarity.RARE, mage.cards.h.HavengulLaboratory.class)); + cards.add(new SetCardInfo("Havengul Mystery", 9, Rarity.RARE, mage.cards.h.HavengulMystery.class)); + cards.add(new SetCardInfo("Othelm, Sigardian Outcast", 6, Rarity.RARE, mage.cards.o.OthelmSigardianOutcast.class)); + cards.add(new SetCardInfo("Sophina, Spearsage Deserter", 7, Rarity.RARE, mage.cards.s.SophinaSpearsageDeserter.class)); + cards.add(new SetCardInfo("Wernog, Rider's Chaplain", 8, Rarity.RARE, mage.cards.w.WernogRidersChaplain.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/WizardsPlayNetwork2009.java b/Mage.Sets/src/mage/sets/WizardsPlayNetwork2009.java index 52ca5d02dd0..bb18f9122f0 100644 --- a/Mage.Sets/src/mage/sets/WizardsPlayNetwork2009.java +++ b/Mage.Sets/src/mage/sets/WizardsPlayNetwork2009.java @@ -16,7 +16,7 @@ public class WizardsPlayNetwork2009 extends ExpansionSet { } private WizardsPlayNetwork2009() { - super("Wizards Play Network 2009", "PWP09", ExpansionSet.buildDate(2009, 1, 1), SetType.PROMOTIONAL); + super("Wizards Play Network 2009", "PW09", ExpansionSet.buildDate(2009, 1, 1), SetType.PROMOTIONAL); this.hasBoosters = false; this.hasBasicLands = false; diff --git a/Mage.Sets/src/mage/sets/WizardsPlayNetwork2010.java b/Mage.Sets/src/mage/sets/WizardsPlayNetwork2010.java index e76290fd14c..b29b28d0543 100644 --- a/Mage.Sets/src/mage/sets/WizardsPlayNetwork2010.java +++ b/Mage.Sets/src/mage/sets/WizardsPlayNetwork2010.java @@ -16,7 +16,7 @@ public class WizardsPlayNetwork2010 extends ExpansionSet { } private WizardsPlayNetwork2010() { - super("Wizards Play Network 2010", "PWP10", ExpansionSet.buildDate(2010, 1, 1), SetType.PROMOTIONAL); + super("Wizards Play Network 2010", "PW10", ExpansionSet.buildDate(2010, 1, 1), SetType.PROMOTIONAL); this.hasBoosters = false; this.hasBasicLands = false; diff --git a/Mage.Sets/src/mage/sets/WizardsPlayNetwork2011.java b/Mage.Sets/src/mage/sets/WizardsPlayNetwork2011.java index e628de4527e..2dab797f192 100644 --- a/Mage.Sets/src/mage/sets/WizardsPlayNetwork2011.java +++ b/Mage.Sets/src/mage/sets/WizardsPlayNetwork2011.java @@ -16,7 +16,7 @@ public class WizardsPlayNetwork2011 extends ExpansionSet { } private WizardsPlayNetwork2011() { - super("Wizards Play Network 2011", "PWP11", ExpansionSet.buildDate(2011, 1, 1), SetType.PROMOTIONAL); + super("Wizards Play Network 2011", "PW11", ExpansionSet.buildDate(2011, 1, 1), SetType.PROMOTIONAL); this.hasBoosters = false; this.hasBasicLands = false; diff --git a/Mage.Sets/src/mage/sets/WizardsPlayNetwork2012.java b/Mage.Sets/src/mage/sets/WizardsPlayNetwork2012.java index 2c732534d8d..3c6b3dab84d 100644 --- a/Mage.Sets/src/mage/sets/WizardsPlayNetwork2012.java +++ b/Mage.Sets/src/mage/sets/WizardsPlayNetwork2012.java @@ -16,7 +16,7 @@ public class WizardsPlayNetwork2012 extends ExpansionSet { } private WizardsPlayNetwork2012() { - super("Wizards Play Network 2012", "PWP12", ExpansionSet.buildDate(2012, 1, 1), SetType.PROMOTIONAL); + super("Wizards Play Network 2012", "PW12", ExpansionSet.buildDate(2012, 1, 1), SetType.PROMOTIONAL); this.hasBoosters = false; this.hasBasicLands = false; diff --git a/Mage.Sets/src/mage/sets/Worldwake.java b/Mage.Sets/src/mage/sets/Worldwake.java index 590a8c01aa5..743901f1d72 100644 --- a/Mage.Sets/src/mage/sets/Worldwake.java +++ b/Mage.Sets/src/mage/sets/Worldwake.java @@ -1,10 +1,16 @@ - package mage.sets; import mage.cards.ExpansionSet; +import mage.collation.BoosterCollator; +import mage.collation.BoosterStructure; +import mage.collation.CardRun; +import mage.collation.RarityConfiguration; import mage.constants.Rarity; import mage.constants.SetType; +import java.util.ArrayList; +import java.util.List; + /** * * @author BetaSteward_at_googlemail.com @@ -175,4 +181,56 @@ public final class Worldwake extends ExpansionSet { cards.add(new SetCardInfo("Wrexial, the Risen Deep", 120, Rarity.MYTHIC, mage.cards.w.WrexialTheRisenDeep.class)); } + @Override + public BoosterCollator createCollator() { + return new WorldwakeCollator(); + } +} + +// Booster collation info from https://www.lethe.xyz/mtg/collation/wwk.html +// Using USA collation for common/uncommon, rare collation inferred from other sets +class WorldwakeCollator implements BoosterCollator { + private final CardRun commonA = new CardRun(true, "69", "14", "46", "140", "91", "132", "103", "51", "8", "27", "125", "90", "137", "56", "95", "2", "24", "138", "91", "25", "128", "63", "101", "5", "140", "78", "27", "143", "14", "95", "90", "63", "117", "39", "143", "9", "58", "78", "142", "103", "46", "56", "9", "82", "125", "142", "117", "69", "25", "2", "83", "101", "132", "128", "58", "24", "82", "8", "104", "137", "51", "39", "138", "5", "83", "104"); + private final CardRun commonB = new CardRun(true, "55", "75", "112", "23", "29", "62", "88", "108", "6", "33", "126", "65", "73", "102", "4", "43", "60", "71", "99", "23", "42", "131", "62", "73", "100", "6", "29", "52", "71", "112", "18", "26", "126", "55", "77", "108", "10", "43", "52", "75", "99", "4", "26", "131", "65", "88", "100", "18", "42", "60", "77", "102", "10", "33"); + private final CardRun uncommonA = new CardRun(true, "13", "30", "50", "80", "54", "44", "116", "7", "79", "114", "41", "17", "50", "44", "92", "70", "116", "123", "13", "79", "30", "68", "7", "97", "123", "70", "80", "41", "13", "124", "114", "94", "68", "12", "41", "97", "45", "54", "79", "17", "114", "30", "80", "107", "7", "50", "45", "92", "124", "70", "107", "17", "94", "45", "12", "97", "124", "54", "92", "123", "44", "12", "116", "68", "107", "94"); + private final CardRun uncommonB = new CardRun(true, "129", "87", "61", "110", "145", "38", "16", "135", "89", "61", "111", "34", "19", "145", "87", "67", "38", "111", "89", "129", "36", "16", "110", "67", "86", "135", "61", "34", "16", "98", "66", "38", "11", "87", "135", "110", "36", "66", "129", "19", "86", "34", "98", "145", "11", "89", "67", "36", "111", "66", "19", "98", "11", "86"); + private final CardRun rare = new CardRun(false, "3", "15", "20", "21", "22", "28", "32", "35", "37", "40", "48", "49", "53", "57", "59", "64", "72", "74", "84", "85", "93", "105", "106", "113", "115", "118", "121", "122", "127", "130", "133", "134", "139", "141", "144"); + private final CardRun mythic = new CardRun(false, "1", "31", "47", "76", "81", "96", "109", "119", "120", "136"); + private final CardRun land = new CardRun(false, "ZEN_230", "ZEN_231", "ZEN_232", "ZEN_233", "ZEN_234", "ZEN_235", "ZEN_236", "ZEN_237", "ZEN_238", "ZEN_239", "ZEN_240", "ZEN_241", "ZEN_242", "ZEN_243", "ZEN_244", "ZEN_245", "ZEN_246", "ZEN_247", "ZEN_248", "ZEN_249"); + + private final BoosterStructure AAAAABBBBB = new BoosterStructure( + commonA, commonA, commonA, commonA, commonA, + commonB, commonB, commonB, commonB, commonB + ); + private final BoosterStructure AAAAAABBBB = new BoosterStructure( + commonA, commonA, commonA, commonA, commonA, commonA, + commonB, commonB, commonB, commonB + ); + private final BoosterStructure AAB = new BoosterStructure(uncommonA, uncommonA, uncommonB); + private final BoosterStructure ABB = new BoosterStructure(uncommonA, uncommonB, uncommonB); + private final BoosterStructure R1 = new BoosterStructure(rare); + private final BoosterStructure M1 = new BoosterStructure(mythic); + private final BoosterStructure L1 = new BoosterStructure(land); + + private final RarityConfiguration commonRuns = new RarityConfiguration(AAAAABBBBB, AAAAAABBBB); + // In order for equal numbers of each uncommon to exist, the average booster must contain: + // 1.65 A uncommons (33 / 20) + // 1.35 B uncommons (27 / 20) + // These numbers are the same for all sets with 40 uncommons in asymmetrical A/B print runs + private final RarityConfiguration uncommonRuns = new RarityConfiguration( + AAB, AAB, AAB, AAB, AAB, AAB, AAB, AAB, AAB, AAB, AAB, AAB, AAB, + ABB, ABB, ABB, ABB, ABB, ABB, ABB + ); + private final RarityConfiguration rareRuns = new RarityConfiguration(R1, R1, R1, R1, R1, R1, R1, M1); + private final RarityConfiguration landRuns = new RarityConfiguration(L1); + + @Override + public List makeBooster() { + List booster = new ArrayList<>(); + booster.addAll(commonRuns.getNext().makeRun()); + booster.addAll(uncommonRuns.getNext().makeRun()); + booster.addAll(rareRuns.getNext().makeRun()); + booster.addAll(landRuns.getNext().makeRun()); + return booster; + } } diff --git a/Mage.Tests/piperDecks/ThePrismaticPiper1.dck b/Mage.Tests/piperDecks/ThePrismaticPiper1.dck new file mode 100644 index 00000000000..4e6b8c1bb96 --- /dev/null +++ b/Mage.Tests/piperDecks/ThePrismaticPiper1.dck @@ -0,0 +1,3 @@ +NAME:The Prismatic Piper Test +99 [CMR:506] Island +SB: 1 [CMR:1] The Prismatic Piper diff --git a/Mage.Tests/piperDecks/ThePrismaticPiper2.dck b/Mage.Tests/piperDecks/ThePrismaticPiper2.dck new file mode 100644 index 00000000000..4dfc1188f4e --- /dev/null +++ b/Mage.Tests/piperDecks/ThePrismaticPiper2.dck @@ -0,0 +1,5 @@ +NAME:The Prismatic Piper Test +98 [CMR:506] Island +1 [CMR:508] Mountain +SB: 1 [CMR:1] The Prismatic Piper +SB: 1 [CMR:71] Ghost of Ramirez DePietro diff --git a/Mage.Tests/piperDecks/ThePrismaticPiper3.dck b/Mage.Tests/piperDecks/ThePrismaticPiper3.dck new file mode 100644 index 00000000000..3f468b783e2 --- /dev/null +++ b/Mage.Tests/piperDecks/ThePrismaticPiper3.dck @@ -0,0 +1,5 @@ +NAME:The Prismatic Piper Test +98 [CMR:506] Island +1 [CMR:508] Mountain +SB: 1 [CMR:1] The Prismatic Piper +SB: 1 [C16:34] Kraum, Ludevic's Opus diff --git a/Mage.Tests/piperDecks/ThePrismaticPiper4.dck b/Mage.Tests/piperDecks/ThePrismaticPiper4.dck new file mode 100644 index 00000000000..bd819cc4b15 --- /dev/null +++ b/Mage.Tests/piperDecks/ThePrismaticPiper4.dck @@ -0,0 +1,4 @@ +NAME:The Prismatic Piper Test +98 [CMR:508] Mountain +1 [CMR:506] Island +SB: 1 [CMR:1] The Prismatic Piper diff --git a/Mage.Tests/piperDecks/ThePrismaticPiper5.dck b/Mage.Tests/piperDecks/ThePrismaticPiper5.dck new file mode 100644 index 00000000000..4732bc05f07 --- /dev/null +++ b/Mage.Tests/piperDecks/ThePrismaticPiper5.dck @@ -0,0 +1,6 @@ +NAME:The Prismatic Piper Test +97 [CMR:508] Mountain +1 [CMR:506] Island +1 [CMR:504] Plains +SB: 1 [CMR:1] The Prismatic Piper +SB: 1 [C16:34] Kraum, Ludevic's Opus diff --git a/Mage.Tests/piperDecks/ThePrismaticPiper6.dck b/Mage.Tests/piperDecks/ThePrismaticPiper6.dck new file mode 100644 index 00000000000..3cbb6f6c772 --- /dev/null +++ b/Mage.Tests/piperDecks/ThePrismaticPiper6.dck @@ -0,0 +1,7 @@ +NAME:The Prismatic Piper Test +96 [CMR:508] Mountain +1 [CMR:506] Island +1 [CMR:504] Plains +1 [CMR:510] Forest +SB: 1 [CMR:1] The Prismatic Piper +SB: 1 [C16:34] Kraum, Ludevic's Opus diff --git a/Mage.Tests/piperDecks/ThePrismaticPiper7.dck b/Mage.Tests/piperDecks/ThePrismaticPiper7.dck new file mode 100644 index 00000000000..931f12eb6b3 --- /dev/null +++ b/Mage.Tests/piperDecks/ThePrismaticPiper7.dck @@ -0,0 +1,4 @@ +NAME:The Prismatic Piper Test +97 [CMR:508] Mountain +1 [CMR:510] Forest +SB: 2 [CMR:1] The Prismatic Piper diff --git a/Mage.Tests/piperDecks/ThePrismaticPiper8.dck b/Mage.Tests/piperDecks/ThePrismaticPiper8.dck new file mode 100644 index 00000000000..e17dcfac384 --- /dev/null +++ b/Mage.Tests/piperDecks/ThePrismaticPiper8.dck @@ -0,0 +1,7 @@ +NAME:The Prismatic Piper Test +97 [CMR:508] Mountain +1 [CMR:506] Island +1 [CMR:510] Forest +SB: 1 [CMR:1] The Prismatic Piper +SB: 1 [C16:34] Kraum, Ludevic's Opus +SB: 1 [IKO:225] Keruga, the Macrosage diff --git a/Mage.Tests/src/test/java/org/mage/test/AI/basic/TargetPriorityTest.java b/Mage.Tests/src/test/java/org/mage/test/AI/basic/TargetPriorityTest.java index 8c24dff2651..5810451be42 100644 --- a/Mage.Tests/src/test/java/org/mage/test/AI/basic/TargetPriorityTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/AI/basic/TargetPriorityTest.java @@ -231,7 +231,7 @@ public class TargetPriorityTest extends CardTestPlayerBaseAI { @Test public void test_targetAmount_NormalCase() { - Ability ability = new SimpleActivatedAbility(Zone.ALL, new DamageMultiEffect(3), new ManaCostsImpl("R")); + Ability ability = new SimpleActivatedAbility(Zone.ALL, new DamageMultiEffect(3), new ManaCostsImpl<>("{R}")); ability.addTarget(new TargetCreaturePermanentAmount(3)); addCustomCardWithAbility("damage 3", playerA, ability); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); @@ -258,7 +258,7 @@ public class TargetPriorityTest extends CardTestPlayerBaseAI { @Test public void test_targetAmount_BadCase() { // choose targets as enters battlefield (e.g. can't be canceled) - SpellAbility spell = new SpellAbility(new ManaCostsImpl("R"), "damage 3", Zone.HAND); + SpellAbility spell = new SpellAbility(new ManaCostsImpl<>("{R}"), "damage 3", Zone.HAND); Ability ability = new EntersBattlefieldTriggeredAbility(new DamageMultiEffect(3)); ability.addTarget(new TargetCreaturePermanentAmount(3)); addCustomCardWithSpell(playerA, spell, ability, CardType.ENCHANTMENT); @@ -293,7 +293,7 @@ public class TargetPriorityTest extends CardTestPlayerBaseAI { public void test_targetAmount_Performance() { int cardsMultiplier = 3; - Ability ability = new SimpleActivatedAbility(Zone.ALL, new DamageMultiEffect(3), new ManaCostsImpl("R")); + Ability ability = new SimpleActivatedAbility(Zone.ALL, new DamageMultiEffect(3), new ManaCostsImpl<>("{R}")); ability.addTarget(new TargetCreaturePermanentAmount(3)); addCustomCardWithAbility("damage 3", playerA, ability); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/PutOntoBattlefieldTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/PutOntoBattlefieldTest.java index e9a0c8e66e1..ae5b6e837e6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/PutOntoBattlefieldTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/PutOntoBattlefieldTest.java @@ -35,8 +35,8 @@ public class PutOntoBattlefieldTest extends CardTestPlayerBase { execute(); assertPowerToughness(playerA, "Kalonian Hydra", 2, 2); - assertPermanentCount(playerA, "Ooze", 1); - assertPowerToughness(playerA, "Ooze", 2, 2); + assertPermanentCount(playerA, "Ooze Token", 1); + assertPowerToughness(playerA, "Ooze Token", 2, 2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/PutToGraveyardTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/PutToGraveyardTest.java index df738625941..1d4c912815a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/PutToGraveyardTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/PutToGraveyardTest.java @@ -41,7 +41,7 @@ public class PutToGraveyardTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Silvercoat Lion", 0); assertExileCount(playerB, 0); assertGraveyardCount(playerB, "Silvercoat Lion", 1); - assertPermanentCount(playerA, "Eldrazi Scion", 1); + assertPermanentCount(playerA, "Eldrazi Scion Token", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/ReconfigureTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/ReconfigureTest.java new file mode 100644 index 00000000000..1b078a7378c --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/ReconfigureTest.java @@ -0,0 +1,105 @@ +package org.mage.test.cards.abilities.activated; + +import mage.abilities.keyword.TrampleAbility; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.SubType; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class ReconfigureTest extends CardTestPlayerBase { + + private static final String lion = "Silvercoat Lion"; + private static final String boar = "Bronzeplate Boar"; + private static final String aid = "Sigarda's Aid"; + private static final String paladin = "Puresteel Paladin"; + private static final String relic = "Darksteel Relic"; + + @Test + public void testAttach() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.BATTLEFIELD, playerA, lion); + addCard(Zone.BATTLEFIELD, playerA, boar); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reconfigure", lion); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertType(boar, CardType.CREATURE, false); + assertSubtype(boar, SubType.EQUIPMENT); + assertIsAttachedTo(playerA, boar, lion); + assertPowerToughness(playerA, lion, 2 + 3, 2 + 2); + assertAbility(playerA, lion, TrampleAbility.getInstance(), true); + } + + @Test + public void testAttachDetach() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 10); + addCard(Zone.BATTLEFIELD, playerA, lion); + addCard(Zone.BATTLEFIELD, playerA, boar); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reconfigure", lion); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{5}:"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertType(boar, CardType.CREATURE, true); + assertSubtype(boar, SubType.EQUIPMENT); + assertPowerToughness(playerA, lion, 2, 2); + assertAbility(playerA, lion, TrampleAbility.getInstance(), false); + } + + @Test + public void testSigardasAid() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + addCard(Zone.BATTLEFIELD, playerA, lion); + addCard(Zone.BATTLEFIELD, playerA, aid); + addCard(Zone.HAND, playerA, boar); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, boar); + addTarget(playerA, lion); + setChoice(playerA, true); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertType(boar, CardType.CREATURE, false); + assertSubtype(boar, SubType.EQUIPMENT); + assertIsAttachedTo(playerA, boar, lion); + assertPowerToughness(playerA, lion, 2 + 3, 2 + 2); + assertAbility(playerA, lion, TrampleAbility.getInstance(), true); + } + + @Test + public void testPuresteelPaladin() { + addCard(Zone.BATTLEFIELD, playerA, lion); + addCard(Zone.BATTLEFIELD, playerA, boar); + addCard(Zone.BATTLEFIELD, playerA, paladin); + addCard(Zone.BATTLEFIELD, playerA, relic, 2); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip", lion); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertType(boar, CardType.CREATURE, false); + assertSubtype(boar, SubType.EQUIPMENT); + assertIsAttachedTo(playerA, boar, lion); + assertPowerToughness(playerA, lion, 2 + 3, 2 + 2); + assertAbility(playerA, lion, TrampleAbility.getInstance(), true); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/TokenImplActivatedAbilityTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/TokenImplActivatedAbilityTest.java index a7c77f6eead..2ef4e8cbb62 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/TokenImplActivatedAbilityTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/TokenImplActivatedAbilityTest.java @@ -30,7 +30,7 @@ public class TokenImplActivatedAbilityTest extends CardTestPlayerBase { setStopAt(3, PhaseStep.PRECOMBAT_MAIN); execute(); - assertPermanentCount(playerA, "Elf Druid", 2); + assertPermanentCount(playerA, "Elf Druid Token", 2); assertPermanentCount(playerA, "Freyalise, Llanowar's Fury", 1); Assert.assertEquals("one green mana has to be in the mana pool", 1, playerA.getManaPool().get(ManaType.GREEN)); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/curses/CurseOfShallowGravesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/curses/CurseOfShallowGravesTest.java index 5e9fe33e016..ecbcae1b9ce 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/curses/CurseOfShallowGravesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/curses/CurseOfShallowGravesTest.java @@ -32,12 +32,12 @@ public class CurseOfShallowGravesTest extends CardTestPlayerBase { // turn 1 - attack without token attack(1, playerA, "Balduvian Bears", playerB); setChoice(playerA, false); // don't create token - checkPermanentCount("zombie 0", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Zombie", 0); + checkPermanentCount("zombie 0", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Zombie Token", 0); // turn 3 - attack with token attack(3, playerA, "Balduvian Bears", playerB); setChoice(playerA, true); // create token - checkPermanentCount("zombie 1", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Zombie", 1); + checkPermanentCount("zombie 1", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Zombie Token", 1); setStopAt(3, PhaseStep.END_TURN); execute(); @@ -61,12 +61,12 @@ public class CurseOfShallowGravesTest extends CardTestPlayerBase { // turn 1 - attack player without token attack(1, playerA, "Balduvian Bears", playerB); setChoice(playerA, false); // don't create token - checkPermanentCount("zombie 0", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Zombie", 0); + checkPermanentCount("zombie 0", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Zombie Token", 0); // turn 3 - attack planeswalker (no choices at all) attack(3, playerA, "Balduvian Bears", "Chandra Ablaze"); //setChoice(playerA, true); - checkPermanentCount("zombie 0", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Zombie", 0); + checkPermanentCount("zombie 0", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Zombie Token", 0); setStopAt(3, PhaseStep.END_TURN); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/DearlyDepartedTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/DearlyDepartedTest.java index 58d90b4d1ac..49bbfd8d2b6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/DearlyDepartedTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/DearlyDepartedTest.java @@ -39,8 +39,8 @@ public class DearlyDepartedTest extends CardTestPlayerBase { assertPowerToughness(playerA, "Thraben Doomsayer", 3, 3); - assertPermanentCount(playerA, "Human", 1); + assertPermanentCount(playerA, "Human Token", 1); // check that the +1/+1 counter was added to the token - assertPowerToughness(playerA, "Human", 2, 2); + assertPowerToughness(playerA, "Human Token", 2, 2); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/GatherSpecimensTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/GatherSpecimensTest.java index f02ce590df8..d46e4c57f55 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/GatherSpecimensTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/GatherSpecimensTest.java @@ -63,8 +63,8 @@ public class GatherSpecimensTest extends CardTestPlayerBase { execute(); - assertPermanentCount(playerA, "Spirit", 3); - assertPermanentCount(playerB, "Spirit", 0); + assertPermanentCount(playerA, "Spirit Token", 3); + assertPermanentCount(playerB, "Spirit Token", 0); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/BatterskullTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/BatterskullTest.java index b329b52f15b..648dc5f6847 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/BatterskullTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/BatterskullTest.java @@ -37,7 +37,7 @@ public class BatterskullTest extends CardTestPlayerBase { assertHandCount(playerA, 0); assertPermanentCount(playerA, "Batterskull", 1); - assertPermanentCount(playerA, "Phyrexian Germ", 1); - assertPowerToughness(playerA, "Phyrexian Germ", 4, 4); + assertPermanentCount(playerA, "Phyrexian Germ Token", 1); + assertPowerToughness(playerA, "Phyrexian Germ Token", 4, 4); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/SwordOfTheMeekTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/SwordOfTheMeekTest.java index d04dee810f2..49297182e06 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/SwordOfTheMeekTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/SwordOfTheMeekTest.java @@ -48,12 +48,12 @@ public class SwordOfTheMeekTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Chromatic Star", 1); - assertPermanentCount(playerA, "Myr", 1); - assertPowerToughness(playerA, "Myr", 2, 2); + assertPermanentCount(playerA, "Myr Token", 1); + assertPowerToughness(playerA, "Myr Token", 2, 2); assertPermanentCount(playerA, "Sword of the Meek", 0); assertPowerToughness(playerA, "Master of Etherium", 3, 3); - Permanent myr = getPermanent("Myr", playerA.getId()); + Permanent myr = getPermanent("Myr Token", playerA.getId()); Assert.assertTrue("Myr may not have any attachments", myr.getAttachments().isEmpty()); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BlitzTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BlitzTest.java new file mode 100644 index 00000000000..9bad1199a90 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BlitzTest.java @@ -0,0 +1,145 @@ +package org.mage.test.cards.abilities.keywords; + +import mage.abilities.Ability; +import mage.abilities.keyword.HasteAbility; +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 TheElk801 + */ +public class BlitzTest extends CardTestPlayerBase { + + private static final String withBlitz = " with Blitz"; + private static final String decoy = "Riveteers Decoy"; + private static final String underdog = "Tenacious Underdog"; + private static final String will = "Yawgmoth's Will"; + + private void assertBlitzed(String cardName, boolean isBlitzed) { + assertPermanentCount(playerA, cardName, 1); + Permanent permanent = getPermanent(cardName); + Assert.assertEquals( + "Permanent should " + (isBlitzed ? "" : "not ") + "have haste", isBlitzed, + permanent.hasAbility(HasteAbility.getInstance(), currentGame) + ); + Assert.assertEquals( + "Permanent should " + (isBlitzed ? "" : "not ") + "have card draw trigger", isBlitzed, + permanent + .getAbilities(currentGame) + .stream() + .map(Ability::getRule) + .anyMatch("When this creature dies, draw a card."::equals) + ); + } + + @Test + public void testBlitz() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); + addCard(Zone.HAND, playerA, decoy); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, decoy + withBlitz); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, decoy, 1); + assertBlitzed(decoy, true); + } + + @Test + public void testBlitzSacrificed() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); + addCard(Zone.HAND, playerA, decoy); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, decoy + withBlitz); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, decoy, 0); + assertGraveyardCount(playerA, decoy, 1); + assertHandCount(playerA, 1); + } + + @Test + public void testNoBlitz() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); + addCard(Zone.HAND, playerA, decoy); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, decoy); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, decoy, 1); + assertBlitzed(decoy, false); + } + + @Test + public void testTenaciousUnderdogNormal() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + addCard(Zone.GRAVEYARD, playerA, underdog); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, underdog); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + try { + execute(); + } catch (AssertionError e) { + Assert.assertEquals( + "Shouldn't be able to cast normally from graveyard", + "Missing CAST/ACTIVATE def for turn 1, step PRECOMBAT_MAIN, PlayerA\n" + + "Can't find available command - activate:Cast Tenacious Underdog " + + "(use checkPlayableAbility for \"non available\" checks)", e.getMessage() + ); + } + + assertGraveyardCount(playerA, underdog, 1); + assertLife(playerA, 20); + } + + @Test + public void testTenaciousUnderdogBlitz() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); + addCard(Zone.GRAVEYARD, playerA, underdog); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, underdog + withBlitz); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + assertAllCommandsUsed(); + + assertBlitzed(underdog, true); + assertLife(playerA, 20 - 2); + } + + @Test + public void testTenaciousUnderdogYawgmothsWill() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 5); + addCard(Zone.HAND, playerA, will); + addCard(Zone.GRAVEYARD, playerA, underdog); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, will); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, underdog); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + assertAllCommandsUsed(); + + assertBlitzed(underdog, false); + assertLife(playerA, 20); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BuybackTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BuybackTest.java index fc6f4b7629c..293ca054c73 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BuybackTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/BuybackTest.java @@ -143,7 +143,7 @@ public class BuybackTest extends CardTestPlayerBase { // bolt 2 - cast (R) and copy as free cast (R), return reiterate with buyback (RRR) castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerA); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}, {T}:"); - setChoice(playerA, "Reiterate"); // free cast + setChoice(playerA, true); // cast for free setChoice(playerA, true); // use buyback addTarget(playerA, "Lightning Bolt"); // copy target setChoice(playerA, false); // same bolt's target diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CascadeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CascadeTest.java index 9371c2d614d..ad970d74d39 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CascadeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CascadeTest.java @@ -42,7 +42,7 @@ public class CascadeTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Predatory Advantage", 1); assertPermanentCount(playerA, "Sejiri Merfolk", 1); - assertPermanentCount(playerA, "Lizard", 1); + assertPermanentCount(playerA, "Lizard Token", 1); } @@ -196,7 +196,7 @@ public class CascadeTest extends CardTestPlayerBase { assertLife(playerA, 15); assertHandCount(playerA, 5); - assertPermanentCount(playerA, "Demon", 0); + assertPermanentCount(playerA, "Demon Token", 0); assertPermanentCount(playerA, "Enlisted Wurm", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ChangelingTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ChangelingTest.java index 838fd0c6295..a1effc69a41 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ChangelingTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ChangelingTest.java @@ -83,7 +83,7 @@ public class ChangelingTest extends CardTestPlayerBase { * NOTE: As of 05/06/2017 this test is failing due to a bug in code. * See issue #3316 *

- * Kaseto, Orochi Archmage do not give Chameleon Colossus +2/+2 , even though Chameleon Colossus should have the "snake" type + * Kaseto, Orochi Archmage do not give Chameleon Colossus +2/+2 , even though Chameleon Colossus should have the "Snake Token" type */ @Test public void kasetoOrochiArchmageSnakeTest() { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CompleatedTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CompleatedTest.java new file mode 100644 index 00000000000..1bd21b656aa --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CompleatedTest.java @@ -0,0 +1,47 @@ +package org.mage.test.cards.abilities.keywords; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class CompleatedTest extends CardTestPlayerBase { + + private static final String tamiyo = "Tamiyo, Compleated Sage"; + + @Test + public void testLifePaid() { + addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 4); + addCard(Zone.HAND, playerA, tamiyo); + + setChoice(playerA, true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, tamiyo); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertCounterCount(playerA, tamiyo, CounterType.LOYALTY, 3); + } + + @Test + public void testManaPaid() { + addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 5); + addCard(Zone.HAND, playerA, tamiyo); + + setChoice(playerA, false); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, tamiyo); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertCounterCount(playerA, tamiyo, CounterType.LOYALTY, 5); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConspireTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConspireTest.java index e9d95cdb6cb..792b566d989 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConspireTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConspireTest.java @@ -48,7 +48,7 @@ public class ConspireTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertLife(playerB, 14); + assertLife(playerB, 20 - 3 - 3); assertGraveyardCount(playerA, "Burn Trail", 1); assertTapped("Goblin Roughrider", true); assertTapped("Raging Goblin", true); @@ -68,7 +68,7 @@ public class ConspireTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertLife(playerB, 17); + assertLife(playerB, 20 - 3); assertGraveyardCount(playerA, "Burn Trail", 1); assertTapped("Goblin Roughrider", false); assertTapped("Raging Goblin", false); @@ -90,8 +90,8 @@ public class ConspireTest extends CardTestPlayerBase { // cast with conspire castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerB); setChoice(playerA, true); // use conspire - setChoice(playerA, "Goblin Warrior"); - setChoice(playerA, "Goblin Warrior"); + setChoice(playerA, "Goblin Warrior Token"); + setChoice(playerA, "Goblin Warrior Token"); setChoice(playerA, false); // keep targets setStrictChooseMode(true); @@ -101,12 +101,70 @@ public class ConspireTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Wort, the Raidmother", 1); assertGraveyardCount(playerA, "Lightning Bolt", 1); - assertLife(playerB, 14); + assertLife(playerB, 20 - 3 - 3); } @Test - public void testWortTheRaidmotherWithConspireSpell() { + public void testWortTheRaidmotherTwoSpells() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8); + addCard(Zone.BATTLEFIELD, playerA, "Raging Goblin", 2); + // When Wort, the Raidmother enters the battlefield, put two 1/1 red and green Goblin Warrior creature tokens onto the battlefield. + // Each red or green instant or sorcery spell you cast has conspire. + // (As you cast the spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose new targets for the copy.) + addCard(Zone.HAND, playerA, "Wort, the Raidmother"); + addCard(Zone.HAND, playerA, "Lightning Bolt"); + addCard(Zone.HAND, playerA, "Shock"); + + // prepare goblins + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wort, the Raidmother");// {4}{R/G}{R/G} + + // cast with conspire + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + setChoice(playerA, true); // use conspire + setChoice(playerA, "Goblin Warrior Token"); + setChoice(playerA, "Goblin Warrior Token"); + setChoice(playerA, false); // keep targets + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Shock", playerB); + setChoice(playerA, false); // don't use conspire + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Wort, the Raidmother", 1); + assertGraveyardCount(playerA, "Lightning Bolt", 1); + assertTapped("Raging Goblin", false); + assertLife(playerB, 20 - 3 - 3 - 2); + + } + + @Test + public void testWortTheRaidmotherWithConspireSpellOnce() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 10); + // When Wort, the Raidmother enters the battlefield, put two 1/1 red and green Goblin Warrior creature tokens onto the battlefield. + // Each red or green instant or sorcery spell you cast has conspire. + // (As you cast the spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose new targets for the copy.) + addCard(Zone.HAND, playerA, "Wort, the Raidmother"); + addCard(Zone.HAND, playerA, "Burn Trail"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wort, the Raidmother"); // {4}{R/G}{R/G} + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Burn Trail", playerB); + setChoice(playerA, true); // use Conspire from Burn Trail itself + setChoice(playerA, false); // don't use Conspire gained from Wort, the Raidmother + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertPermanentCount(playerA, "Wort, the Raidmother", 1); + assertLife(playerB, 20 - 3 - 3); + assertLife(playerA, 20); + assertGraveyardCount(playerA, "Burn Trail", 1); + } + + @Test + public void testWortTheRaidmotherWithConspireSpellTwice() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 10); addCard(Zone.BATTLEFIELD, playerA, "Raging Goblin", 2); // When Wort, the Raidmother enters the battlefield, put two 1/1 red and green Goblin Warrior creature tokens onto the battlefield. @@ -124,12 +182,66 @@ public class ConspireTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.END_TURN); execute(); assertPermanentCount(playerA, "Wort, the Raidmother", 1); - assertLife(playerB, 11); + assertLife(playerB, 20 - 3 - 3 - 3); assertLife(playerA, 20); assertGraveyardCount(playerA, "Burn Trail", 1); } + @Test + public void testWortTheRaidmotherWithSakashimaOnce() { + addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 11); + // When Wort, the Raidmother enters the battlefield, put two 1/1 red and green Goblin Warrior creature tokens onto the battlefield. + // Each red or green instant or sorcery spell you cast has conspire. + // (As you cast the spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose new targets for the copy.) + addCard(Zone.HAND, playerA, "Wort, the Raidmother"); + addCard(Zone.HAND, playerA, "Sakashima the Impostor"); + addCard(Zone.HAND, playerA, "Lightning Bolt"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wort, the Raidmother"); // {4}{R/G}{R/G} + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sakashima the Impostor"); // {2}{U}{U} + setChoice(playerA, "Wort, the Raidmother"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + setChoice(playerA, true); // use Conspire gained from Wort, the Raidmother + setChoice(playerA, false); // don't use Conspire gained from Sakashima the Imposter + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertPermanentCount(playerA, "Wort, the Raidmother", 1); + assertPermanentCount(playerA, "Sakashima the Impostor", 1); + assertLife(playerB, 20 - 3 - 3); + assertLife(playerA, 20); + assertGraveyardCount(playerA, "Lightning Bolt", 1); + } + + @Test + public void testWortTheRaidmotherWithSakashimaTwice() { + addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 11); + // When Wort, the Raidmother enters the battlefield, put two 1/1 red and green Goblin Warrior creature tokens onto the battlefield. + // Each red or green instant or sorcery spell you cast has conspire. + // (As you cast the spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose new targets for the copy.) + addCard(Zone.HAND, playerA, "Wort, the Raidmother"); + addCard(Zone.HAND, playerA, "Sakashima the Impostor"); + addCard(Zone.HAND, playerA, "Lightning Bolt"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wort, the Raidmother"); // {4}{R/G}{R/G} + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sakashima the Impostor"); // {2}{U}{U} + setChoice(playerA, "Wort, the Raidmother"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + setChoice(playerA, true); // use Conspire gained from Wort, the Raidmother + setChoice(playerA, true); // use Conspire gained from Sakashima the Imposter + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertPermanentCount(playerA, "Wort, the Raidmother", 1); + assertPermanentCount(playerA, "Sakashima the Impostor", 1); + assertLife(playerB, 20 - 3 - 3 - 3); + assertLife(playerA, 20); + assertGraveyardCount(playerA, "Lightning Bolt", 1); + } + @Test public void testConspire_User() { // Burn Trail deals 3 damage to any target. @@ -151,7 +263,7 @@ public class ConspireTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertGraveyardCount(playerA, "Burn Trail", 1); - assertLife(playerB, 20 - 3 * 2); + assertLife(playerB, 20 - 3 - 3); assertTapped("Goblin Assailant", true); } @@ -176,7 +288,7 @@ public class ConspireTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertGraveyardCount(playerA, "Burn Trail", 1); - assertLife(playerB, 20 - 3 * 2); + assertLife(playerB, 20 - 3 - 3); assertTapped("Goblin Assailant", true); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConvokeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConvokeTest.java index 4f5a181ad8e..4b242e1d88c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConvokeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ConvokeTest.java @@ -280,7 +280,7 @@ public class ConvokeTest extends CardTestPlayerBaseWithAIHelps { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Call the Scions"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Call the Scions"); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); - checkPermanentCount("scions", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Eldrazi Scion", 4); + checkPermanentCount("scions", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Eldrazi Scion Token", 4); // test case 1 - playable abilities must not show it as playable (not work, cause we don't known real payment order before payment) //checkPlayableAbility("can't use convoke", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Will-Forged Golem", false); @@ -363,6 +363,6 @@ public class ConvokeTest extends CardTestPlayerBaseWithAIHelps { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Soldier", 1); + assertPermanentCount(playerA, "Soldier Token", 1); } } \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CrewTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CrewTest.java index dfd0f46cba9..31ac01d196a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CrewTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CrewTest.java @@ -6,6 +6,7 @@ import mage.constants.CardType; import mage.constants.PhaseStep; import mage.constants.SubType; import mage.constants.Zone; +import mage.counters.CounterType; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -15,23 +16,38 @@ import org.mage.test.serverside.base.CardTestPlayerBase; // http://magic.wizards.com/en/articles/archive/feature/kaladesh-mechanics-2016-09-02 public class CrewTest extends CardTestPlayerBase { + private static final String lion = "Silvercoat Lion"; + private static final String caravan = "Cultivator's Caravan"; + private static final String fanatic = "Speedway Fanatic"; + private static final String copter = "Smuggler's Copter"; + private static final String evacuation = "Evacuation"; + private static final String ox = "Giant Ox"; + private static final String plow = "Colossal Plow"; + private static final String kotori = "Kotori, Pilot Prodigy"; + private static final String crusher = "Irontread Crusher"; + private static final String mechanic = "Hotshot Mechanic"; + private static final String express = "Aradara Express"; + private static final String heart = "Heart of Kiran"; + private static final String jace = "Jace Beleren"; + @Test public void crewBasicTest() { // {T}: Add one mana of any color. // Crew 3 (Tap any number of creatures you control with total power 3 or more: This Vehicle becomes an artifact creature until end of turn.)"; - addCard(Zone.BATTLEFIELD, playerA, "Cultivator's Caravan", 1); + addCard(Zone.BATTLEFIELD, playerA, caravan, 1); - addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 2); + addCard(Zone.BATTLEFIELD, playerA, lion, 2); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crew 3"); - setChoice(playerA, "Silvercoat Lion^Silvercoat Lion"); + setChoice(playerA, lion + "^" + lion); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); - assertTappedCount("Silvercoat Lion", true, 2); - assertPowerToughness(playerA, "Cultivator's Caravan", 5, 5); - assertType("Cultivator's Caravan", CardType.CREATURE, SubType.VEHICLE); + assertTappedCount(lion, true, 2); + assertPowerToughness(playerA, caravan, 5, 5); + assertType(caravan, CardType.CREATURE, SubType.VEHICLE); } @Test @@ -39,56 +55,107 @@ public class CrewTest extends CardTestPlayerBase { // Flying // Whenever Smuggler's Copter attacks or blocks, you may draw a card. If you do, discard a card. // Crew 1 (Tap any number of creatures you control with total power 3 or more: This Vehicle becomes an artifact creature until end of turn.)"; - addCard(Zone.BATTLEFIELD, playerA, "Smuggler's Copter", 1); + addCard(Zone.BATTLEFIELD, playerA, copter, 1); - addCard(Zone.BATTLEFIELD, playerA, "Speedway Fanatic", 1); + addCard(Zone.BATTLEFIELD, playerA, fanatic, 1); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crew 1"); - setChoice(playerA, "Speedway Fanatic"); + setChoice(playerA, fanatic); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); - assertTappedCount("Speedway Fanatic", true, 1); - assertPowerToughness(playerA, "Smuggler's Copter", 3, 3); - assertAbility(playerA, "Smuggler's Copter", HasteAbility.getInstance(), true); - assertType("Smuggler's Copter", CardType.CREATURE, SubType.VEHICLE); + assertTappedCount(fanatic, true, 1); + assertPowerToughness(playerA, copter, 3, 3); + assertAbility(playerA, copter, HasteAbility.getInstance(), true); + assertType(copter, CardType.CREATURE, SubType.VEHICLE); } @Test public void testThatBouncingACrewedVehicleWillUncrewIt() { - addCard(Zone.BATTLEFIELD, playerA, "Smuggler's Copter", 1); - addCard(Zone.BATTLEFIELD, playerA, "Speedway Fanatic", 1); + addCard(Zone.BATTLEFIELD, playerA, copter, 1); + addCard(Zone.BATTLEFIELD, playerA, fanatic, 1); addCard(Zone.BATTLEFIELD, playerA, "Island", 7); - addCard(Zone.HAND, playerA, "Evacuation", 1); + addCard(Zone.HAND, playerA, evacuation, 1); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crew 1"); - setChoice(playerA, "Speedway Fanatic"); + setChoice(playerA, fanatic); // Return all creatures to there owners hands - castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Evacuation"); + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, evacuation); // (Re)Cast Smugglers Copter - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Smuggler's Copter"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, copter); setStopAt(1, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); // Only crewed vehicles have card type creature - assertNotType("Smuggler's Copter", CardType.CREATURE); + assertNotType(copter, CardType.CREATURE); } @Test public void testGiantOx() { - addCard(Zone.BATTLEFIELD, playerA, "Giant Ox"); - addCard(Zone.BATTLEFIELD, playerA, "Colossal Plow"); + addCard(Zone.BATTLEFIELD, playerA, ox); + addCard(Zone.BATTLEFIELD, playerA, plow); activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crew"); setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); + assertAllCommandsUsed(); - assertTapped("Giant Ox", true); - assertType("Colossal Plow", CardType.CREATURE, true); + assertTapped(ox, true); + assertType(plow, CardType.CREATURE, true); + } + + @Test + public void testGrantedAbility() { + addCard(Zone.BATTLEFIELD, playerA, kotori); + addCard(Zone.BATTLEFIELD, playerA, crusher); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crew 2"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertTapped(kotori, true); + assertType(crusher, CardType.ARTIFACT, true); + assertType(crusher, CardType.CREATURE, SubType.VEHICLE); + } + + @Test + public void testHotshotMechanic() { + addCard(Zone.BATTLEFIELD, playerA, mechanic); + addCard(Zone.BATTLEFIELD, playerA, express); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crew 4"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertTapped(mechanic, true); + assertType(express, CardType.ARTIFACT, true); + assertType(express, CardType.CREATURE, SubType.VEHICLE); + } + + @Test + public void testHeartOfKiran() { + addCard(Zone.BATTLEFIELD, playerA, jace); + addCard(Zone.BATTLEFIELD, playerA, heart); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Crew 3"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertCounterCount(playerA, jace, CounterType.LOYALTY, 2); + assertType(heart, CardType.ARTIFACT, true); + assertType(heart, CardType.CREATURE, SubType.VEHICLE); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DashTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DashTest.java index 290b579e918..0691e76bbe9 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DashTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DashTest.java @@ -8,7 +8,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author BetaSteward */ public class DashTest extends CardTestPlayerBase { @@ -31,7 +30,6 @@ public class DashTest extends CardTestPlayerBase { * may cast this spell for its dash cost. If you do, it gains haste, and * it's returned from the battlefield to its owner's hand at the beginning * of the next end step.) - * */ @Test public void testDash() { @@ -117,4 +115,37 @@ public class DashTest extends CardTestPlayerBase { assertHandCount(playerA, "Screamreach Brawler", 0); assertAbility(playerA, "Screamreach Brawler", HasteAbility.getInstance(), true); } + + @Test + public void testWarbringerCostReduction() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.BATTLEFIELD, playerA, "Warbringer"); + addCard(Zone.HAND, playerA, "Warbringer"); + + setStrictChooseMode(true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Warbringer"); + setChoice(playerA, true); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Warbringer", 2); + assertHandCount(playerA, "Warbringer", 0); + } + + @Test + public void testRegularCostReduction() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.BATTLEFIELD, playerA, "Ruby Medallion"); + addCard(Zone.HAND, playerA, "Screamreach Brawler"); + + setStrictChooseMode(true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Screamreach Brawler"); + setChoice(playerA, true); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Ruby Medallion", 1); + assertPermanentCount(playerA, "Screamreach Brawler", 1); + assertHandCount(playerA, "Screamreach Brawler", 0); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DecayedTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DecayedTest.java index 63f082fac31..b76f0cfad21 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DecayedTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DecayedTest.java @@ -14,13 +14,13 @@ public class DecayedTest extends CardTestPlayerBase { setStrictChooseMode(true); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Falcon Abomination"); - attack(3, playerA, "Zombie"); + attack(3, playerA, "Zombie Token"); setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); execute(); assertAllCommandsUsed(); assertPermanentCount(playerA, "Falcon Abomination", 1); - assertPermanentCount(playerA, "Zombie", 0); + assertPermanentCount(playerA, "Zombie Token", 0); } @Test diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DeliriumTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DeliriumTest.java index 09485c1c5a3..c1616f25ec2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DeliriumTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DeliriumTest.java @@ -42,7 +42,7 @@ public class DeliriumTest extends CardTestPlayerBaseWithAIHelps { assertExileCount(playerA, "Balduvian Bears", 4); assertGraveyardCount(playerA, "Descend upon the Sinful", 1); - assertPermanentCount(playerA, "Angel", 0); + assertPermanentCount(playerA, "Angel Token", 0); } @@ -75,7 +75,7 @@ public class DeliriumTest extends CardTestPlayerBaseWithAIHelps { assertExileCount(playerA, "Balduvian Bears", 4); assertGraveyardCount(playerA, "Descend upon the Sinful", 1); - assertPermanentCount(playerA, "Angel", 1); + assertPermanentCount(playerA, "Angel Token", 1); } @@ -117,7 +117,7 @@ public class DeliriumTest extends CardTestPlayerBaseWithAIHelps { assertGraveyardCount(playerA, "Spirit Mantle", 1); assertGraveyardCount(playerA, "Descend upon the Sinful", 1); - assertPermanentCount(playerA, "Angel", 0); + assertPermanentCount(playerA, "Angel Token", 0); } @@ -151,7 +151,7 @@ public class DeliriumTest extends CardTestPlayerBaseWithAIHelps { assertExileCount(playerA, "Balduvian Bears", 4); assertGraveyardCount(playerA, "Descend upon the Sinful", 1); - assertPermanentCount(playerA, "Angel", 0); + assertPermanentCount(playerA, "Angel Token", 0); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DredgeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DredgeTest.java index dd5de817944..ebfe9b4461b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DredgeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DredgeTest.java @@ -46,7 +46,7 @@ public class DredgeTest extends CardTestPlayerBase { assertHandCount(playerA, "Silvercoat Lion", 1); assertGraveyardCount(playerA, "Silvercoat Lion", 3); - assertPermanentCount(playerA, "Zombie", 1); // May only be one creature + assertPermanentCount(playerA, "Zombie Token", 1); // May only be one creature } @@ -78,7 +78,7 @@ public class DredgeTest extends CardTestPlayerBase { assertHandCount(playerB, "Stinkweed Imp", 1); assertGraveyardCount(playerB, "Silvercoat Lion", 5); - assertPermanentCount(playerB, "Zombie", 1); // May only be one creature + assertPermanentCount(playerB, "Zombie Token", 1); // May only be one creature } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EpicTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EpicTest.java index 95a61e6cc4a..5ffa218c58a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EpicTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EpicTest.java @@ -23,7 +23,7 @@ public class EpicTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Snake", 3 + 3 + 4 + 5); + assertPermanentCount(playerA, "Snake Token", 3 + 3 + 4 + 5); assertPermanentCount(playerA, "Forest", 8); } @@ -41,7 +41,7 @@ public class EpicTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Snake", 2 * (3 + 3 + 4 + 5)); + assertPermanentCount(playerA, "Snake Token", 2 * (3 + 3 + 4 + 5)); assertPermanentCount(playerA, "Tropical Island", 10); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java index d6c8ac6eb63..f0ccc1ce210 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java @@ -198,7 +198,7 @@ public class FlashbackTest extends CardTestPlayerBase { execute(); assertPermanentCount(playerA, "Snapcaster Mage", 1); - assertPermanentCount(playerA, "Kor Ally", 4); + assertPermanentCount(playerA, "Kor Ally Token", 4); assertExileCount("Unified Front", 1); } @@ -435,7 +435,7 @@ public class FlashbackTest extends CardTestPlayerBase { execute(); assertExileCount(playerA, fCatBlitz, 1); - assertPermanentCount(playerA, "Elemental Cat", 1); + assertPermanentCount(playerA, "Elemental Cat Token", 1); assertGraveyardCount(playerA, mountain, 1); } @@ -471,7 +471,7 @@ public class FlashbackTest extends CardTestPlayerBase { assertTapped(yOx, true); assertTapped(wKnight, true); assertExileCount(playerA, bScreech, 1); // this fails, but the creatures are tapped as part of paying the cost - assertPermanentCount(playerA, "Bird", 2); // if you comment out the above line, this is failing as well + assertPermanentCount(playerA, "Bird Token", 2); // if you comment out the above line, this is failing as well } /* @@ -617,7 +617,7 @@ public class FlashbackTest extends CardTestPlayerBase { checkPlayableAbility("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Flashback {1}{U}", true); runCode("test", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { long flashbackCount = player.getPlayable(game, true).stream() - .filter(ability -> ability instanceof FlashbackAbility) + .filter(FlashbackAbility.class::isInstance) .count(); Assert.assertEquals("must have only two playable abilities without duplicates", 2, flashbackCount); }); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ForetellTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ForetellTest.java new file mode 100644 index 00000000000..4ed228e957b --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ForetellTest.java @@ -0,0 +1,85 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.mage.test.cards.abilities.keywords; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author jeffwadsworth + */ +public class ForetellTest extends CardTestPlayerBase { + + @Test + public void testForetellKeyword() { + // verify that the foretold card is in the exile zone + setStrictChooseMode(true); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); // Foretell cost 2 mana + addCard(Zone.HAND, playerA, "Behold the Multiverse"); // (Instant) Scry 2 and draw 2 cards + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fore"); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertAllCommandsUsed(); + assertExileCount(playerA, "Behold the Multiverse", 1); + + } + + @Test + public void testForetoldCastSameTurnAsForetold() { + // verify that foretold card can't be cast the same turn it was foretold + setStrictChooseMode(true); + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); // Foretell cost 2 mana and {1}{U} for foretell cast from exile + addCard(Zone.HAND, playerA, "Behold the Multiverse"); // (Instant) Scry 2 and draw 2 cards + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fore"); + checkPlayableAbility("Can't cast turn it was forefold", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Foretell {1}{U}", false); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAllCommandsUsed(); + assertExileCount(playerA, "Behold the Multiverse", 1); // still in exile because it can't be cast the same turn + } + + @Test + public void testForetoldCastOtherTurnAsForetold() { + // verify that foretold card can be cast on a turn other than the one it was foretold + setStrictChooseMode(true); + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); // Foretell cost 2 mana and {1}{U} for foretell cast from exile + addCard(Zone.HAND, playerA, "Behold the Multiverse"); // (Instant) Scry 2 and draw 2 cards + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fore"); + activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Foretell {1}{U}"); + setStopAt(2, PhaseStep.END_TURN); + execute(); + + assertAllCommandsUsed(); + assertExileCount(playerA, "Behold the Multiverse", 0); // no longer in exile + assertGraveyardCount(playerA, "Behold the Multiverse", 1); // now in graveyard + assertHandCount(playerA, 2); // 2 cards drawn + } + + @Test + public void testDreamDevourerTrigger() { + // Issue #8876 + setStrictChooseMode(true); + addCard(Zone.BATTLEFIELD, playerA, "Dream Devourer", 1); // if a card is foretelled, this gets +2 power + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); // 3 mana for suspend and 2 for foretell + addCard(Zone.HAND, playerA, "Sol Talisman", 1); // Suspend card + addCard(Zone.HAND, playerA, "Lightning Bolt", 1); // card to foretell + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Susp"); // suspend the Sol Talisman + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fore"); // foretell the Lightning Bolt + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertAllCommandsUsed(); + assertExileCount(playerA, "Sol Talisman", 1); // suspend card in exile + assertExileCount(playerA, "Lightning Bolt", 1); // foretold card in exile + assertPowerToughness(playerA, "Dream Devourer", 2, 3); // +2 power boost from trigger due to foretell of Lightning Bolt + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/GoadTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/GoadTest.java index e0729305b41..ed3f413b762 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/GoadTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/GoadTest.java @@ -1,6 +1,5 @@ package org.mage.test.cards.abilities.keywords; -import java.io.FileNotFoundException; import mage.constants.MultiplayerAttackOption; import mage.constants.PhaseStep; import mage.constants.RangeOfInfluence; @@ -10,16 +9,29 @@ import mage.game.Game; import mage.game.GameException; import mage.game.mulligan.MulliganType; import mage.game.permanent.Permanent; +import mage.players.Player; import org.junit.Assert; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestMultiPlayerBase; +import java.io.FileNotFoundException; +import java.util.Arrays; +import java.util.UUID; +import java.util.stream.Collectors; + /** - * * @author LevelX2 */ public class GoadTest extends CardTestMultiPlayerBase { + private static final String marisi = "Marisi, Breaker of the Coil"; + private static final String griffin = "Abbey Griffin"; + private static final String ray = "Ray of Command"; + private static final String homunculus = "Jeering Homunculus"; + private static final String lion = "Silvercoat Lion"; + private static final String archon = "Blazing Archon"; + @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, MulliganType.GAME_DEFAULT.getMulligan(0), 40); @@ -31,85 +43,155 @@ public class GoadTest extends CardTestMultiPlayerBase { return game; } + private void assertAttacking(String attacker, TestPlayer... players) { + Assert.assertTrue("At least one player should be provided", players.length > 0); + Permanent permanent = getPermanent(attacker); + Assert.assertTrue("Creature should be tapped", permanent.isTapped()); + Assert.assertTrue("Creature should be attacking", permanent.isAttacking()); + UUID defenderId = currentGame.getCombat().getDefenderId(permanent.getId()); + Assert.assertTrue( + "Creature should be attacking one the following players: " + + Arrays + .stream(players) + .map(Player::getName) + .reduce((a, b) -> a + ", " + b) + .orElse(""), + Arrays.stream(players) + .map(TestPlayer::getId) + .anyMatch(defenderId::equals) + ); + } + + private void assertGoaded(String attacker, TestPlayer... players) { + Assert.assertTrue("At least one player should be provided", players.length > 0); + Permanent permanent = getPermanent(attacker); + Assert.assertEquals( + "Creature should be goaded by " + + Arrays + .stream(players) + .map(Player::getName) + .reduce((a, b) -> a + ", " + b).orElse(""), + permanent.getGoadingPlayers(), + Arrays.stream(players) + .map(TestPlayer::getId) + .collect(Collectors.toSet()) + ); + } + @Test - public void goadWithOwnedCreatureTest() { - // Your opponents can't cast spells during combat. - // Whenever a creature you control deals combat damage to a player, goad each creature that player controls - // (Until your next turn, that creature attacks each combat if able and attacks a player other than you if able.) - addCard(Zone.BATTLEFIELD, playerD, "Marisi, Breaker of the Coil", 1); // Creature 5/4 + public void testCantAttackGoadingPlayer() { + addCard(Zone.HAND, playerA, homunculus); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerD, lion); - addCard(Zone.BATTLEFIELD, playerC, "Abbey Griffin", 3); // Creature 2/2 + addTarget(playerA, lion); + setChoice(playerA, "Yes"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, homunculus); - attack(2, playerD, "Marisi, Breaker of the Coil", playerC); - - setStopAt(3, PhaseStep.BEGIN_COMBAT); - - setStrictChooseMode(true); + setStopAt(2, PhaseStep.DECLARE_BLOCKERS); execute(); assertAllCommandsUsed(); - Permanent griffinPermanent = getPermanent("Abbey Griffin"); - - Assert.assertFalse("Griffin can attack playerD but should not be able", - griffinPermanent.canAttack(playerD.getId(), currentGame)); - Assert.assertTrue("Griffin can't attack playerA but should be able", - griffinPermanent.canAttack(playerA.getId(), currentGame)); - Assert.assertTrue("Griffin can't attack playerB but should be able", - griffinPermanent.canAttack(playerB.getId(), currentGame)); - - assertLife(playerC, 35); - assertLife(playerD, 40); // player D can not be attacked from C because the creatures are goaded - assertLife(playerA, 40); - assertLife(playerB, 40); - + assertGoaded(lion, playerA); + assertAttacking(lion, playerB, playerC); } - /** - * In a game of commander, my opponent gained control of Marisi, Breaker of - * Coils (until end of turn) and did combat damage to another player. This - * caused the creatures damaged by Marisi's controller to be goaded. - * However, when the goaded creatures went to attack, they could not attack - * me but could attack the (former) controller of Marisi. - */ @Test - public void goadWithNotOwnedCreatureTest() { - // Your opponents can't cast spells during combat. - // Whenever a creature you control deals combat damage to a player, goad each creature that player controls - // (Until your next turn, that creature attacks each combat if able and attacks a player other than you if able.) - addCard(Zone.BATTLEFIELD, playerA, "Marisi, Breaker of the Coil", 1); // Creature 5/4 + public void testCanOnlyAttackOnePlayer() { + addCard(Zone.HAND, playerA, homunculus); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerD, lion); + addCard(Zone.BATTLEFIELD, playerB, archon); - // Untap target creature an opponent controls and gain control of it until end of turn. - // That creature gains haste until end of turn. - // When you lose control of the creature, tap it. - addCard(Zone.HAND, playerD, "Ray of Command"); // Instant {3}{U} - addCard(Zone.BATTLEFIELD, playerD, "Island", 4); + addTarget(playerA, lion); + setChoice(playerA, "Yes"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, homunculus); - addCard(Zone.BATTLEFIELD, playerC, "Silvercoat Lion", 1); // Creature 2/2 - - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerD, "Ray of Command", "Marisi, Breaker of the Coil"); - - attack(2, playerD, "Marisi, Breaker of the Coil", playerC); - - setStopAt(3, PhaseStep.BEGIN_COMBAT); - setStrictChooseMode(true); + setStopAt(2, PhaseStep.DECLARE_BLOCKERS); execute(); - assertAllCommandsUsed(); - assertGraveyardCount(playerD, "Ray of Command", 1); - assertPermanentCount(playerA, "Marisi, Breaker of the Coil", 1); - - Permanent lion = getPermanent("Silvercoat Lion", playerC); - - Assert.assertFalse("Silvercoat lion shouldn't be able to attack player D but can", lion.canAttack(playerD.getId(), currentGame)); - Assert.assertTrue("Silvercoat lion should be able to attack player A but can't", lion.canAttack(playerA.getId(), currentGame)); - Assert.assertTrue("Silvercoat lion should be able to attack player B but can't", lion.canAttack(playerB.getId(), currentGame)); - - assertLife(playerD, 40); - assertLife(playerC, 35); - assertLife(playerA, 40); - assertLife(playerB, 40); - + assertGoaded(lion, playerA); + assertAttacking(lion, playerC); } + @Test + public void testMustAttackGoader() { + addCard(Zone.HAND, playerA, homunculus); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerD, lion); + addCard(Zone.BATTLEFIELD, playerB, archon); + addCard(Zone.BATTLEFIELD, playerC, archon); + + addTarget(playerA, lion); + setChoice(playerA, "Yes"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, homunculus); + + setStopAt(2, PhaseStep.DECLARE_BLOCKERS); + execute(); + assertAllCommandsUsed(); + + assertGoaded(lion, playerA); + assertAttacking(lion, playerA); + } + + @Test + public void testMultipleGoad() { + addCard(Zone.HAND, playerA, homunculus); + addCard(Zone.HAND, playerD, homunculus); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerD, "Island", 2); + addCard(Zone.BATTLEFIELD, playerC, lion); + + addTarget(playerA, lion); + setChoice(playerA, "Yes"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, homunculus); + + addTarget(playerD, lion); + setChoice(playerD, "Yes"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerD, homunculus); + + setStopAt(3, PhaseStep.DECLARE_BLOCKERS); + execute(); + assertAllCommandsUsed(); + + assertGoaded(lion, playerA, playerD); + assertAttacking(lion, playerB); + } + + @Test + public void testMultipleGoadRestriction() { + addCard(Zone.HAND, playerA, homunculus); + addCard(Zone.HAND, playerD, homunculus); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerD, "Island", 2); + addCard(Zone.BATTLEFIELD, playerB, archon); + addCard(Zone.BATTLEFIELD, playerC, lion); + + addTarget(playerA, lion); + setChoice(playerA, "Yes"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, homunculus); + + addTarget(playerD, lion); + setChoice(playerD, "Yes"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerD, homunculus); + + setStopAt(3, PhaseStep.DECLARE_BLOCKERS); + execute(); + assertAllCommandsUsed(); + + assertGoaded(lion, playerA, playerD); + assertAttacking(lion, playerA, playerD); + } + + @Test + public void testRegularCombatRequirement() { + addCard(Zone.BATTLEFIELD, playerA, "Berserkers of Blood Ridge"); + + setStopAt(1, PhaseStep.DECLARE_BLOCKERS); + execute(); + assertAllCommandsUsed(); + + assertAttacking("Berserkers of Blood Ridge", playerB, playerC, playerD); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/InvestigateTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/InvestigateTest.java index fe22f4c6e50..981ab6fc6e2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/InvestigateTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/InvestigateTest.java @@ -37,7 +37,7 @@ public class InvestigateTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Briarbridge Patrol", 1); assertHandCount(playerA, 2); // 1 from sacrificed Clue and 1 from draw of turn 3 - assertPermanentCount(playerA, "Clue", 1); + assertPermanentCount(playerA, "Clue Token", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/KickerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/KickerTest.java index 2b4e91d129a..2630bf37fad 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/KickerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/KickerTest.java @@ -670,7 +670,6 @@ public class KickerTest extends CardTestPlayerBase { // attack and prepare free cast, use kicker attack(1, playerA, "Etali, Primal Storm", playerB); setChoice(playerA, true); // cast for free - setChoice(playerA, "Ardent Soldier"); // cast for free setChoice(playerA, true); // use kicker setStrictChooseMode(true); @@ -703,7 +702,6 @@ public class KickerTest extends CardTestPlayerBase { // attack and prepare free cast attack(1, playerA, "Etali, Primal Storm", playerB); setChoice(playerA, true); // cast for free - setChoice(playerA, "Thieving Skydiver"); // cast for free setChoice(playerA, true); // use kicker setChoiceAmount(playerA, 2); // X=2 for Kicker X addTarget(playerA, "Brain in a Jar"); // kicker's target (take control of artifact) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java index 4f472402029..2983cb92226 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java @@ -262,8 +262,8 @@ public class MorphTest extends CardTestPlayerBase { assertHandCount(playerA, "Ponyback Brigade", 0); assertHandCount(playerB, "Doomwake Giant", 0); assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); - assertPermanentCount(playerA, "Goblin", 3); - assertPowerToughness(playerA, "Goblin", 1, 1, Filter.ComparisonScope.Any); + assertPermanentCount(playerA, "Goblin Token", 3); + assertPowerToughness(playerA, "Goblin Token", 1, 1, Filter.ComparisonScope.Any); assertPermanentCount(playerB, "Doomwake Giant", 1); assertPermanentCount(playerA, "Ponyback Brigade", 1); assertPowerToughness(playerA, "Ponyback Brigade", 1, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PersistTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PersistTest.java index 60523a47363..b9a73de769c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PersistTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PersistTest.java @@ -72,7 +72,7 @@ public class PersistTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", "Safehold Elite"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Shadowfeed", "Safehold Elite", "Persist (When this creature dies, if it had no -1/-1 counters on it, return it to the battlefield under its owner's control with a -1/-1 counter on it.)"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Shadowfeed", "Safehold Elite", "persist"); setStopAt(1, PhaseStep.END_TURN); execute(); @@ -150,7 +150,7 @@ public class PersistTest extends CardTestPlayerBase { assertLife(playerB, 26); // +6 from lifelink of Wurmcoil assertPermanentCount(playerB, "Wurmcoil Engine", 0); - assertPermanentCount(playerB, "Phyrexian Wurm", 2); + assertPermanentCount(playerB, "Phyrexian Wurm Token", 2); assertPermanentCount(playerA, "Kitchen Finks", 2); assertPowerToughness(playerA, "Kitchen Finks", 2, 1, Filter.ComparisonScope.All); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ReboundTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ReboundTest.java index 889788ec3d2..60e56bdcf2f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ReboundTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ReboundTest.java @@ -64,7 +64,7 @@ public class ReboundTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Distortion Strike", "Memnite"); setStopAt(3, PhaseStep.PRECOMBAT_MAIN); - execute(); + execute();assertAllCommandsUsed(); //check exile and graveyard assertPowerToughness(playerA, "Memnite", 2, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/RetraceTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/RetraceTest.java index 41af3104cd4..0fd150fee37 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/RetraceTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/RetraceTest.java @@ -115,7 +115,7 @@ public class RetraceTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "Worm", 3); + assertPermanentCount(playerA, "Worm Token", 3); assertGraveyardCount(playerA, "Mountain", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SurgeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SurgeTest.java index 9759b54b9b5..70047064ed6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SurgeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SurgeTest.java @@ -62,7 +62,7 @@ public class SurgeTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Lightning Bolt", 1); assertGraveyardCount(playerB, "Cackling Counterpart", 1); assertGraveyardCount(playerA, "Crush of Tentacles", 1); - assertPermanentCount(playerA, "Octopus", 1); + assertPermanentCount(playerA, "Octopus Token", 1); assertPermanentCount(playerB, "Silvercoat Lion", 0); assertHandCount(playerA, "Silvercoat Lion", 1); assertHandCount(playerB, "Silvercoat Lion", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java index 9ef18543e73..f574fbf9853 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/TransformTest.java @@ -73,7 +73,7 @@ public class TransformTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Liliana, Defiant Necromancer", 1); assertCounterCount("Liliana, Defiant Necromancer", CounterType.LOYALTY, 3); - assertPermanentCount(playerA, "Zombie", 1); + assertPermanentCount(playerA, "Zombie Token", 1); } @@ -102,7 +102,7 @@ public class TransformTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Languish", 1); assertPermanentCount(playerA, "Liliana, Defiant Necromancer", 0); - assertPermanentCount(playerA, "Zombie", 0); + assertPermanentCount(playerA, "Zombie Token", 0); assertGraveyardCount(playerA, "Silvercoat Lion", 1); assertGraveyardCount(playerA, "Liliana, Heretical Healer", 1); @@ -152,7 +152,7 @@ public class TransformTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Cult of the Waxing Moon", 1); assertPermanentCount(playerA, "Timber Shredder", 1); // Night-side card of Hinterland Logger, Werewolf (non-human) - assertPermanentCount(playerA, "Wolf", 1); // wolf token created + assertPermanentCount(playerA, "Wolf Token", 1); // wolf token created } /** @@ -377,7 +377,7 @@ public class TransformTest extends CardTestPlayerBase { execute(); assertLife(playerA, 24); - assertPermanentCount(playerA, "Wolf", 2); + assertPermanentCount(playerA, "Wolf Token", 2); assertPermanentCount(playerB, "Eldrazi Displacer", 1); @@ -410,7 +410,7 @@ public class TransformTest extends CardTestPlayerBase { assertLife(playerA, 24); assertLife(playerB, 18); - assertPermanentCount(playerA, "Wolf", 2); + assertPermanentCount(playerA, "Wolf Token", 2); assertPermanentCount(playerA, "Silvercoat Lion", 2); assertPermanentCount(playerA, "Ravager of the Fells", 0); assertPermanentCount(playerA, "Huntmaster of the Fells", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counter/AddingCountersToPermanentsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counter/AddingCountersToPermanentsTest.java index 31bd38c3430..eab560962df 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counter/AddingCountersToPermanentsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counter/AddingCountersToPermanentsTest.java @@ -155,6 +155,6 @@ public class AddingCountersToPermanentsTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Lightning Bolt", 1); assertPowerToughness(playerA, "Kitchen Finks", 2, 1); - assertPermanentCount(playerA, "Snake", 1); + assertPermanentCount(playerA, "Snake Token", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counterspell/CounterActivatedAbilityTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counterspell/CounterActivatedAbilityTest.java index 107029e0159..808b622c8d9 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counterspell/CounterActivatedAbilityTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counterspell/CounterActivatedAbilityTest.java @@ -38,7 +38,7 @@ public class CounterActivatedAbilityTest extends CardTestPlayerBase { execute(); assertGraveyardCount(playerB, "Squelch", 1); - assertPermanentCount(playerA, "Soldier", 0); + assertPermanentCount(playerA, "Soldier Token", 0); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counterspell/EndrekSahrMasterBreederTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counterspell/EndrekSahrMasterBreederTest.java index 41c9b448583..8627af103b8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counterspell/EndrekSahrMasterBreederTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/counterspell/EndrekSahrMasterBreederTest.java @@ -39,7 +39,7 @@ public class EndrekSahrMasterBreederTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Silvercoat Lion", 1); assertGraveyardCount(playerB, "Counterspell", 1); - assertPermanentCount(playerA, "Thrull", 2); + assertPermanentCount(playerA, "Thrull Token", 2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/CelestialPurgeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/CelestialPurgeTest.java index 8df9c1e4ac9..5d757f50ac0 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/CelestialPurgeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/CelestialPurgeTest.java @@ -36,7 +36,7 @@ public class CelestialPurgeTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Celestial Purge", 1); assertExileCount("Bitterblossom", 1); - assertPermanentCount(playerB, "Faerie Rogue", 1); + assertPermanentCount(playerB, "Faerie Rogue Token", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/ExileAndReturnTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/ExileAndReturnTest.java index 7a802e59d0f..2ac1f0e8bd4 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/ExileAndReturnTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/ExileAndReturnTest.java @@ -109,7 +109,7 @@ public class ExileAndReturnTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Blanchwood Armor", 1); assertGraveyardCount(playerB, "Frog Tongue", 0); assertPermanentCount(playerB, "Frog Tongue", 1); - assertPermanentCount(playerB, "Saproling", 8); + assertPermanentCount(playerB, "Saproling Token", 8); assertPowerToughness(playerB, "Bramble Elemental", 10, 10); assertAbility(playerB, "Bramble Elemental", ReachAbility.getInstance(), true); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/GainAbilitiesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/GainAbilitiesTest.java index 03a690f6965..43a088ca4fd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/GainAbilitiesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/GainAbilitiesTest.java @@ -37,7 +37,7 @@ public class GainAbilitiesTest extends CardTestPlayerBase { Permanent permanent = getPermanent("Balduvian Bears"); Assert.assertEquals("must have only 1 singleton ability instance from two attachments", - 1, permanent.getAbilities(currentGame).stream().filter(a -> a instanceof VigilanceAbility).count()); + 1, permanent.getAbilities(currentGame).stream().filter(VigilanceAbility.class::isInstance).count()); } @Test @@ -63,7 +63,7 @@ public class GainAbilitiesTest extends CardTestPlayerBase { Permanent permanent = getPermanent("Balduvian Bears"); Assert.assertEquals("must have 2 dynamic ability instances from two attachments", 2, permanent.getAbilities(currentGame).stream().filter( - a -> a.getEffects().stream().anyMatch(e -> e instanceof DrawCardSourceControllerEffect) + a -> a.getEffects().stream().anyMatch(DrawCardSourceControllerEffect.class::isInstance) ).count()); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/GainMenaceAbilityAsSingletonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/GainMenaceAbilityAsSingletonTest.java index 473f9327a3e..13279c767da 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/GainMenaceAbilityAsSingletonTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/GainMenaceAbilityAsSingletonTest.java @@ -53,7 +53,7 @@ public class GainMenaceAbilityAsSingletonTest extends CardTestPlayerBase { Permanent permanent = getPermanent("Minotaur", playerA); Assert.assertEquals("must have only 1 Menace instance", 1, permanent.getAbilities(currentGame).stream() - .filter(a -> a instanceof MenaceAbility).count()); + .filter(MenaceAbility.class::isInstance).count()); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/SakashimaTheImpostorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/SakashimaTheImpostorTest.java index b6cbba80e8a..b1ac2c1f05a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/SakashimaTheImpostorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/SakashimaTheImpostorTest.java @@ -67,7 +67,7 @@ public class SakashimaTheImpostorTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Silvercoat Lion", 1); assertGraveyardCount(playerB, "Sakashima the Impostor", 1); - assertPermanentCount(playerA, "Eldrazi Spawn", 1); - assertPermanentCount(playerB, "Eldrazi Spawn", 1); + assertPermanentCount(playerA, "Eldrazi Spawn Token", 1); + assertPermanentCount(playerB, "Eldrazi Spawn Token", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/SpellFizzlesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/SpellFizzlesTest.java index 5320adfdca7..d8f8a133476 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/SpellFizzlesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/SpellFizzlesTest.java @@ -33,7 +33,7 @@ public class SpellFizzlesTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Adverse Conditions", 1); assertGraveyardCount(playerB, "Lightning Bolt", 1); assertGraveyardCount(playerB, "Silvercoat Lion", 1); - assertPermanentCount(playerA, "Eldrazi Scion", 0); // All targets were illegal - spell fizzles + assertPermanentCount(playerA, "Eldrazi Scion Token", 0); // All targets were illegal - spell fizzles } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/StormTheVaultTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/StormTheVaultTest.java index f43cc3b6b52..c565224a387 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/StormTheVaultTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/StormTheVaultTest.java @@ -40,7 +40,7 @@ public class StormTheVaultTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.END_TURN); execute(); - assertPermanentCount(playerA, "Treasure", 2); + assertPermanentCount(playerA, "Treasure Token", 2); } @Test @@ -55,6 +55,6 @@ public class StormTheVaultTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.END_TURN); execute(); - assertPermanentCount(playerA, "Treasure", 1); + assertPermanentCount(playerA, "Treasure Token", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/asthough/PlayFromNonHandZoneTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/asthough/PlayFromNonHandZoneTest.java index 89a89938bea..b437bfecca7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/asthough/PlayFromNonHandZoneTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/asthough/PlayFromNonHandZoneTest.java @@ -463,7 +463,7 @@ public class PlayFromNonHandZoneTest extends CardTestPlayerBaseWithAIHelps { assertGraveyardCount(playerA, "Angelic Purge", 1); assertGraveyardCount(playerB, "Silvercoat Lion", 1); // sacrificed for Purge - assertPermanentCount(playerB, "Food", 1); + assertPermanentCount(playerB, "Food Token", 1); assertExileCount(playerA, "Curious Pair", 1); assertHandCount(playerB, 1); // 1 from Turn 2 draw diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/conditional/DoIfCostPaidTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/conditional/DoIfCostPaidTest.java index fc9256ea34c..0705a4722a2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/conditional/DoIfCostPaidTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/conditional/DoIfCostPaidTest.java @@ -26,7 +26,7 @@ public class DoIfCostPaidTest extends CardTestPlayerBase { execute(); assertPermanentCount(playerB, "Awaken the Sky Tyrant", 0); - assertPermanentCount(playerB, "Dragon", 1); + assertPermanentCount(playerB, "Dragon Token", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/ChangelingTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/ChangelingTest.java index 4e60df5f3b0..24f93f0cd54 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/ChangelingTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/ChangelingTest.java @@ -3,6 +3,7 @@ package org.mage.test.cards.continuous; import mage.constants.CardType; import mage.constants.PhaseStep; import mage.constants.Zone; +import mage.counters.CounterType; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -66,10 +67,11 @@ public class ChangelingTest extends CardTestPlayerBase { assertPowerToughness(playerA, copter, 3, 3); } + private static final String mimic = "Metallic Mimic"; + @Test public void testMetallicMimicChangelingTrigger() { // all creatures with the chosen subtype come into play with a +1/+1 counter - final String mimic = "Metallic Mimic"; addCard(Zone.HAND, playerA, mimic, 1); addCard(Zone.HAND, playerA, woodlandChangeling, 1); @@ -86,4 +88,44 @@ public class ChangelingTest extends CardTestPlayerBase { // 2/2 + +1/+1 counter assertPowerToughness(playerA, woodlandChangeling, 3, 3); } + + private static final String paragon = "Bramblewood Paragon"; + private static final String cohort = "Irregular Cohort"; + + @Test + public void testTokensHaveTypesAsTheyEnter() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.BATTLEFIELD, playerA, paragon); + addCard(Zone.HAND, playerA, cohort); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cohort); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertCounterCount(playerA, cohort, CounterType.P1P1, 1); + assertCounterCount(playerA, "Shapeshifter Token", CounterType.P1P1, 1); + } + + private static final String amoeboid = "Amoeboid Changeling"; + + @Test + public void testTokensCanLoseTypes() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.BATTLEFIELD, playerA, "Wizened Cenn"); + addCard(Zone.BATTLEFIELD, playerA, amoeboid); + addCard(Zone.HAND, playerA, cohort); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, cohort); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{T}: Target creature loses", "Shapeshifter Token"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertTapped(amoeboid, true); + assertPowerToughness(playerA, "Shapeshifter Token", 2, 2); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/CommandersCastTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/CommandersCastTest.java index 9d871dfe06b..10d8fb721cf 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/CommandersCastTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/CommandersCastTest.java @@ -150,7 +150,7 @@ public class CommandersCastTest extends CardTestCommander4PlayersWithAIHelps { setModeChoice(playerA, "1"); setModeChoice(playerA, "4"); - checkPermanentCount("after", 1, PhaseStep.BEGIN_COMBAT, playerA, "Citizen", 3); + checkPermanentCount("after", 1, PhaseStep.BEGIN_COMBAT, playerA, "Citizen Token", 3); checkLife("after", 1, PhaseStep.BEGIN_COMBAT, playerA, 20 + 4); setStopAt(1, PhaseStep.END_TURN); @@ -179,7 +179,7 @@ public class CommandersCastTest extends CardTestCommander4PlayersWithAIHelps { setModeChoice(playerA, "4"); setChoice(playerA, true); // return commander - checkPermanentCount("after", 1, PhaseStep.BEGIN_COMBAT, playerA, "Citizen", 3); + checkPermanentCount("after", 1, PhaseStep.BEGIN_COMBAT, playerA, "Citizen Token", 3); checkLife("after", 1, PhaseStep.BEGIN_COMBAT, playerA, 20 + 4); setStopAt(1, PhaseStep.END_TURN); @@ -409,7 +409,7 @@ public class CommandersCastTest extends CardTestCommander4PlayersWithAIHelps { setChoice(playerA, true); // return commander waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); checkCommandCardCount("after first cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curious Pair", 1); - checkPermanentCount("after first cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Food", 1); + checkPermanentCount("after first cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Food Token", 1); // commander tax: 1x // can't cast due commander cost added (we stil have 2x mana) checkPlayableAbility("after first cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Curious Pair", false); @@ -425,7 +425,7 @@ public class CommandersCastTest extends CardTestCommander4PlayersWithAIHelps { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treats to Share"); setChoice(playerA, false); // do not return commander waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - checkPermanentCount("after second cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Food", 2); + checkPermanentCount("after second cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Food Token", 2); checkPlayableAbility("after second cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Curious Pair", false); checkPlayableAbility("after second cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Treats to Share", false); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/DaxosTheReturnedTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/DaxosTheReturnedTest.java index c616dab5536..653c7fecfdd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/DaxosTheReturnedTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/DaxosTheReturnedTest.java @@ -43,8 +43,8 @@ public class DaxosTheReturnedTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Underworld Dreams", 2); assertCounterCount(playerA, CounterType.EXPERIENCE, 2); - assertPowerToughness(playerA, "Spirit", 2, 2, Filter.ComparisonScope.All); - assertType("Spirit", CardType.ENCHANTMENT, SubType.SPIRIT); + assertPowerToughness(playerA, "Spirit Token", 2, 2, Filter.ComparisonScope.All); + assertType("Spirit Token", CardType.ENCHANTMENT, SubType.SPIRIT); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/DependentEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/DependentEffectsTest.java index 331ccbb3c61..bd3f57f592e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/DependentEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/DependentEffectsTest.java @@ -93,7 +93,7 @@ public class DependentEffectsTest extends CardTestPlayerBase { assertPowerToughness(playerB, "Cobblebrute", 4, 4); assertPowerToughness(playerA, "Cobblebrute", 4, 4); - assertPermanentCount(playerB, "Soldier", 0); + assertPermanentCount(playerB, "Soldier Token", 0); assertPermanentCount(playerA, "Island", 0); assertPermanentCount(playerB, "Plains", 0); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/GainAbilityDependenciesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/GainAbilityDependenciesTest.java index c2eb0444742..a8e4fcb660e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/GainAbilityDependenciesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/GainAbilityDependenciesTest.java @@ -77,15 +77,15 @@ public class GainAbilityDependenciesTest extends CardTestPlayerBase { // cast token castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Elephant Ambush"); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - checkPermanentCount("token must exist", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Elephant", 1); + checkPermanentCount("token must exist", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Elephant Token", 1); // equip - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip {3}", "Elephant"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip {3}", "Elephant Token"); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // attack with +1 token - attack(3, playerA, "Elephant", playerB); - checkPermanentCounters("must have counter", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Elephant", CounterType.P1P1, 1); + attack(3, playerA, "Elephant Token", playerB); + checkPermanentCounters("must have counter", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Elephant Token", CounterType.P1P1, 1); setStrictChooseMode(true); setStopAt(3, PhaseStep.END_TURN); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/MerfolkTricksterTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/MerfolkTricksterTest.java index 49a0b6857be..4edafc58829 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/MerfolkTricksterTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/MerfolkTricksterTest.java @@ -112,10 +112,10 @@ public class MerfolkTricksterTest extends CardTestPlayerBase { activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-2:"); - attack(3, playerA, "Devil"); + attack(3, playerA, "Devil Token"); castSpell(3, PhaseStep.DECLARE_ATTACKERS, playerB, mTrickster); - addTarget(playerB, "Devil"); - block(3, playerB, mTrickster, "Devil"); + addTarget(playerB, "Devil Token"); + block(3, playerB, mTrickster, "Devil Token"); addTarget(playerA, mTrickster); setStopAt(3, PhaseStep.END_COMBAT); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/SubTypeChangingEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/SubTypeChangingEffectsTest.java index 1e34eed275b..c051c66dc10 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/SubTypeChangingEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/SubTypeChangingEffectsTest.java @@ -268,11 +268,11 @@ public class SubTypeChangingEffectsTest extends CardTestPlayerBase { Assert.assertTrue(silvercoatLion.hasSubtype(SubType.CAT, currentGame)); Assert.assertFalse(silvercoatLion.hasSubtype(SubType.ORC, currentGame)); - Permanent beast = getPermanent("Beast", playerA); + Permanent beast = getPermanent("Beast Token", playerA); Assert.assertTrue(beast.hasSubtype(SubType.BEAST, currentGame)); Assert.assertFalse(beast.hasSubtype(SubType.ORC, currentGame)); - Permanent wurm = getPermanent("Wurm", playerA); + Permanent wurm = getPermanent("Wurm Token", playerA); Assert.assertTrue(wurm.hasSubtype(SubType.WURM, currentGame)); Assert.assertFalse(wurm.hasSubtype(SubType.ORC, currentGame)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/SwarmSurgeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/SwarmSurgeTest.java index 6882c442a1c..f315c670f0f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/SwarmSurgeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/SwarmSurgeTest.java @@ -40,8 +40,8 @@ public class SwarmSurgeTest extends CardTestPlayerBase { assertPowerToughness(playerA, "Birthing Hulk", 7, 4); assertAbility(playerA, "Birthing Hulk", FirstStrikeAbility.getInstance(), true); - assertPowerToughness(playerA, "Eldrazi Scion", 3, 1, Filter.ComparisonScope.All); - assertAbility(playerA, "Eldrazi Scion", FirstStrikeAbility.getInstance(), true, 2); + assertPowerToughness(playerA, "Eldrazi Scion Token", 3, 1, Filter.ComparisonScope.All); + assertAbility(playerA, "Eldrazi Scion Token", FirstStrikeAbility.getInstance(), true, 2); assertPowerToughness(playerA, "Silvercoat Lion", 4, 2); assertAbility(playerA, "Silvercoat Lion", FirstStrikeAbility.getInstance(), false); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/UntilNextEndStepTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/UntilNextEndStepTest.java new file mode 100644 index 00000000000..8578b055576 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/UntilNextEndStepTest.java @@ -0,0 +1,77 @@ +package org.mage.test.cards.continuous; + +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class UntilNextEndStepTest extends CardTestPlayerBase { + + public void doTest(int startTurnNum, PhaseStep startPhaseStep, int endTurnNum, PhaseStep endPhaseStep, boolean stillActive) { + addCustomCardWithAbility( + "tester", playerA, + new SimpleActivatedAbility(new BoostSourceEffect( + 1, 1, Duration.UntilYourNextEndStep + ), new ManaCostsImpl<>("{0}")), null, + CardType.CREATURE, "", Zone.BATTLEFIELD + ); + + activateAbility(startTurnNum, startPhaseStep, playerA, "{0}"); + + setStrictChooseMode(true); + setStopAt(endTurnNum, endPhaseStep); + execute(); + assertAllCommandsUsed(); + + int powerToughness = stillActive ? 2 : 1; + assertPowerToughness(playerA, "tester", powerToughness, powerToughness); + } + + @Test + public void testSameTurnTrue() { + doTest(1, PhaseStep.PRECOMBAT_MAIN, 1, PhaseStep.POSTCOMBAT_MAIN, true); + } + + @Test + public void testSameTurnFalse() { + doTest(1, PhaseStep.PRECOMBAT_MAIN, 1, PhaseStep.END_TURN, false); + } + + @Test + public void testNextTurnTrue() { + doTest(1, PhaseStep.END_TURN, 2, PhaseStep.PRECOMBAT_MAIN, true); + } + + @Test + public void testNextTurnFalse() { + doTest(1, PhaseStep.PRECOMBAT_MAIN, 2, PhaseStep.PRECOMBAT_MAIN, false); + } + + @Test + public void testTurnCycleTrue() { + doTest(1, PhaseStep.END_TURN, 3, PhaseStep.PRECOMBAT_MAIN, true); + } + + @Test + public void testTurnCycleFalse() { + doTest(1, PhaseStep.END_TURN, 3, PhaseStep.END_TURN, false); + } + + @Test + public void testOpponentTurnTrue() { + doTest(2, PhaseStep.PRECOMBAT_MAIN, 3, PhaseStep.PRECOMBAT_MAIN, true); + } + + @Test + public void testOpponentTurnFalse() { + doTest(2, PhaseStep.PRECOMBAT_MAIN, 3, PhaseStep.END_TURN, false); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/control/GontiLordOfLuxuryEffectTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/control/GontiLordOfLuxuryEffectTest.java index 1877430ba45..ab2baf7910a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/control/GontiLordOfLuxuryEffectTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/control/GontiLordOfLuxuryEffectTest.java @@ -136,9 +136,9 @@ public class GontiLordOfLuxuryEffectTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Gonti, Lord of Luxury", 1); assertPowerToughness(playerA, "Gonti, Lord of Luxury", 2, 3); - assertPermanentCount(playerA, "Spirit", 2); + assertPermanentCount(playerA, "Spirit Token", 2); - assertPermanentCount(playerB, "Spirit", 2); + assertPermanentCount(playerB, "Spirit Token", 2); assertExileCount("Lingering Souls", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/ArtisanOfFormsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/ArtisanOfFormsTest.java index 6692cacce39..50990755610 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/ArtisanOfFormsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/ArtisanOfFormsTest.java @@ -84,7 +84,7 @@ public class ArtisanOfFormsTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Cackling Counterpart", 1); assertPermanentCount(playerA, "Artisan of Forms", 0); assertPermanentCount(playerB, "Silvercoat Lion", 1); - assertPermanentCount(playerA, "Bird", 1); + assertPermanentCount(playerA, "Bird Token", 1); // 3 Silvercoat Lion at the end assertPermanentCount(playerA, "Silvercoat Lion", 3); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java index 446c645d300..4d0f9af52b7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java @@ -209,7 +209,7 @@ public class CleverImpersonatorTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Memnite"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Kindred Discovery"); - setChoice(playerA, "Construct"); + setChoice(playerA, "Construct Token"); castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Clever Impersonator"); setChoice(playerB, "Kindred Discovery"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java index 9a54c822245..dc4f99abfe8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java @@ -221,7 +221,7 @@ public class CopySpellTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Giant Growth", 1); assertPowerToughness(playerA, "Silverfur Partisan", 5, 5); assertPowerToughness(playerA, "Zada, Hedron Grinder", 6, 6); - assertPermanentCount(playerA, "Wolf", 1); // created from Silverfur ability + assertPermanentCount(playerA, "Wolf Token", 1); // created from Silverfur ability } */ diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildCopyTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildCopyTest.java index b83b65c939a..9f175997835 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildCopyTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildCopyTest.java @@ -118,7 +118,7 @@ public class EssenceOfTheWildCopyTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Soldier", 0); + assertPermanentCount(playerA, "Soldier Token", 0); assertPermanentCount(playerA, "Essence of the Wild", 1 + 5); List list = new ArrayList<>(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/FelhideSpiritbinderTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/FelhideSpiritbinderTest.java index 100fe2006e9..6dda9149d6d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/FelhideSpiritbinderTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/FelhideSpiritbinderTest.java @@ -88,11 +88,11 @@ public class FelhideSpiritbinderTest extends CardTestPlayerBase { setStopAt(4, PhaseStep.PRECOMBAT_MAIN); execute(); - assertPermanentCount(playerA, "Elephant", 1); - assertPermanentCount(playerB, "Elephant", 1); - assertAbility(playerB, "Elephant", HasteAbility.getInstance(), true); + assertPermanentCount(playerA, "Elephant Token", 1); + assertPermanentCount(playerB, "Elephant Token", 1); + assertAbility(playerB, "Elephant Token", HasteAbility.getInstance(), true); - Permanent copiedTokenElephant = getPermanent("Elephant", playerB); + Permanent copiedTokenElephant = getPermanent("Elephant Token", playerB); Assert.assertEquals("Elephant has Enchantment card type", true, copiedTokenElephant.getCardType(currentGame).contains(CardType.ENCHANTMENT)); assertLife(playerA, 17); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/FlameshadowConjuringTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/FlameshadowConjuringTest.java index a000092bea2..a7fef278b6f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/FlameshadowConjuringTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/FlameshadowConjuringTest.java @@ -40,7 +40,7 @@ public class FlameshadowConjuringTest extends CardTestPlayerBase { execute(); assertPermanentCount(playerA, "Priest of the Blood Rite", 1); - assertPermanentCount(playerA, "Demon", 2); + assertPermanentCount(playerA, "Demon Token", 2); assertLife(playerB, 20); assertLife(playerA, 18); @@ -79,7 +79,7 @@ public class FlameshadowConjuringTest extends CardTestPlayerBase { assertLife(playerB, 14); assertLife(playerA, 26); - assertPermanentCount(playerA, "Phyrexian Wurm", 2); + assertPermanentCount(playerA, "Phyrexian Wurm Token", 2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/HiveMindTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/HiveMindTest.java index c95eef5e7a5..f3b18c08ba3 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/HiveMindTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/HiveMindTest.java @@ -63,8 +63,8 @@ public class HiveMindTest extends CardTestPlayerBase { execute(); assertGraveyardCount(playerA, "Pact of the Titan", 1); - assertPermanentCount(playerA, "Giant", 0); // was countered by Chalice - assertPermanentCount(playerB, "Giant", 1); // was not countered by Chalice because it was not cast + assertPermanentCount(playerA, "Giant Token", 0); // was countered by Chalice + assertPermanentCount(playerB, "Giant Token", 1); // was not countered by Chalice because it was not cast assertWonTheGame(playerA); assertLostTheGame(playerB); assertLife(playerB, 20); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/KikiJikiMirrorBreakerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/KikiJikiMirrorBreakerTest.java index 6a9fac02066..8eb54bf6750 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/KikiJikiMirrorBreakerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/KikiJikiMirrorBreakerTest.java @@ -46,7 +46,7 @@ public class KikiJikiMirrorBreakerTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); - assertPermanentCount(playerA, "Elemental", 1); // because the copy was sacrificed + assertPermanentCount(playerA, "Elemental Token", 1); // because the copy was sacrificed assertPermanentCount(playerA, "Voice of Resurgence", 1); } @@ -74,7 +74,7 @@ public class KikiJikiMirrorBreakerTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Voice of Resurgence", 0); assertGraveyardCount(playerA, "Voice of Resurgence", 1); - assertPermanentCount(playerA, "Elemental", 2); + assertPermanentCount(playerA, "Elemental Token", 2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java index 7ccde5232a7..3163f3eb68a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java @@ -382,7 +382,7 @@ public class PhantasmalImageTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Wurmcoil Engine", 1); assertGraveyardCount(playerB, "Phantasmal Image", 1); - assertPermanentCount(playerB, "Phyrexian Wurm", 2); // if triggered ability did not work, the Titan would be in the graveyard instaed + assertPermanentCount(playerB, "Phyrexian Wurm Token", 2); // if triggered ability did not work, the Titan would be in the graveyard instaed } @@ -574,8 +574,8 @@ public class PhantasmalImageTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Phantasmal Image", 1); assertGraveyardCount(playerB, "Wurmcoil Engine", 1); - assertPermanentCount(playerA, "Phyrexian Wurm", 2); - assertPermanentCount(playerB, "Phyrexian Wurm", 2); + assertPermanentCount(playerA, "Phyrexian Wurm Token", 2); + assertPermanentCount(playerB, "Phyrexian Wurm Token", 2); } @@ -605,8 +605,8 @@ public class PhantasmalImageTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Phantasmal Image", 1); assertGraveyardCount(playerB, "Voice of Resurgence", 1); - assertPermanentCount(playerB, "Elemental", 1); - assertPermanentCount(playerA, "Elemental", 1); + assertPermanentCount(playerB, "Elemental Token", 1); + assertPermanentCount(playerA, "Elemental Token", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhyrexianMetamorphTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhyrexianMetamorphTest.java index 2ee953c2cca..93b9b7a0679 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhyrexianMetamorphTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhyrexianMetamorphTest.java @@ -44,7 +44,7 @@ public class PhyrexianMetamorphTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Cloudshift", 1); assertPermanentCount(playerA, "Ponyback Brigade", 1); - assertPermanentCount(playerA, "Goblin", 3); + assertPermanentCount(playerA, "Goblin Token", 3); } @@ -87,7 +87,7 @@ public class PhyrexianMetamorphTest extends CardTestPlayerBase { assertLife(playerB, 18); assertPermanentCount(playerA, "Ponyback Brigade", 1); - assertPermanentCount(playerA, "Goblin", 3); + assertPermanentCount(playerA, "Goblin Token", 3); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/SparkDoubleTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/SparkDoubleTest.java index dbdebe836fd..300c0fd0bad 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/SparkDoubleTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/SparkDoubleTest.java @@ -68,7 +68,6 @@ public class SparkDoubleTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Spark Double"); setChoice(playerA, true); setChoice(playerA, "Ajani, the Greathearted"); - setChoice(playerA, "Ajani, the Greathearted"); // two etb effects (own + copy) setStrictChooseMode(true); setStopAt(1, PhaseStep.BEGIN_COMBAT); @@ -120,7 +119,6 @@ public class SparkDoubleTest extends CardTestPlayerBase { castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Spark Double"); setChoice(playerA, true); setChoice(playerA, "Gideon, Ally of Zendikar"); - setChoice(playerA, "Gideon, Ally of Zendikar"); // two etb effects (own + copy) setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/adventure/AdventureCardsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/adventure/AdventureCardsTest.java index 16a66f2dad3..73c2b8a2dd9 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/adventure/AdventureCardsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/adventure/AdventureCardsTest.java @@ -34,7 +34,7 @@ public class AdventureCardsTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertHandCount(playerA, 0); - assertPermanentCount(playerA, "Food", 1); + assertPermanentCount(playerA, "Food Token", 1); assertExileCount(playerA, "Curious Pair", 1); assertGraveyardCount(playerA, 0); } @@ -56,7 +56,7 @@ public class AdventureCardsTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertHandCount(playerA, 0); - assertPermanentCount(playerA, "Food", 1); + assertPermanentCount(playerA, "Food Token", 1); assertExileCount(playerA, "Curious Pair", 1); assertGraveyardCount(playerA, 0); } @@ -75,7 +75,7 @@ public class AdventureCardsTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertHandCount(playerA, 0); - assertPermanentCount(playerA, "Food", 0); + assertPermanentCount(playerA, "Food Token", 0); assertPermanentCount(playerA, "Curious Pair", 1); assertExileCount(playerA, "Curious Pair", 0); assertGraveyardCount(playerA, 0); @@ -97,7 +97,7 @@ public class AdventureCardsTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertHandCount(playerA, 0); - assertPermanentCount(playerA, "Food", 1); + assertPermanentCount(playerA, "Food Token", 1); assertPermanentCount(playerA, "Curious Pair", 1); assertExileCount(playerA, "Curious Pair", 0); assertGraveyardCount(playerA, 0); @@ -125,7 +125,7 @@ public class AdventureCardsTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertHandCount(playerA, 0); - assertPermanentCount(playerA, "Food", 1); + assertPermanentCount(playerA, "Food Token", 1); assertPermanentCount(playerA, "Curious Pair", 0); assertExileCount(playerA, "Curious Pair", 1); assertGraveyardCount(playerA, 0); @@ -146,7 +146,7 @@ public class AdventureCardsTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertHandCount(playerA, 1); - assertPermanentCount(playerA, "Food", 0); + assertPermanentCount(playerA, "Food Token", 0); assertPermanentCount(playerA, "Curious Pair", 1); assertExileCount(playerA, "Curious Pair", 0); assertGraveyardCount(playerA, 0); @@ -169,7 +169,7 @@ public class AdventureCardsTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertHandCount(playerA, 1); - assertPermanentCount(playerA, "Food", 1); + assertPermanentCount(playerA, "Food Token", 1); assertPermanentCount(playerA, "Curious Pair", 1); assertExileCount(playerA, "Curious Pair", 0); assertGraveyardCount(playerA, 0); @@ -189,7 +189,7 @@ public class AdventureCardsTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertHandCount(playerA, 0); - assertPermanentCount(playerA, "Food", 0); + assertPermanentCount(playerA, "Food Token", 0); assertPermanentCount(playerA, "Curious Pair", 1); assertPowerToughness(playerA, "Curious Pair", 2, 4); assertExileCount(playerA, "Curious Pair", 0); @@ -248,7 +248,7 @@ public class AdventureCardsTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertHandCount(playerA, 0); - assertPermanentCount(playerA, "Food", 2); + assertPermanentCount(playerA, "Food Token", 2); assertPermanentCount(playerA, "Curious Pair", 0); assertExileCount(playerA, "Curious Pair", 1); assertGraveyardCount(playerA, 0); @@ -276,7 +276,7 @@ public class AdventureCardsTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertHandCount(playerA, 0); - assertPermanentCount(playerA, "Food", 2); + assertPermanentCount(playerA, "Food Token", 2); assertPermanentCount(playerA, 5); assertExileCount(playerA, "Curious Pair", 1); assertExileCount(playerA, 1); @@ -306,7 +306,7 @@ public class AdventureCardsTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertHandCount(playerA, 0); - assertPermanentCount(playerA, "Food", 0); + assertPermanentCount(playerA, "Food Token", 0); assertPermanentCount(playerA, 1); assertExileCount(playerA, 0); assertGraveyardCount(playerA, "Curious Pair", 1); @@ -343,7 +343,7 @@ public class AdventureCardsTest extends CardTestPlayerBase { assertHandCount(playerA, 0); assertHandCount(playerB, 0); assertPermanentCount(playerB, 0); - assertPermanentCount(playerA, "Food", 1); + assertPermanentCount(playerA, "Food Token", 1); assertPermanentCount(playerA, "Curious Pair", 1); assertExileCount(playerA, 0); assertExileCount(playerB, 0); @@ -451,7 +451,7 @@ public class AdventureCardsTest extends CardTestPlayerBase { assertHandCount(playerA, 0); assertPermanentCount(playerA, 4); - assertPermanentCount(playerA, "Food", 2); + assertPermanentCount(playerA, "Food Token", 2); assertPermanentCount(playerA, "Curious Pair", 0); assertExileCount(playerA, "Curious Pair", 1); assertGraveyardCount(playerA, 0); @@ -501,7 +501,7 @@ public class AdventureCardsTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertHandCount(playerA, 0); - assertPermanentCount(playerA, "Food", 0); + assertPermanentCount(playerA, "Food Token", 0); assertPermanentCount(playerA, "Curious Pair", 1); assertExileCount(playerA, 0); assertGraveyardCount(playerA, 0); @@ -524,7 +524,7 @@ public class AdventureCardsTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Food", 0); + assertPermanentCount(playerA, "Food Token", 0); assertLibraryCount(playerA, 1); } @@ -559,7 +559,7 @@ public class AdventureCardsTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertHandCount(playerA, 0); - assertPermanentCount(playerA, "Food", 1); + assertPermanentCount(playerA, "Food Token", 1); assertPermanentCount(playerA, "Curious Pair", 0); assertPermanentCount(playerA, "Wrenn and Six", 1); assertEmblemCount(playerA, 1); @@ -594,7 +594,7 @@ public class AdventureCardsTest extends CardTestPlayerBase { assertHandCount(playerA, 0); assertPermanentCount(playerA, 3); - assertPermanentCount(playerA, "Food", 1); + assertPermanentCount(playerA, "Food Token", 1); assertPermanentCount(playerA, "Curious Pair", 0); assertExileCount(playerA, "Curious Pair", 1); assertGraveyardCount(playerA, 0); @@ -759,11 +759,129 @@ public class AdventureCardsTest extends CardTestPlayerBase { // play as adventure spell castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Treats to Share"); waitStackResolved(3, PhaseStep.POSTCOMBAT_MAIN); - checkPermanentCount("after play 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Food", 1); + checkPermanentCount("after play 3", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Food Token", 1); setStrictChooseMode(true); setStopAt(3, PhaseStep.END_TURN); execute(); assertAllCommandsUsed(); } + + @Test + public void test_Cascade_CuriousPair() { + // If a player cascades into Curious Pair with Bloodbraid Elf they can cast either spell + removeAllCardsFromLibrary(playerA); + skipInitShuffling(); + + // Cascade + addCard(Zone.HAND, playerA, "Bloodbraid Elf"); // {2}{R}{G} + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + // + addCard(Zone.LIBRARY, playerA, "Swamp", 2); + addCard(Zone.LIBRARY, playerA, "Curious Pair", 1); + addCard(Zone.LIBRARY, playerA, "Island", 2); + + // play elf with cascade + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bloodbraid Elf"); + setChoice(playerA, true); // use free cast + setChoice(playerA, "Cast Treats to Share"); // can cast either + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Curious Pair", 0); + assertPermanentCount(playerA, "Food Token", 1); + assertExileCount(playerA, "Curious Pair", 1); + } + + @Test + public void test_Cascade_FlaxenIntruder() { + // If a player cascades into Flaxen Intruder with Bloodbraid Elf they shouldn't be able to cast Welcome Home + removeAllCardsFromLibrary(playerA); + skipInitShuffling(); + + // Cascade + addCard(Zone.HAND, playerA, "Bloodbraid Elf"); // {2}{R}{G} + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + // + addCard(Zone.LIBRARY, playerA, "Swamp", 2); + addCard(Zone.LIBRARY, playerA, "Flaxen Intruder", 1); + addCard(Zone.LIBRARY, playerA, "Island", 2); + + // play elf with cascade + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bloodbraid Elf"); + setChoice(playerA, true); // use free cast + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Flaxen Intruder", 1); + assertPermanentCount(playerA, "Bear", 0); + } + + @Test + public void test_SramsExpertise_CuriousPair() { + addCard(Zone.HAND, playerA, "Sram's Expertise"); + addCard(Zone.HAND, playerA, "Curious Pair"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sram's Expertise"); + setChoice(playerA, true); // use free cast + setChoice(playerA, "Cast Treats to Share"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Curious Pair", 0); + assertPermanentCount(playerA, "Food Token", 1); + assertPermanentCount(playerA, "Servo Token", 3); + assertExileCount(playerA, "Curious Pair", 1); + } + + @Test + public void test_SramsExpertise_FlaxenIntruder() { + addCard(Zone.HAND, playerA, "Sram's Expertise"); + addCard(Zone.HAND, playerA, "Flaxen Intruder"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sram's Expertise"); + setChoice(playerA, true); // use free cast + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Flaxen Intruder", 1); + assertPermanentCount(playerA, "Bear", 0); + assertPermanentCount(playerA, "Servo Token", 3); + } + + @Test + public void test_SramsExpertise_LonesomeUnicorn() { + addCard(Zone.HAND, playerA, "Sram's Expertise"); + addCard(Zone.HAND, playerA, "Lonesome Unicorn"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sram's Expertise"); + setChoice(playerA, true); // use free cast + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Lonesome Unicorn", 0); + assertPermanentCount(playerA, "Knight Token", 1); + assertPermanentCount(playerA, "Servo Token", 3); + assertExileCount(playerA, "Lonesome Unicorn", 1); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/BolassCitadelTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/BolassCitadelTest.java index 66398a7dff1..d43766a8227 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/BolassCitadelTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/alternate/BolassCitadelTest.java @@ -53,7 +53,7 @@ public class BolassCitadelTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertHandCount(playerA, 0); - assertPermanentCount(playerA, "Food", 1); + assertPermanentCount(playerA, "Food Token", 1); assertExileCount(playerA, "Curious Pair", 1); assertGraveyardCount(playerA, 0); assertLife(playerA, 19); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaces/ModalDoubleFacesCardsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaces/ModalDoubleFacesCardsTest.java index 5102c3debc7..81fcd83b1c9 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaces/ModalDoubleFacesCardsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaces/ModalDoubleFacesCardsTest.java @@ -866,6 +866,44 @@ public class ModalDoubleFacesCardsTest extends CardTestPlayerBase { assertPermanentCount(playerA, "The Omenkeel", 1); } + @Test + public void test_SramsExpertise_ValkiGodOfLies() { + addCard(Zone.HAND, playerA, "Sram's Expertise"); + addCard(Zone.HAND, playerA, "Valki, God of Lies"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sram's Expertise"); + setChoice(playerA, true); // use free cast + setChoice(playerA, TestPlayer.CHOICE_SKIP); // no choices for valki's etb exile + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Valki, God of Lies", 1); + assertPermanentCount(playerA, "Servo Token", 3); + } + + @Test + public void test_SramsExpertise_CosimaGodOfTheVoyage() { + addCard(Zone.HAND, playerA, "Sram's Expertise"); + addCard(Zone.HAND, playerA, "Cosima, God of the Voyage"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sram's Expertise"); + setChoice(playerA, true); // use free cast + setChoice(playerA, "Cast The Omenkeel"); // can cast any side here + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "The Omenkeel", 1); + assertPermanentCount(playerA, "Servo Token", 3); + } + @Test public void test_Copy_AsSpell() { addCard(Zone.HAND, playerA, "Akoum Warrior", 1); // {5}{R} @@ -1000,4 +1038,4 @@ public class ModalDoubleFacesCardsTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); } -} \ No newline at end of file +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/BattlefieldThaumaturgeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/BattlefieldThaumaturgeTest.java index 29e983685ff..7f391086ca7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/BattlefieldThaumaturgeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/BattlefieldThaumaturgeTest.java @@ -117,7 +117,7 @@ public class BattlefieldThaumaturgeTest extends CardTestPlayerBase { assertPermanentCount(playerA, creature, 1); } // Each has a solider token generated while attacking - assertPermanentCount(playerA, "Soldier", 5); + assertPermanentCount(playerA, "Soldier Token", 5); // Battlefield Thaumaturge will have hexproof from heroic trigger Permanent battlefieldThaumaturge = getPermanent("Battlefield Thaumaturge", playerA.getId()); Assert.assertTrue("Battlefield Thaumaturge must have hexproof", battlefieldThaumaturge.getAbilities().contains(HexproofAbility.getInstance())); @@ -166,7 +166,7 @@ public class BattlefieldThaumaturgeTest extends CardTestPlayerBase { } // All 4 creatures have been replaced by boars - assertPermanentCount(playerB, "Boar", 4); + assertPermanentCount(playerB, "Boar Token", 4); /* Cost to target 4 permanents will be: * + {4}{U}{U} for the base spell with X = 4 @@ -216,8 +216,8 @@ public class BattlefieldThaumaturgeTest extends CardTestPlayerBase { } // And each player has 3 dragons - assertPermanentCount(playerA, "Dragon", 3); - assertPermanentCount(playerB, "Dragon", 3); + assertPermanentCount(playerA, "Dragon Token", 3); + assertPermanentCount(playerB, "Dragon Token", 3); /* Cost to target 6 creatures will be * + {4}{R}{R} for the fixed cost base spell diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java index 8afb4166c59..f3dfbbd34f7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java @@ -34,7 +34,6 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mindclaw Shaman"); addTarget(playerA, playerB); - setChoice(playerA, "Wear // Tear"); // select card setChoice(playerA, true); // confirm to cast setChoice(playerA, "Cast Tear"); // select tear side addTarget(playerA, "Sanguine Bond"); // target for tear @@ -67,7 +66,6 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mindclaw Shaman"); addTarget(playerA, playerB); - setChoice(playerA, "Wear // Tear"); // select card setChoice(playerA, true); // confirm to cast setChoice(playerA, "Cast Wear"); // select wear side addTarget(playerA, "Icy Manipulator"); // target for wear @@ -100,7 +98,6 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mindclaw Shaman"); addTarget(playerA, playerB); - setChoice(playerA, "Wear // Tear"); // select card setChoice(playerA, true); // confirm to cast setChoice(playerA, "Cast fused Wear // Tear"); // select fused addTarget(playerA, "Icy Manipulator"); // target for wear @@ -137,7 +134,6 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { attack(2, playerB, "Etali, Primal Storm"); setChoice(playerB, true); // free cast - setChoice(playerB, "Fire // Ice"); // card to cast setChoice(playerB, "Cast Fire"); // ability to cast addTargetAmount(playerB, "Silvercoat Lion", 2); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/dungeons/DungeonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/dungeons/DungeonTest.java index 76fe266b309..9fb16de613b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/dungeons/DungeonTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/dungeons/DungeonTest.java @@ -89,7 +89,7 @@ public class DungeonTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertPowerToughness(playerA, FLAMESPEAKER_ADEPT, 2 + 2, 3); - assertPermanentCount(playerA, "Goblin", 0); + assertPermanentCount(playerA, "Goblin Token", 0); assertDungeonRoom(LOST_MINE_OF_PHANDELVER, "Cave Entrance"); assertLife(playerA, 20); assertLife(playerB, 20); @@ -112,7 +112,7 @@ public class DungeonTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertPowerToughness(playerA, FLAMESPEAKER_ADEPT, 2 + 2, 3); - assertPermanentCount(playerA, "Goblin", 1); + assertPermanentCount(playerA, "Goblin Token", 1); assertDungeonRoom(LOST_MINE_OF_PHANDELVER, "Goblin Lair"); assertLife(playerA, 20); assertLife(playerB, 20); @@ -138,7 +138,7 @@ public class DungeonTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertPowerToughness(playerA, FLAMESPEAKER_ADEPT, 2 + 2, 3); - assertPermanentCount(playerA, "Goblin", 1); + assertPermanentCount(playerA, "Goblin Token", 1); assertDungeonRoom(LOST_MINE_OF_PHANDELVER, "Dark Pool"); assertLife(playerA, 20 + 1); assertLife(playerB, 20 - 1); @@ -166,7 +166,7 @@ public class DungeonTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertPowerToughness(playerA, FLAMESPEAKER_ADEPT, 2 + 2, 3); - assertPermanentCount(playerA, "Goblin", 1); + assertPermanentCount(playerA, "Goblin Token", 1); assertDungeonRoom(null, null); assertLife(playerA, 20 + 1); assertLife(playerB, 20 - 1); @@ -189,7 +189,7 @@ public class DungeonTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Goblin", 1); + assertPermanentCount(playerA, "Goblin Token", 1); assertDungeonRoom(null, null); assertLife(playerA, 20 + 1); assertLife(playerB, 20 - 1); @@ -213,7 +213,7 @@ public class DungeonTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Goblin", 1); + assertPermanentCount(playerA, "Goblin Token", 1); assertDungeonRoom(LOST_MINE_OF_PHANDELVER, "Goblin Lair"); assertLife(playerA, 20); assertLife(playerB, 20); @@ -247,7 +247,7 @@ public class DungeonTest extends CardTestPlayerBase { assertPowerToughness(playerA, SILVERCOAT_LION, 3, 3); assertCounterCount(playerA, SILVERCOAT_LION, CounterType.P1P1, 1); - assertPermanentCount(playerA, "Goblin", 1); + assertPermanentCount(playerA, "Goblin Token", 1); assertDungeonRoom(LOST_MINE_OF_PHANDELVER, "Storeroom"); assertLife(playerA, 20); assertLife(playerB, 20); @@ -286,8 +286,8 @@ public class DungeonTest extends CardTestPlayerBase { assertPowerToughness(playerA, FLAMESPEAKER_ADEPT, 2 + 2, 3); assertPowerToughness(playerB, FLAMESPEAKER_ADEPT, 2 + 2 + 2, 3); - assertPermanentCount(playerA, "Goblin", 1); - assertPermanentCount(playerB, "Treasure", 1); + assertPermanentCount(playerA, "Goblin Token", 1); + assertPermanentCount(playerB, "Treasure Token", 1); assertDungeonRoom(playerA, LOST_MINE_OF_PHANDELVER, "Dark Pool"); assertDungeonRoom(playerB, DUNGEON_OF_THE_MAD_MAGE, "Lost Level"); assertLife(playerA, 20 + 1); @@ -406,7 +406,7 @@ public class DungeonTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertPowerToughness(playerA, FLAMESPEAKER_ADEPT, 2 + 2 + 2, 3); - assertPermanentCount(playerA, "Goblin", 2); + assertPermanentCount(playerA, "Goblin Token", 2); assertDungeonRoom(LOST_MINE_OF_PHANDELVER, "Dark Pool"); assertLife(playerA, 20 + 1 + 1); assertLife(playerB, 20 - 1 - 1); @@ -433,7 +433,7 @@ public class DungeonTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertPowerToughness(playerA, FLAMESPEAKER_ADEPT, 2 + 2, 3); - assertPermanentCount(playerA, "Goblin", 1); + assertPermanentCount(playerA, "Goblin Token", 1); assertDungeonRoom(LOST_MINE_OF_PHANDELVER, "Dark Pool"); assertLife(playerA, 20 + 1); assertLife(playerB, 20 - 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/NumericSetToEffectValueTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/SavedDamageValueTest.java similarity index 94% rename from Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/NumericSetToEffectValueTest.java rename to Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/SavedDamageValueTest.java index 5be1d4ca712..30d0406e504 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/NumericSetToEffectValueTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/SavedDamageValueTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.dynamicvalue; import mage.constants.PhaseStep; @@ -11,8 +10,7 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * @author LevelX2 */ -public class NumericSetToEffectValueTest extends CardTestPlayerBase { - +public class SavedDamageValueTest extends CardTestPlayerBase { /** * Check that the dealt damage is added to life @@ -40,7 +38,5 @@ public class NumericSetToEffectValueTest extends CardTestPlayerBase { assertLife(playerA, 24); assertLife(playerB, 16); - } - -} \ No newline at end of file +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/NestOfScarabsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/NestOfScarabsTest.java index 2e723097d8d..d7f83aee677 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/NestOfScarabsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/NestOfScarabsTest.java @@ -49,7 +49,7 @@ public class NestOfScarabsTest extends CardTestPlayerBase { assertPermanentCount(playerA, stinger, 1); assertCounterCount(playerA, stinger, CounterType.M1M1, 2); assertPowerToughness(playerA, stinger, 2, 3); // 4/5 with two -1/-1 counters - assertPermanentCount(playerA, "Insect", 2); // two counters = two insects + assertPermanentCount(playerA, "Insect Token", 2); // two counters = two insects } /* @@ -98,7 +98,7 @@ public class NestOfScarabsTest extends CardTestPlayerBase { assertCounterCount(playerB, hillGiant, CounterType.M1M1, 1); assertPowerToughness(playerB, grizzly, 1, 1); // 2/2 with -1/-1 counter assertPowerToughness(playerB, hillGiant, 2, 2); // 3/3 with -1/-1 counter - assertPermanentCount(playerA, "Insect", 4); // 4 counters = 4 insects + assertPermanentCount(playerA, "Insect Token", 4); // 4 counters = 4 insects } /* @@ -150,8 +150,8 @@ public class NestOfScarabsTest extends CardTestPlayerBase { assertCounterCount(playerB, hillGiant, CounterType.M1M1, 1); assertPowerToughness(playerB, grizzly, 1, 1); // 2/2 with -1/-1 counter assertPowerToughness(playerB, hillGiant, 2, 2); // 3/3 with -1/-1 counter - assertPermanentCount(playerB, "Insect", 0); // playerB did not place the -1/-1 counters, should not trigger - assertPermanentCount(playerA, "Insect", 4); // 4 counters = 4 insects + assertPermanentCount(playerB, "Insect Token", 0); // playerB did not place the -1/-1 counters, should not trigger + assertPermanentCount(playerA, "Insect Token", 4); // 4 counters = 4 insects } /* @@ -177,7 +177,7 @@ public class NestOfScarabsTest extends CardTestPlayerBase { assertCounterCount(playerB, CounterType.POISON, 0); assertPowerToughness(playerB, wOmens, -1, 3); // 0/4 with -1/-1 counter assertCounterCount(playerB, wOmens, CounterType.M1M1, 1); - assertPermanentCount(playerA, "Insect", 1); + assertPermanentCount(playerA, "Insect Token", 1); } /* @@ -203,6 +203,6 @@ public class NestOfScarabsTest extends CardTestPlayerBase { assertLife(playerB, 20); assertPowerToughness(playerB, wOmens, -2, 2); // 0/4 with two -1/-1 counters assertCounterCount(playerB, wOmens, CounterType.M1M1, 2); - assertPermanentCount(playerA, "Insect", 2); + assertPermanentCount(playerA, "Insect Token", 2); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/ParadoxHazeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/ParadoxHazeTest.java index 6189deb3e89..ab60ab2c514 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/ParadoxHazeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/ParadoxHazeTest.java @@ -30,7 +30,7 @@ public class ParadoxHazeTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Paradox Haze", 1); assertPermanentCount(playerA, "Verdant Force", 1); - assertPermanentCount(playerA, "Saproling", 3);// 1 from turn 2 and 2 from turn 3 + assertPermanentCount(playerA, "Saproling Token", 3);// 1 from turn 2 and 2 from turn 3 } @Test @@ -57,6 +57,6 @@ public class ParadoxHazeTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Paradox Haze", 2); assertPermanentCount(playerA, "Verdant Force", 1); - assertPermanentCount(playerA, "Saproling", 4); // 1 from turn 2 and 3 from turn 3 + assertPermanentCount(playerA, "Saproling Token", 4); // 1 from turn 2 and 3 from turn 3 } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SagaTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SagaTest.java index 132a744d379..c1c0f735089 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SagaTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/SagaTest.java @@ -29,13 +29,13 @@ public class SagaTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.PRECOMBAT_MAIN); execute(); assertCounterCount(rite, CounterType.LORE, 1); - assertPermanentCount(playerA, "Cleric", 2); + assertPermanentCount(playerA, "Cleric Token", 2); setStopAt(3, PhaseStep.PRECOMBAT_MAIN); execute(); assertCounterCount(rite, CounterType.LORE, 2); - assertPermanentCount(playerA, "Cleric", 4); + assertPermanentCount(playerA, "Cleric Token", 4); setStopAt(5, PhaseStep.BEGIN_COMBAT); execute(); @@ -43,8 +43,8 @@ public class SagaTest extends CardTestPlayerBase { assertGraveyardCount(playerA, rite, 1); assertPermanentCount(playerA, rite, 0); - assertPermanentCount(playerA, "Cleric", 4); - assertPermanentCount(playerA, "Demon", 1); + assertPermanentCount(playerA, "Cleric Token", 4); + assertPermanentCount(playerA, "Demon Token", 1); } @Test @@ -59,13 +59,13 @@ public class SagaTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.PRECOMBAT_MAIN); execute(); assertCounterCount(rite, CounterType.LORE, 1); - assertPermanentCount(playerA, "Cleric", 2); + assertPermanentCount(playerA, "Cleric Token", 2); setStopAt(3, PhaseStep.PRECOMBAT_MAIN); execute(); assertCounterCount(rite, CounterType.LORE, 2); - assertPermanentCount(playerA, "Cleric", 4); + assertPermanentCount(playerA, "Cleric Token", 4); castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerA, flicker, rite); setStopAt(3, PhaseStep.END_TURN); @@ -75,8 +75,8 @@ public class SagaTest extends CardTestPlayerBase { assertGraveyardCount(playerA, rite, 0); assertPermanentCount(playerA, rite, 1); assertCounterCount(playerA, rite, CounterType.LORE, 1); - assertPermanentCount(playerA, "Cleric", 6); - assertPermanentCount(playerA, "Demon", 0); + assertPermanentCount(playerA, "Cleric Token", 6); + assertPermanentCount(playerA, "Demon Token", 0); } @Test @@ -91,13 +91,13 @@ public class SagaTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.PRECOMBAT_MAIN); execute(); assertCounterCount(rite, CounterType.LORE, 1); - assertPermanentCount(playerA, "Cleric", 2); + assertPermanentCount(playerA, "Cleric Token", 2); setStopAt(3, PhaseStep.PRECOMBAT_MAIN); execute(); assertCounterCount(rite, CounterType.LORE, 2); - assertPermanentCount(playerA, "Cleric", 4); + assertPermanentCount(playerA, "Cleric Token", 4); castSpell(5, PhaseStep.PRECOMBAT_MAIN, playerA, boomerang, rite); setStopAt(5, PhaseStep.BEGIN_COMBAT); @@ -107,8 +107,8 @@ public class SagaTest extends CardTestPlayerBase { assertHandCount(playerA, rite, 1); assertPermanentCount(playerA, rite, 0); assertGraveyardCount(playerA, boomerang, 1); - assertPermanentCount(playerA, "Cleric", 4); - assertPermanentCount(playerA, "Demon", 1); + assertPermanentCount(playerA, "Cleric Token", 4); + assertPermanentCount(playerA, "Demon Token", 1); } @Test @@ -122,7 +122,7 @@ public class SagaTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.PRECOMBAT_MAIN); execute(); assertCounterCount(rite, CounterType.LORE, 2); - assertPermanentCount(playerA, "Cleric", 4); + assertPermanentCount(playerA, "Cleric Token", 4); setStopAt(3, PhaseStep.PRECOMBAT_MAIN); execute(); @@ -130,8 +130,8 @@ public class SagaTest extends CardTestPlayerBase { assertGraveyardCount(playerA, rite, 1); assertPermanentCount(playerA, rite, 0); - assertPermanentCount(playerA, "Cleric", 4); - assertPermanentCount(playerA, "Demon", 1); + assertPermanentCount(playerA, "Cleric Token", 4); + assertPermanentCount(playerA, "Demon Token", 1); } @Test diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/filters/IvoryGuardiansTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/filters/IvoryGuardiansTest.java index 22a0dcc2285..2a0358b34ab 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/filters/IvoryGuardiansTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/filters/IvoryGuardiansTest.java @@ -34,7 +34,7 @@ public class IvoryGuardiansTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPowerToughness(playerA, "Goblin", 1, 1); + assertPowerToughness(playerA, "Goblin Token", 1, 1); assertPowerToughness(playerB, "Ivory Guardians", 3, 3); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/mana/ForbiddenOrchardTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/mana/ForbiddenOrchardTest.java index 7e2bd1568b4..1a3289aea19 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/mana/ForbiddenOrchardTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/mana/ForbiddenOrchardTest.java @@ -27,8 +27,8 @@ public class ForbiddenOrchardTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Silvercoat Lion", 1); - assertPermanentCount(playerB, "Spirit", 1); - assertPermanentCount(playerA, "Spirit", 0); + assertPermanentCount(playerB, "Spirit Token", 1); + assertPermanentCount(playerA, "Spirit Token", 0); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/mana/RosheenMeandererManaXTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/mana/RosheenMeandererManaXTest.java index 40f3e79ef18..c2e284bbe10 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/mana/RosheenMeandererManaXTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/mana/RosheenMeandererManaXTest.java @@ -30,7 +30,7 @@ public class RosheenMeandererManaXTest extends CardTestPlayerBase { setChoice(playerA, "X=2"); checkPermanentCount("after", 1, PhaseStep.END_TURN, playerA, "Verdeloth the Ancient", 1); - checkPermanentCount("after", 1, PhaseStep.END_TURN, playerA, "Saproling", 2); + checkPermanentCount("after", 1, PhaseStep.END_TURN, playerA, "Saproling Token", 2); setStopAt(1, PhaseStep.END_TURN); setStrictChooseMode(true); @@ -55,7 +55,7 @@ public class RosheenMeandererManaXTest extends CardTestPlayerBase { setChoice(playerA, "X=2"); checkPermanentCount("after", 1, PhaseStep.END_TURN, playerA, "Verdeloth the Ancient", 1); - checkPermanentCount("after", 1, PhaseStep.END_TURN, playerA, "Saproling", 2); + checkPermanentCount("after", 1, PhaseStep.END_TURN, playerA, "Saproling Token", 2); setStopAt(1, PhaseStep.END_TURN); setStrictChooseMode(true); @@ -85,7 +85,7 @@ public class RosheenMeandererManaXTest extends CardTestPlayerBase { setChoice(playerA, "X=0"); checkPermanentCount("after", 1, PhaseStep.END_TURN, playerA, "Verdeloth the Ancient", 1); - checkPermanentCount("after", 1, PhaseStep.END_TURN, playerA, "Saproling", 0); + checkPermanentCount("after", 1, PhaseStep.END_TURN, playerA, "Saproling Token", 0); setStopAt(1, PhaseStep.END_TURN); setStrictChooseMode(true); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/mana/SpendManaAsThoughItWereManaOfAnyColorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/mana/SpendManaAsThoughItWereManaOfAnyColorTest.java index de1a4fd88e1..bf52745f642 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/mana/SpendManaAsThoughItWereManaOfAnyColorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/mana/SpendManaAsThoughItWereManaOfAnyColorTest.java @@ -40,7 +40,7 @@ public class SpendManaAsThoughItWereManaOfAnyColorTest extends CardTestPlayerBas assertExileCount(playerA, 0); assertGraveyardCount(playerA, "Moan of the Unhallowed", 1); - assertPermanentCount(playerB, "Zombie", 2); + assertPermanentCount(playerB, "Zombie Token", 2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/AjaniTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/AjaniTest.java index 5d4152a385e..652c340dcae 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/AjaniTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/AjaniTest.java @@ -52,7 +52,7 @@ public class AjaniTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "Kor Ally", 2); + assertPermanentCount(playerA, "Kor Ally Token", 2); assertPermanentCount(playerA, "Oath of Gideon", 1); assertPermanentCount(playerA, "Ajani Goldmane", 1); assertCounterCount("Ajani Goldmane", CounterType.LOYALTY, 6); // 4 + 1 + 1 = 6 diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/LilianaDefiantNecromancerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/LilianaDefiantNecromancerTest.java index 00ce1f60feb..b684ad9e11c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/LilianaDefiantNecromancerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/LilianaDefiantNecromancerTest.java @@ -38,7 +38,7 @@ public class LilianaDefiantNecromancerTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Lightning Bolt", 1); assertPermanentCount(playerA, "Liliana, Heretical Healer", 0); - assertPermanentCount(playerA, "Zombie", 1); + assertPermanentCount(playerA, "Zombie Token", 1); assertPermanentCount(playerA, "Liliana, Defiant Necromancer", 1); assertCounterCount("Liliana, Defiant Necromancer", CounterType.LOYALTY, 3); // No balid target with X=1 so no counter is removed assertPermanentCount(playerA, "Hill Giant", 0); @@ -73,7 +73,7 @@ public class LilianaDefiantNecromancerTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Lightning Bolt", 1); assertPermanentCount(playerA, "Liliana, Heretical Healer", 0); - assertPermanentCount(playerA, "Zombie", 1); + assertPermanentCount(playerA, "Zombie Token", 1); assertPermanentCount(playerA, "Alesha, Who Smiles at Death", 0); assertGraveyardCount(playerA, "Alesha, Who Smiles at Death", 1); // because target could not be chosen, the counters were never removed? @@ -109,7 +109,7 @@ public class LilianaDefiantNecromancerTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Lightning Bolt", 1); assertPermanentCount(playerA, "Liliana, Heretical Healer", 0); - assertPermanentCount(playerA, "Zombie", 1); + assertPermanentCount(playerA, "Zombie Token", 1); assertPermanentCount(playerA, "Bronze Sable", 1); assertGraveyardCount(playerA, "Bronze Sable", 0); assertPermanentCount(playerA, "Liliana, Defiant Necromancer", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/LilianaTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/LilianaTest.java index 0e77d2deb0c..8ac3196c548 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/LilianaTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/LilianaTest.java @@ -104,6 +104,6 @@ public class LilianaTest extends CardTestPlayerBase { assertCounterCount(playerA, liliannaUbD, CounterType.LOYALTY, 1); assertPermanentCount(playerA, "Carrion Feeder", 1); - assertPermanentCount(playerA, "Bat", 1); + assertPermanentCount(playerA, "Bat Token", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/NissaStewardOfElementsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/NissaStewardOfElementsTest.java new file mode 100644 index 00000000000..478ab343a91 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/NissaStewardOfElementsTest.java @@ -0,0 +1,54 @@ +package org.mage.test.cards.planeswalker; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class NissaStewardOfElementsTest extends CardTestPlayerBase { + + private static final String nissa = "Nissa, Steward of Elements"; + + private void doTest(int xValue) { + addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 2 + xValue); + addCard(Zone.HAND, playerA, nissa); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, nissa); + setChoice(playerA, "X=" + xValue); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + assertAllCommandsUsed(); + + if (xValue == 0) { + assertGraveyardCount(playerA, nissa, 1); + } else { + assertCounterCount(playerA, nissa, CounterType.LOYALTY, xValue); + } + } + + @Test + public void test0Counters() { + doTest(0); + } + + @Test + public void test1Counter() { + doTest(1); + } + + @Test + public void test2Counters() { + doTest(2); + } + + @Test + public void test10Counters() { + doTest(10); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/TamiyoTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/TamiyoTest.java index a2e0edff227..b8a5ca73d6c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/TamiyoTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/planeswalker/TamiyoTest.java @@ -38,10 +38,10 @@ public class TamiyoTest extends CardTestPlayerBase { activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Until end of turn"); // finally, use Tamiyo +1 on both creatures activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Choose up to two"); - addTarget(playerA, "Knight Ally^Gideon, Ally of Zendikar"); // both token and Gideon as creature + addTarget(playerA, "Knight Ally Token^Gideon, Ally of Zendikar"); // both token and Gideon as creature // attack with both unblocked - attack(3, playerA, "Knight Ally"); + attack(3, playerA, "Knight Ally Token"); attack(3, playerA, "Gideon, Ally of Zendikar"); setStopAt(3, PhaseStep.END_COMBAT); @@ -50,7 +50,7 @@ public class TamiyoTest extends CardTestPlayerBase { assertLife(playerB, 13); // 5 + 2 damage, 20 - 7 = 13 assertPermanentCount(playerA, "Tamiyo, Field Researcher", 1); assertPermanentCount(playerA, "Gideon, Ally of Zendikar", 1); - assertPermanentCount(playerA, "Knight Ally", 1); + assertPermanentCount(playerA, "Knight Ally Token", 1); assertHandCount(playerA, 3); // two cards drawn from each creature dealing damage + 1 card drawn on turn } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/AcademyManufactorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/AcademyManufactorTest.java index 25af4cffbaa..585e654799d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/AcademyManufactorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/AcademyManufactorTest.java @@ -22,9 +22,9 @@ public class AcademyManufactorTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Plains", 1); assertPermanentCount(playerA, "Academy Manufactor", 1); assertPermanentCount(playerA, "Thraben Inspector", 1); - assertPermanentCount(playerA, "Clue", 1); - assertPermanentCount(playerA, "Food", 1); - assertPermanentCount(playerA, "Treasure", 1); + assertPermanentCount(playerA, "Clue Token", 1); + assertPermanentCount(playerA, "Food Token", 1); + assertPermanentCount(playerA, "Treasure Token", 1); } @Test @@ -44,9 +44,9 @@ public class AcademyManufactorTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Academy Manufactor", 2); assertPermanentCount(playerA, "Anointed Procession", 1); assertPermanentCount(playerA, "Thraben Inspector", 1); - assertPermanentCount(playerA, "Clue", 6); - assertPermanentCount(playerA, "Food", 6); - assertPermanentCount(playerA, "Treasure", 6); + assertPermanentCount(playerA, "Clue Token", 6); + assertPermanentCount(playerA, "Food Token", 6); + assertPermanentCount(playerA, "Treasure Token", 6); } @Test @@ -88,8 +88,8 @@ public class AcademyManufactorTest extends CardTestPlayerBase { // Gingerbrute token copy becomes a regular Food assertPermanentCount(playerA, "Gingerbrute", 0); assertPermanentCount(playerB, "Gingerbrute", 0); - assertPermanentCount(playerA, "Clue", 3); - assertPermanentCount(playerA, "Food", 3); - assertPermanentCount(playerA, "Treasure", 3); + assertPermanentCount(playerA, "Clue Token", 3); + assertPermanentCount(playerA, "Food Token", 3); + assertPermanentCount(playerA, "Treasure Token", 3); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/ChatterfangSquirrelGeneralTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/ChatterfangSquirrelGeneralTest.java index c9d5c7af8f9..214be36af19 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/ChatterfangSquirrelGeneralTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/ChatterfangSquirrelGeneralTest.java @@ -23,8 +23,8 @@ public class ChatterfangSquirrelGeneralTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertPermanentCount(playerA, "Plains", 2); assertPermanentCount(playerA, chatterfang, 1); - assertPermanentCount(playerA, "Soldier", 2); - assertPermanentCount(playerA, "Squirrel", 2); + assertPermanentCount(playerA, "Soldier Token", 2); + assertPermanentCount(playerA, "Squirrel Token", 2); } @Test @@ -41,10 +41,10 @@ public class ChatterfangSquirrelGeneralTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertPermanentCount(playerA, "Plains", 2); assertPermanentCount(playerB, chatterfang, 1); - assertPermanentCount(playerA, "Soldier", 2); - assertPermanentCount(playerA, "Squirrel", 0); - assertPermanentCount(playerB, "Soldier", 0); - assertPermanentCount(playerB, "Squirrel", 0); + assertPermanentCount(playerA, "Soldier Token", 2); + assertPermanentCount(playerA, "Squirrel Token", 0); + assertPermanentCount(playerB, "Soldier Token", 0); + assertPermanentCount(playerB, "Squirrel Token", 0); } @Test @@ -66,9 +66,9 @@ public class ChatterfangSquirrelGeneralTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Plains", 1); assertPermanentCount(playerA, chatterfang, 1); assertPermanentCount(playerA, "Academy Manufactor", 1); - assertPermanentCount(playerA, "Clue", 1); - assertPermanentCount(playerA, "Food", 1); - assertPermanentCount(playerA, "Treasure", 1); - assertPermanentCount(playerA, "Squirrel", 3); + assertPermanentCount(playerA, "Clue Token", 1); + assertPermanentCount(playerA, "Food Token", 1); + assertPermanentCount(playerA, "Treasure Token", 1); + assertPermanentCount(playerA, "Squirrel Token", 3); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DamageEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DamageEffectsTest.java index fa7606a2f73..fa4d3b42146 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DamageEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DamageEffectsTest.java @@ -42,7 +42,7 @@ public class DamageEffectsTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Ob Nixilis, the Fallen", 1); assertGraveyardCount(playerA, "Wurmcoil Engine", 1); - assertPermanentCount(playerA, "Phyrexian Wurm", 2); + assertPermanentCount(playerA, "Phyrexian Wurm Token", 2); assertLife(playerB, 20); assertLife(playerA, 29); // -2 from Ob Nixilis + 12 from double damage with lifelink from Wurmcoil Engine diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DoublingSeasonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DoublingSeasonTest.java index 381fb09ad22..f93c3839727 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DoublingSeasonTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DoublingSeasonTest.java @@ -88,7 +88,7 @@ public class DoublingSeasonTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); - assertPermanentCount(playerA, "Saproling", 2); + assertPermanentCount(playerA, "Saproling Token", 2); assertCounterCount("Pallid Mycoderm", CounterType.SPORE, 1); } @@ -272,7 +272,7 @@ public class DoublingSeasonTest extends CardTestPlayerBase { assertAllCommandsUsed(); - assertPermanentCount(playerA, "Zombie", 2); + assertPermanentCount(playerA, "Zombie Token", 2); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DrawEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DrawEffectsTest.java index fff624ab762..0f1966e36b6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DrawEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DrawEffectsTest.java @@ -101,7 +101,7 @@ public class DrawEffectsTest extends CardTestPlayerBase { execute(); assertGraveyardCount(playerA, "Counsel of the Soratami", 1); - assertPermanentCount(playerA, "Bear", 1); + assertPermanentCount(playerA, "Bear Token", 1); assertHandCount(playerA, 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/HallowedMoonlightTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/HallowedMoonlightTest.java index 1fbf85cc0ba..f61ec75b385 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/HallowedMoonlightTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/HallowedMoonlightTest.java @@ -41,7 +41,7 @@ public class HallowedMoonlightTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Hallowed Moonlight", 1); assertGraveyardCount(playerB, "Spiritual Visit", 1); - assertPermanentCount(playerB, "Spirit", 0); + assertPermanentCount(playerB, "Spirit Token", 0); assertPermanentCount(playerB, "Silvercoat Lion", 1); assertExileCount(playerB, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/LeylineOfTheVoidTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/LeylineOfTheVoidTest.java index c954d2b6a39..f7e1c2e4d6e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/LeylineOfTheVoidTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/LeylineOfTheVoidTest.java @@ -123,7 +123,7 @@ public class LeylineOfTheVoidTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.END_TURN); execute(); - assertPermanentCount(playerA, "Eldrazi Spawn", 0); + assertPermanentCount(playerA, "Eldrazi Spawn Token", 0); assertExileCount(playerB, 0); assertHandCount(playerB, 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/ShieldCounterTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/ShieldCounterTest.java new file mode 100644 index 00000000000..3353ec7c9a4 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/ShieldCounterTest.java @@ -0,0 +1,87 @@ +package org.mage.test.cards.replacement; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author weirddan455 + */ +public class ShieldCounterTest extends CardTestPlayerBase { + + @Test + public void testNoncombatDamage() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + addCard(Zone.BATTLEFIELD, playerA, "Disciplined Duelist"); + addCard(Zone.HAND, playerA, "Lightning Bolt", 2); + setStrictChooseMode(true); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt"); + addTarget(playerA, "Disciplined Duelist"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAllCommandsUsed(); + assertPermanentCount(playerA, "Disciplined Duelist", 1); + assertCounterCount("Disciplined Duelist", CounterType.SHIELD, 0); + } + + @Test + public void testCombatDamage() { + addCard(Zone.BATTLEFIELD, playerA, "Disciplined Duelist"); + addCard(Zone.BATTLEFIELD, playerB, "Hill Giant"); + setStrictChooseMode(true); + + attack(1, playerA, "Disciplined Duelist"); + block(1, playerB, "Hill Giant", "Disciplined Duelist"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAllCommandsUsed(); + assertPermanentCount(playerA, "Disciplined Duelist", 1); + assertCounterCount("Disciplined Duelist", CounterType.SHIELD, 0); + assertGraveyardCount(playerB, "Hill Giant", 1); + } + + @Test + public void testDestroyEffect() { + addCard(Zone.BATTLEFIELD, playerA, "Disciplined Duelist"); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.HAND, playerA, "Murder"); + setStrictChooseMode(true); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Murder"); + addTarget(playerA, "Disciplined Duelist"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAllCommandsUsed(); + assertPermanentCount(playerA, "Disciplined Duelist", 1); + assertCounterCount("Disciplined Duelist", CounterType.SHIELD, 0); + } + + // Effects that say "Damage can't be prevented" should both remove the shield counter and deal damage + // TODO: Find a high toughness creature with a shield counter to test this better + @Test + public void testDamagePrevention() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + addCard(Zone.BATTLEFIELD, playerA, "Disciplined Duelist"); + addCard(Zone.HAND, playerA, "Call In a Professional", 1); + setStrictChooseMode(true); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Call In a Professional"); + addTarget(playerA, "Disciplined Duelist"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAllCommandsUsed(); + assertGraveyardCount(playerA, "Disciplined Duelist", 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/WouldDieExileInsteadTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/WouldDieExileInsteadTest.java index a8bc214192c..7ff103233ad 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/WouldDieExileInsteadTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/WouldDieExileInsteadTest.java @@ -44,7 +44,7 @@ public class WouldDieExileInsteadTest extends CardTestPlayerBase { assertExileCount("Sigiled Starfish", 1); assertGraveyardCount(playerB, 0); // all 3 creatures of playerB should be exiled not in graveyard assertExileCount("Kalitas, Traitor of Ghet", 0); // player controlled, not opponent so not exiled - assertPermanentCount(playerA, "Zombie", 3); // 3 tokens generated from exiling 3 opponent's creatures + assertPermanentCount(playerA, "Zombie Token", 3); // 3 tokens generated from exiling 3 opponent's creatures } /* diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/ZoneChangeReplacementTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/ZoneChangeReplacementTest.java index c20167908d7..e74df774d61 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/ZoneChangeReplacementTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/ZoneChangeReplacementTest.java @@ -75,7 +75,7 @@ public class ZoneChangeReplacementTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Silvercoat Lion", 1); assertGraveyardCount(playerA, 3); // Diabolic Edict + Bridge from Below + Silvercoat Lion - assertPermanentCount(playerA, "Zombie", 1); // Silvercoat Lion goes to graveyard so a Zombie tokes is created + assertPermanentCount(playerA, "Zombie Token", 1); // Silvercoat Lion goes to graveyard so a Zombie tokes is created } @@ -99,7 +99,7 @@ public class ZoneChangeReplacementTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Progenitus", 0); assertGraveyardCount(playerA, 2); // Diabolic Edict + Bridge from Below - assertPermanentCount(playerA, "Zombie", 0); // Progenitus never touches graveyard - so no Zombie tokes is created + assertPermanentCount(playerA, "Zombie Token", 0); // Progenitus never touches graveyard - so no Zombie tokes is created } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/HardenedScaleTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/HardenedScaleTest.java index 1a98c55f13e..644e307caa9 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/HardenedScaleTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/HardenedScaleTest.java @@ -50,7 +50,7 @@ public class HardenedScaleTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Wastes", 4); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, mMimic); - setChoice(playerA, "Construct"); + setChoice(playerA, "Construct Token"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, hWalker); setChoice(playerA, "X=1"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/LivingLoreTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/LivingLoreTest.java deleted file mode 100644 index caa65d6157a..00000000000 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/entersBattlefield/LivingLoreTest.java +++ /dev/null @@ -1,33 +0,0 @@ - -package org.mage.test.cards.replacement.entersBattlefield; - -import mage.constants.PhaseStep; -import mage.constants.Zone; -import org.junit.Test; -import org.mage.test.serverside.base.CardTestPlayerBase; - -/** - * - * @author LevelX2 - */ -public class LivingLoreTest extends CardTestPlayerBase { - - /** - * That the +1/+1 counters are added to Living Lore before state based - * actions take place - */ - @Test - public void testCountersAdded() { - addCard(Zone.BATTLEFIELD, playerA, "Island", 4); - addCard(Zone.HAND, playerA, "Living Lore"); //{3}{U} - addCard(Zone.GRAVEYARD, playerA, "Natural Connection", 1); // {2}{G} - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Living Lore"); - setStopAt(1, PhaseStep.BEGIN_COMBAT); - execute(); - - assertPermanentCount(playerA, "Living Lore", 1); - assertPowerToughness(playerA, "Living Lore", 3, 3); - } - -} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/restriction/ArrestTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/restriction/ArrestTest.java index c458a53ff58..dcf25af939c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/restriction/ArrestTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/restriction/ArrestTest.java @@ -29,7 +29,7 @@ public class ArrestTest extends CardTestPlayerBase { execute(); assertPermanentCount(playerA, "Arrest", 1); - assertPermanentCount(playerB, "Saproling", 0); // can't use ability so no Saproling + assertPermanentCount(playerB, "Saproling Token", 0); // can't use ability so no Saproling assertLife(playerA, 20); // can't attack so no damage to player assertLife(playerB, 20); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/rolldice/RollDiceTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/rolldice/RollDiceTest.java index a59c2d3798a..07f56214952 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/rolldice/RollDiceTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/rolldice/RollDiceTest.java @@ -46,7 +46,7 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { assertAllCommandsUsed(); assertPermanentCount(playerA, goblins, 1); - assertPermanentCount(playerA, "Goblin", goblinCount); + assertPermanentCount(playerA, "Goblin Token", goblinCount); } @Test @@ -91,7 +91,7 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { assertPermanentCount(playerA, goblins, 1); assertPermanentCount(playerA, guide, 1); - assertPermanentCount(playerA, "Goblin", 2); + assertPermanentCount(playerA, "Goblin Token", 2); } @Test @@ -113,7 +113,7 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { assertPermanentCount(playerA, goblins, 1); assertPermanentCount(playerA, guide, 2); - assertPermanentCount(playerA, "Goblin", 2); + assertPermanentCount(playerA, "Goblin Token", 2); } private void runKrarksOtherThumbTest(int choice, int thumbCount, int goblinCount, int... rolls) { @@ -141,7 +141,7 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { assertPermanentCount(playerA, goblins, 1); assertPermanentCount(playerA, gallery, 1); assertPermanentCount(playerA, thumb, thumbCount); - assertPermanentCount(playerA, "Goblin", goblinCount); + assertPermanentCount(playerA, "Goblin Token", goblinCount); } @Test(expected = AssertionError.class) @@ -198,7 +198,7 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { assertAllCommandsUsed(); assertPermanentCount(playerA, goblins, 1); - assertPermanentCount(playerA, "Goblin", goblinCount); + assertPermanentCount(playerA, "Goblin Token", goblinCount); assertAbility(playerA, farideh, FlyingAbility.getInstance(), true); assertHandCount(playerA, handCount); } @@ -232,7 +232,7 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Eldrazi", 2); + assertPermanentCount(playerA, "Eldrazi Token", 2); assertTappedCount("Mountain", true, 1); // cost for second planar die } @@ -259,7 +259,7 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Eldrazi", 1); + assertPermanentCount(playerA, "Eldrazi Token", 1); } @Test @@ -289,7 +289,7 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Eldrazi", 1); + assertPermanentCount(playerA, "Eldrazi Token", 1); } @Test @@ -323,7 +323,7 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Eldrazi", 0); + assertPermanentCount(playerA, "Eldrazi Token", 0); } @Test @@ -342,7 +342,7 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { setDieRollResult(playerA, 6); // additional roll - will be selected setDieRollResult(playerA, 5); // additional roll waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Goblin", 6); + checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Goblin Token", 6); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -366,11 +366,11 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}{B/R}{B/R}, {T}"); setDieRollResult(playerA, 3); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - checkPermanentCount("after prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Brainiac", 3); + checkPermanentCount("after prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Brainiac Token", 3); // prepare idea effect activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tap three Brainiac"); - setChoice(playerA, "Brainiac", 3); + setChoice(playerA, "Brainiac Token", 3); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // roll and trigger idea replace event @@ -378,7 +378,7 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { setDieRollResult(playerA, 3); // normal roll setDieRollResult(playerA, 6); // additional roll - will be sums waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Goblin", 3 + 6); + checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Goblin Token", 3 + 6); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -401,7 +401,7 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { setDieRollResult(playerA, 6); // additional roll setChoice(playerA, "6"); // keep 6 as roll result waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Goblin", 6); + checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Goblin Token", 6); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -427,7 +427,7 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Eldrazi", 1); + assertPermanentCount(playerA, "Eldrazi Token", 1); } @Test @@ -450,7 +450,7 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Eldrazi", 1); + assertPermanentCount(playerA, "Eldrazi Token", 1); } @Test @@ -471,11 +471,11 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}{B/R}{B/R}, {T}"); setDieRollResult(playerA, 3); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - checkPermanentCount("after prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Brainiac", 3); + checkPermanentCount("after prepare", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Brainiac Token", 3); // prepare idea effect activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tap three Brainiac"); - setChoice(playerA, "Brainiac", 3); + setChoice(playerA, "Brainiac Token", 3); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); // roll planar die, but no triggers with second roll - cause it works with numerical results (sum) @@ -489,7 +489,7 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Eldrazi", 1); + assertPermanentCount(playerA, "Eldrazi Token", 1); } @Test @@ -509,7 +509,7 @@ public class RollDiceTest extends CardTestPlayerBaseWithAIHelps { aiPlayPriority(1, PhaseStep.PRECOMBAT_MAIN, playerA); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Goblin", 6); + checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Goblin Token", 6); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/rules/TokenLimitTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/rules/TokenLimitTest.java index af0f77589a8..b5fd5701cde 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/rules/TokenLimitTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/rules/TokenLimitTest.java @@ -12,7 +12,7 @@ import org.mage.test.serverside.base.CardTestPlayerBase; public class TokenLimitTest extends CardTestPlayerBase { private static final String secure = "Secure the Wastes"; private static final String procession = "Anointed Procession"; - private static final String warrior = "Warrior"; + private static final String warrior = "Warrior Token"; @Test public void testOnePlayerHitsLimit() { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/afc/DeathTyrantTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/afc/DeathTyrantTest.java index fb5528f6024..eda390ed89e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/afc/DeathTyrantTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/afc/DeathTyrantTest.java @@ -20,7 +20,7 @@ public class DeathTyrantTest extends CardTestPlayerBase { execute(); assertGraveyardCount(playerA, "Grizzly Bears", 1); - assertPermanentCount(playerA, "Zombie", 1); + assertPermanentCount(playerA, "Zombie Token", 1); assertPermanentCount(playerA, "Death Tyrant", 1); assertPermanentCount(playerB, "Hill Giant", 1); } @@ -38,7 +38,7 @@ public class DeathTyrantTest extends CardTestPlayerBase { execute(); assertGraveyardCount(playerB, "Grizzly Bears", 1); - assertPermanentCount(playerA, "Zombie", 1); + assertPermanentCount(playerA, "Zombie Token", 1); assertPermanentCount(playerA, "Death Tyrant", 1); assertPermanentCount(playerA, "Hill Giant", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/afc/ShareTheSpoilsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/afc/ShareTheSpoilsTest.java new file mode 100644 index 00000000000..3223c775e33 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/afc/ShareTheSpoilsTest.java @@ -0,0 +1,526 @@ +package org.mage.test.cards.single.afc; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestCommander4Players; + + +public class ShareTheSpoilsTest extends CardTestCommander4Players { + + private static final String shareTheSpoils = "Share the Spoils"; + + /** + * When Share the Spoils enters the battlefield every player exiles one card. + */ + @Test + public void enterTheBattleField() { + addCard(Zone.HAND, playerA, shareTheSpoils); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, shareTheSpoils); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + assertExileCount(playerA, 1); + assertExileCount(playerB, 1); + assertExileCount(playerC, 1); + assertExileCount(playerD, 1); + } + + /** + * When an opponent loses, their exiled cards are removed from the game and all other players exile a new card. + */ + @Test + public void nonOwnerLoses() { + setLife(playerD, 1); + addCard(Zone.BATTLEFIELD, playerA, shareTheSpoils); + addCard(Zone.BATTLEFIELD, playerA, "Banehound", 1); + + attack(1, playerA, "Banehound", playerD); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + assertExileCount(playerA, 1); + assertExileCount(playerB, 1); + assertExileCount(playerC, 1); + assertExileCount(playerD, 0); + } + + /** + * When an opponent loses, their exiled cards are removed from the game and all other players exile a new card. + */ + @Test + public void nonOwnerConcedes() { + addCard(Zone.BATTLEFIELD, playerA, shareTheSpoils); + concede(1, PhaseStep.PRECOMBAT_MAIN, playerD); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + assertExileCount(playerA, 1); + assertExileCount(playerB, 1); + assertExileCount(playerC, 1); + assertExileCount(playerD, 0); + } + + /** + * When owner loses, no new cards should be exiled and owner's exiled cards are removed from the game. + */ + @Test + public void ownerConcedes() { + addCard(Zone.HAND, playerA, shareTheSpoils); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, shareTheSpoils); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + concede(1, PhaseStep.POSTCOMBAT_MAIN, playerA); + + setStopAt(1, PhaseStep.END_TURN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + assertExileCount(playerA, 0); + assertExileCount(playerB, 1); + assertExileCount(playerC, 1); + assertExileCount(playerD, 1); + } + + /** + * When owner loses, no new cards should be exiled and owner's exiled cards are removed from the game. + */ + @Test + public void ownerLoses() { + setLife(playerA, 1); + addCard(Zone.HAND, playerA, shareTheSpoils); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + addCard(Zone.BATTLEFIELD, playerD, "Banehound", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, shareTheSpoils); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + attack(2, playerD, "Banehound", playerA); + + setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + assertExileCount(playerA, 0); + assertExileCount(playerB, 1); + assertExileCount(playerC, 1); + assertExileCount(playerD, 1); + } + + /** + * During your turn, you may cast A card from the cards exiled with share the spoils. + */ + @Test + public void canCastOnOwnTurn() { + addCard(Zone.HAND, playerA, shareTheSpoils); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8); + + // 3rd from the top, exiled when Tana is cast with Share the Spoils + addCard(Zone.LIBRARY, playerA, "Reliquary Tower"); + // 2nd from the top, exile when Share the Spoils is cast + addCard(Zone.LIBRARY, playerA, "Tana, the Bloodsower", 1); // {2}{R}{G} + // Topmost, draw at beginning of turn + addCard(Zone.LIBRARY, playerA, "Exotic Orchard"); + + skipInitShuffling(); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, shareTheSpoils); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tana, the Bloodsower"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + setStopAt(1, PhaseStep.END_TURN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Tana, the Bloodsower", 1); + + assertExileCount(playerA, "Tana, the Bloodsower", 0); + assertExileCount(playerA, "Reliquary Tower", 1); + + assertExileCount(playerA, 1); + assertExileCount(playerB, 1); + assertExileCount(playerC, 1); + assertExileCount(playerD, 1); + } + + /** + * During your turn, you may play A land from the cards exiled with share the spoils. + */ + @Test + public void playLandOnOwnTurn() { + addCard(Zone.HAND, playerA, shareTheSpoils); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8); + + // 3rd from the top, exiled when Exotic Orchard is played with Share the Spoils + addCard(Zone.LIBRARY, playerA, "Reliquary Tower"); + // 2nd from the top, exile when Share the Spoils is cast + addCard(Zone.LIBRARY, playerA, "Exotic Orchard"); + // Topmost, draw at beginning of turn + addCard(Zone.LIBRARY, playerA, "Tana, the Bloodsower", 1); // {2}{R}{G} + + skipInitShuffling(); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, shareTheSpoils); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Exotic Orchard"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + setStopAt(1, PhaseStep.END_TURN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Exotic Orchard", 1); + + assertExileCount(playerA, "Exotic Orchard", 0); + assertExileCount(playerA, "Reliquary Tower", 1); + + assertExileCount(playerA, 1); + assertExileCount(playerB, 1); + assertExileCount(playerC, 1); + assertExileCount(playerD, 1); + } + + /** + * You cannot play a card or cast a spell when it's not your turn. + */ + @Test + public void cannotCastWhenNotYourTurn() { + addCard(Zone.HAND, playerA, shareTheSpoils); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8); + + // 2nd from the top, exile when Share the Spoils is cast + addCard(Zone.LIBRARY, playerA, "Lightning Bolt", 1); // {R} + // Topmost, draw at beginning of turn + addCard(Zone.LIBRARY, playerA, "Exotic Orchard"); + + addCard(Zone.LIBRARY, playerB, "Reliquary Tower"); + + skipInitShuffling(); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, shareTheSpoils); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + checkPlayableAbility("normal cast", 2, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Lightning Bolt", false); + checkPlayableAbility("before play", 2, PhaseStep.PRECOMBAT_MAIN, playerA, "Play Reliquary Tower", false); + + setStopAt(2, PhaseStep.END_TURN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + + assertExileCount(playerA, "Lightning Bolt", 1); + assertExileCount(playerA, "Reliquary Tower", 0); + + assertExileCount(playerA, 1); + assertExileCount(playerB, 1); + assertExileCount(playerC, 1); + assertExileCount(playerD, 1); + + assertGraveyardCount(playerA, 0); + } + + /** + * You may cast A spell or play A card, you cannot do both, or multiple of either. + */ + @Test + public void tryToCastOrPlayASecondCard() { + addCard(Zone.HAND, playerA, shareTheSpoils); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8); + + // 3rd from the top, exiled when card is played with Share the Spoils + addCard(Zone.LIBRARY, playerA, "Lightning Bolt", 1); // {R} + // 2nd from the top, exile when Share the Spoils is cast + addCard(Zone.LIBRARY, playerA, "Exotic Orchard"); + // Topmost, draw at beginning of turn + addCard(Zone.LIBRARY, playerA, "Reliquary Tower"); + + skipInitShuffling(); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, shareTheSpoils); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Exotic Orchard"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + // Abilities available after casting with Share the Spoils + checkPlayableAbility("Available Abilities", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Lightning Bolt", false); + + setStopAt(1, PhaseStep.END_TURN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + + assertExileCount(playerA, "Exotic Orchard", 0); + assertExileCount(playerA, "Lightning Bolt", 1); + + assertExileCount(playerA, 1); + assertExileCount(playerB, 1); + assertExileCount(playerC, 1); + assertExileCount(playerD, 1); + } + + /** + * Ensure that the spending mana as if it were any color only works for cards exiled with Share the Spoils. + */ + @Test + public void checkManaSpendingForOtherExileSource() { + addCard(Zone.HAND, playerA, shareTheSpoils); + addCard(Zone.HAND, playerA, "Augury Raven"); + addCard(Zone.BATTLEFIELD, playerA, "Prosper, Tome-Bound"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); + + // 3rd from the top, exile at end of turn with propser + addCard(Zone.LIBRARY, playerA, "Tana, the Bloodsower", 1); // {2}{R}{G} + // 2nd from the top, exile when Share the Spoils is cast + addCard(Zone.LIBRARY, playerA, "Exotic Orchard"); + // Topmost, draw at beginning of turn + addCard(Zone.LIBRARY, playerA, "Ardenvale Tactician"); // Adventure part is "Dizzying Swoop" + + skipInitShuffling(); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, shareTheSpoils); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + // Foretell Augury Raven + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Foretell"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + // Try to cast Tana, you should not be able to since there isn't the {G} for it since she was exiled by Proser + checkPlayableAbility("normal cast", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Tana, the Bloodsower", false); + + // Try to activate the foretell on Augury Raven, but we can't since we don't have the {U} for it. + checkPlayableAbility("foretell creature cast", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Foretell {1}{U}", false); + + // Cast an adventure card from hand + castSpell(5, PhaseStep.PRECOMBAT_MAIN, playerA, "Dizzying Swoop"); + addTarget(playerA, "Prosper, Tome-Bound"); + waitStackResolved(5, PhaseStep.PRECOMBAT_MAIN); + + // Make sure the creature card can't be played from exile since there isn't the {W}{W} for it + checkPlayableAbility("creature cast", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Ardenvale Tactician", false); + + setStopAt(5, PhaseStep.POSTCOMBAT_MAIN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + + // 1 exiled with Share the Spoils + // 1 exiled Prosper (he only exiles one since we stop before the end step of playerA's second turn) + // 1 for the foretold Augury Raven + // 1 for the Dizzying Swoop Adventure + assertExileCount(playerA, 4); + assertExileCount(playerB, 1); + assertExileCount(playerC, 1); + assertExileCount(playerD, 1); + } + + /** + * Make sure that the more difficult types cards work properly. + */ + @Test + public void checkDifficultCards() { + addCard(Zone.HAND, playerA, shareTheSpoils); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8); + + // 3rd from the top, exile Lovestruck Beast is cast + addCard(Zone.LIBRARY, playerA, "Ardenvale Tactician"); // Adventure, creature half {1}{W}{W} + // 2nd from the top, exile when Share the Spoils is cast + addCard(Zone.LIBRARY, playerA, "Lovestruck Beast"); // Adventure, adventure half "Heart's Desire" {G} + // Topmost, draw at beginning of turn + addCard(Zone.LIBRARY, playerA, "Mountain"); + + // Modal dual face, cast front + addCard(Zone.LIBRARY, playerB, "Alrund, God of the Cosmos"); // Backside is "Hakka, Whispering Raven" + // Modal fual face, cast back + addCard(Zone.LIBRARY, playerC, "Esika, God of the Tree"); // Backside is "The Prismatic Bridge" + // Split card + addCard(Zone.LIBRARY, playerD, "Fire // Ice"); + + skipInitShuffling(); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, shareTheSpoils); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + // Cast the Adventure half of an Adventure card + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Heart's Desire"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + // Cast the Creature half of an Adventure card + castSpell(5, PhaseStep.PRECOMBAT_MAIN, playerA, "Ardenvale Tactician"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + // Cast split card + castSpell(9, PhaseStep.PRECOMBAT_MAIN, playerA, "Ice"); + addTarget(playerA, "Mountain"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + // Cast front side of Modal dual face card + castSpell(13, PhaseStep.PRECOMBAT_MAIN, playerA, "Alrund, God of the Cosmos"); + setChoice(playerA, "Land"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + // Cast back side of Modal dual face card + castSpell(17, PhaseStep.PRECOMBAT_MAIN, playerA, "The Prismatic Bridge"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + setStopAt(17, PhaseStep.POSTCOMBAT_MAIN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Ardenvale Tactician", 1); + + assertExileCount(playerA, "Lovestruck Beast", 1); + + // 1 from Share the Spoils exiling a card for ETB + // 1 from casting the Adventur half of a card (Heart's Desire) and leaving it in exile + // 1 from casting "Ice" + // 1 from casting "Alrund, God of the Cosmos" + // 1 from casting "The Prismatic Bridge + assertExileCount(playerA, 5); + // 0 since playerA cast their card and replaced it with one of their own + assertExileCount(playerB, 0); + // 0 since playerA cast their card and replaced it with one of their own + assertExileCount(playerC, 0); + // 0 since playerA cast their card and replaced it with one of their own + assertExileCount(playerD, 0); + + // Ice is the only card that went in here + assertGraveyardCount(playerD, 1); + } + + /** + * When Share the Spoils leaves the battlefield, the exiled cards are no longer playable. + */ + @Test + public void ensureCardsNotPlayable() { + addCard(Zone.HAND, playerA, shareTheSpoils); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8); + + // 3rd from the top, exiled when card is played with Share the Spoils + addCard(Zone.LIBRARY, playerA, "Exotic Orchard"); + // 2nd from the top, exile when Share the Spoils is cast + addCard(Zone.LIBRARY, playerA, "Aether Helix", 1); // {3}{G}{U} + // Topmost, draw at beginning of turn + addCard(Zone.LIBRARY, playerA, "Reliquary Tower"); + + // Target in graveyard for Aether Helix + addCard(Zone.GRAVEYARD, playerA, "Aether Spellbomb"); + + skipInitShuffling(); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, shareTheSpoils); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Aether Helix"); + addTarget(playerA, shareTheSpoils); + addTarget(playerA, "Aether Spellbomb"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + checkPlayableAbility("before play", 5, PhaseStep.PRECOMBAT_MAIN, playerA, "Play Exotic Orchard", false); + + setStopAt(5, PhaseStep.END_TURN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + + assertExileCount(playerA, "Aether Helix", 0); + assertExileCount(playerA, "Exotic Orchard", 1); + + assertExileCount(playerA, 1); + assertExileCount(playerB, 1); + assertExileCount(playerC, 1); + assertExileCount(playerD, 1); + + assertGraveyardCount(playerA, 1); + } + + /** + * When this share the spoils is destroyed and it is somehow recast, it will create a new pool of cards. + * The previous cards are no longer playable. + */ + @Test + public void checkDifferentCardPools() { + addCard(Zone.HAND, playerA, shareTheSpoils); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 9); + + // 3rd from the top, exiled when card is played with Share the Spoils + addCard(Zone.LIBRARY, playerA, "Exotic Orchard"); + // 2nd from the top, exile when Share the Spoils is cast + addCard(Zone.LIBRARY, playerA, "Aether Helix", 1); // {3}{G}{U} + // Topmost, draw at beginning of turn + addCard(Zone.LIBRARY, playerA, "Reliquary Tower"); + + // Target in graveyard for Aether Helix + addCard(Zone.GRAVEYARD, playerA, "Aether Spellbomb"); + + skipInitShuffling(); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, shareTheSpoils); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + // Casting Aether Helix from exile with Share the spoils. + // Doing so exiles Exotic Orchard. + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Aether Helix"); + addTarget(playerA, shareTheSpoils); + addTarget(playerA, "Aether Spellbomb"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + // Recast, exile a new set of cards + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, shareTheSpoils); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA); + + // Exotic Orchard was exile by the first Share the Spoils, so can't be cast again with the new one + checkPlayableAbility("before play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Play Exotic Orchard", false); + + setStopAt(1, PhaseStep.END_TURN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + + assertExileCount(playerA, "Aether Helix", 0); + assertExileCount(playerA, "Exotic Orchard", 1); + + assertExileCount(playerA, 2); + assertExileCount(playerB, 2); + assertExileCount(playerC, 2); + assertExileCount(playerD, 2); + + assertGraveyardCount(playerA, 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/afr/ProsperousInnkeeperTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/afr/ProsperousInnkeeperTest.java index 1f3e03a8083..7e974a494d0 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/afr/ProsperousInnkeeperTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/afr/ProsperousInnkeeperTest.java @@ -19,7 +19,7 @@ public class ProsperousInnkeeperTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Treasure", 1); + assertPermanentCount(playerA, "Treasure Token", 1); } @Test diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/akh/AnnointedProcessionTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/akh/AnnointedProcessionTest.java index b7f3d793931..b8dbceaa297 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/akh/AnnointedProcessionTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/akh/AnnointedProcessionTest.java @@ -22,7 +22,7 @@ public class AnnointedProcessionTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); - assertPermanentCount(playerA, "Zombie", 4); + assertPermanentCount(playerA, "Zombie Token", 4); assertLife(playerA, 24); } @@ -38,7 +38,7 @@ public class AnnointedProcessionTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); - assertPermanentCount(playerA, "Zombie", 8); + assertPermanentCount(playerA, "Zombie Token", 8); assertLife(playerA, 28); } @@ -54,7 +54,7 @@ public class AnnointedProcessionTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); - assertPermanentCount(playerA, "Zombie", 2); + assertPermanentCount(playerA, "Zombie Token", 2); assertLife(playerA, 20); } @@ -82,6 +82,6 @@ public class AnnointedProcessionTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); - assertPermanentCount(playerA, "Zombie", 6); + assertPermanentCount(playerA, "Zombie Token", 6); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/akh/HapatraVizierOfPoisonsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/akh/HapatraVizierOfPoisonsTest.java index 1c525b158a7..8d095c31bfe 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/akh/HapatraVizierOfPoisonsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/akh/HapatraVizierOfPoisonsTest.java @@ -38,8 +38,8 @@ public class HapatraVizierOfPoisonsTest extends CardTestPlayerBase { assertLife(playerB, 18); assertCounterCount(playerB, gBears, CounterType.M1M1, 1); assertPowerToughness(playerB, gBears, 1, 1); // 2/2 with -1/1 counter - assertPermanentCount(playerA, "Snake", 1); - assertAbility(playerA, "Snake", DeathtouchAbility.getInstance(), true); + assertPermanentCount(playerA, "Snake Token", 1); + assertAbility(playerA, "Snake Token", DeathtouchAbility.getInstance(), true); } /* @@ -66,8 +66,8 @@ public class HapatraVizierOfPoisonsTest extends CardTestPlayerBase { assertCounterCount(playerB, CounterType.POISON, 0); assertPowerToughness(playerB, wOmens, -1, 3); // 0/4 with -1/-1 counter assertCounterCount(playerB, wOmens, CounterType.M1M1, 1); - assertPermanentCount(playerA, "Snake", 1); - assertAbility(playerA, "Snake", DeathtouchAbility.getInstance(), true); + assertPermanentCount(playerA, "Snake Token", 1); + assertAbility(playerA, "Snake Token", DeathtouchAbility.getInstance(), true); } /* @@ -95,8 +95,8 @@ public class HapatraVizierOfPoisonsTest extends CardTestPlayerBase { assertCounterCount(playerA, dDruid, CounterType.M1M1, 1); assertPowerToughness(playerA, dDruid, -1, 1); // 0/2 with -1/-1 - assertPermanentCount(playerA, "Snake", 1); - assertAbility(playerA, "Snake", DeathtouchAbility.getInstance(), true); + assertPermanentCount(playerA, "Snake Token", 1); + assertAbility(playerA, "Snake Token", DeathtouchAbility.getInstance(), true); } /** @@ -122,15 +122,15 @@ public class HapatraVizierOfPoisonsTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, sprout); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, triumphOfTheHordes); - attack(1, playerA, "Saproling"); - block(1, playerB, krakenHatchling, "Saproling"); + attack(1, playerA, "Saproling Token"); + block(1, playerB, krakenHatchling, "Saproling Token"); setStopAt(1, PhaseStep.END_COMBAT); setStrictChooseMode(true); execute(); assertPowerToughness(playerB, krakenHatchling, -2, 2); assertCounterCount(playerB, krakenHatchling, CounterType.M1M1, 2); - assertPermanentCount(playerA, "Snake", 1); //Should have triggered when Saproling added -1/-1 counter + assertPermanentCount(playerA, "Snake Token", 1); //Should have triggered when Saproling added -1/-1 counter assertAllCommandsUsed(); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/ala/DeathBaronTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/ala/DeathBaronTest.java new file mode 100644 index 00000000000..ca8a65e7ce3 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/ala/DeathBaronTest.java @@ -0,0 +1,66 @@ +package org.mage.test.cards.single.ala; + +import mage.abilities.Ability; +import mage.abilities.keyword.DeathtouchAbility; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author awjackson + */ +public class DeathBaronTest extends CardTestPlayerBase { + + private static final String baron = "Death Baron"; + private static final String skeleton = "Drudge Skeletons"; + private static final String zombie = "Scathe Zombies"; + private static final String knight = "Black Knight"; + + @Test + public void testDoesntNormallyAffectSelf() { + addCard(Zone.BATTLEFIELD, playerA, baron); + addCard(Zone.BATTLEFIELD, playerA, skeleton); + addCard(Zone.BATTLEFIELD, playerA, zombie); + addCard(Zone.BATTLEFIELD, playerA, knight); + + addCard(Zone.BATTLEFIELD, playerB, skeleton); + addCard(Zone.BATTLEFIELD, playerB, zombie); + + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + + Ability deathtouch = DeathtouchAbility.getInstance(); + + // Death Baron doesn't normally affect itself + assertPowerToughness(playerA, baron, 2, 2); + assertAbility(playerA, baron, deathtouch, false); + + assertPowerToughness(playerA, skeleton, 2, 2); + assertPowerToughness(playerA, zombie, 3, 3); + assertPowerToughness(playerA, knight, 2, 2); + assertAbility(playerA, skeleton, deathtouch, true); + assertAbility(playerA, zombie, deathtouch, true); + assertAbility(playerA, knight, deathtouch, false); + + assertPowerToughness(playerB, skeleton, 1, 1); + assertPowerToughness(playerB, zombie, 2, 2); + assertAbility(playerB, skeleton, deathtouch, false); + assertAbility(playerB, zombie, deathtouch, false); + } + + @Test + public void testBecomeSkeleton() { + addCard(Zone.BATTLEFIELD, playerA, baron); + addCard(Zone.BATTLEFIELD, playerA, "Amoeboid Changeling"); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Target creature gains", baron); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + // If you manage to turn it into a Skeleton, however, then it will give itself +1/+1 and deathtouch + assertPowerToughness(playerA, baron, 3, 3); + assertAbility(playerA, baron, DeathtouchAbility.getInstance(), true); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/bok/ShireiShizosCaretakerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/bok/ShireiShizosCaretakerTest.java new file mode 100644 index 00000000000..294fe1f6141 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/bok/ShireiShizosCaretakerTest.java @@ -0,0 +1,73 @@ +package org.mage.test.cards.single.bok; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class ShireiShizosCaretakerTest extends CardTestPlayerBase { + private static final String shirei = "Shirei, Shizo's Caretaker"; + private static final String rats = "Muck Rats"; + private static final String murder = "Murder"; + private static final String blink = "Momentary Blink"; + + @Test + public void testRegular() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.BATTLEFIELD, playerA, shirei); + addCard(Zone.BATTLEFIELD, playerA, rats); + addCard(Zone.HAND, playerA, murder); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, murder, rats); + setChoice(playerA, true); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + assertPermanentCount(playerA, shirei, 1); + assertPermanentCount(playerA, rats, 1); + } + + @Test + public void testLeftBattlefield() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6); + addCard(Zone.BATTLEFIELD, playerA, shirei); + addCard(Zone.BATTLEFIELD, playerA, rats); + addCard(Zone.HAND, playerA, murder, 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, murder, rats); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, murder, shirei); + setChoice(playerA, true); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + assertPermanentCount(playerA, shirei, 0); + assertPermanentCount(playerA, rats, 0); + } + + @Test + public void testBlinked() { + addCard(Zone.BATTLEFIELD, playerA, "Scrubland", 5); + addCard(Zone.BATTLEFIELD, playerA, shirei); + addCard(Zone.BATTLEFIELD, playerA, rats); + addCard(Zone.HAND, playerA, murder); + addCard(Zone.HAND, playerA, blink); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, murder, rats); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, blink, shirei); + setChoice(playerA, true); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + assertPermanentCount(playerA, shirei, 1); + assertPermanentCount(playerA, rats, 0); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/c17/KessDissidentMageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/c17/KessDissidentMageTest.java index 1278853b2e4..ed32251741a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/c17/KessDissidentMageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/c17/KessDissidentMageTest.java @@ -51,7 +51,7 @@ public class KessDissidentMageTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Centaur", 1); + assertPermanentCount(playerA, "Centaur Token", 1); assertLife(playerA, 20); assertExileCount(playerA, "Alive // Well", 1); } @@ -76,7 +76,7 @@ public class KessDissidentMageTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Centaur", 1); + assertPermanentCount(playerA, "Centaur Token", 1); assertLife(playerA, 20 + 2); assertGraveyardCount(playerA, "Alive // Well", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/c18/VarchildBetrayerOfKjeldorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/c18/VarchildBetrayerOfKjeldorTest.java index 7238656ffb0..59a1aad69bc 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/c18/VarchildBetrayerOfKjeldorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/c18/VarchildBetrayerOfKjeldorTest.java @@ -30,7 +30,7 @@ public class VarchildBetrayerOfKjeldorTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Varchild, Betrayer of Kjeldor", 1); - assertPermanentCount(playerB, "Survivor", 3); + assertPermanentCount(playerB, "Survivor Token", 3); } @Test @@ -62,10 +62,10 @@ public class VarchildBetrayerOfKjeldorTest extends CardTestPlayerBase { assertExileCount(playerA, "Varchild, Betrayer of Kjeldor", 1); assertLife(playerA, 23); - assertPermanentCount(playerA, "Survivor", 3); + assertPermanentCount(playerA, "Survivor Token", 3); assertPermanentCount(playerB, "Irregular Cohort", 1); - assertPermanentCount(playerB, "Shapeshifter", 1); + assertPermanentCount(playerB, "Shapeshifter Token", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/chk/TatsumasaTheDragonsFangTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/chk/TatsumasaTheDragonsFangTest.java new file mode 100644 index 00000000000..1afb305ae37 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/chk/TatsumasaTheDragonsFangTest.java @@ -0,0 +1,34 @@ +package org.mage.test.cards.single.chk; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class TatsumasaTheDragonsFangTest extends CardTestPlayerBase { + + private static final String tatsumasa = "Tatsumasa, the Dragon's Fang"; + private static final String murder = "Murder"; + + @Test + public void testTatsumasa() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 9); + addCard(Zone.BATTLEFIELD, playerA, tatsumasa); + addCard(Zone.HAND, playerA, murder); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{6}"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, murder, "Dragon Spirit Token"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, tatsumasa, 1); + assertGraveyardCount(playerA, murder, 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/cmd/AcornCatapultTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/cmd/AcornCatapultTest.java index 9bed69cc0fc..4775c5e3329 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/cmd/AcornCatapultTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/cmd/AcornCatapultTest.java @@ -36,7 +36,7 @@ public class AcornCatapultTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Acolyte of Xathrid", 1); - assertPermanentCount(playerB, "Squirrel", 1); + assertPermanentCount(playerB, "Squirrel Token", 1); } @Test @@ -61,7 +61,7 @@ public class AcornCatapultTest extends CardTestPlayerBase { assertLife(playerB, 19); - assertPermanentCount(playerB, "Squirrel", 1); + assertPermanentCount(playerB, "Squirrel Token", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/cmr/ProfaneTransfusionTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/cmr/ProfaneTransfusionTest.java index 756a5258093..51218bf8e43 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/cmr/ProfaneTransfusionTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/cmr/ProfaneTransfusionTest.java @@ -34,8 +34,8 @@ public class ProfaneTransfusionTest extends CardTestPlayerBase { assertLife(playerA, 16); assertLife(playerB, 24); - assertPermanentCount(playerA, "Phyrexian Horror", 1); - assertPowerToughness(playerA, "Phyrexian Horror", 24 - 16, 24 - 16); + assertPermanentCount(playerA, "Phyrexian Horror Token", 1); + assertPowerToughness(playerA, "Phyrexian Horror Token", 24 - 16, 24 - 16); assertGraveyardCount(playerA, transfusion, 1); } @@ -60,8 +60,8 @@ public class ProfaneTransfusionTest extends CardTestPlayerBase { assertLife(playerA, 24); assertLife(playerB, 16); - assertPermanentCount(playerA, "Phyrexian Horror", 1); - assertPowerToughness(playerA, "Phyrexian Horror", 24 - 16, 24 - 16); + assertPermanentCount(playerA, "Phyrexian Horror Token", 1); + assertPowerToughness(playerA, "Phyrexian Horror Token", 24 - 16, 24 - 16); assertGraveyardCount(playerA, transfusion, 1); } @@ -86,8 +86,8 @@ public class ProfaneTransfusionTest extends CardTestPlayerBase { assertLife(playerA, 16); assertLife(playerB, 32); - assertPermanentCount(playerA, "Phyrexian Horror", 1); - assertPowerToughness(playerA, "Phyrexian Horror", 32 - 16, 32 - 16); + assertPermanentCount(playerA, "Phyrexian Horror Token", 1); + assertPowerToughness(playerA, "Phyrexian Horror Token", 32 - 16, 32 - 16); assertGraveyardCount(playerA, transfusion, 1); } @@ -110,8 +110,8 @@ public class ProfaneTransfusionTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 17); - assertPermanentCount(playerA, "Phyrexian Horror", 1); - assertPowerToughness(playerA, "Phyrexian Horror", 20 - 17, 20 - 17); + assertPermanentCount(playerA, "Phyrexian Horror Token", 1); + assertPowerToughness(playerA, "Phyrexian Horror Token", 20 - 17, 20 - 17); assertGraveyardCount(playerA, transfusion, 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dis/AzoriusAethermageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dis/AzoriusAethermageTest.java new file mode 100644 index 00000000000..a7bb0f69afe --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dis/AzoriusAethermageTest.java @@ -0,0 +1,54 @@ +package org.mage.test.cards.single.dis; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class AzoriusAethermageTest extends CardTestPlayerBase { + + /** + * Whenever you bounce a permanent (tokens included) you may pay {1}, if you do, draw a card + */ + @Test + public void testBouncedLand() { + /* + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); // Used for paying ability cost + addCard(Zone.BATTLEFIELD, playerA, "Island", 2*3); + addCard(Zone.BATTLEFIELD, playerA, "Toggo, Goblin Weaponsmith"); + addCard(Zone.HAND, playerA, "Boomerang",3); + + // Permanents to bounce + addCard(Zone.HAND, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Azorius Aethermage"); + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plains"); // Create a Rock token with Toggo + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Plains"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA, true); + setChoice(playerA, "Yes"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Rock"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA, true); + setChoice(playerA, "Yes"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Azorius Aethermage"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA, true); + setChoice(playerA, "Yes"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + setStopAt(1, PhaseStep.END_TURN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + + // 3 cards bounced: plains, token, and aethermage, but the token never makes it to the hand -> +2 cards in hand + // 3 cards drawn -> +3 cards in hand + assertHandCount(playerA, (1+1) + (1) + (1+1)); + */ + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/AltarOfTheLostTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/AltarOfTheLostTest.java index f9f0fc11ffb..e74e465a5d2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/AltarOfTheLostTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/AltarOfTheLostTest.java @@ -33,7 +33,7 @@ public class AltarOfTheLostTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); - assertPermanentCount(playerA, "Spirit", 2); + assertPermanentCount(playerA, "Spirit Token", 2); } @Test @@ -53,7 +53,7 @@ public class AltarOfTheLostTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); - assertPermanentCount(playerA, "Spirit", 0); + assertPermanentCount(playerA, "Spirit Token", 0); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/FeedThePackTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/FeedThePackTest.java index e04dc44a16a..3bd064ff387 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/FeedThePackTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/FeedThePackTest.java @@ -21,7 +21,7 @@ public class FeedThePackTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); - assertPermanentCount(playerA, "Wolf", 4); + assertPermanentCount(playerA, "Wolf Token", 4); assertPermanentCount(playerB, "Craw Wurm", 0); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/GrafdiggersCageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/GrafdiggersCageTest.java index 2b6c3ff9b6d..6c4fcfbac8e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/GrafdiggersCageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/GrafdiggersCageTest.java @@ -28,7 +28,7 @@ public class GrafdiggersCageTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); - assertPermanentCount(playerA, "Spirit", 0); + assertPermanentCount(playerA, "Spirit Token", 0); assertGraveyardCount(playerA, "Lingering Souls", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/HuntmasterOfTheFellsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/HuntmasterOfTheFellsTest.java index e1fb2ce4b26..fa76f5da383 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/HuntmasterOfTheFellsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/HuntmasterOfTheFellsTest.java @@ -41,7 +41,7 @@ public class HuntmasterOfTheFellsTest extends CardTestPlayerBase { assertLife(playerA, 20 + 2); assertLife(playerB, 20); assertPermanentCount(playerA, "Huntmaster of the Fells", 1); - assertPermanentCount(playerA, "Wolf", 1); + assertPermanentCount(playerA, "Wolf Token", 1); assertPermanentCount(playerA, "Ravager of the Fells", 0); } @@ -59,7 +59,7 @@ public class HuntmasterOfTheFellsTest extends CardTestPlayerBase { assertLife(playerA, 20 + 2); assertLife(playerB, 20 - 2); assertPermanentCount(playerA, "Huntmaster of the Fells", 0); - assertPermanentCount(playerA, "Wolf", 1); + assertPermanentCount(playerA, "Wolf Token", 1); assertPermanentCount(playerA, "Ravager of the Fells", 1); } @@ -84,7 +84,7 @@ public class HuntmasterOfTheFellsTest extends CardTestPlayerBase { assertLife(playerA, 20 + 2 + 2); assertLife(playerB, 20 - 2 - 3 * 2); assertPermanentCount(playerA, "Huntmaster of the Fells", 1); - assertPermanentCount(playerA, "Wolf", 2); + assertPermanentCount(playerA, "Wolf Token", 2); assertPermanentCount(playerA, "Ravager of the Fells", 0); assertPermanentCount(playerA, "Lightning Bolt", 0); } @@ -112,7 +112,7 @@ public class HuntmasterOfTheFellsTest extends CardTestPlayerBase { assertLife(playerA, 20 + 2 + 2); assertLife(playerB, 20 - 2 - 3 * 2); assertPermanentCount(playerA, "Huntmaster of the Fells", 1); - assertPermanentCount(playerA, "Wolf", 2); + assertPermanentCount(playerA, "Wolf Token", 2); assertPermanentCount(playerA, "Ravager of the Fells", 0); assertPermanentCount(playerA, "Lightning Bolt", 0); assertPermanentCount(playerB, "Balduvian Bears", 0); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/IncreasingCardsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/IncreasingCardsTest.java index 8d7b1eed059..7a5bb88a941 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/IncreasingCardsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/IncreasingCardsTest.java @@ -81,7 +81,7 @@ public class IncreasingCardsTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); assertGraveyardCount(playerA, 0); - assertPermanentCount(playerA, "Human", 15); + assertPermanentCount(playerA, "Human Token", 15); assertExileCount("Increasing Devotion", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/SecretsOfTheDeadTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/SecretsOfTheDeadTest.java index 5d798749ea3..b5c68198b22 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/SecretsOfTheDeadTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/SecretsOfTheDeadTest.java @@ -23,7 +23,7 @@ public class SecretsOfTheDeadTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); - assertPermanentCount(playerA, "Spirit", 2); + assertPermanentCount(playerA, "Spirit Token", 2); assertHandCount(playerA, 1); } @@ -38,7 +38,7 @@ public class SecretsOfTheDeadTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); - assertPermanentCount(playerA, "Spirit", 2); + assertPermanentCount(playerA, "Spirit Token", 2); assertHandCount(playerA, 0); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/SorinLordOfInnistradTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/SorinLordOfInnistradTest.java index 43b56c46b05..a3c9722f834 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/SorinLordOfInnistradTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dka/SorinLordOfInnistradTest.java @@ -26,7 +26,7 @@ public class SorinLordOfInnistradTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); assertPermanentCount(playerA, "Sorin, Lord of Innistrad", 1); - assertPermanentCount(playerA, "Vampire", 1); + assertPermanentCount(playerA, "Vampire Token", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dst/EchoingTruthTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dst/EchoingTruthTest.java index 2c3b67abd4d..eaff4aba478 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/dst/EchoingTruthTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dst/EchoingTruthTest.java @@ -25,7 +25,7 @@ public class EchoingTruthTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Echoing Truth"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Spectral Procession"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Echoing Truth", "Spirit"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Echoing Truth", "Spirit Token"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -35,7 +35,7 @@ public class EchoingTruthTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Spectral Procession", 1); assertGraveyardCount(playerB, "Echoing Truth", 1); - assertPermanentCount(playerA, "Spirit", 0); + assertPermanentCount(playerA, "Spirit Token", 0); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dtk/LivingLoreTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dtk/LivingLoreTest.java new file mode 100644 index 00000000000..70358ce0604 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dtk/LivingLoreTest.java @@ -0,0 +1,54 @@ +package org.mage.test.cards.single.dtk; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author LevelX2 + */ +public class LivingLoreTest extends CardTestPlayerBase { + + /** + * That the +1/+1 counters are added to Living Lore before state based + * actions take place + */ + @Test + public void testCountersAdded() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + addCard(Zone.HAND, playerA, "Living Lore"); //{3}{U} + addCard(Zone.GRAVEYARD, playerA, "Natural Connection", 1); // {2}{G} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Living Lore"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Living Lore", 1); + assertPowerToughness(playerA, "Living Lore", 3, 3); + } + + @Test + public void testCastSpell() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + addCard(Zone.HAND, playerA, "Living Lore"); //{3}{U} + addCard(Zone.GRAVEYARD, playerA, "Lightning Bolt", 1); // {R} + + addTarget(playerA, "Lightning Bolt"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Living Lore"); + + attack(3, playerA, "Living Lore", playerB); + setChoice(playerA, true); // sacrifice + setChoice(playerA, true); // cast spell + addTarget(playerA, playerB); + + setStrictChooseMode(true); + setStopAt(3, PhaseStep.END_COMBAT); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Living Lore", 0); + assertGraveyardCount(playerA, "Lightning Bolt", 1); + assertLife(playerB, 20 - 1 - 3); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/eld/BarteredCowTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/eld/BarteredCowTest.java index 7be461ae765..672e3c3542d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/eld/BarteredCowTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/eld/BarteredCowTest.java @@ -29,7 +29,7 @@ public class BarteredCowTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Lightning Bolt", 1); assertGraveyardCount(playerA, "Bartered Cow", 1); - assertPermanentCount(playerA, "Food", 1); + assertPermanentCount(playerA, "Food Token", 1); } @Test @@ -56,7 +56,7 @@ public class BarteredCowTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Funeral Charm", 1); assertGraveyardCount(playerA, "Bartered Cow", 1); - assertPermanentCount(playerA, "Food", 1); + assertPermanentCount(playerA, "Food Token", 1); } @Test @@ -82,7 +82,7 @@ public class BarteredCowTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Bartered Cow", 1); assertHandCount(playerA, "Silvercoat Lion", 1); - assertPermanentCount(playerA, "Food", 1); + assertPermanentCount(playerA, "Food Token", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/eld/OnceUponATimeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/eld/OnceUponATimeTest.java index 2982fe655c5..fb702e3d2c5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/eld/OnceUponATimeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/eld/OnceUponATimeTest.java @@ -35,7 +35,7 @@ public class OnceUponATimeTest extends CardTestPlayerBase { setChoice(playerA, false); // Cast without paying its mana cost? setChoice(playerA, true); // Do you wish to reveal a creature or land card and put into your hand? - setChoice(playerA, "Silvercoat Lion"); + addTarget(playerA, "Silvercoat Lion"); setStopAt(2, PhaseStep.END_TURN); execute(); @@ -68,12 +68,12 @@ public class OnceUponATimeTest extends CardTestPlayerBase { castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Once Upon a Time"); setChoice(playerA, true); // Cast without paying its mana cost? setChoice(playerA, true); // Do you wish to reveal a creature or land card and put into your hand? - setChoice(playerA, "Silvercoat Lion"); + addTarget(playerA, "Silvercoat Lion"); castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Once Upon a Time"); setChoice(playerB, true); // Cast without paying its mana cost? setChoice(playerB, true); // Do you wish to reveal a creature or land card and put into your hand? - setChoice(playerB, "Silvercoat Lion"); + addTarget(playerB, "Silvercoat Lion"); setStopAt(2, PhaseStep.END_TURN); execute(); @@ -86,4 +86,4 @@ public class OnceUponATimeTest extends CardTestPlayerBase { assertHandCount(playerA, "Silvercoat Lion", 1); assertHandCount(playerB, "Silvercoat Lion", 2); } -} \ No newline at end of file +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/eld/SyrKonradTheGrimTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/eld/SyrKonradTheGrimTest.java index 56c83b7568d..01de677aa43 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/eld/SyrKonradTheGrimTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/eld/SyrKonradTheGrimTest.java @@ -30,4 +30,26 @@ public class SyrKonradTheGrimTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 18); } + + @Test + public void reanimateFromOtherGraveyardTest() { + addCard(Zone.HAND, playerA, "Reanimate"); + addCard(Zone.BATTLEFIELD, playerA, "Swamp"); + addCard(Zone.BATTLEFIELD, playerA, "Syr Konrad, the Grim"); + addCard(Zone.GRAVEYARD, playerB, "Grizzly Bears"); + + setStopAt(1, PhaseStep.UNTAP); + execute(); + + assertLife(playerB, 20); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", "Grizzly Bears"); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerB, 0); + assertPermanentCount(playerA, "Grizzly Bears", 1); + assertLife(playerA, 18); // loss of 2 from reanimate + assertLife(playerB, 20); // card leaving B's graveyard *shouldn't* cause loss of life + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/emn/SoulSeparatorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/emn/SoulSeparatorTest.java index 9fc9834b7b1..6b684730433 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/emn/SoulSeparatorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/emn/SoulSeparatorTest.java @@ -36,8 +36,8 @@ public class SoulSeparatorTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Soul Separator", 1); assertExileCount("Sylvan Advocate", 1); assertPermanentCount(playerA, "Sylvan Advocate", 1); - assertPermanentCount(playerA, "Zombie", 1); - assertPowerToughness(playerA, "Zombie", 2, 3); + assertPermanentCount(playerA, "Zombie Token", 1); + assertPowerToughness(playerA, "Zombie Token", 2, 3); Permanent saToken = getPermanent("Sylvan Advocate", playerA); Assert.assertTrue(saToken.getAbilities().contains(FlyingAbility.getInstance())); @@ -72,8 +72,8 @@ public class SoulSeparatorTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Soul Separator", 1); assertExileCount("Tree of Perdition", 1); assertPermanentCount(playerA, "Tree of Perdition", 1); - assertPermanentCount(playerA, "Zombie", 1); - assertPowerToughness(playerA, "Zombie", 0, 13); + assertPermanentCount(playerA, "Zombie Token", 1); + assertPowerToughness(playerA, "Zombie Token", 0, 13); Permanent treeToken = getPermanent("Tree of Perdition", playerA); Assert.assertTrue(treeToken.getAbilities().contains(FlyingAbility.getInstance())); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/eve/HotheadedGiantTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/eve/HotheadedGiantTest.java new file mode 100644 index 00000000000..4e482fd70e1 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/eve/HotheadedGiantTest.java @@ -0,0 +1,47 @@ +package org.mage.test.cards.single.eve; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class HotheadedGiantTest extends CardTestPlayerBase { + private static final String giant = "Hotheaded Giant"; + private static final String goblin = "Mons's Goblin Raiders"; + + @Test + public void testSpell() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.HAND, playerA, goblin); + addCard(Zone.HAND, playerA, giant); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, goblin); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, giant); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertCounterCount(playerA, giant, CounterType.M1M1, 0); + } + + @Test + public void testNoSpell() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + addCard(Zone.HAND, playerA, giant); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, giant); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertCounterCount(playerA, giant, CounterType.M1M1, 2); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/eve/SoulReapTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/eve/SoulReapTest.java new file mode 100644 index 00000000000..13013b89dc9 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/eve/SoulReapTest.java @@ -0,0 +1,56 @@ +package org.mage.test.cards.single.eve; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class SoulReapTest extends CardTestPlayerBase { + private static final String reap = "Soul Reap"; + private static final String lion = "Silvercoat Lion"; + private static final String rats = "Muck Rats"; + + @Test + public void testSpell() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.BATTLEFIELD, playerA, lion); + addCard(Zone.HAND, playerA, reap); + addCard(Zone.HAND, playerA, rats); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, rats); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, reap, lion); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, lion, 0); + assertPermanentCount(playerA, rats, 1); + assertGraveyardCount(playerA, lion, 1); + assertGraveyardCount(playerA, reap, 1); + assertLife(playerA, 20 - 3); + } + + @Test + public void testNoSpell() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + addCard(Zone.BATTLEFIELD, playerA, lion); + addCard(Zone.HAND, playerA, reap); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, reap, lion); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, lion, 0); + assertGraveyardCount(playerA, lion, 1); + assertGraveyardCount(playerA, reap, 1); + assertLife(playerA, 20); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java index c5deb734b3d..5fb8020e10a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java @@ -101,7 +101,7 @@ public class MuragandaPetroglyphsTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPowerToughness(playerA, "Soldier", 3, 3); + assertPowerToughness(playerA, "Soldier Token", 3, 3); } @Test diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/grn/PeltCollectorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/grn/PeltCollectorTest.java index ea87437b731..44722249fd8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/grn/PeltCollectorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/grn/PeltCollectorTest.java @@ -88,7 +88,7 @@ public class PeltCollectorTest extends CardTestPlayerBase { assertPowerToughness(playerB, collector, 1, 1); - assertPowerToughness(playerA, "Soldier", 2, 2, Filter.ComparisonScope.All); + assertPowerToughness(playerA, "Soldier Token", 2, 2, Filter.ComparisonScope.All); assertPowerToughness(playerA, lion, 3, 3); assertPowerToughness(playerA, collector, 3, 3); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/hou/AbandonedSarcophagusTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/hou/AbandonedSarcophagusTest.java new file mode 100644 index 00000000000..78a337ba301 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/hou/AbandonedSarcophagusTest.java @@ -0,0 +1,108 @@ +package org.mage.test.cards.single.hou; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + + +public class AbandonedSarcophagusTest extends CardTestPlayerBase { + + /** + * You may cast non-land card with cycling from your graveyard + */ + @Test + public void castNonLandFromGraveyard() { + addCard(Zone.BATTLEFIELD, playerA, "Abandoned Sarcophagus"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); + addCard(Zone.GRAVEYARD, playerA, "Astral Drift"); // {2}{W} Enchantment + addCard(Zone.GRAVEYARD, playerA, "Ash Barrens"); // Land + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Astral Drift"); + // Can't play lands with this ability + checkPlayableAbility("before play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Play Ash Barrens", false); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Astral Drift", 1); + } + + /** + * You can only cast the card from the graveyard, you CANNOT cycle it + */ + @Test + public void cantCycleFromGraveyard() { + addCard(Zone.BATTLEFIELD, playerA, "Abandoned Sarcophagus"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); + addCard(Zone.GRAVEYARD, playerA, "Astral Drift"); // {2}{W} Enchantment + addCard(Zone.GRAVEYARD, playerA, "Ash Barrens"); // Land + + checkPlayableAbility("before play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cycling", false); + checkPlayableAbility("before play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Basic landcycling", false); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + } + + /** + * When a card with cycling is cycled it still goes to the graveyard + */ + @Test + public void cycledCardGoesToGraveyard() { + addCard(Zone.LIBRARY, playerA, "Forest", 5); + addCard(Zone.BATTLEFIELD, playerA, "Abandoned Sarcophagus"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.HAND, playerA, "Astral Drift"); // {2}{W} Enchantment + addCard(Zone.HAND, playerA, "Ash Barrens"); // Land + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Basic landcycling"); + addTarget(playerA, "Forest"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cycling"); + + setStopAt(1, PhaseStep.END_TURN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + + assertHandCount(playerA, 2); + assertGraveyardCount(playerA, 2); + } + + /** + * When a card goes to the graveyard and it WAS NOT cycled, it gets exiled + */ + @Test + public void nonCycledCardGoesToExile() { + addCard(Zone.BATTLEFIELD, playerA, "Abandoned Sarcophagus"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 6); + addCard(Zone.HAND, playerA, "Astral Drift"); // {2}{W} Enchantment + addCard(Zone.HAND, playerA, "Ash Barrens"); // Land + addCard(Zone.HAND, playerA, "Beast Within", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Astral Drift"); + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ash Barrens"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Beast Within", "Astral Drift"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Beast Within", "Ash Barrens"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + + assertExileCount(playerA, 2); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/GenesisUltimatumTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/GenesisUltimatumTest.java index c780e34c0b9..d1385bfadb2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/GenesisUltimatumTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/GenesisUltimatumTest.java @@ -30,7 +30,7 @@ public class GenesisUltimatumTest extends CardTestPlayerBase { // cast spell and put 3 cards to battle castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Genesis Ultimatum"); - setChoice(playerA, "Grizzly Bears^Kitesail Corsair^Riverglide Pathway"); + addTarget(playerA, "Grizzly Bears^Kitesail Corsair^Riverglide Pathway"); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -44,4 +44,4 @@ public class GenesisUltimatumTest extends CardTestPlayerBase { assertHandCount(playerA, "Alpha Tyrranax", 1); assertLibraryCount(playerA, 0); } -} \ No newline at end of file +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/KinnanBonderProdigyTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/KinnanBonderProdigyTest.java index da049ff07a3..358c13c70c3 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/KinnanBonderProdigyTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/KinnanBonderProdigyTest.java @@ -66,6 +66,6 @@ public class KinnanBonderProdigyTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertPermanentCount(playerA, hovermyr, 1); - assertPermanentCount(playerA, "Treasure", 0); + assertPermanentCount(playerA, "Treasure Token", 0); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/SkycatSovereignTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/SkycatSovereignTest.java index d94ae7d1b5c..1d6bf85f297 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/SkycatSovereignTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/iko/SkycatSovereignTest.java @@ -80,10 +80,10 @@ public class SkycatSovereignTest extends CardTestPlayerBase { assertAllCommandsUsed(); - assertPermanentCount(playerA, "Cat Bird", 1); - assertColor(playerA, "Cat Bird", ObjectColor.WHITE, true); - assertColor(playerA, "Cat Bird", ObjectColor.BLUE, false); - assertAbility(playerA, "Cat Bird", FlyingAbility.getInstance(), true); + assertPermanentCount(playerA, "Cat Bird Token", 1); + assertColor(playerA, "Cat Bird Token", ObjectColor.WHITE, true); + assertColor(playerA, "Cat Bird Token", ObjectColor.BLUE, false); + assertAbility(playerA, "Cat Bird Token", FlyingAbility.getInstance(), true); assertPowerToughness(playerA, "Skycat Sovereign", 4, 4); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/isd/GutterGrimeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/isd/GutterGrimeTest.java index d19d980285d..3cb75acfc38 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/isd/GutterGrimeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/isd/GutterGrimeTest.java @@ -31,7 +31,7 @@ public class GutterGrimeTest extends CardTestPlayerBase { setStopAt(3, PhaseStep.END_TURN); execute(); - assertPermanentCount(playerA, "Ooze", 0); + assertPermanentCount(playerA, "Ooze Token", 0); } @Test @@ -55,7 +55,7 @@ public class GutterGrimeTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Gutter Grime", 1); assertPermanentCount(playerA, "Intangible Virtue", 1); - assertPermanentCount(playerA, "Ooze", 1); - assertPowerToughness(playerA, "Ooze", 2, 2, Filter.ComparisonScope.Any); + assertPermanentCount(playerA, "Ooze Token", 1); + assertPowerToughness(playerA, "Ooze Token", 2, 2, Filter.ComparisonScope.Any); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/DraugrNecromancerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/DraugrNecromancerTest.java index 4c188d7bcb6..31e7655372f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/DraugrNecromancerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/DraugrNecromancerTest.java @@ -136,7 +136,7 @@ public class DraugrNecromancerTest extends CardTestPlayerBase { assertExileCount(playerB, pair, 1); assertGraveyardCount(playerB, pair, 0); - assertPermanentCount(playerA, "Food", 1); + assertPermanentCount(playerA, "Food Token", 1); } @Test @@ -179,7 +179,7 @@ public class DraugrNecromancerTest extends CardTestPlayerBase { assertExileCount(playerB, pair, 1); assertGraveyardCount(playerB, pair, 0); - assertPermanentCount(playerA, "Food", 1); + assertPermanentCount(playerA, "Food Token", 1); } @Test diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/DreamDevourerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/DreamDevourerTest.java index 6fc0d298cad..36b900e1b01 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/DreamDevourerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/DreamDevourerTest.java @@ -190,7 +190,7 @@ public class DreamDevourerTest extends CardTestPlayerBase { activateAbility(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Foretell {2}{W}"); waitStackResolved(3, PhaseStep.POSTCOMBAT_MAIN); checkPermanentCount("after foretell cast", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lonesome Unicorn", 1); - checkPermanentCount("after foretell cast", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Knight", 1); + checkPermanentCount("after foretell cast", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Knight Token", 1); activateAbility(5, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Lonesome Unicorn"); waitStackResolved(5, PhaseStep.PRECOMBAT_MAIN); @@ -203,6 +203,6 @@ public class DreamDevourerTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertPermanentCount(playerA, "Lonesome Unicorn", 2); - assertPermanentCount(playerA, "Knight", 1); + assertPermanentCount(playerA, "Knight Token", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/ValkiGodOfLiesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/ValkiGodOfLiesTest.java index 77ed48941e8..a705bddecff 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/ValkiGodOfLiesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/khm/ValkiGodOfLiesTest.java @@ -18,7 +18,6 @@ public class ValkiGodOfLiesTest extends CardTestPlayerBase { addCard(Zone.LIBRARY, playerB, "Ephemerate"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tibalt, Cosmic Impostor"); - setChoice(playerA, "Tibalt, Cosmic Impostor"); // two etb effects activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+2: Exile the top card of each player's library."); playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plains"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ephemerate", "Grizzly Bears"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/m20/AetherGustTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/m20/AetherGustTest.java index 92fbbf2ecf2..b34e46b108e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/m20/AetherGustTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/m20/AetherGustTest.java @@ -1,5 +1,3 @@ - - package org.mage.test.cards.single.m20; import mage.constants.PhaseStep; @@ -8,10 +6,8 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author jgray1206 */ - public class AetherGustTest extends CardTestPlayerBase { /* Aether Gust - Instant {1}{U} @@ -70,5 +66,4 @@ public class AetherGustTest extends CardTestPlayerBase { assertLibraryCount(playerA, 1); assertAllCommandsUsed(); } - } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/AngelicAscensionTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/AngelicAscensionTest.java index 5fd3ead499c..54e29433dbf 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/AngelicAscensionTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/AngelicAscensionTest.java @@ -25,8 +25,8 @@ public class AngelicAscensionTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertExileCount(playerB, 1); - assertPermanentCount(playerB, "Angel", 1); - assertPowerToughness(playerB, "Angel", 4, 4); + assertPermanentCount(playerB, "Angel Token", 1); + assertPowerToughness(playerB, "Angel Token", 4, 4); } @Test @@ -43,7 +43,7 @@ public class AngelicAscensionTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertExileCount(playerA, 1); - assertPermanentCount(playerA, "Angel", 1); - assertPowerToughness(playerA, "Angel", 4, 4); + assertPermanentCount(playerA, "Angel Token", 1); + assertPowerToughness(playerA, "Angel Token", 4, 4); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/ArchfiendsVesselTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/ArchfiendsVesselTest.java index d151dfd5f75..fac3ac955f5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/ArchfiendsVesselTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/ArchfiendsVesselTest.java @@ -25,7 +25,7 @@ public class ArchfiendsVesselTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Demon", 1); + assertPermanentCount(playerA, "Demon Token", 1); assertPermanentCount(playerA, archfiendsVessel, 0); assertExileCount(playerA, archfiendsVessel, 1); assertGraveyardCount(playerA, archfiendsVessel, 0); @@ -48,7 +48,7 @@ public class ArchfiendsVesselTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Demon", 1); + assertPermanentCount(playerA, "Demon Token", 1); assertPermanentCount(playerA, archfiendsVessel, 0); assertExileCount(playerA, archfiendsVessel, 1); assertGraveyardCount(playerA, archfiendsVessel, 0); @@ -73,7 +73,7 @@ public class ArchfiendsVesselTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Demon", 0); + assertPermanentCount(playerA, "Demon Token", 0); assertPermanentCount(playerA, archfiendsVessel, 0); assertExileCount(playerA, archfiendsVessel, 0); assertGraveyardCount(playerA, archfiendsVessel, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/BasriKetTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/BasriKetTest.java index 649ca14c351..c5baeb4668b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/BasriKetTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/BasriKetTest.java @@ -43,7 +43,7 @@ public class BasriKetTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertLife(playerB, 17); - assertPermanentCount(playerA, "Soldier", 1); + assertPermanentCount(playerA, "Soldier Token", 1); } @Test @@ -70,7 +70,7 @@ public class BasriKetTest extends CardTestPlayerBase { assertAllCommandsUsed(); assertLife(playerB, 14); - assertPermanentCount(playerA, "Soldier", 1); + assertPermanentCount(playerA, "Soldier Token", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/BasrisLieutenantTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/BasrisLieutenantTest.java index 1d45a0b40ba..b1ee80c3797 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/BasrisLieutenantTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/BasrisLieutenantTest.java @@ -28,7 +28,7 @@ public class BasrisLieutenantTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Knight", 1); + assertPermanentCount(playerA, "Knight Token", 1); } @Test @@ -51,7 +51,7 @@ public class BasrisLieutenantTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Knight", 1); + assertPermanentCount(playerA, "Knight Token", 1); } @Test @@ -74,6 +74,6 @@ public class BasrisLieutenantTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Knight", 0); + assertPermanentCount(playerA, "Knight Token", 0); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/ChromeReplicatorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/ChromeReplicatorTest.java index 6ad543cb6b8..aefb5b59edd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/ChromeReplicatorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/ChromeReplicatorTest.java @@ -22,7 +22,7 @@ public class ChromeReplicatorTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Construct", 1); + assertPermanentCount(playerA, "Construct Token", 1); } @Test @@ -39,7 +39,7 @@ public class ChromeReplicatorTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Construct", 0); + assertPermanentCount(playerA, "Construct Token", 0); } @Test @@ -60,6 +60,6 @@ public class ChromeReplicatorTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Construct", 0); + assertPermanentCount(playerA, "Construct Token", 0); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/DeathbloomThallidTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/DeathbloomThallidTest.java index 65eacfd0573..7074b44a10e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/DeathbloomThallidTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/DeathbloomThallidTest.java @@ -20,7 +20,7 @@ public class DeathbloomThallidTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Saproling", 1); + assertPermanentCount(playerA, "Saproling Token", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/ElderGargarothTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/ElderGargarothTest.java index b2c77885906..7636054033f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/ElderGargarothTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/ElderGargarothTest.java @@ -22,7 +22,7 @@ public class ElderGargarothTest extends CardTestPlayerBase { setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Beast", 1); + assertPermanentCount(playerA, "Beast Token", 1); } @Test diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/FungalRebirthTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/FungalRebirthTest.java index e34017cb3d6..6456aa46724 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/FungalRebirthTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/m21/FungalRebirthTest.java @@ -25,6 +25,6 @@ public class FungalRebirthTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Saproling", 2); + assertPermanentCount(playerA, "Saproling Token", 2); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mh2/GristTheHungerTideTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh2/GristTheHungerTideTest.java index 1e5594788bf..17ad098fef8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/mh2/GristTheHungerTideTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh2/GristTheHungerTideTest.java @@ -80,7 +80,7 @@ public class GristTheHungerTideTest extends CardTestPlayerBase { assertAllCommandsUsed(); // Grist is a creature spell when cast and triggers bounty - assertPermanentCount(playerA, "Beast", 1); + assertPermanentCount(playerA, "Beast Token", 1); // But not a creature on the battlefield assertPermanentCount(playerA, grist, 1); assertType(grist, CardType.CREATURE, false); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mir/LightningCoilsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mir/LightningCoilsTest.java index d98c8353f6b..1103b541cfd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/mir/LightningCoilsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mir/LightningCoilsTest.java @@ -44,7 +44,7 @@ public class LightningCoilsTest extends CardTestPlayerBase { assertGraveyardCount(playerA, bGnomes, gnomeCount); assertPermanentCount(playerA, lCoils, 1); assertCounterCount(playerA, lCoils, CounterType.CHARGE, 0); - assertPermanentCount(playerA, "Elemental", gnomeCount); + assertPermanentCount(playerA, "Elemental Token", gnomeCount); } @Test @@ -92,7 +92,7 @@ public class LightningCoilsTest extends CardTestPlayerBase { assertGraveyardCount(playerA, bGnomes, tokenCount); assertPermanentCount(playerA, lCoils, 1); assertCounterCount(playerA, lCoils, CounterType.CHARGE, 0); - assertPermanentCount(playerA, "Elemental", 0); + assertPermanentCount(playerA, "Elemental Token", 0); int remainingLife = 20 - (tokenCount * 3); // each elemental does 3 damage assertLife(playerB, remainingLife); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mrd/CullingScalesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mrd/CullingScalesTest.java index 61006f8f70e..03cb0874ec6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/mrd/CullingScalesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mrd/CullingScalesTest.java @@ -58,7 +58,7 @@ public class CullingScalesTest extends CardTestPlayerBase { execute(); // Culling Scales trigger fizzles since the Visionary no longer has the lowest CMC - assertPermanentCount(playerB, "Soldier", 2); + assertPermanentCount(playerB, "Soldier Token", 2); assertPermanentCount(playerB, "Elvish Visionary", 1); assertPermanentCount(playerB, "Plains", 5); assertPermanentCount(playerA, "Culling Scales", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/neo/StoryweaveTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/neo/StoryweaveTest.java new file mode 100644 index 00000000000..78307475651 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/neo/StoryweaveTest.java @@ -0,0 +1,92 @@ +package org.mage.test.cards.single.neo; + +import mage.cards.s.Storyweave; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class StoryweaveTest extends CardTestPlayerBase { + private static final String fang = "Fang of Shigeki"; + private static final String colossus = "Nyxborn Colossus"; + private static final String intervention = "Fated Intervention"; + + private void addEffectToGame() { + // casting the spell is a pain to set up, this is easier + addCustomCardWithAbility("tester", playerA, Storyweave.makeAbility()); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{0}"); + } + + @Test + public void test__WorksOnlyOnce() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 7); + addCard(Zone.HAND, playerA, fang); + addCard(Zone.HAND, playerA, colossus); + + addEffectToGame(); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, fang); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, colossus); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertCounterCount(playerA, fang, CounterType.P1P1, 2); + assertCounterCount(playerA, colossus, CounterType.P1P1, 0); + } + + @Test + public void test__MultipleOnlyOnce() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 6); + addCard(Zone.HAND, playerA, intervention); + addCard(Zone.HAND, playerA, fang); + + addEffectToGame(); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, intervention); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, fang); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertCounterCount(playerA, fang, CounterType.P1P1, 0); + assertPermanentCount(playerA, "Centaur Token", 2); + currentGame + .getBattlefield() + .getAllActivePermanents() + .stream() + .filter(permanent -> "Centaur Token".equals(permanent.getName())) + .noneMatch(permanent -> permanent.getCounters(currentGame).getCount(CounterType.P1P1) != 2); + } + + @Test + public void test__SingleOnlyOnce() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 6); + addCard(Zone.HAND, playerA, intervention); + addCard(Zone.HAND, playerA, fang); + + addEffectToGame(); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, fang); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, intervention); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertCounterCount(playerA, fang, CounterType.P1P1, 2); + assertPermanentCount(playerA, "Centaur Token", 2); + currentGame + .getBattlefield() + .getAllActivePermanents() + .stream() + .filter(permanent -> "Centaur Token".equals(permanent.getName())) + .noneMatch(permanent -> permanent.getCounters(currentGame).getCount(CounterType.P1P1) != 0); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/pc2/FracturedPowerstoneTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/pc2/FracturedPowerstoneTest.java new file mode 100644 index 00000000000..35cc75b5d68 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/pc2/FracturedPowerstoneTest.java @@ -0,0 +1,61 @@ +package org.mage.test.cards.single.pc2; + +import mage.constants.PhaseStep; +import mage.constants.Planes; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBaseWithAIHelps; + +public class FracturedPowerstoneTest extends CardTestPlayerBaseWithAIHelps { + + @Test + public void test_FracturedPowerstone_Single() { + // Active player can roll the planar die: Whenever you roll {CHAOS}, create a 7/7 colorless Eldrazi creature with annhilator 1 + addPlane(playerA, Planes.PLANE_HEDRON_FIELDS_OF_AGADEEM); + addCard(Zone.BATTLEFIELD, playerA, "Fractured Powerstone", 1); + + // first chaos + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{0}: Roll the planar"); + setDieRollResult(playerA, 1); // make chaos + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + //second chaos (fractured powerstone) + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Roll the planar"); + setDieRollResult(playerA, 1); // make chaos + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Eldrazi Token", 2); + assertTappedCount("Fractured Powerstone", true, 1); + } + + @Test + public void test_FracturedPowerstone_NoCost() { + // Active player can roll the planar die: Whenever you roll {CHAOS}, create a 7/7 colorless Eldrazi creature with annhilator 1 + addPlane(playerA, Planes.PLANE_HEDRON_FIELDS_OF_AGADEEM); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.BATTLEFIELD, playerA, "Fractured Powerstone", 1); + + // first chaos + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{0}: Roll the planar"); + setDieRollResult(playerA, 1); // make chaos + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + //second chaos (fractured powerstone) + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Roll the planar"); + setDieRollResult(playerA, 1); // make chaos + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + // third chaos (with additional cost) + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{0}: Roll the planar"); + setDieRollResult(playerA, 1); // make chaos + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Eldrazi Token", 3); + assertTappedCount("Mountain", true, 1); // cost for second planar die + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/BriarbridgePatrolTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/BriarbridgePatrolTest.java index 9bbcb7cc209..27bf06b3d27 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/BriarbridgePatrolTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/BriarbridgePatrolTest.java @@ -34,7 +34,7 @@ public class BriarbridgePatrolTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); - assertPermanentCount(playerA, "Clue", 1); + assertPermanentCount(playerA, "Clue Token", 1); assertPermanentCount(playerA, "Briarbridge Patrol", 1); assertPermanentCount(playerB, "Elite Vanguard", 0); assertGraveyardCount(playerB, "Elite Vanguard", 1); @@ -59,7 +59,7 @@ public class BriarbridgePatrolTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); - assertPermanentCount(playerA, "Clue", 1); + assertPermanentCount(playerA, "Clue Token", 1); assertPermanentCount(playerA, "Briarbridge Patrol", 1); assertPermanentCount(playerB, "Wall of Roots", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/DeclarationInStoneTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/DeclarationInStoneTest.java index 355b9aabf0f..5d80cf06c20 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/DeclarationInStoneTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/DeclarationInStoneTest.java @@ -36,7 +36,7 @@ public class DeclarationInStoneTest extends CardTestPlayerBase { assertPermanentCount(playerB, hGiant, 1); assertPermanentCount(playerB, memnite, 0); assertExileCount(playerB, memnite, 3); - assertPermanentCount(playerB, "Clue", 3); // 3 creatures exiled = 3 clues for them + assertPermanentCount(playerB, "Clue Token", 3); // 3 creatures exiled = 3 clues for them } @Test @@ -62,14 +62,14 @@ public class DeclarationInStoneTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Plains", 2); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, gTitan); - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, dStone, "Zombie"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, dStone, "Zombie Token"); setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); assertGraveyardCount(playerB, dStone, 1); assertPermanentCount(playerA, gTitan, 1); - assertPermanentCount(playerA, "Zombie", 0); - assertPermanentCount(playerA, "Clue", 0); // tokens exiled do not generate clues + assertPermanentCount(playerA, "Zombie Token", 0); + assertPermanentCount(playerA, "Clue Token", 0); // tokens exiled do not generate clues } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/EngulfTheShoreTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/EngulfTheShoreTest.java index 754d759a25c..8725bfdb8a8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/EngulfTheShoreTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/EngulfTheShoreTest.java @@ -63,7 +63,7 @@ public class EngulfTheShoreTest extends CardTestPlayerBase { assertHandCount(playerA, "Bronze Sable", 2); assertPermanentCount(playerB, "Hill Giant", 1); - assertPermanentCount(playerB, "Goblin", 0); + assertPermanentCount(playerB, "Goblin Token", 0); assertGraveyardCount(playerA, "Engulf the Shore", 1); assertGraveyardCount(playerB, "Hordeling Outburst", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/ErdwalIlluminatorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/ErdwalIlluminatorTest.java index de915c58289..c36710a09cd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/ErdwalIlluminatorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/ErdwalIlluminatorTest.java @@ -26,7 +26,7 @@ public class ErdwalIlluminatorTest extends CardTestPlayerBase { setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); execute(); - assertPermanentCount(playerA, "Clue", 2); + assertPermanentCount(playerA, "Clue Token", 2); } @Test @@ -41,7 +41,7 @@ public class ErdwalIlluminatorTest extends CardTestPlayerBase { setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); execute(); - assertPermanentCount(playerB, "Clue", 1); + assertPermanentCount(playerB, "Clue Token", 1); } @Test @@ -57,7 +57,7 @@ public class ErdwalIlluminatorTest extends CardTestPlayerBase { setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); execute(); - assertPermanentCount(playerA, "Clue", 3); + assertPermanentCount(playerA, "Clue Token", 3); } @Test @@ -73,6 +73,6 @@ public class ErdwalIlluminatorTest extends CardTestPlayerBase { setStopAt(4, PhaseStep.POSTCOMBAT_MAIN); execute(); - assertPermanentCount(playerA, "Clue", 4); + assertPermanentCount(playerA, "Clue Token", 4); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/SilverfurPartisanTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/SilverfurPartisanTest.java index 93cf91f4ebb..34c2c7a11cb 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/SilverfurPartisanTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/SilverfurPartisanTest.java @@ -35,7 +35,7 @@ public class SilverfurPartisanTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Enlarge", 1); assertPowerToughness(playerA, "Silverfur Partisan", 5, 5); // +3+3 from Giant Growth assertPowerToughness(playerA, "Howlpack Wolf", 10, 10); // +7+7 from Enlarge - assertPermanentCount(playerA, "Wolf", 2); + assertPermanentCount(playerA, "Wolf Token", 2); } /** @@ -63,6 +63,6 @@ public class SilverfurPartisanTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Arrow Storm", 1); assertGraveyardCount(playerA, "Howlpack Wolf", 1); assertGraveyardCount(playerA, "Silverfur Partisan", 1); - assertPermanentCount(playerA, "Wolf", 2); + assertPermanentCount(playerA, "Wolf Token", 2); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/SurviveTheNightTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/SurviveTheNightTest.java index d96af683aa9..650bf3197a2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/SurviveTheNightTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/SurviveTheNightTest.java @@ -33,7 +33,7 @@ public class SurviveTheNightTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Survive the Night", 1); assertGraveyardCount(playerB, "Bloodbriar", 1); - assertPermanentCount(playerA, "Clue", 1); + assertPermanentCount(playerA, "Clue Token", 1); assertPermanentCount(playerA, "Hinterland Logger", 1); assertPowerToughness(playerA, "Hinterland Logger", 3, 1); assertAbility(playerA, "Hinterland Logger", IndestructibleAbility.getInstance(), true); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/ThingInTheIceTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/ThingInTheIceTest.java index c6736d348a3..d431e5a4c39 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/ThingInTheIceTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/ThingInTheIceTest.java @@ -53,7 +53,7 @@ public class ThingInTheIceTest extends CardTestPlayerBase { setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "Clue", 1); + assertPermanentCount(playerA, "Clue Token", 1); assertHandCount(playerA, "Tireless Tracker", 1); // returned to hand assertPermanentCount(playerA, "Tireless Tracker", 0); assertPermanentCount(playerB, "Awoken Horror", 1); // transformed diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/TirelessTrackerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/TirelessTrackerTest.java index fe4adf12e73..2b39ad28c22 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/TirelessTrackerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/TirelessTrackerTest.java @@ -33,7 +33,7 @@ public class TirelessTrackerTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Forest", 1); assertPermanentCount(playerB, "Wastes", 1); - assertPermanentCount(playerA, "Clue", 1); + assertPermanentCount(playerA, "Clue Token", 1); } // TODO: add tests for 2nd ability diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/ths/AshiokNightmareWaeverTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/ths/AshiokNightmareWeaverTest.java similarity index 96% rename from Mage.Tests/src/test/java/org/mage/test/cards/single/ths/AshiokNightmareWaeverTest.java rename to Mage.Tests/src/test/java/org/mage/test/cards/single/ths/AshiokNightmareWeaverTest.java index 4ad535a8301..5b810af0a22 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/ths/AshiokNightmareWaeverTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/ths/AshiokNightmareWeaverTest.java @@ -1,5 +1,3 @@ - - package org.mage.test.cards.single.ths; import mage.constants.PhaseStep; @@ -9,15 +7,14 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ -public class AshiokNightmareWaeverTest extends CardTestPlayerBase { +public class AshiokNightmareWeaverTest extends CardTestPlayerBase { /** * Ashiok, Nightmare Weaver {1}{U}{B} - 3 - * + *

* +2: Exile the top three cards of target opponent's library. * -X: Put a creature card with converted mana cost X exiled with Ashiok, Nightmare Weaver onto the battlefield under your control. That creature is a Nightmare in addition to its other types. * -10: Exile all cards from all opponents' hands and graveyards.);Tests Heliod get a God with devotion to white >>= 5 @@ -55,9 +52,9 @@ public class AshiokNightmareWaeverTest extends CardTestPlayerBase { setChoice(playerA, "X=5"); addTarget(playerA, "Prophet of Kruphix"); - + castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerB); - + setStopAt(4, PhaseStep.PRECOMBAT_MAIN); execute(); @@ -70,4 +67,4 @@ public class AshiokNightmareWaeverTest extends CardTestPlayerBase { assertTapped("Mountain", false); // Must be untapped because of Prophet of Kruphix } -} \ No newline at end of file +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/tmp/KnightOfDuskTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/tmp/KnightOfDuskTest.java new file mode 100644 index 00000000000..8240c3592c9 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/tmp/KnightOfDuskTest.java @@ -0,0 +1,86 @@ +package org.mage.test.cards.single.tmp; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class KnightOfDuskTest extends CardTestPlayerBase { + private static final String knight = "Knight of Dusk"; + private static final String lion = "Silvercoat Lion"; + private static final String murder = "Murder"; + private static final String blink = "Momentary Blink"; + + @Test + public void testRegular() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + addCard(Zone.BATTLEFIELD, playerA, knight); + addCard(Zone.BATTLEFIELD, playerB, lion); + + attack(1, playerA, knight); + block(1, playerB, lion, knight); + + activateAbility(1, PhaseStep.DECLARE_BLOCKERS, playerA, "{B}{B}", lion); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, knight, 1); + assertPermanentCount(playerB, lion, 0); + assertGraveyardCount(playerA, knight, 0); + assertGraveyardCount(playerB, lion, 1); + } + + @Test + public void testLeavesBattlefield() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 5); + addCard(Zone.BATTLEFIELD, playerA, knight); + addCard(Zone.BATTLEFIELD, playerB, lion); + addCard(Zone.HAND, playerA, murder); + + attack(1, playerA, knight); + block(1, playerB, lion, knight); + + activateAbility(1, PhaseStep.DECLARE_BLOCKERS, playerA, "{B}{B}", lion); + castSpell(1, PhaseStep.DECLARE_BLOCKERS, playerA, murder, knight); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, knight, 0); + assertPermanentCount(playerB, lion, 0); + assertGraveyardCount(playerA, knight, 1); + assertGraveyardCount(playerB, lion, 1); + } + + @Test + public void testLeavesBattlefieldReturns() { + addCard(Zone.BATTLEFIELD, playerA, "Scrubland", 4); + addCard(Zone.BATTLEFIELD, playerA, knight); + addCard(Zone.BATTLEFIELD, playerB, lion); + addCard(Zone.HAND, playerA, blink); + + attack(1, playerA, knight); + block(1, playerB, lion, knight); + + activateAbility(1, PhaseStep.DECLARE_BLOCKERS, playerA, "{B}{B}", lion); + castSpell(1, PhaseStep.DECLARE_BLOCKERS, playerA, blink, knight); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, knight, 1); + assertPermanentCount(playerB, lion, 0); + assertGraveyardCount(playerA, knight, 0); + assertGraveyardCount(playerB, lion, 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/tmp/SpiritMirrorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/tmp/SpiritMirrorTest.java index dd8c0c09f51..b6def7430b2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/tmp/SpiritMirrorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/tmp/SpiritMirrorTest.java @@ -27,8 +27,8 @@ public class SpiritMirrorTest extends CardTestPlayerBase { execute(); - assertPermanentCount(playerA, "Reflection", 1); - Permanent reflection = getPermanent("Reflection"); + assertPermanentCount(playerA, "Reflection Token", 1); + Permanent reflection = getPermanent("Reflection Token"); Assert.assertTrue(reflection.hasSubtype(SubType.REFLECTION, currentGame)); } @@ -38,12 +38,12 @@ public class SpiritMirrorTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Spirit Mirror"); // Destroy playerAs own reflection token - activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{0}: Destroy target Reflection", "Reflection"); + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{0}: Destroy target Reflection", "Reflection Token"); setStopAt(3, PhaseStep.END_TURN); execute(); - assertPermanentCount(playerA, "Reflection", 0); + assertPermanentCount(playerA, "Reflection Token", 0); } @Test @@ -59,8 +59,8 @@ public class SpiritMirrorTest extends CardTestPlayerBase { execute(); // Only one token created - assertPermanentCount(playerA, "Reflection", 1); - Permanent reflection = getPermanent("Reflection"); + assertPermanentCount(playerA, "Reflection Token", 1); + Permanent reflection = getPermanent("Reflection Token"); Assert.assertTrue(reflection.hasSubtype(SubType.REFLECTION, currentGame)); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/WeatherseedTotemTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/WeatherseedTotemTest.java new file mode 100644 index 00000000000..adf7bfcdec2 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/WeatherseedTotemTest.java @@ -0,0 +1,52 @@ +package org.mage.test.cards.single.tsp; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class WeatherseedTotemTest extends CardTestPlayerBase { + private static final String totem = "Weatherseed Totem"; + private static final String naturalize = "Naturalize"; + + @Test + public void testNonCreature() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); + addCard(Zone.BATTLEFIELD, playerA, totem); + addCard(Zone.HAND, playerA, naturalize); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, naturalize, totem); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertHandCount(playerA, totem, 0); + assertGraveyardCount(playerA, totem, 1); + assertGraveyardCount(playerA, naturalize, 1); + } + + @Test + public void testCreature() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 7); + addCard(Zone.BATTLEFIELD, playerA, totem); + addCard(Zone.HAND, playerA, naturalize); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}{G}{G}{G}"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, naturalize, totem); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertHandCount(playerA, totem, 1); + assertGraveyardCount(playerA, totem, 0); + assertGraveyardCount(playerA, naturalize, 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/ulg/GoblinWelderTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/ulg/GoblinWelderTest.java index 272573b623c..b245d8e08ec 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/ulg/GoblinWelderTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/ulg/GoblinWelderTest.java @@ -41,6 +41,6 @@ public class GoblinWelderTest extends CardTestPlayerBase { assertGraveyardCount(playerA, wurmcoil, 1); assertPermanentCount(playerA, relic, 1); assertCounterCount(aspirant, CounterType.P1P1, 1); - assertPermanentCount(playerA, "Wurm", 2); + assertPermanentCount(playerA, "Wurm Token", 2); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/vow/SaviorOfOllenbockTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/vow/SaviorOfOllenbockTest.java new file mode 100644 index 00000000000..7ae499f98b1 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/vow/SaviorOfOllenbockTest.java @@ -0,0 +1,99 @@ +package org.mage.test.cards.single.vow; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class SaviorOfOllenbockTest extends CardTestPlayerBase { + private static final String savior = "Savior of Ollenbock"; + private static final String lion = "Silvercoat Lion"; + private static final String bear = "Grizzly Bears"; + private static final String murder = "Murder"; + + @Test + public void test_ExilePermanent() { + addCard(Zone.BATTLEFIELD, playerA, savior); + addCard(Zone.BATTLEFIELD, playerA, lion); + + attack(1, playerA, savior); + attack(1, playerA, lion); + addTarget(playerA, lion); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertExileCount(playerA, lion, 1); + } + + @Test + public void test_ExileCard() { + addCard(Zone.BATTLEFIELD, playerA, savior); + addCard(Zone.BATTLEFIELD, playerA, lion); + addCard(Zone.GRAVEYARD, playerA, bear); + + attack(1, playerA, savior); + attack(1, playerA, lion); + addTarget(playerA, bear); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertExileCount(playerA, bear, 1); + } + + @Test + public void test_ExilePermanentAndReturn() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.BATTLEFIELD, playerA, savior); + addCard(Zone.BATTLEFIELD, playerA, lion); + addCard(Zone.HAND, playerA, murder); + + attack(1, playerA, savior); + attack(1, playerA, lion); + addTarget(playerA, lion); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, murder, savior); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, savior, 0); + assertPermanentCount(playerA, lion, 1); + assertGraveyardCount(playerA, murder, 1); + } + + @Test + public void test_ExileCardAndReturn() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.BATTLEFIELD, playerA, savior); + addCard(Zone.BATTLEFIELD, playerA, lion); + addCard(Zone.GRAVEYARD, playerB, bear); + addCard(Zone.HAND, playerA, murder); + + attack(1, playerA, savior); + attack(1, playerA, lion); + addTarget(playerA, bear); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, murder, savior); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, savior, 0); + assertPermanentCount(playerA, lion, 1); + assertPermanentCount(playerB, bear, 1); + assertGraveyardCount(playerA, murder, 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/wwk/TerastodonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/wwk/TerastodonTest.java index 22fd7ace2c5..64556955261 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/wwk/TerastodonTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/wwk/TerastodonTest.java @@ -28,6 +28,6 @@ public class TerastodonTest extends CardTestPlayerBase { execute(); assertGraveyardCount(playerA, 3); - assertPermanentCount(playerA, "Elephant", 3); + assertPermanentCount(playerA, "Elephant Token", 3); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/xln/TreasureCoveTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/xln/TreasureCoveTest.java index dcb9dc645e3..7c2daef4d33 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/xln/TreasureCoveTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/xln/TreasureCoveTest.java @@ -22,14 +22,14 @@ public class TreasureCoveTest extends CardTestPlayerBase { waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); checkHandCount("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 0); - checkPermanentCount("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treasure", 2); // from saga + checkPermanentCount("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treasure Token", 2); // from saga // sacrifice and draw activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}, Sacrifice"); - setChoice(playerA, "Treasure"); + setChoice(playerA, "Treasure Token"); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); checkHandCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 1); - checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treasure", 2 - 1); + checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treasure Token", 2 - 1); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/zen/CobraTrapTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/zen/CobraTrapTest.java index 0fe59117250..c933fc7bba2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/zen/CobraTrapTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/zen/CobraTrapTest.java @@ -27,7 +27,7 @@ public class CobraTrapTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); assertPermanentCount(playerA, "Forest", 1); - assertPermanentCount(playerA, "Snake", 4); + assertPermanentCount(playerA, "Snake Token", 4); } @Test @@ -45,7 +45,7 @@ public class CobraTrapTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); assertPermanentCount(playerA, "Forest", 2); - assertPermanentCount(playerA, "Snake", 0); + assertPermanentCount(playerA, "Snake Token", 0); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/zen/KalitasBloodchiefOfGhetTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/zen/KalitasBloodchiefOfGhetTest.java index cf5f535c166..d09d434b971 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/zen/KalitasBloodchiefOfGhetTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/zen/KalitasBloodchiefOfGhetTest.java @@ -25,6 +25,6 @@ public class KalitasBloodchiefOfGhetTest extends CardTestPlayerBase { execute(); - assertPermanentCount(playerA, "Vampire", 0); + assertPermanentCount(playerA, "Vampire Token", 0); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/BonecladNecromancerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/BonecladNecromancerTest.java index 4b2981dbd75..ace78c7fecb 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/BonecladNecromancerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/BonecladNecromancerTest.java @@ -34,7 +34,7 @@ public class BonecladNecromancerTest extends CardTestPlayerBase { execute(); assertPermanentCount(playerA, "Boneclad Necromancer", 1); - assertPermanentCount(playerA, "Zombie", 1); + assertPermanentCount(playerA, "Zombie Token", 1); assertExileCount(playerA, "Raptor Hatchling", 1); assertGraveyardCount(playerA, "Raptor Hatchling", 0); } @@ -51,7 +51,7 @@ public class BonecladNecromancerTest extends CardTestPlayerBase { execute(); assertPermanentCount(playerA, "Boneclad Necromancer", 1); - assertPermanentCount(playerA, "Zombie", 1); + assertPermanentCount(playerA, "Zombie Token", 1); assertExileCount(playerB, "Raptor Hatchling", 1); assertGraveyardCount(playerB, "Raptor Hatchling", 0); } @@ -68,7 +68,7 @@ public class BonecladNecromancerTest extends CardTestPlayerBase { execute(); assertPermanentCount(playerA, "Boneclad Necromancer", 1); - assertPermanentCount(playerA, "Zombie", 0); + assertPermanentCount(playerA, "Zombie Token", 0); assertExileCount(playerA, "Feral Invocation", 0); assertGraveyardCount(playerA, "Feral Invocation", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/BroodSliverTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/BroodSliverTest.java index 49f81af4963..7fbb3c22e82 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/BroodSliverTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/BroodSliverTest.java @@ -28,7 +28,7 @@ public class BroodSliverTest extends CardTestPlayerBase { execute(); assertLife(playerB, 19); - assertPermanentCount(playerA, "Sliver", 1); - assertPermanentCount(playerB, "Sliver", 0); + assertPermanentCount(playerA, "Sliver Token", 1); + assertPermanentCount(playerB, "Sliver Token", 0); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/DayOfTheDragonsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/DayOfTheDragonsTest.java index 36fababf4c9..7f0c9d29872 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/DayOfTheDragonsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/DayOfTheDragonsTest.java @@ -31,7 +31,7 @@ public class DayOfTheDragonsTest extends CardTestPlayerBase { assertExileCount("Silvercoat Lion", 1); assertExileCount("Pillarfield Ox", 1); - assertPermanentCount(playerA, "Dragon", 2); + assertPermanentCount(playerA, "Dragon Token", 2); assertPermanentCount(playerB, "Silvercoat Lion", 1); assertPermanentCount(playerB, "Shivan Dragon", 1); @@ -62,7 +62,7 @@ public class DayOfTheDragonsTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Silvercoat Lion", 1); assertPermanentCount(playerA, "Pillarfield Ox", 1); - assertPermanentCount(playerA, "Dragon", 0); + assertPermanentCount(playerA, "Dragon Token", 0); assertPermanentCount(playerB, "Silvercoat Lion", 1); assertPermanentCount(playerB, "Shivan Dragon", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/DivineVisitationTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/DivineVisitationTest.java index 3c8fe42df00..08cd6daa977 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/DivineVisitationTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/DivineVisitationTest.java @@ -9,7 +9,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author luziferius */ public class DivineVisitationTest extends CardTestPlayerBase { @@ -35,17 +34,17 @@ public class DivineVisitationTest extends CardTestPlayerBase { setChoice(playerA, "Whenever an opponent draws a card", 2); // choose order of triggers setChoice(playerB, false, 3); // Decline to pay 2 setStopAt(1, PhaseStep.BEGIN_COMBAT); - + setStrictChooseMode(true); execute(); assertAllCommandsUsed(); - + assertHandCount(playerB, 3); - assertPermanentCount(playerA, "Treasure", 3); - assertType("Treasure", CardType.ARTIFACT, SubType.TREASURE); - assertNotType("Treasure", CardType.CREATURE); - assertNotSubtype("Treasure", SubType.ANGEL); - assertPermanentCount(playerA, "Angel", 0); + assertPermanentCount(playerA, "Treasure Token", 3); + assertType("Treasure Token", CardType.ARTIFACT, SubType.TREASURE); + assertNotType("Treasure Token", CardType.CREATURE); + assertNotSubtype("Treasure Token", SubType.ANGEL); + assertPermanentCount(playerA, "Angel Token", 0); assertPermanentCount(playerA, 6); assertGraveyardCount(playerA, 1); } @@ -62,20 +61,37 @@ public class DivineVisitationTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Dragon Fodder"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Dragon Fodder"); setStopAt(1, PhaseStep.BEGIN_COMBAT); - + setStrictChooseMode(true); execute(); assertAllCommandsUsed(); assertGraveyardCount(playerA, 1); assertPermanentCount(playerA, 5); - assertPermanentCount(playerA, "Goblin", 0); - assertPermanentCount(playerA, "Angel", 2); - assertType("Angel", CardType.CREATURE, SubType.ANGEL); - assertColor(playerA, "Angel", ObjectColor.WHITE, true); - assertColor(playerA, "Angel", ObjectColor.RED, false); - assertPowerToughness(playerA, "Angel", 4,4); - assertNotSubtype("Angel", SubType.GOBLIN); - + assertPermanentCount(playerA, "Goblin Token", 0); + assertPermanentCount(playerA, "Angel Token", 2); + assertType("Angel Token", CardType.CREATURE, SubType.ANGEL); + assertColor(playerA, "Angel Token", ObjectColor.WHITE, true); + assertColor(playerA, "Angel Token", ObjectColor.RED, false); + assertPowerToughness(playerA, "Angel Token", 4, 4); + assertNotSubtype("Angel Token", SubType.GOBLIN); + } -} \ No newline at end of file + + @Test + public void testSacrificeEOT() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + addCard(Zone.BATTLEFIELD, playerA, "Divine Visitation"); + addCard(Zone.HAND, playerA, "Thatcher Revolt"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thatcher Revolt"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Human Token", 0); + assertPermanentCount(playerA, "Angel Token", 0); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/EnterLeaveBattlefieldExileTargetTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/EnterLeaveBattlefieldExileTargetTest.java index 427c0e2778e..50e6f7579fd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/EnterLeaveBattlefieldExileTargetTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/EnterLeaveBattlefieldExileTargetTest.java @@ -103,7 +103,7 @@ public class EnterLeaveBattlefieldExileTargetTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Knight Ally", 2); + assertPermanentCount(playerA, "Knight Ally Token", 2); assertPermanentCount(playerA, "Angel of Serenity", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/EntersTheBattlefieldTriggerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/EntersTheBattlefieldTriggerTest.java index 07187e7f3bd..ea46a70e43c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/EntersTheBattlefieldTriggerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/EntersTheBattlefieldTriggerTest.java @@ -97,7 +97,7 @@ public class EntersTheBattlefieldTriggerTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Reanimate", 1); assertPermanentCount(playerA, "Scion of Vitu-Ghazi", 1); - assertPermanentCount(playerA, "Bird", 2); // only 2 from cast from hand creation and populate. Populate may not trigger from reanimate + assertPermanentCount(playerA, "Bird Token", 2); // only 2 from cast from hand creation and populate. Populate may not trigger from reanimate assertLife(playerA, 15); assertLife(playerB, 20); @@ -325,8 +325,8 @@ public class EntersTheBattlefieldTriggerTest extends CardTestPlayerBase { execute(); assertPermanentCount(playerA, "Hearthcage Giant", 1); - assertPermanentCount(playerA, "Elemental Shaman", 2); - assertPowerToughness(playerA, "Elemental Shaman", 3, 1); + assertPermanentCount(playerA, "Elemental Shaman Token", 2); + assertPowerToughness(playerA, "Elemental Shaman Token", 3, 1); } /** diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GeistOfSaintTraftTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GeistOfSaintTraftTest.java index f3a9c548547..9001b48c31e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GeistOfSaintTraftTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GeistOfSaintTraftTest.java @@ -31,8 +31,8 @@ public class GeistOfSaintTraftTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Geist of Saint Traft", 1); assertPowerToughness(playerB, "Geist of Saint Traft", 2, 2); - assertPermanentCount(playerB, "Angel", 1); - assertPowerToughness(playerB, "Angel", 4, 4); + assertPermanentCount(playerB, "Angel Token", 1); + assertPowerToughness(playerB, "Angel Token", 4, 4); assertLife(playerA, 14); assertLife(playerB, 20); @@ -50,7 +50,7 @@ public class GeistOfSaintTraftTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Geist of Saint Traft", 1); assertPowerToughness(playerB, "Geist of Saint Traft", 2, 2); - assertPermanentCount(playerB, "Angel", 0); + assertPermanentCount(playerB, "Angel Token", 0); assertLife(playerA, 14); assertLife(playerB, 20); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GoldnightCommanderTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GoldnightCommanderTest.java index f4297e89959..56450ef3b0a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GoldnightCommanderTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GoldnightCommanderTest.java @@ -30,8 +30,8 @@ public class GoldnightCommanderTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "Human", 3); - assertPowerToughness(playerA, "Human", 4, 4, Filter.ComparisonScope.All); + assertPermanentCount(playerA, "Human Token", 3); + assertPowerToughness(playerA, "Human Token", 4, 4, Filter.ComparisonScope.All); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/OneOrMoreCardsGoToGraveyardTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/OneOrMoreCardsGoToGraveyardTest.java index 7b31083065c..a117e1dc122 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/OneOrMoreCardsGoToGraveyardTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/OneOrMoreCardsGoToGraveyardTest.java @@ -32,7 +32,7 @@ public class OneOrMoreCardsGoToGraveyardTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Evolving Wilds", 1); assertPermanentCount(playerA, "Mountain", 1); - assertPermanentCount(playerA, "Insect", 2); + assertPermanentCount(playerA, "Insect Token", 2); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/RanarTheEverWatchfulTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/RanarTheEverWatchfulTest.java index 10c4525c411..9df4137a6f6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/RanarTheEverWatchfulTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/RanarTheEverWatchfulTest.java @@ -46,17 +46,17 @@ public class RanarTheEverWatchfulTest extends CardTestPlayerBase { addTarget(playerA, "Serra Angel"); addTarget(playerA, "Bog Imp"); addTarget(playerA, "Sengir Vampire"); - addTarget(playerA, "Knight"); - addTarget(playerA, "Knight"); + addTarget(playerA, "Knight Token"); + addTarget(playerA, "Knight Token"); setStopAt(4, PhaseStep.POSTCOMBAT_MAIN); execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Boar", 3); // created token by Curse - assertPermanentCount(playerA, "Spirit", 1); // created token by Ranar - assertPermanentCount(playerB, "Boar", 3); // created token by Curse - assertPermanentCount(playerB, "Spirit", 0); // no Spirit token for playerB + assertPermanentCount(playerA, "Boar Token", 3); // created token by Curse + assertPermanentCount(playerA, "Spirit Token", 1); // created token by Ranar + assertPermanentCount(playerB, "Boar Token", 3); // created token by Curse + assertPermanentCount(playerB, "Spirit Token", 0); // no Spirit token for playerB } @Test @@ -83,8 +83,8 @@ public class RanarTheEverWatchfulTest extends CardTestPlayerBase { execute(); assertAllCommandsUsed(); - assertPermanentCount(playerA, "Spirit", 1); // created token by Ranar - assertPermanentCount(playerB, "Spirit", 0); // no Spirit tokens for the other player + assertPermanentCount(playerA, "Spirit Token", 1); // created token by Ranar + assertPermanentCount(playerB, "Spirit Token", 0); // no Spirit tokens for the other player } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToBattlefieldEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToBattlefieldEffectsTest.java index 5291e0fa661..610e810be89 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToBattlefieldEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToBattlefieldEffectsTest.java @@ -121,7 +121,7 @@ public class ReturnToBattlefieldEffectsTest extends CardTestPlayerBase { execute(); assertPermanentCount(playerB, "Pharika, God of Affliction", 1); - assertPermanentCount(playerA, "Snake", 1); + assertPermanentCount(playerA, "Snake Token", 1); assertPermanentCount(playerA, "Pine Walker", 1); assertExileCount("Deathmist Raptor", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToHandEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToHandEffectsTest.java index 765f5b8028b..2582706f2bf 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToHandEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToHandEffectsTest.java @@ -65,7 +65,7 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lab Rats"); setChoice(playerA, false); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Boomerang", "Rat"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Boomerang", "Rat Token"); setStopAt(1, PhaseStep.END_TURN); execute(); @@ -75,8 +75,8 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Lab Rats", 1); assertGraveyardCount(playerB, "Boomerang", 1); - assertPermanentCount(playerA, "Soldier", 3); - assertPermanentCount(playerA, "Rat", 0); + assertPermanentCount(playerA, "Soldier Token", 3); + assertPermanentCount(playerA, "Rat Token", 0); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellCastTriggerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellCastTriggerTest.java index 2da89a251fc..f02692111ec 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellCastTriggerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellCastTriggerTest.java @@ -60,9 +60,9 @@ public class SpellCastTriggerTest extends CardTestPlayerBase { assertLife(playerB, 14); assertGraveyardCount(playerA, "Lightning Bolt", 2); - assertPermanentCount(playerA, "Monk", 2); - assertPowerToughness(playerA, "Monk", 2, 2); - assertPowerToughness(playerA, "Monk", 1, 1); + assertPermanentCount(playerA, "Monk Token", 2); + assertPowerToughness(playerA, "Monk Token", 2, 2); + assertPowerToughness(playerA, "Monk Token", 1, 1); assertPowerToughness(playerA, "Monastery Mentor", 4, 4); } @@ -84,7 +84,7 @@ public class SpellCastTriggerTest extends CardTestPlayerBase { execute(); assertGraveyardCount(playerA, "Dance with Devils", 2); - assertPermanentCount(playerA, "Devil", 4); + assertPermanentCount(playerA, "Devil Token", 4); } /** @@ -114,7 +114,7 @@ public class SpellCastTriggerTest extends CardTestPlayerBase { execute(); assertGraveyardCount(playerA, "Dance with Devils", 1); - assertPermanentCount(playerA, "Devil", 2); + assertPermanentCount(playerA, "Devil Token", 2); assertGraveyardCount(playerA, "Read the Bones", 2); assertHandCount(playerA, 5); // one normally drawn + 4 from Read the Bones diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/StrictProctorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/StrictProctorTest.java new file mode 100644 index 00000000000..1dede1407c4 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/StrictProctorTest.java @@ -0,0 +1,64 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +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 jeffwadsworth + */ +public class StrictProctorTest extends CardTestPlayerBase { + + @Test + public void testStrictProctorPaid() { + setStrictChooseMode(true); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + // Whenever a permanent entering the battlefield causes a triggered ability to + // trigger, counter that ability unless its controller pays {2}. + addCard(Zone.BATTLEFIELD, playerA, "Strict Proctor", 1); + // Whenever a land enters the battlefield under your control, you gain 3 life. + addCard(Zone.BATTLEFIELD, playerA, "Primeval Bounty", 1); + // land to play for trigger + addCard(Zone.HAND, playerA, "Swamp", 1); + + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Swamp"); // play land + setChoice(playerA, "Yes"); // pay the {2} mana cost to prevent the countering of the trigger + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 23); // player gains the 3 life + + } + + @Test + public void testStrictProctorNotPaid() { + setStrictChooseMode(true); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + // Whenever a permanent entering the battlefield causes a triggered ability to + // trigger, counter that ability unless its controller pays {2}. + addCard(Zone.BATTLEFIELD, playerA, "Strict Proctor", 1); + // Whenever a land enters the battlefield under your control, you gain 3 life. + addCard(Zone.BATTLEFIELD, playerA, "Primeval Bounty", 1); + // land to play for trigger + addCard(Zone.HAND, playerA, "Swamp", 1); + + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Swamp"); // play land + setChoice(playerA, "No"); // do not pay the {2} mana cost to prevent the countering of the trigger + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20); // player does not gain the 3 life + + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/WoodlandChampionTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/WoodlandChampionTest.java index 97f1fe0b212..8058a2e8560 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/WoodlandChampionTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/WoodlandChampionTest.java @@ -25,7 +25,7 @@ public class WoodlandChampionTest extends CardTestPlayerBase { checkPermanentCounters("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Woodland Champion", CounterType.P1P1, 0); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Acorn Harvest"); - checkPermanentCount("after", 1, PhaseStep.BEGIN_COMBAT, playerA, "Squirrel", 2); + checkPermanentCount("after", 1, PhaseStep.BEGIN_COMBAT, playerA, "Squirrel Token", 2); checkPermanentCounters("after", 1, PhaseStep.BEGIN_COMBAT, playerA, "Woodland Champion", CounterType.P1P1, 2); setStrictChooseMode(true); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ElendaTheDuskRoseTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ElendaTheDuskRoseTest.java index c88fa78c1b5..1329d220803 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ElendaTheDuskRoseTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ElendaTheDuskRoseTest.java @@ -75,8 +75,8 @@ public class ElendaTheDuskRoseTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Silvercoat Lion", 1); assertGraveyardCount(playerA, "Elenda, the Dusk Rose", 1); - assertPermanentCount(playerA, "Vampire", 2); - assertPowerToughness(playerA, "Vampire", 1, 1, Filter.ComparisonScope.All); + assertPermanentCount(playerA, "Vampire Token", 2); + assertPowerToughness(playerA, "Vampire Token", 1, 1, Filter.ComparisonScope.All); } @Test @@ -116,8 +116,8 @@ public class ElendaTheDuskRoseTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Silvercoat Lion", 1); assertGraveyardCount(playerA, "Elenda, the Dusk Rose", 0); - assertPermanentCount(playerA, "Vampire", 2); - assertPowerToughness(playerA, "Vampire", 1, 1, Filter.ComparisonScope.All); + assertPermanentCount(playerA, "Vampire Token", 2); + assertPowerToughness(playerA, "Vampire Token", 1, 1, Filter.ComparisonScope.All); } @Test @@ -161,8 +161,8 @@ public class ElendaTheDuskRoseTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Silvercoat Lion", 1); assertGraveyardCount(playerA, "Elenda, the Dusk Rose", 0); - assertPermanentCount(playerA, "Vampire", 1); - assertPowerToughness(playerA, "Vampire", 1, 1, Filter.ComparisonScope.All); + assertPermanentCount(playerA, "Vampire Token", 1); + assertPowerToughness(playerA, "Vampire Token", 1, 1, Filter.ComparisonScope.All); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ReefWormTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ReefWormTest.java index 94cdb2bfbb8..81403f1f469 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ReefWormTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ReefWormTest.java @@ -24,9 +24,9 @@ public class ReefWormTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Reef Worm", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Reef Worm"); - castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Lightning Bolt", "Fish"); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Whale"); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Whale"); + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Lightning Bolt", "Fish Token"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Whale Token"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Whale Token"); setStopAt(1, PhaseStep.END_TURN); execute(); @@ -36,9 +36,9 @@ public class ReefWormTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Lightning Bolt", 4); - assertPermanentCount(playerB, "Fish", 0); - assertPermanentCount(playerB, "Whale", 0); - assertPermanentCount(playerB, "Kraken", 1); + assertPermanentCount(playerB, "Fish Token", 0); + assertPermanentCount(playerB, "Whale Token", 0); + assertPermanentCount(playerB, "Kraken Token", 1); assertGraveyardCount(playerB, "Reef Worm", 1); assertGraveyardCount(playerA, "Lightning Bolt", 4); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/SidisiBroodTyrantTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/SidisiBroodTyrantTest.java index 021b6279bf8..a8c70f52ace 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/SidisiBroodTyrantTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/SidisiBroodTyrantTest.java @@ -43,7 +43,7 @@ public class SidisiBroodTyrantTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Sidisi, Brood Tyrant", 1); assertGraveyardCount(playerA, 4); - assertPermanentCount(playerA, "Zombie", 0); + assertPermanentCount(playerA, "Zombie Token", 0); } @@ -83,7 +83,7 @@ public class SidisiBroodTyrantTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Satyr Wayfinder", 1); assertHandCount(playerA, "Swamp", 1); assertGraveyardCount(playerA, "Silvercoat Lion", 6); - assertPermanentCount(playerA, "Zombie", 2); + assertPermanentCount(playerA, "Zombie Token", 2); } @@ -126,7 +126,7 @@ public class SidisiBroodTyrantTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Swamp", 1); assertGraveyardCount(playerA, "Silvercoat Lion", 0); assertExileCount("Silvercoat Lion", 2); - assertPermanentCount(playerA, "Zombie", 0); + assertPermanentCount(playerA, "Zombie Token", 0); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ThragtuskTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ThragtuskTest.java index 5dbf4a10bc1..c817e9afa34 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ThragtuskTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/ThragtuskTest.java @@ -46,7 +46,7 @@ public class ThragtuskTest extends CardTestPlayerBase { assertLife(playerA, 23); assertLife(playerB, 20); // Thragtusk ETB ability does not trigger if set to battlefield on test game start - assertPermanentCount(playerA, "Beast", 1); + assertPermanentCount(playerA, "Beast Token", 1); } @@ -93,7 +93,7 @@ public class ThragtuskTest extends CardTestPlayerBase { assertLife(playerA, 23); assertLife(playerB, 20); // Thragtusk ETB ability does not trigger if set to battlefield on test game start - assertPermanentCount(playerA, "Beast", 0); + assertPermanentCount(playerA, "Beast Token", 0); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/VoiceOfResurgenceTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/VoiceOfResurgenceTest.java index 4dcdd21bbce..ce3081e57f1 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/VoiceOfResurgenceTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/VoiceOfResurgenceTest.java @@ -47,8 +47,8 @@ public class VoiceOfResurgenceTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Treachery", 1); assertGraveyardCount(playerB, "Voice of Resurgence", 1); - assertPermanentCount(playerA, "Elemental", 2); // one from the Lightning Bolt and one from the Voice of Resurgence dying - assertPowerToughness(playerA, "Elemental", 3, 3, Filter.ComparisonScope.All); + assertPermanentCount(playerA, "Elemental Token", 2); // one from the Lightning Bolt and one from the Voice of Resurgence dying + assertPowerToughness(playerA, "Elemental Token", 3, 3, Filter.ComparisonScope.All); assertTappedCount("Island", true, 0); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/XathridNecromancerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/XathridNecromancerTest.java index 8cc89616f12..551cf3fa357 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/XathridNecromancerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/XathridNecromancerTest.java @@ -41,8 +41,8 @@ public class XathridNecromancerTest extends CardTestPlayerBase { attack(2, playerB, "Pillarfield Ox"); attack(2, playerB, "Siege Mastodon"); - block(2, playerA, "Human:0", "Silvercoat Lion"); - block(2, playerA, "Human:1", "Pillarfield Ox"); + block(2, playerA, "Human Token:0", "Silvercoat Lion"); + block(2, playerA, "Human Token:1", "Pillarfield Ox"); block(2, playerA, "Xathrid Necromancer", "Siege Mastodon"); setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); @@ -51,8 +51,8 @@ public class XathridNecromancerTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Xathrid Necromancer", 1); assertGraveyardCount(playerA, "Gather the Townsfolk", 1); - assertPermanentCount(playerA, "Human", 0); - assertPermanentCount(playerA, "Zombie", 3); + assertPermanentCount(playerA, "Human Token", 0); + assertPermanentCount(playerA, "Zombie Token", 3); assertLife(playerA, 20); assertLife(playerB, 20); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/events/UnequipEventTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/events/UnequipEventTest.java index daffafbc607..96c6cee7392 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/events/UnequipEventTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/events/UnequipEventTest.java @@ -97,7 +97,7 @@ public class UnequipEventTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Hammer of Nazahn", 1); assertGraveyardCount(playerA, "Beast Within", 1); - assertPowerToughness(playerA, "Beast", 3, 3); + assertPowerToughness(playerA, "Beast Token", 3, 3); assertGraveyardCount(playerA, "Grafted Exoskeleton", 1); assertGraveyardCount(playerA, "Nazahn, Revered Bladesmith", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/watchers/SpiritOfTheLabyrinthTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/watchers/SpiritOfTheLabyrinthTest.java index 8cf128f6aa9..e7c1c13c341 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/watchers/SpiritOfTheLabyrinthTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/watchers/SpiritOfTheLabyrinthTest.java @@ -51,7 +51,7 @@ public class SpiritOfTheLabyrinthTest extends CardTestPlayerBase { setStopAt(2, PhaseStep.PRECOMBAT_MAIN); execute(); - assertPermanentCount(playerB, "Spirit", 2); + assertPermanentCount(playerB, "Spirit Token", 2); this.assertHandCount(playerA, 1); this.assertHandCount(playerB, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/watchers/UnscytheKillerOfKingsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/watchers/UnscytheKillerOfKingsTest.java index 469b01f252b..f13f44b118f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/watchers/UnscytheKillerOfKingsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/watchers/UnscytheKillerOfKingsTest.java @@ -37,7 +37,7 @@ public class UnscytheKillerOfKingsTest extends CardTestPlayerBase { execute(); assertPermanentCount(playerB, "Sejiri Merfolk", 0); - assertPermanentCount(playerA, "Zombie", 1); + assertPermanentCount(playerA, "Zombie Token", 1); assertExileCount("Sejiri Merfolk", 1); } @@ -60,7 +60,7 @@ public class UnscytheKillerOfKingsTest extends CardTestPlayerBase { execute(); assertPermanentCount(playerB, "Craw Wurm", 0); - assertPermanentCount(playerA, "Zombie", 1); + assertPermanentCount(playerA, "Zombie Token", 1); assertExileCount("Craw Wurm", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/watchers/ZuberasTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/watchers/ZuberasTest.java index aab8d0787df..56c3a2fa682 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/watchers/ZuberasTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/watchers/ZuberasTest.java @@ -58,7 +58,7 @@ public class ZuberasTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.DECLARE_BLOCKERS); execute(); - assertPermanentCount(playerA, "Spirit", 1); + assertPermanentCount(playerA, "Spirit Token", 1); assertHandCount(playerB, 1); assertHandCount(playerA, 4); assertLife(playerB, 17); diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/duel/AnafenzaTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/duel/AnafenzaTest.java index eccb5adbf0b..6b77b93eb71 100644 --- a/Mage.Tests/src/test/java/org/mage/test/commander/duel/AnafenzaTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/commander/duel/AnafenzaTest.java @@ -89,9 +89,9 @@ public class AnafenzaTest extends CardTestCommanderDuelBase { playLand(4, PhaseStep.PRECOMBAT_MAIN, playerB, "Forest"); attack(5, playerA, "Acidic Slime"); - block(5, playerB, "Elemental:0", "Acidic Slime"); + block(5, playerB, "Elemental Token:0", "Acidic Slime"); attack(5, playerA, "Anafenza, the Foremost"); - block(5, playerB, "Elemental:1", "Anafenza, the Foremost"); + block(5, playerB, "Elemental Token:1", "Anafenza, the Foremost"); addTarget(playerB, playerA); setStopAt(5, PhaseStep.POSTCOMBAT_MAIN); @@ -100,7 +100,7 @@ public class AnafenzaTest extends CardTestCommanderDuelBase { assertExileCount(playerA, 0); assertExileCount(playerB, 0); - assertPermanentCount(playerB, "Elemental", 1); + assertPermanentCount(playerB, "Elemental Token", 1); assertGraveyardCount(playerA, "Acidic Slime", 1); assertGraveyardCount(playerA, "Anafenza, the Foremost", 0); diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/duel/CastBRGCommanderTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/duel/CastBRGCommanderTest.java index 471441723d2..e0dd95faf04 100644 --- a/Mage.Tests/src/test/java/org/mage/test/commander/duel/CastBRGCommanderTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/commander/duel/CastBRGCommanderTest.java @@ -173,7 +173,7 @@ public class CastBRGCommanderTest extends CardTestCommanderDuelBase { assertGraveyardCount(playerA, "Mogg Infestation", 1); assertCommandZoneCount(playerB, "Daxos of Meletis", 1); - assertPermanentCount(playerB, "Goblin", 2); + assertPermanentCount(playerB, "Goblin Token", 2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/duel/CommanderAffinityTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/duel/CommanderAffinityTest.java index 76c55a542b6..c807c68454a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/commander/duel/CommanderAffinityTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/commander/duel/CommanderAffinityTest.java @@ -91,7 +91,7 @@ public class CommanderAffinityTest extends CardTestCommanderDuelBase { public void test_Gained_Affinity() { // bug: Mycosynth Golem did not allow my commander, Karn, Silver Golem, to cost 0 even though I had 7+ artifacts on the board. - Ability ability = new SimpleActivatedAbility(Zone.ALL, new CreateTokenEffect(new ArtifactWallToken(), 7), new ManaCostsImpl("R")); + Ability ability = new SimpleActivatedAbility(Zone.ALL, new CreateTokenEffect(new ArtifactWallToken(), 7), new ManaCostsImpl<>("{R}")); addCustomCardWithAbility("generate tokens", playerA, ability); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); // @@ -129,7 +129,7 @@ public class CommanderAffinityTest extends CardTestCommanderDuelBase { // generate artifact tokens activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: Create"); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); - checkPermanentCount("after tokens", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wall", 7); + checkPermanentCount("after tokens", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wall Token", 7); checkPlayableAbility("after tokens", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Karn, Silver Golem", true); setStrictChooseMode(true); diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/duel/CommanderReplaceEffectTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/duel/CommanderReplaceEffectTest.java index cfd47484f12..5d2a062bff2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/commander/duel/CommanderReplaceEffectTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/commander/duel/CommanderReplaceEffectTest.java @@ -45,8 +45,8 @@ public class CommanderReplaceEffectTest extends CardTestCommanderDuelBase { assertPermanentCount(playerA, "Daxos of Meletis", 0); assertGraveyardCount(playerA, "Daxos of Meletis", 0); - assertPermanentCount(playerB, "Phyrexian Horror", 1); - assertPowerToughness(playerB, "Phyrexian Horror", 1, 1); + assertPermanentCount(playerB, "Phyrexian Horror Token", 1); + assertPowerToughness(playerB, "Phyrexian Horror Token", 1, 1); } @Test @@ -74,8 +74,8 @@ public class CommanderReplaceEffectTest extends CardTestCommanderDuelBase { setStopAt(3, PhaseStep.UPKEEP); execute(); - assertPermanentCount(playerB, "Phyrexian Horror", 1); - assertPowerToughness(playerB, "Phyrexian Horror", 1, 1); + assertPermanentCount(playerB, "Phyrexian Horror Token", 1); + assertPowerToughness(playerB, "Phyrexian Horror Token", 1, 1); assertPermanentCount(playerA, "Daxos of Meletis", 1); assertPermanentCount(playerA, "Gift of Immortality", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/duel/CurseOfTheSwineTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/duel/CurseOfTheSwineTest.java index 1645b5e3129..3c72b8b24bb 100644 --- a/Mage.Tests/src/test/java/org/mage/test/commander/duel/CurseOfTheSwineTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/commander/duel/CurseOfTheSwineTest.java @@ -38,6 +38,6 @@ public class CurseOfTheSwineTest extends CardTestCommanderDuelBase { assertCommandZoneCount(playerA, "Daxos of Meletis", 1); assertExileCount("Daxos of Meletis", 0); - assertPermanentCount(playerA, "Boar", 1); + assertPermanentCount(playerA, "Boar Token", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/duel/OpalPalaceTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/duel/OpalPalaceTest.java index 82a06303bb5..cc62b292f5c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/commander/duel/OpalPalaceTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/commander/duel/OpalPalaceTest.java @@ -32,7 +32,6 @@ public class OpalPalaceTest extends CardTestCommanderDuelBase { // showAvailableAbilities("abi", 1, PhaseStep.PRECOMBAT_MAIN, playerA); activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {G}"); activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}, {T}"); - setChoice(playerA, "Opal Palace"); // activate mana replace effect first (+3 counters) castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ob Nixilis of the Black Oath"); // {3}{B}{B} setStrictChooseMode(true); diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperBaseTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperBaseTest.java new file mode 100644 index 00000000000..fb1293f918f --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperBaseTest.java @@ -0,0 +1,16 @@ +package org.mage.test.commander.piper; + +import org.mage.test.serverside.base.CardTestCommanderDuelBase; + +/** + * @author TheElk801 + */ +public abstract class ThePrismaticPiperBaseTest extends CardTestCommanderDuelBase { + + protected static final String piper = "The Prismatic Piper"; + + protected ThePrismaticPiperBaseTest(int number) { + super(); + this.deckNameA = "piperDecks/ThePrismaticPiper" + number + ".dck"; + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest1.java b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest1.java new file mode 100644 index 00000000000..a8b4a8e8e69 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest1.java @@ -0,0 +1,33 @@ +package org.mage.test.commander.piper; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; + +/** + * @author TheElk801 + */ +public class ThePrismaticPiperTest1 extends ThePrismaticPiperBaseTest { + + // Decklist: + // 99 Island + // SB: 1 The Prismatic Piper + + public ThePrismaticPiperTest1() { + super(1); + } + + @Test + public void testColor() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piper); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertColor(playerA, piper, "U", true); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest2.java b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest2.java new file mode 100644 index 00000000000..cdf672f916e --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest2.java @@ -0,0 +1,53 @@ +package org.mage.test.commander.piper; + +import mage.abilities.mana.ManaOptions; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.utils.ManaOptionsTestUtils; + +import static org.mage.test.utils.ManaOptionsTestUtils.assertDuplicatedManaOptions; + +/** + * @author TheElk801 + */ +public class ThePrismaticPiperTest2 extends ThePrismaticPiperBaseTest { + + // Decklist: + // 98 Island + // 1 Mountain + // SB: 1 The Prismatic Piper + // SB: 1 Ghost of Ramirez DePietro + + public ThePrismaticPiperTest2() { + super(2); + } + + @Test + public void testColor() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piper); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertColor(playerA, piper, "R", true); + } + + @Test + public void testManaOptions() { + addCard(Zone.BATTLEFIELD, playerA, "Command Tower"); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); + assertDuplicatedManaOptions(manaOptions); + Assert.assertEquals("mana variations don't fit", 2, manaOptions.size()); + ManaOptionsTestUtils.assertManaOptions("{U}", manaOptions); + ManaOptionsTestUtils.assertManaOptions("{R}", manaOptions); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest3.java b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest3.java new file mode 100644 index 00000000000..57e79abc718 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest3.java @@ -0,0 +1,36 @@ +package org.mage.test.commander.piper; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; + +/** + * @author TheElk801 + */ +public class ThePrismaticPiperTest3 extends ThePrismaticPiperBaseTest { + + // Decklist: + // 98 Island + // 1 Mountain + // SB: 1 The Prismatic Piper + // SB: 1 Kraum, Ludevic's Opus + + public ThePrismaticPiperTest3() { + super(3); + } + + @Test + public void testColor() { + setChoice(playerA, "White"); + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piper); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertColor(playerA, piper, "W", true); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest4.java b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest4.java new file mode 100644 index 00000000000..a8860f596fd --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest4.java @@ -0,0 +1,25 @@ +package org.mage.test.commander.piper; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; + +/** + * @author TheElk801 + */ +public class ThePrismaticPiperTest4 extends ThePrismaticPiperBaseTest { + + // Decklist: + // 98 Mountain + // 1 Island + // SB: 1 The Prismatic Piper + + public ThePrismaticPiperTest4() { + super(4); + } + + @Test(expected = UnsupportedOperationException.class) + public void testColor() { + execute(); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest5.java b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest5.java new file mode 100644 index 00000000000..2a8c9172a0e --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest5.java @@ -0,0 +1,36 @@ +package org.mage.test.commander.piper; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; + +/** + * @author TheElk801 + */ +public class ThePrismaticPiperTest5 extends ThePrismaticPiperBaseTest { + + // Decklist: + // 97 Mountain + // 1 Island + // 1 Plains + // SB: 1 The Prismatic Piper + // SB: 1 Kraum, Ludevic's Opus + + public ThePrismaticPiperTest5() { + super(5); + } + + @Test + public void testColor() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piper); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertColor(playerA, piper, "W", true); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest6.java b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest6.java new file mode 100644 index 00000000000..cde2e730e83 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest6.java @@ -0,0 +1,26 @@ +package org.mage.test.commander.piper; + +import org.junit.Test; + +/** + * @author TheElk801 + */ +public class ThePrismaticPiperTest6 extends ThePrismaticPiperBaseTest { + + // Decklist: + // 96 Mountain + // 1 Island + // 1 Plains + // 1 Forest + // SB: 1 The Prismatic Piper + // SB: 1 Kraum, Ludevic's Opus + + public ThePrismaticPiperTest6() { + super(6); + } + + @Test(expected = UnsupportedOperationException.class) + public void testColor() { + execute(); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest7.java b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest7.java new file mode 100644 index 00000000000..f8457448530 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest7.java @@ -0,0 +1,62 @@ +package org.mage.test.commander.piper; + +import mage.ObjectColor; +import mage.abilities.mana.ManaOptions; +import mage.cards.Card; +import mage.constants.CommanderCardType; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.utils.ManaOptionsTestUtils; + +import java.util.ArrayList; +import java.util.List; + +import static org.mage.test.utils.ManaOptionsTestUtils.assertDuplicatedManaOptions; + +/** + * @author TheElk801 + */ +public class ThePrismaticPiperTest7 extends ThePrismaticPiperBaseTest { + + // Decklist: + // 97 Mountain + // 1 Forest + // SB: 2 The Prismatic Piper + + public ThePrismaticPiperTest7() { + super(7); + } + + @Test + public void testColor() { + execute(); + + List commanders = new ArrayList<>(currentGame.getCommanderCardsFromCommandZone(playerA, CommanderCardType.ANY)); + Card piper1; + Card piper2; + if (commanders.get(0).getColor(currentGame).isRed()) { + piper1 = commanders.get(0); + piper2 = commanders.get(1); + } else { + piper1 = commanders.get(1); + piper2 = commanders.get(0); + } + Assert.assertEquals("One Piper must be red", piper1.getColor(currentGame), ObjectColor.RED); + Assert.assertEquals("One Piper must be green", piper2.getColor(currentGame), ObjectColor.GREEN); + } + + @Test + public void testManaOptions() { + addCard(Zone.BATTLEFIELD, playerA, "Command Tower"); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); + assertDuplicatedManaOptions(manaOptions); + Assert.assertEquals("mana variations don't fit", 2, manaOptions.size()); + ManaOptionsTestUtils.assertManaOptions("{R}", manaOptions); + ManaOptionsTestUtils.assertManaOptions("{G}", manaOptions); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest8.java b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest8.java new file mode 100644 index 00000000000..5b788024ace --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/commander/piper/ThePrismaticPiperTest8.java @@ -0,0 +1,60 @@ +package org.mage.test.commander.piper; + +import mage.abilities.mana.ManaOptions; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.utils.ManaOptionsTestUtils; + +import static org.mage.test.utils.ManaOptionsTestUtils.assertDuplicatedManaOptions; + +/** + * @author TheElk801 + */ +public class ThePrismaticPiperTest8 extends ThePrismaticPiperBaseTest { + + // Decklist: + // 97 Mountain + // 1 Island + // 1 Forest + // SB: 1 The Prismatic Piper + // SB: 1 Kraum, Ludevic's Opus + // SB: 1 Keruga, the Macrosage + + public ThePrismaticPiperTest8() { + super(8); + } + + @Test + public void testColor() { + setChoice(playerA, true); // Companion + addCard(Zone.BATTLEFIELD, playerA, "Island", 8); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, piper); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Companion"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertColor(playerA, piper, "G", true); + assertHandCount(playerA, "Keruga, the Macrosage", 1); + } + + @Test + public void testManaOptions() { + setChoice(playerA, true); // Companion + addCard(Zone.BATTLEFIELD, playerA, "Command Tower"); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + ManaOptions manaOptions = playerA.getAvailableManaTest(currentGame); + assertDuplicatedManaOptions(manaOptions); + Assert.assertEquals("mana variations don't fit", 3, manaOptions.size()); + ManaOptionsTestUtils.assertManaOptions("{U}", manaOptions); + ManaOptionsTestUtils.assertManaOptions("{R}", manaOptions); + ManaOptionsTestUtils.assertManaOptions("{G}", manaOptions); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/game/ends/GameIsADrawTest.java b/Mage.Tests/src/test/java/org/mage/test/game/ends/GameIsADrawTest.java index 6ed52f4c5c3..606fdfbf653 100644 --- a/Mage.Tests/src/test/java/org/mage/test/game/ends/GameIsADrawTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/game/ends/GameIsADrawTest.java @@ -137,7 +137,7 @@ public class GameIsADrawTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "Angel", 20); + assertPermanentCount(playerA, "Angel Token", 20); Assert.assertFalse("Game should not have ended.", currentGame.hasEnded()); assertLife(playerA, 100); diff --git a/Mage.Tests/src/test/java/org/mage/test/lki/LastKnownInformationTest.java b/Mage.Tests/src/test/java/org/mage/test/lki/LastKnownInformationTest.java index 3fd6ee02708..e8ec1aa6608 100644 --- a/Mage.Tests/src/test/java/org/mage/test/lki/LastKnownInformationTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/lki/LastKnownInformationTest.java @@ -50,7 +50,7 @@ public class LastKnownInformationTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Murder Investigation", 1); assertPermanentCount(playerA, "Safehold Elite", 0); // because enchanted Safehold Elite's P/T was 2/2, Murder Investigation has to put 2 Soldier onto the battlefield - assertPermanentCount(playerA, "Soldier", 2); + assertPermanentCount(playerA, "Soldier Token", 2); assertGraveyardCount(playerB, "Lightning Bolt", 2); assertActionsCount(playerB, 0); diff --git a/Mage.Tests/src/test/java/org/mage/test/multiplayer/VotingTest.java b/Mage.Tests/src/test/java/org/mage/test/multiplayer/VotingTest.java index d9c6065d9a3..03465c5589c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/multiplayer/VotingTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/multiplayer/VotingTest.java @@ -65,7 +65,7 @@ public class VotingTest extends CardTestCommander4PlayersWithAIHelps { assertAllCommandsUsed(); assertPowerToughness(playerA, lieutenant, 6, 6); - assertPermanentCount(playerA, "Soldier", 0); + assertPermanentCount(playerA, "Soldier Token", 0); } @Test @@ -82,7 +82,7 @@ public class VotingTest extends CardTestCommander4PlayersWithAIHelps { assertAllCommandsUsed(); assertPowerToughness(playerA, lieutenant, 2, 2); - assertPermanentCount(playerA, "Soldier", 4); + assertPermanentCount(playerA, "Soldier Token", 4); } @Test @@ -99,7 +99,7 @@ public class VotingTest extends CardTestCommander4PlayersWithAIHelps { assertAllCommandsUsed(); assertPowerToughness(playerA, lieutenant, 4, 4); - assertPermanentCount(playerA, "Soldier", 2); + assertPermanentCount(playerA, "Soldier Token", 2); } @Test @@ -177,7 +177,7 @@ public class VotingTest extends CardTestCommander4PlayersWithAIHelps { assertAllCommandsUsed(); assertPowerToughness(playerA, lieutenant, 5, 5); - assertPermanentCount(playerA, "Soldier", 2); + assertPermanentCount(playerA, "Soldier Token", 2); } @Test @@ -197,7 +197,7 @@ public class VotingTest extends CardTestCommander4PlayersWithAIHelps { assertAllCommandsUsed(); assertPowerToughness(playerA, lieutenant, 4, 4); - assertPermanentCount(playerA, "Soldier", 3); + assertPermanentCount(playerA, "Soldier Token", 3); } @Test @@ -216,7 +216,7 @@ public class VotingTest extends CardTestCommander4PlayersWithAIHelps { assertAllCommandsUsed(); assertPowerToughness(playerA, lieutenant, 6, 6); - assertPermanentCount(playerA, "Soldier", 0); + assertPermanentCount(playerA, "Soldier Token", 0); } @Test @@ -236,7 +236,7 @@ public class VotingTest extends CardTestCommander4PlayersWithAIHelps { assertAllCommandsUsed(); assertPowerToughness(playerA, lieutenant, 7, 7); - assertPermanentCount(playerA, "Soldier", 0); + assertPermanentCount(playerA, "Soldier Token", 0); } @Test @@ -258,7 +258,7 @@ public class VotingTest extends CardTestCommander4PlayersWithAIHelps { assertAllCommandsUsed(); assertPowerToughness(playerA, lieutenant, 6, 6); - assertPermanentCount(playerA, "Soldier", 0); + assertPermanentCount(playerA, "Soldier Token", 0); } @Test @@ -278,7 +278,7 @@ public class VotingTest extends CardTestCommander4PlayersWithAIHelps { assertAllCommandsUsed(); assertPowerToughness(playerA, lieutenant, 4, 4); - assertPermanentCount(playerA, "Soldier", 3); + assertPermanentCount(playerA, "Soldier Token", 3); assertLife(playerA, 20); assertLife(playerB, 20 - 2); assertLife(playerC, 20 - 2); @@ -304,7 +304,7 @@ public class VotingTest extends CardTestCommander4PlayersWithAIHelps { assertAllCommandsUsed(); assertPowerToughness(playerA, lieutenant, 6, 6); - assertPermanentCount(playerA, "Soldier", 2); + assertPermanentCount(playerA, "Soldier Token", 2); assertLife(playerA, 20); assertLife(playerB, 20); assertLife(playerC, 20); diff --git a/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java index d65201b1319..91cbaa1b52f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java @@ -222,7 +222,7 @@ public class RandomPlayer extends ComputerPlayer { } protected boolean chooseRandomTarget(Target target, Ability source, Game game) { - Set possibleTargets = target.possibleTargets(source == null ? null : source.getSourceId(), playerId, game); + Set possibleTargets = target.possibleTargets(playerId, source, game); if (possibleTargets.isEmpty()) { return false; } @@ -246,12 +246,12 @@ public class RandomPlayer extends ComputerPlayer { } @Override - public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { + public boolean choose(Outcome outcome, Target target, Ability source, Game game) { return chooseRandom(target, game); } @Override - public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map options) { + public boolean choose(Outcome outcome, Target target, Ability source, Game game, Map options) { return chooseRandom(target, game); } @@ -294,7 +294,7 @@ public class RandomPlayer extends ComputerPlayer { @Override public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) { - Set possibleTargets = target.possibleTargets(source == null ? null : source.getSourceId(), playerId, game); + Set possibleTargets = target.possibleTargets(playerId, source, game); if (possibleTargets.isEmpty()) { return !target.isRequired(source); } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java index 9908787ee2a..05e9ae53f21 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java @@ -1,5 +1,6 @@ package org.mage.test.player; +import mage.abilities.Ability; import mage.choices.Choice; import mage.constants.Outcome; import mage.constants.RangeOfInfluence; @@ -7,8 +8,6 @@ import mage.game.Game; import mage.player.ai.ComputerPlayer; import mage.target.Target; -import java.util.UUID; - /** * @author JayDi85 */ @@ -43,11 +42,11 @@ public class TestComputerPlayer extends ComputerPlayer { } @Override - public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { + public boolean choose(Outcome outcome, Target target, Ability source, Game game) { if (testPlayerLink.canChooseByComputer()) { - return super.choose(outcome, target, sourceId, game); + return super.choose(outcome, target, source, game); } else { - return testPlayerLink.choose(outcome, target, sourceId, game); + return testPlayerLink.choose(outcome, target, source, game); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java index 0017004e43e..64c587fae3f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java @@ -1,5 +1,6 @@ package org.mage.test.player; +import mage.abilities.Ability; import mage.choices.Choice; import mage.constants.Outcome; import mage.constants.RangeOfInfluence; @@ -7,8 +8,6 @@ import mage.game.Game; import mage.player.ai.ComputerPlayer7; import mage.target.Target; -import java.util.UUID; - /** * Copied-pasted methods from TestComputerPlayer, see docs in there * @@ -28,11 +27,11 @@ public class TestComputerPlayer7 extends ComputerPlayer7 { } @Override - public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { + public boolean choose(Outcome outcome, Target target, Ability source, Game game) { if (testPlayerLink.canChooseByComputer()) { - return super.choose(outcome, target, sourceId, game); + return super.choose(outcome, target, source, game); } else { - return testPlayerLink.choose(outcome, target, sourceId, game); + return testPlayerLink.choose(outcome, target, source, game); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayerMonteCarlo.java b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayerMonteCarlo.java index e55d22749f1..9f6168ff0f7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayerMonteCarlo.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayerMonteCarlo.java @@ -1,5 +1,6 @@ package org.mage.test.player; +import mage.abilities.Ability; import mage.choices.Choice; import mage.constants.Outcome; import mage.constants.RangeOfInfluence; @@ -7,8 +8,6 @@ import mage.game.Game; import mage.player.ai.ComputerPlayerMCTS; import mage.target.Target; -import java.util.UUID; - /** * Copied-pasted methods from TestComputerPlayer, see docs in there * @@ -28,11 +27,11 @@ public class TestComputerPlayerMonteCarlo extends ComputerPlayerMCTS { } @Override - public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { + public boolean choose(Outcome outcome, Target target, Ability source, Game game) { if (testPlayerLink.canChooseByComputer()) { - return super.choose(outcome, target, sourceId, game); + return super.choose(outcome, target, source, game); } else { - return testPlayerLink.choose(outcome, target, sourceId, game); + return testPlayerLink.choose(outcome, target, source, game); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 2a61c4fdda5..0b915137008 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -499,7 +499,7 @@ public class TestPlayer implements Player { targetName = targetName.substring(0, targetName.length() - 11); } } - for (UUID id : currentTarget.possibleTargets(ability.getSourceId(), ability.getControllerId(), game)) { + for (UUID id : currentTarget.possibleTargets(ability.getControllerId(), ability, game)) { if (!currentTarget.getTargets().contains(id)) { MageObject object = game.getObject(id); @@ -2056,7 +2056,7 @@ public class TestPlayer implements Player { } @Override - public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map options) { + public boolean choose(Outcome outcome, Target target, Ability source, Game game, Map options) { UUID abilityControllerId = computerPlayer.getId(); if (target.getTargetController() != null && target.getAbilityController() != null) { abilityControllerId = target.getAbilityController(); @@ -2064,7 +2064,7 @@ public class TestPlayer implements Player { // ignore player select if (target.getMessage().equals("Select a starting player")) { - return computerPlayer.choose(outcome, target, sourceId, game, options); + return computerPlayer.choose(outcome, target, source, game, options); } assertAliasSupportInChoices(true); @@ -2082,11 +2082,6 @@ public class TestPlayer implements Player { List usedChoices = new ArrayList<>(); List usedTargets = new ArrayList<>(); - Ability source = null; - StackObject stackObject = game.getStack().getStackObject(sourceId); - if (stackObject != null) { - source = stackObject.getStackAbility(); - } if ((target.getOriginalTarget() instanceof TargetPermanent) || (target.getOriginalTarget() instanceof TargetPermanentOrPlayer)) { // player target not implemted yet @@ -2112,7 +2107,7 @@ public class TestPlayer implements Player { targetName = targetName.substring(0, targetName.length() - 11); } } - for (Permanent permanent : game.getBattlefield().getActivePermanents(filterPermanent, abilityControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filterPermanent, abilityControllerId, source, game)) { if (target.getTargets().contains(permanent.getId())) { continue; } @@ -2178,7 +2173,7 @@ public class TestPlayer implements Player { CheckOneChoice: for (String possibleChoice : possibleChoices) { - Set possibleCards = target.possibleTargets(sourceId, abilityControllerId, game); + Set possibleCards = target.possibleTargets(abilityControllerId, source, game); CheckTargetsList: for (UUID targetId : possibleCards) { MageObject targetObject = game.getCard(targetId); @@ -2232,7 +2227,7 @@ public class TestPlayer implements Player { if (target.getOriginalTarget() instanceof TargetSource) { Set possibleTargets; TargetSource t = ((TargetSource) target.getOriginalTarget()); - possibleTargets = t.possibleTargets(sourceId, abilityControllerId, game); + possibleTargets = t.possibleTargets(abilityControllerId, source, game); for (String choiceRecord : choices) { String[] targetList = choiceRecord.split("\\^"); boolean targetFound = false; @@ -2268,8 +2263,8 @@ public class TestPlayer implements Player { */ } - this.chooseStrictModeFailed("choice", game, getInfo(game.getObject(sourceId)) + ";\n" + getInfo(target)); - return computerPlayer.choose(outcome, target, sourceId, game, options); + this.chooseStrictModeFailed("choice", game, getInfo(game.getObject(source)) + ";\n" + getInfo(target)); + return computerPlayer.choose(outcome, target, source, game, options); } private void checkTargetDefinitionMarksSupport(Target needTarget, String targetDefinition, String canSupportChars) { @@ -2380,7 +2375,7 @@ public class TestPlayer implements Player { if (filter instanceof FilterPermanentOrSuspendedCard) { filter = ((FilterPermanentOrSuspendedCard) filter).getPermanentFilter(); } - for (Permanent permanent : game.getBattlefield().getActivePermanents((FilterPermanent) filter, abilityControllerId, sourceId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents((FilterPermanent) filter, abilityControllerId, source, game)) { if (hasObjectTargetNameOrAlias(permanent, targetName) || (permanent.getName() + '-' + permanent.getExpansionSetCode()).equals(targetName)) { // TODO: remove exp code search? if (target.canTarget(abilityControllerId, permanent.getId(), source, game) && !target.getTargets().contains(permanent.getId())) { if ((permanent.isCopy() && !originOnly) || (!permanent.isCopy() && !copyOnly)) { @@ -2466,7 +2461,7 @@ public class TestPlayer implements Player { } // card in battlefield - if (target instanceof TargetCardInGraveyardOrBattlefield) { + if (target instanceof TargetCardInGraveyardBattlefieldOrStack) { TargetCard targetFull = (TargetCard) target; for (String targetDefinition : targets) { checkTargetDefinitionMarksSupport(target, targetDefinition, "^"); @@ -2494,7 +2489,7 @@ public class TestPlayer implements Player { if (target.getOriginalTarget() instanceof TargetCardInOpponentsGraveyard || target.getOriginalTarget() instanceof TargetCardInYourGraveyard || target.getOriginalTarget() instanceof TargetCardInGraveyard - || target.getOriginalTarget() instanceof TargetCardInGraveyardOrBattlefield + || target.getOriginalTarget() instanceof TargetCardInGraveyardBattlefieldOrStack || (target.getOriginalTarget() instanceof TargetCard && target.getOriginalTarget().getZone() == Zone.GRAVEYARD)) { targetCardZonesChecked.add(Zone.GRAVEYARD); TargetCard targetFull = (TargetCard) target.getOriginalTarget(); @@ -3966,10 +3961,10 @@ public class TestPlayer implements Player { @Override public boolean choose(Outcome outcome, Target target, - UUID sourceId, Game game + Ability source, Game game ) { // needed to call here the TestPlayer because it's overwitten - return choose(outcome, target, sourceId, game, null); + return choose(outcome, target, source, game, null); } @Override @@ -4066,7 +4061,7 @@ public class TestPlayer implements Player { Assert.assertTrue("target amount must be <= remaining = " + target.getAmountRemaining() + " " + targetInfo, targetAmount <= target.getAmountRemaining()); if (target.getAmountRemaining() > 0) { - for (UUID possibleTarget : target.possibleTargets(source.getSourceId(), source.getControllerId(), game)) { + for (UUID possibleTarget : target.possibleTargets(source.getControllerId(), source, game)) { boolean foundTarget = false; // permanent @@ -4364,19 +4359,17 @@ public class TestPlayer implements Player { @Override public SpellAbility chooseAbilityForCast(Card card, Game game, boolean noMana) { assertAliasSupportInChoices(false); - MageObject object = game.getObject(card.getId()); // must be object to find real abilities (example: commander) - Map useable = PlayerImpl.getCastableSpellAbilities(game, this.getId(), object, game.getState().getZone(object.getId()), noMana); - String allInfo = useable.values().stream().map(Object::toString).collect(Collectors.joining("\n")); + Map useable = PlayerImpl.getCastableSpellAbilities(game, this.getId(), object, game.getState().getZone(object.getId()), noMana); if (useable.size() == 1) { - return (SpellAbility) useable.values().iterator().next(); + return useable.values().iterator().next(); } if (!choices.isEmpty()) { - for (ActivatedAbility ability : useable.values()) { + for (SpellAbility ability : useable.values()) { if (ability.toString().startsWith(choices.get(0))) { choices.remove(0); - return (SpellAbility) ability; + return ability; } } @@ -4384,6 +4377,7 @@ public class TestPlayer implements Player { //Assert.fail("Wrong choice"); } + String allInfo = useable.values().stream().map(Object::toString).collect(Collectors.joining("\n")); this.chooseStrictModeFailed("choice", game, getInfo(card) + " - can't select ability to cast.\n" + "Card's abilities:\n" + allInfo); return computerPlayer.chooseAbilityForCast(card, game, noMana); } diff --git a/Mage.Tests/src/test/java/org/mage/test/rollback/NewCreaturesAreRemovedTest.java b/Mage.Tests/src/test/java/org/mage/test/rollback/NewCreaturesAreRemovedTest.java index f2cd3eecaf4..a9f81004873 100644 --- a/Mage.Tests/src/test/java/org/mage/test/rollback/NewCreaturesAreRemovedTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/rollback/NewCreaturesAreRemovedTest.java @@ -53,7 +53,7 @@ public class NewCreaturesAreRemovedTest extends CardTestPlayerBase { assertLife(playerB, 14); assertPermanentCount(playerA, "Port Town", 1); assertTapped("Port Town", false); - assertPermanentCount(playerA, "Clue", 3); + assertPermanentCount(playerA, "Clue Token", 3); } @@ -107,7 +107,7 @@ public class NewCreaturesAreRemovedTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Port Town", 1); assertTapped("Port Town", false); - assertPermanentCount(playerA, "Clue", 3); + assertPermanentCount(playerA, "Clue Token", 3); assertLife(playerB, 14); assertLife(playerA, 14); diff --git a/Mage.Tests/src/test/java/org/mage/test/rollback/StateValuesTest.java b/Mage.Tests/src/test/java/org/mage/test/rollback/StateValuesTest.java index c8c309da1b3..99fecb26d89 100644 --- a/Mage.Tests/src/test/java/org/mage/test/rollback/StateValuesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/rollback/StateValuesTest.java @@ -80,7 +80,7 @@ public class StateValuesTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); - assertPermanentCount(playerA, "Clue", 2); + assertPermanentCount(playerA, "Clue Token", 2); } @@ -96,8 +96,8 @@ public class StateValuesTest extends CardTestPlayerBase { castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Battle Screech"); activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Flashback"); - setChoice(playerA, "Bird"); - setChoice(playerA, "Bird"); + setChoice(playerA, "Bird Token"); + setChoice(playerA, "Bird Token"); setChoice(playerA, "Silvercoat Lion"); setStrictChooseMode(true); @@ -108,9 +108,9 @@ public class StateValuesTest extends CardTestPlayerBase { // Before rollback assertTappedCount("Plains", true, 4); - assertTappedCount("Bird", true, 2); + assertTappedCount("Bird Token", true, 2); assertTappedCount("Silvercoat Lion", true, 1); - assertPermanentCount(playerA, "Bird", 4); + assertPermanentCount(playerA, "Bird Token", 4); assertHandCount(playerA, 0); assertExileCount(playerA, "Battle Screech", 1); @@ -119,7 +119,7 @@ public class StateValuesTest extends CardTestPlayerBase { // After rollback to turn 1 assertTappedCount("Plains", true, 0); assertTappedCount("Silvercoat Lion", true, 0); - assertPermanentCount(playerA, "Bird", 0); + assertPermanentCount(playerA, "Bird Token", 0); assertLibraryCount(playerA, "Battle Screech", 1); assertHandCount(playerA, 0); } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java index ffd9f92a1b9..67251890204 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java @@ -78,6 +78,7 @@ public abstract class MageTestPlayerBase { protected Map> graveyardCards = new HashMap<>(); protected Map> libraryCards = new HashMap<>(); protected Map> commandCards = new HashMap<>(); + protected Map> exiledCards = new HashMap<>(); protected Map> commands = new HashMap<>(); @@ -349,6 +350,15 @@ public abstract class MageTestPlayerBase { return res; } + protected List getExiledCards(TestPlayer player) { + if (exiledCards.containsKey(player)) { + return exiledCards.get(player); + } + List res = new ArrayList<>(); + exiledCards.put(player, res); + return res; + } + protected Map getCommands(TestPlayer player) { if (commands.containsKey(player)) { return commands.get(player); @@ -441,6 +451,9 @@ public abstract class MageTestPlayerBase { case COMMAND: getCommandCards(controllerPlayer).add(newCard); break; + case EXILED: + getExiledCards(controllerPlayer).add(newCard); + break; default: Assert.fail("Unsupported zone: " + putAtZone); } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index 7147cf4de8f..bd329162c2c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -238,6 +238,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement getHandCards(testPlayer).clear(); getBattlefieldCards(testPlayer).clear(); getGraveCards(testPlayer).clear(); + getExiledCards(testPlayer).clear(); // Reset the turn counter for tests ((TestPlayer) player).setInitialTurns(0); } @@ -731,6 +732,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement return getLibraryCards(player); case COMMAND: return getCommandCards(player); + case EXILED: + return getExiledCards(player); default: break; } @@ -1442,7 +1445,21 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } } } - Assert.assertEquals("(Exile " + owner.getName() + ") Card counts are not equal (" + cardName + ')', count, actualCount); + Assert.assertEquals("(Exile " + owner.getName() + ") Card counts are not equal (" + cardName + ").", count, actualCount); + } + + /** + * Assert card count in a specific exile zone. + * + * @param exileZoneName Name of the exile zone to be counted. + * @param count Expected count. + * @throws AssertionError + */ + public void assertExileZoneCount(String exileZoneName, int count) throws AssertionError { + ExileZone exileZone = currentGame.getExile().getExileZone(CardUtil.getExileZoneId(exileZoneName, currentGame)); + int actualCount = exileZone.getCards(currentGame).size(); + + Assert.assertEquals("(Exile \"" + exileZoneName + "\") Card counts are not equal.", count, actualCount); } /** @@ -1713,7 +1730,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * Ends a block of actions to be added after an rollback action */ public void rollbackAfterActionsEnd() throws IllegalStateException { - if (rollbackBlockActive = false || rollbackPlayer == null) { + if (!rollbackBlockActive || rollbackPlayer == null) { throw new IllegalStateException("There was no rollback action defined before or no rollback block started. You can use this command only after a rollback action."); } rollbackBlockActive = false; diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/deck/CommanderDeckValidationTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/deck/CommanderDeckValidationTest.java new file mode 100644 index 00000000000..6301b9eefc2 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/deck/CommanderDeckValidationTest.java @@ -0,0 +1,74 @@ +package org.mage.test.serverside.deck; + +import mage.deck.Commander; +import org.junit.Test; +import org.mage.test.serverside.base.MageTestBase; + +/** + * @author TheElk801 + */ +public class CommanderDeckValidationTest extends MageTestBase { + + private static final String piper = "The Prismatic Piper"; + + @Test + public void testGristCommander() { + // Grist, the Hunger Tide can be your commander as its first ability applies during deck construction. + DeckTester deckTester = new DeckTester(new Commander()); + deckTester.addMaindeck("Forest", 49); + deckTester.addMaindeck("Swamp", 50); + + deckTester.addSideboard("Grist, the Hunger Tide", 1); + + deckTester.validate("Grist should be legal as a commander"); + } + + @Test + public void testPrismaticPiperOneCopy() { + DeckTester deckTester = new DeckTester(new Commander()); + deckTester.addMaindeck("Forest", 99); + + deckTester.addSideboard(piper, 1); + + deckTester.validate(); + } + + @Test + public void testPrismaticPiper2() { + DeckTester deckTester = new DeckTester(new Commander()); + deckTester.addMaindeck("Forest", 49); + deckTester.addMaindeck("Island", 49); + + deckTester.addSideboard(piper, 1); + deckTester.addSideboard("Anara, Wolvid Familiar", 1); + + deckTester.validate(); + } + + @Test + public void testPrismaticPiper3() { + DeckTester deckTester = new DeckTester(new Commander()); + deckTester.addMaindeck("Forest", 48); + deckTester.addMaindeck("Island", 48); + deckTester.addMaindeck("Mountain", 2); + + deckTester.addSideboard(piper, 1); + deckTester.addSideboard("Thrasios, Triton Hero", 1); + + deckTester.validate(); + } + + @Test(expected = AssertionError.class) + public void testPrismaticPiper4() { + DeckTester deckTester = new DeckTester(new Commander()); + deckTester.addMaindeck("Forest", 48); + deckTester.addMaindeck("Island", 48); + deckTester.addMaindeck("Mountain", 1); + deckTester.addMaindeck("Plains", 1); + + deckTester.addSideboard(piper, 1); + deckTester.addSideboard("Thrasios, Triton Hero", 1); + + deckTester.validate(); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/deck/CompanionTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/deck/CompanionDeckValidationTest.java similarity index 98% rename from Mage.Tests/src/test/java/org/mage/test/serverside/deck/CompanionTest.java rename to Mage.Tests/src/test/java/org/mage/test/serverside/deck/CompanionDeckValidationTest.java index 44378bc50f0..aa398d88b13 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/deck/CompanionTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/deck/CompanionDeckValidationTest.java @@ -7,7 +7,7 @@ import org.mage.test.serverside.base.MageTestBase; /** * @author TheElk801 */ -public class CompanionTest extends MageTestBase { +public class CompanionDeckValidationTest extends MageTestBase { @Test public void testGyrudaTrue() { diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/deck/DeckValidatorTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/deck/DeckValidatorTest.java index c7aea177cd4..b461b6f9c18 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/deck/DeckValidatorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/deck/DeckValidatorTest.java @@ -68,18 +68,6 @@ public class DeckValidatorTest extends MageTestBase { deckTester.validate("only 4 of a card are allowed", false); } - @Test - public void testGristCommander() { - // Grist, the Hunger Tide can be your commander as its first ability applies during deck construction. - DeckTester deckTester = new DeckTester(new Commander()); - deckTester.addMaindeck("Forest", 49); - deckTester.addMaindeck("Swamp", 50); - - deckTester.addSideboard("Grist, the Hunger Tide", 1); - - deckTester.validate("Grist should be legal as a commander"); - } - private void assertCounterspellValid(ArrayList deckList) { final boolean needValid = true; // card valid after Modern Horizons 2 boolean valid = testDeckValid(new Modern(), deckList); diff --git a/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java b/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java index 21d63665766..69fcd7755b0 100644 --- a/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java @@ -249,26 +249,6 @@ public class BoosterGenerationTest extends MageTestBase { } } - @Test - public void testAmonkhetRemastered_MustHaveSpecialLand() { - // AKR replace all basic lands with special (1 per booster) - // https://mtg.gamepedia.com/Amonkhet_Remastered - - for (int i = 1; i <= 5; i++) { - List booster = AmonkhetRemastered.getInstance().createBooster(); - - // no basic lands in booster - assertFalse(str(booster), contains(booster, basics, null)); - - // special lands in land slot (can have multiple special lands per booster: one from land slot, one from common slot) - List boosterLands = booster.stream().filter(card -> !card.isBasic() && card.isLand(currentGame)).collect(Collectors.toList()); - Assert.assertTrue("Amonkhet Remastered's booster must contains minimum 1 special land", boosterLands.size() >= 1); - - // Regal Caracal is top-boxer card, not booster - assertFalse("Amonkhet Remastered's booster must not contains Regal Caracal", contains(booster, "Regal Caracal", null)); - } - } - @Test public void testZendikarRising_MDFC() { for (int i = 0; i < 20; i++) { @@ -373,7 +353,7 @@ public class BoosterGenerationTest extends MageTestBase { fail("Booster can't have more than three snow lands"); } - long mdfcCount = booster.stream().filter(card -> card instanceof ModalDoubleFacesCard).count(); + long mdfcCount = booster.stream().filter(ModalDoubleFacesCard.class::isInstance).count(); assertTrue("Booster can't have more than one MDFC", mdfcCount < 2); foundMDFC |= mdfcCount > 0; diff --git a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java index 58ed90d7d8d..6eb65426805 100644 --- a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java +++ b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java @@ -841,12 +841,12 @@ public class PlayerStub implements Player { } @Override - public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { + public boolean choose(Outcome outcome, Target target, Ability source, Game game) { return false; } @Override - public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map options) { + public boolean choose(Outcome outcome, Target target, Ability source, Game game, Map options) { return false; } diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index 58695447992..57d8f045331 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -2,9 +2,12 @@ package mage.verify; import com.google.common.base.CharMatcher; import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.common.SagaAbility; import mage.abilities.common.WerewolfBackTriggeredAbility; import mage.abilities.common.WerewolfFrontTriggeredAbility; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.FightTargetsEffect; import mage.abilities.effects.keyword.ScryEffect; import mage.abilities.keyword.*; @@ -56,7 +59,7 @@ public class VerifyCardDataTest { private static final Logger logger = Logger.getLogger(VerifyCardDataTest.class); - private static final String FULL_ABILITIES_CHECK_SET_CODE = "VOC"; // check all abilities and output cards with wrong abilities texts; + private static final String FULL_ABILITIES_CHECK_SET_CODE = "NCC"; // check all abilities and output cards with wrong abilities texts; private static final boolean AUTO_FIX_SAMPLE_DECKS = false; // debug only: auto-fix sample decks by test_checkSampleDecks test run private static final boolean ONLY_TEXT = false; // use when checking text locally, suppresses unnecessary checks and output messages @@ -77,8 +80,9 @@ public class VerifyCardDataTest { private static final String SKIP_LIST_WRONG_CARD_NUMBERS = "WRONG_CARD_NUMBERS"; private static final String SKIP_LIST_SAMPLE_DECKS = "SAMPLE_DECKS"; private static final List evergreenKeywords = Arrays.asList( - "flying", "lifelink", "menace", "trample", "haste", "first strike", "hexproof", - "deathtouch", "double strike", "indestructible", "reach", "flash", "defender", "vigilance" + "flying", "lifelink", "menace", "trample", "haste", "first strike", "hexproof", "fear", + "deathtouch", "double strike", "indestructible", "reach", "flash", "defender", "vigilance", + "plainswalk", "islandwalk", "swampwalk", "mountainwalk", "forestwalk" ); static { @@ -102,7 +106,6 @@ public class VerifyCardDataTest { skipListAddName(SKIP_LIST_TYPE, "UNH", "Old Fogey"); // uses summon word as a joke card skipListAddName(SKIP_LIST_TYPE, "UND", "Old Fogey"); skipListAddName(SKIP_LIST_TYPE, "UST", "capital offense"); // uses "instant" instead "Instant" as a joke card - skipListAddName(SKIP_LIST_TYPE, "NEO", "Oni-Cult Anvil"); // temporary // subtype skipListCreate(SKIP_LIST_SUBTYPE); @@ -234,7 +237,7 @@ public class VerifyCardDataTest { } private static boolean evergreenCheck(String s) { - return evergreenKeywords.contains(s) || s.startsWith("protection from") || s.startsWith("hexproof from"); + return evergreenKeywords.contains(s) || s.startsWith("protection from") || s.startsWith("hexproof from") || s.startsWith("ward "); } private static boolean eqSet(Collection a, Collection b) { @@ -1134,7 +1137,7 @@ public class VerifyCardDataTest { Token token = (Token) createNewObject(tokenClass); if (token == null) { errorsList.add("Error: token must have default constructor with zero params: " + tokenClass.getName()); - } else if (tokDataNamesIndex.getOrDefault(token.getName(), "").isEmpty()) { + } else if (tokDataNamesIndex.getOrDefault(token.getName().replace(" Token", ""), "").isEmpty()) { errorsList.add("Error: can't find data in card-pictures-tok.txt for token: " + tokenClass.getName() + " -> " + token.getName()); } } @@ -1482,6 +1485,13 @@ public class VerifyCardDataTest { newRule = newRule.replaceAll("(?i) \\(.+\\)", ""); newRule = newRule.replaceAll("(?i) \\(.+\\)", ""); + // fix specifically for mana abilities + if (newRule.startsWith("({T}: Add")) { + newRule = newRule + .replace("(", "") + .replace(")", ""); + } + // replace special text and symbols newRule = newRule .replace("{this}", cardName) @@ -1544,7 +1554,7 @@ public class VerifyCardDataTest { .replace("{this}", card.getName()) //.replace("", "") //.replace("", "") - .replace("—", "—");; + .replace("—", "—"); boolean found = false; for (String refRule : refRules) { @@ -1582,13 +1592,20 @@ public class VerifyCardDataTest { } }*/ private static final boolean compareText(String cardText, String refText, String name) { - if (cardText.equals(refText)) { - return true; - } - if (cardText.replace(name, name.split(", ")[0]).equals(refText)) { - return true; - } - return cardText.replace(name, name.split(" ")[0]).equals(refText); + return cardText.equals(refText) + || cardText.replace(name, name.split(", ")[0]).equals(refText) + || cardText.replace(name, name.split(" ")[0]).equals(refText); + } + + private static final boolean checkForEffect(Card card, Class effectClazz) { + return card.getAbilities() + .stream() + .map(Ability::getModes) + .map(LinkedHashMap::values) + .flatMap(Collection::stream) + .map(Mode::getEffects) + .flatMap(Collection::stream) + .anyMatch(effectClazz::isInstance); } private void checkWrongAbilitiesText(Card card, MtgJsonCard ref, int cardIndex) { @@ -1602,24 +1619,20 @@ public class VerifyCardDataTest { } String refText = ref.text; - // lands fix - if (refText.startsWith("(") && refText.endsWith(")")) { - refText = refText.substring(1, refText.length() - 1); - } // planeswalker fix [-7]: xxx - refText = refText.replaceAll("\\[([\\−\\+]?\\d*)\\]\\: ", "$1: "); + refText = refText.replaceAll("\\[([\\−\\+]?\\d*)\\]\\: ", "$1: ").replaceAll("\\[\\−X\\]\\: ", "-X: "); // evergreen keyword fix - for (String s : refText.split("[\\$\\\n]")) { + for (String s : refText.replaceAll(" \\(.+?\\)", "").split("[\\$\\\n]")) { if (Arrays - .stream(s.split(", ")) + .stream(s.split("[,;] ")) .map(String::toLowerCase) .allMatch(VerifyCardDataTest::evergreenCheck)) { String replacement = Arrays - .stream(s.split(", ")) + .stream(s.split("[,;] ")) .map(CardUtil::getTextWithFirstCharUpperCase) - .reduce("", (a, b) -> a + '\n' + b); - refText = refText.replace(s, replacement.substring(1)); + .collect(Collectors.joining("\n")); + refText = refText.replace(s, replacement); } } // modal spell fix @@ -1634,7 +1647,8 @@ public class VerifyCardDataTest { } // mana ability fix for (String s : refText.split("[\\$\\\n]")) { - if (!(s.startsWith("{T}: Add {") || s.startsWith("({T}: Add {")) || !s.contains("} or {")) { + if (!(s.startsWith("{T}: Add {") || s.startsWith("({T}: Add {")) + || !(s.contains("} or {") || s.contains("}, or {"))) { continue; } String newStr = ""; @@ -1643,6 +1657,9 @@ public class VerifyCardDataTest { newStr += "{T}: Add {" + c + "}.\n"; } } + if (!newStr.isEmpty()) { + newStr = newStr.substring(0, newStr.length() - 1); + } refText = refText.replace(s, newStr); } @@ -1655,9 +1672,11 @@ public class VerifyCardDataTest { String[] cardRules = card .getRules() .stream() - .reduce("", (a, b) -> a + '\n' + b) + .collect(Collectors.joining("\n")) .replace("
", "\n") .replace("
", "\n") + .replace("", "") + .replace("", "") .split("[\\$\\\n]"); for (int i = 0; i < cardRules.length; i++) { cardRules[i] = prepareRule(card.getName(), cardRules[i]); @@ -1689,6 +1708,7 @@ public class VerifyCardDataTest { for (int j = 0; j <= refRules.length - 1; j++) { String refRule = refRules[j]; if (!refRule.startsWith("+ ")) { + isFine = false; refRules[j] = "- " + refRules[j]; } } diff --git a/Mage/src/main/java/mage/MageIdentifier.java b/Mage/src/main/java/mage/MageIdentifier.java index e2c4fc1c1c5..1948a8c407e 100644 --- a/Mage/src/main/java/mage/MageIdentifier.java +++ b/Mage/src/main/java/mage/MageIdentifier.java @@ -14,6 +14,7 @@ public enum MageIdentifier { KessDissidentMageWatcher, LurrusOfTheDreamDenWatcher, MuldrothaTheGravetideWatcher, + ShareTheSpoilsWatcher, WishWatcher, GlimpseTheCosmosWatcher } diff --git a/Mage/src/main/java/mage/MageObject.java b/Mage/src/main/java/mage/MageObject.java index 970fc3627ce..1a668b8eab2 100644 --- a/Mage/src/main/java/mage/MageObject.java +++ b/Mage/src/main/java/mage/MageObject.java @@ -4,7 +4,6 @@ import mage.abilities.Abilities; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; -import mage.abilities.text.TextPart; import mage.cards.Card; import mage.cards.FrameStyle; import mage.constants.CardType; @@ -117,25 +116,6 @@ public interface MageObject extends MageItem, Serializable, Copyable void setStartingLoyalty(int startingLoyalty); - /** - * Dynamic cost modification for card (process only OWN abilities). - *

- * Usage example: if it need stack related info (like real targets) then must check two - * states (game.inCheckPlayableState): - *

- * 1. In playable state it must check all possible use cases (e.g. allow to - * reduce on any available target and modes) - *

- * 2. In real cast state it must check current use case (e.g. real selected - * targets and modes) - * - * @param ability - * @param game - */ - void adjustCosts(Ability ability, Game game); - - void adjustTargets(Ability ability, Game game); - // memory object copy (not mtg) @Override MageObject copy(); @@ -508,13 +488,5 @@ public interface MageObject extends MageItem, Serializable, Copyable */ void setIsAllCreatureTypes(Game game, boolean value); - List getTextParts(); - - TextPart addTextPart(TextPart textPart); - void removePTCDA(); - - default void changeSubType(SubType fromSubType, SubType toSubType) { - - } } diff --git a/Mage/src/main/java/mage/MageObjectImpl.java b/Mage/src/main/java/mage/MageObjectImpl.java index ffbcdcd9e97..8b3798f3955 100644 --- a/Mage/src/main/java/mage/MageObjectImpl.java +++ b/Mage/src/main/java/mage/MageObjectImpl.java @@ -3,16 +3,12 @@ package mage; import mage.abilities.Abilities; import mage.abilities.AbilitiesImpl; import mage.abilities.Ability; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; -import mage.abilities.keyword.ChangelingAbility; import mage.abilities.mana.ActivatedManaAbilityImpl; -import mage.abilities.text.TextPart; -import mage.abilities.text.TextPartSubType; import mage.cards.FrameStyle; import mage.cards.mock.MockCard; import mage.constants.*; @@ -43,9 +39,9 @@ public abstract class MageObjectImpl implements MageObject { protected String text; protected MageInt power; protected MageInt toughness; + protected int startingLoyalty = -1; // -2 means X, -1 means none, 0 and up is normal protected boolean copy; protected MageObject copyFrom; // copied card INFO (used to call original adjusters) - protected List textParts; public MageObjectImpl() { this(UUID.randomUUID()); @@ -60,7 +56,6 @@ public abstract class MageObjectImpl implements MageObject { frameStyle = FrameStyle.M15_NORMAL; manaCost = new ManaCostsImpl<>(); abilities = new AbilitiesImpl<>(); - textParts = new ArrayList<>(); } public MageObjectImpl(final MageObjectImpl object) { @@ -73,14 +68,13 @@ public abstract class MageObjectImpl implements MageObject { frameStyle = object.frameStyle; power = object.power.copy(); toughness = object.toughness.copy(); + startingLoyalty = object.startingLoyalty; abilities = object.abilities.copy(); this.cardType.addAll(object.cardType); this.subtype.copyFrom(object.subtype); supertype.addAll(object.supertype); this.copy = object.copy; this.copyFrom = (object.copyFrom != null ? object.copyFrom.copy() : null); - textParts = new ArrayList<>(); - textParts.addAll(object.textParts); } @Override @@ -174,21 +168,12 @@ public abstract class MageObjectImpl implements MageObject { @Override public int getStartingLoyalty() { - for (Ability ab : getAbilities()) { - if (ab instanceof PlaneswalkerEntersWithLoyaltyCountersAbility) { - return ((PlaneswalkerEntersWithLoyaltyCountersAbility) ab).getStartingLoyalty(); - } - } - return 0; + return startingLoyalty; } @Override public void setStartingLoyalty(int startingLoyalty) { - for (Ability ab : getAbilities()) { - if (ab instanceof PlaneswalkerEntersWithLoyaltyCountersAbility) { - ((PlaneswalkerEntersWithLoyaltyCountersAbility) ab).setStartingLoyalty(startingLoyalty); - } - } + this.startingLoyalty = startingLoyalty; } @Override @@ -249,16 +234,6 @@ public abstract class MageObjectImpl implements MageObject { return 0; } - @Override - public final void adjustCosts(Ability ability, Game game) { - ability.adjustCosts(game); - } - - @Override - public final void adjustTargets(Ability ability, Game game) { - ability.adjustTargets(game); - } - @Override public boolean hasSubtype(SubType value, Game game) { if (value == null) { @@ -316,26 +291,6 @@ public abstract class MageObjectImpl implements MageObject { this.getSubtype(game).setIsAllCreatureTypes(value && (this.isTribal(game) || this.isCreature(game))); } - @Override - public List getTextParts() { - return textParts; - } - - @Override - public TextPart addTextPart(TextPart textPart) { - textParts.add(textPart); - return textPart; - } - - @Override - public void changeSubType(SubType fromSubType, SubType toSubType) { - for (TextPart textPart : textParts) { - if (textPart instanceof TextPartSubType && textPart.getCurrentValue().equals(fromSubType)) { - textPart.replaceWith(toSubType); - } - } - } - /** * Remove power/toughness character defining abilities */ diff --git a/Mage/src/main/java/mage/MageObjectReference.java b/Mage/src/main/java/mage/MageObjectReference.java index f8ca0fb9271..c12604c2bde 100644 --- a/Mage/src/main/java/mage/MageObjectReference.java +++ b/Mage/src/main/java/mage/MageObjectReference.java @@ -138,13 +138,25 @@ public class MageObjectReference implements Comparable, Ser } public boolean refersTo(MageObject mageObject, Game game) { - if (mageObject != null) { - if (mageObject instanceof Spell) { - return Objects.equals(((Spell) mageObject).getSourceId(), this.sourceId) && this.zoneChangeCounter == mageObject.getZoneChangeCounter(game); - } - return mageObject.getId().equals(sourceId) && this.zoneChangeCounter == mageObject.getZoneChangeCounter(game); + return refersTo(mageObject, game, 0); + } + + public boolean refersTo(MageObject mageObject, Game game, int offset) { + if (mageObject == null) { + return false; } - return false; + if (mageObject instanceof Spell) { + return Objects.equals(((Spell) mageObject).getSourceId(), this.sourceId) && this.zoneChangeCounter + offset == mageObject.getZoneChangeCounter(game); + } + return mageObject.getId().equals(sourceId) && this.zoneChangeCounter + offset == mageObject.getZoneChangeCounter(game); + } + + public boolean refersTo(Ability source, Game game) { + if (source == null || !source.getSourceId().equals(sourceId)) { + return false; + } + return zoneChangeCounter * source.getSourceObjectZoneChangeCounter() == 0 + || zoneChangeCounter == source.getSourceObjectZoneChangeCounter(); } public Permanent getPermanent(Game game) { diff --git a/Mage/src/main/java/mage/ManaSymbol.java b/Mage/src/main/java/mage/ManaSymbol.java index 35b692de7b7..ca46df5cb13 100644 --- a/Mage/src/main/java/mage/ManaSymbol.java +++ b/Mage/src/main/java/mage/ManaSymbol.java @@ -83,6 +83,16 @@ public enum ManaSymbol { PHYREXIAN_R("{R/P}", R, Type.PHYREXIAN, Type.COLORED, Type.MONOCOLORED), PHYREXIAN_B("{B/P}", B, Type.PHYREXIAN, Type.COLORED, Type.MONOCOLORED), PHYREXIAN_U("{U/P}", U, Type.PHYREXIAN, Type.COLORED, Type.MONOCOLORED), + PHYREXIAN_HYBRID_WU("{W/U/P}", W, U, Type.PHYREXIAN, Type.HYBRID, Type.COLORED), + PHYREXIAN_HYBRID_WB("{W/B/P}", W, B, Type.PHYREXIAN, Type.HYBRID, Type.COLORED), + PHYREXIAN_HYBRID_UB("{U/B/P}", U, B, Type.PHYREXIAN, Type.HYBRID, Type.COLORED), + PHYREXIAN_HYBRID_UR("{U/R/P}", U, R, Type.PHYREXIAN, Type.HYBRID, Type.COLORED), + PHYREXIAN_HYBRID_BR("{B/R/P}", B, R, Type.PHYREXIAN, Type.HYBRID, Type.COLORED), + PHYREXIAN_HYBRID_BG("{B/G/P}", B, G, Type.PHYREXIAN, Type.HYBRID, Type.COLORED), + PHYREXIAN_HYBRID_RG("{R/G/P}", R, G, Type.PHYREXIAN, Type.HYBRID, Type.COLORED), + PHYREXIAN_HYBRID_RW("{R/W/P}", R, W, Type.PHYREXIAN, Type.HYBRID, Type.COLORED), + PHYREXIAN_HYBRID_GW("{G/W/P}", G, W, Type.PHYREXIAN, Type.HYBRID, Type.COLORED), + PHYREXIAN_HYBRID_GU("{G/U/P}", G, U, Type.PHYREXIAN, Type.HYBRID, Type.COLORED), SNOW("{S}", Type.SNOW); private enum Type { diff --git a/Mage/src/main/java/mage/ObjectColor.java b/Mage/src/main/java/mage/ObjectColor.java index 8f41df79ad5..4d9292feb0d 100644 --- a/Mage/src/main/java/mage/ObjectColor.java +++ b/Mage/src/main/java/mage/ObjectColor.java @@ -1,15 +1,15 @@ package mage; +import mage.constants.ColoredManaSymbol; +import mage.util.Copyable; + import java.io.Serializable; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; -import mage.constants.ColoredManaSymbol; -import mage.util.Copyable; - public class ObjectColor implements Serializable, Copyable, Comparable { public static final ObjectColor WHITE = new ObjectColor("W"); @@ -182,13 +182,13 @@ public class ObjectColor implements Serializable, Copyable, Compara } public void setColor(ObjectColor color) { - this.setBlack(color.isBlack()); - this.setBlue(color.isBlue()); - this.setGreen(color.isGreen()); - this.setRed(color.isRed()); - this.setWhite(color.isWhite()); + this.setBlack(color != null && color.isBlack()); + this.setBlue(color != null && color.isBlue()); + this.setGreen(color != null && color.isGreen()); + this.setRed(color != null && color.isRed()); + this.setWhite(color != null && color.isWhite()); - this.setGold(color.isGold()); + this.setGold(color != null && color.isGold()); } public void addColor(ObjectColor color) { diff --git a/Mage/src/main/java/mage/abilities/Ability.java b/Mage/src/main/java/mage/abilities/Ability.java index 725c671925a..42b6ab715bc 100644 --- a/Mage/src/main/java/mage/abilities/Ability.java +++ b/Mage/src/main/java/mage/abilities/Ability.java @@ -541,7 +541,7 @@ public interface Ability extends Controllable, Serializable { boolean canFizzle(); - void setTargetAdjuster(TargetAdjuster targetAdjuster); + Ability setTargetAdjuster(TargetAdjuster targetAdjuster); TargetAdjuster getTargetAdjuster(); diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index 2fe0359df17..7d987a81323 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -4,7 +4,10 @@ import mage.MageIdentifier; import mage.MageObject; import mage.abilities.costs.*; import mage.abilities.costs.common.PayLifeCost; -import mage.abilities.costs.mana.*; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.costs.mana.ManaCosts; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; @@ -357,8 +360,8 @@ public abstract class AbilityImpl implements Ability { // and/or zones become the target of a spell trigger at this point; they'll wait to be put on // the stack until the spell has finished being cast.) - if (sourceObject != null && this.getAbilityType() != AbilityType.TRIGGERED) { // triggered abilities check this already in playerImpl.triggerAbility - sourceObject.adjustTargets(this, game); + if (this.getAbilityType() != AbilityType.TRIGGERED) { // triggered abilities check this already in playerImpl.triggerAbility + adjustTargets(game); } if (!getTargets().isEmpty()) { @@ -384,8 +387,8 @@ public abstract class AbilityImpl implements Ability { boolean needCostModification = !CardUtil.isFusedPartAbility(this, game); //20101001 - 601.2e - if (needCostModification && sourceObject != null) { - sourceObject.adjustCosts(this, game); // still needed for CostAdjuster objects (to handle some types of dynamic costs) + if (needCostModification) { + adjustCosts(game); // still needed for CostAdjuster objects (to handle some types of dynamic costs) game.getContinuousEffects().costModification(this, game); } @@ -536,14 +539,15 @@ public abstract class AbilityImpl implements Ability { while (costIterator.hasNext()) { ManaCost cost = costIterator.next(); - if (cost instanceof PhyrexianManaCost) { - PhyrexianManaCost phyrexianManaCost = (PhyrexianManaCost) cost; - PayLifeCost payLifeCost = new PayLifeCost(2); - if (payLifeCost.canPay(this, this, controller.getId(), game) - && controller.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + phyrexianManaCost.getBaseText() + '?', this, game)) { - costIterator.remove(); - costs.add(payLifeCost); - } + if (!cost.isPhyrexian()) { + continue; + } + PayLifeCost payLifeCost = new PayLifeCost(2); + if (payLifeCost.canPay(this, this, controller.getId(), game) + && controller.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + cost.getText().replace("/P", "") + '?', this, game)) { + costIterator.remove(); + costs.add(payLifeCost); + manaCostsToPay.incrPhyrexianPaid(); } } } @@ -962,7 +966,7 @@ public abstract class AbilityImpl implements Ability { if (target.getTargetController() != null) { abilityControllerId = target.getTargetController(); } - if (!target.canChoose(ability.getSourceId(), abilityControllerId, game)) { + if (!target.canChoose(abilityControllerId, ability, game)) { validTargets = false; break; } @@ -1325,8 +1329,9 @@ public abstract class AbilityImpl implements Ability { } @Override - public void setTargetAdjuster(TargetAdjuster targetAdjuster) { + public AbilityImpl setTargetAdjuster(TargetAdjuster targetAdjuster) { this.targetAdjuster = targetAdjuster; + return this; } @Override diff --git a/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java b/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java index 2149d7fe87d..62cef1c9976 100644 --- a/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java @@ -6,10 +6,8 @@ import mage.abilities.condition.Condition; import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; import mage.abilities.costs.mana.ManaCosts; -import mage.abilities.costs.mana.PhyrexianManaCost; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; -import mage.abilities.keyword.FlashAbility; import mage.abilities.mana.ManaOptions; import mage.cards.Card; import mage.constants.*; @@ -61,19 +59,13 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa public ActivatedAbilityImpl(Zone zone, Effect effect) { super(AbilityType.ACTIVATED, zone); - if (effect != null) { - this.addEffect(effect); - } + this.addEffect(effect); } public ActivatedAbilityImpl(Zone zone, Effect effect, ManaCosts cost) { super(AbilityType.ACTIVATED, zone); - if (effect != null) { - this.addEffect(effect); - } - if (cost != null) { - this.addManaCost(cost); - } + this.addEffect(effect); + this.addManaCost(cost); } public ActivatedAbilityImpl(Zone zone, Effects effects, ManaCosts cost) { @@ -83,30 +75,18 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa this.addEffect(effect); } } - if (cost != null) { - this.addManaCost(cost); - } + this.addManaCost(cost); } public ActivatedAbilityImpl(Zone zone, Effect effect, Cost cost) { super(AbilityType.ACTIVATED, zone); - if (effect != null) { - this.addEffect(effect); - } - if (cost != null) { - if (cost instanceof PhyrexianManaCost) { - this.addManaCost((PhyrexianManaCost) cost); - } else { - this.addCost(cost); - } - } + this.addEffect(effect); + this.addCost(cost); } public ActivatedAbilityImpl(Zone zone, Effect effect, Costs costs) { super(AbilityType.ACTIVATED, zone); - if (effect != null) { - this.addEffect(effect); - } + this.addEffect(effect); if (costs != null) { for (Cost cost : costs) { this.addCost(cost); @@ -121,15 +101,13 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa this.addEffect(effect); } } - if (cost != null) { - this.addCost(cost); - } + this.addCost(cost); } public ActivatedAbilityImpl(Zone zone, Effects effects, Costs costs) { super(AbilityType.ACTIVATED, zone); - for (Effect effect : effects) { - if (effect != null) { + if (effects != null) { + for (Effect effect : effects) { this.addEffect(effect); } } @@ -205,11 +183,6 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa game); asInstant = approvingObject != null; asInstant |= (timing == TimingRule.INSTANT); - Card card = game.getCard(getSourceId()); - if (card != null) { - asInstant |= card.isInstant(game); - asInstant |= card.hasAbility(FlashAbility.getInstance(), game); - } if (!asInstant && !game.canPlaySorcery(playerId)) { return ActivationStatus.getFalse(); } diff --git a/Mage/src/main/java/mage/abilities/Mode.java b/Mage/src/main/java/mage/abilities/Mode.java index fd821ec118e..0016423483b 100644 --- a/Mage/src/main/java/mage/abilities/Mode.java +++ b/Mage/src/main/java/mage/abilities/Mode.java @@ -18,10 +18,6 @@ public class Mode implements Serializable { protected final Effects effects; protected String flavorWord; - public Mode() { - this((Effect) null); - } - public Mode(Effect effect) { this.id = UUID.randomUUID(); this.targets = new Targets(); @@ -54,23 +50,25 @@ public class Mode implements Serializable { return targets; } - public void addTarget(Target target) { - this.addTarget(target, false); + public Mode addTarget(Target target) { + return this.addTarget(target, false); } - public void addTarget(Target target, Boolean addChooseHintFromEffect) { + public Mode addTarget(Target target, Boolean addChooseHintFromEffect) { targets.add(target); if (addChooseHintFromEffect) { target.withChooseHint(this.getEffects().getText(this)); } + return this; } public Effects getEffects() { return effects; } - public void addEffect(Effect effect) { + public Mode addEffect(Effect effect) { effects.add(effect); + return this; } public String getFlavorWord() { diff --git a/Mage/src/main/java/mage/abilities/Modes.java b/Mage/src/main/java/mage/abilities/Modes.java index b64179d50e9..3be3e125bdb 100644 --- a/Mage/src/main/java/mage/abilities/Modes.java +++ b/Mage/src/main/java/mage/abilities/Modes.java @@ -2,6 +2,7 @@ package mage.abilities; import mage.abilities.condition.Condition; import mage.abilities.costs.OptionalAdditionalModeSourceCosts; +import mage.abilities.effects.Effect; import mage.cards.Card; import mage.constants.Outcome; import mage.constants.TargetController; @@ -42,7 +43,7 @@ public class Modes extends LinkedHashMap { private boolean mayChooseNone = false; public Modes() { - this.currentMode = new Mode(); + this.currentMode = new Mode((Effect) null); this.put(currentMode.getId(), currentMode); this.minModes = 1; this.maxModes = 1; @@ -209,7 +210,7 @@ public class Modes extends LinkedHashMap { // use case: make all modes chooseable if (moreCondition != null && moreCondition.apply(game, source)) { - realMaxModes = Integer.MAX_VALUE; + realMaxModes = this.size(); } // use case: limit max modes by opponents (wtf?!) @@ -218,7 +219,7 @@ public class Modes extends LinkedHashMap { realMaxModes = 0; for (UUID targetPlayerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player targetPlayer = game.getPlayer(targetPlayerId); - if (((FilterPlayer) this.maxModesFilter).match(targetPlayer, source.getSourceId(), source.getControllerId(), game)) { + if (((FilterPlayer) this.maxModesFilter).match(targetPlayer, source.getControllerId(), source, game)) { realMaxModes++; } } @@ -291,7 +292,7 @@ public class Modes extends LinkedHashMap { } for (Mode mode : this.values()) { if ((!isEachModeOnlyOnce() || onceSelectedModes == null || !onceSelectedModes.contains(mode.getId())) - && mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) { + && mode.getTargets().canChoose(source.getControllerId(), source, game)) { this.addSelectedMode(mode.getId()); } } @@ -305,19 +306,18 @@ public class Modes extends LinkedHashMap { // Some spells and abilities specify that a player other than their controller chooses a mode for it. // In that case, the other player does so when the spell or ability's controller normally would do so. // If there is more than one other player who could make such a choice, the spell or ability's controller decides which of those players will make the choice. - UUID playerId = null; + UUID playerId; if (modeChooser == TargetController.OPPONENT) { TargetOpponent targetOpponent = new TargetOpponent(); - if (targetOpponent.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), game)) { - playerId = targetOpponent.getFirstTarget(); - } + targetOpponent.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), source, game); + playerId = targetOpponent.getFirstTarget(); } else { playerId = source.getControllerId(); } - if (playerId == null) { + Player player = game.getPlayer(playerId); + if (player == null) { return false; } - Player player = game.getPlayer(playerId); // player chooses modes manually this.currentMode = null; @@ -340,7 +340,13 @@ public class Modes extends LinkedHashMap { if (isEachModeOnlyOnce()) { setAlreadySelectedModes(source, game); } - return true; + if (modeChooser == TargetController.OPPONENT) { + selectedModes + .stream() + .map(this::get) + .map(Mode::getEffects) + .forEach(effects -> effects.setValue("choosingPlayer", playerId)); + } } else { // only one mode available if (currentMode == null) { @@ -349,8 +355,8 @@ public class Modes extends LinkedHashMap { this.addSelectedMode(mode.getId()); this.setActiveMode(mode); } - return true; } + return true; } /** @@ -467,23 +473,30 @@ public class Modes extends LinkedHashMap { if (mayChooseNone) { sb.append("you may "); } - if (this.chooseText != null) { - sb.append(chooseText); - } else if (this.getMinModes() == 0 && this.getMaxModes(null, null) == 1) { - sb.append("choose up to one"); - } else if (this.getMinModes() == 0 && this.getMaxModes(null, null) > 2) { - sb.append("choose any number"); - } else if (this.getMinModes() == 1 && this.getMaxModes(null, null) == 2) { - sb.append("choose one or both"); - } else if (this.getMinModes() == 1 && this.getMaxModes(null, null) > 2) { - sb.append("choose one or more"); - } else if (this.getMinModes() == this.getMaxModes(null, null)) { - sb.append("choose " + CardUtil.numberToText(this.getMinModes())); + if (this.chooseText == null) { + if (modeChooser == TargetController.OPPONENT) { + sb.append("an opponent chooses "); + } else { + sb.append("choose "); + } + if (this.getMinModes() == 0 && this.getMaxModes(null, null) == 1) { + sb.append("up to one"); + } else if (this.getMinModes() == 0 && this.getMaxModes(null, null) > 2) { + sb.append("any number"); + } else if (this.getMinModes() == 1 && this.getMaxModes(null, null) == 2) { + sb.append("one or both"); + } else if (this.getMinModes() == 1 && this.getMaxModes(null, null) > 2) { + sb.append("one or more"); + } else if (this.getMinModes() == this.getMaxModes(null, null)) { + sb.append(CardUtil.numberToText(this.getMinModes())); + } else { + throw new UnsupportedOperationException("no text available for this selection of min and max modes"); + } } else { - throw new UnsupportedOperationException("no text available for this selection of min and max modes"); + sb.append(chooseText); } - if (isEachModeOnlyOnce()) { + if (isEachModeOnlyOnce() && this.getMaxModesFilter() == null) { sb.append(" that hasn't been chosen"); } if (isResetEachTurn()) { diff --git a/Mage/src/main/java/mage/abilities/SpellAbility.java b/Mage/src/main/java/mage/abilities/SpellAbility.java index 53db5121fc1..96c18cc532b 100644 --- a/Mage/src/main/java/mage/abilities/SpellAbility.java +++ b/Mage/src/main/java/mage/abilities/SpellAbility.java @@ -7,6 +7,7 @@ import mage.abilities.costs.VariableCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.keyword.FlashAbility; +import mage.cards.AdventureCardSpell; import mage.cards.Card; import mage.cards.SplitCard; import mage.constants.*; @@ -69,7 +70,7 @@ public class SpellAbility extends ActivatedAbilityImpl { // forced to cast (can be part id or main id) Set idsToCheck = new HashSet<>(); idsToCheck.add(object.getId()); - if (object instanceof Card) { + if (object instanceof Card && !(object instanceof AdventureCardSpell)) { idsToCheck.add(((Card) object).getMainCard().getId()); } for (UUID idToCheck : idsToCheck) { diff --git a/Mage/src/main/java/mage/abilities/TriggeredAbilities.java b/Mage/src/main/java/mage/abilities/TriggeredAbilities.java index 644313f542d..aa6f89bb1d5 100644 --- a/Mage/src/main/java/mage/abilities/TriggeredAbilities.java +++ b/Mage/src/main/java/mage/abilities/TriggeredAbilities.java @@ -91,8 +91,11 @@ public class TriggeredAbilities extends ConcurrentHashMap ability is not valid } diff --git a/Mage/src/main/java/mage/abilities/abilityword/GrandeurAbility.java b/Mage/src/main/java/mage/abilities/abilityword/GrandeurAbility.java index 921f53e4a66..9fcb8b55b48 100644 --- a/Mage/src/main/java/mage/abilities/abilityword/GrandeurAbility.java +++ b/Mage/src/main/java/mage/abilities/abilityword/GrandeurAbility.java @@ -8,7 +8,7 @@ import mage.abilities.effects.Effect; import mage.constants.AbilityWord; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.NamePredicate; import mage.target.common.TargetCardInHand; @@ -26,7 +26,7 @@ public class GrandeurAbility extends ActivatedAbilityImpl { FilterCard filter = new FilterCard("another card named " + cardName); filter.add(new NamePredicate(cardName)); - filter.add(new AnotherCardPredicate()); + filter.add(AnotherPredicate.instance); this.addCost(new DiscardTargetCost(new TargetCardInHand(filter))); setAbilityWord(AbilityWord.GRANDEUR); } diff --git a/Mage/src/main/java/mage/abilities/common/ActivateOnlyByOpponentActivatedAbility.java b/Mage/src/main/java/mage/abilities/common/ActivateOnlyByOpponentActivatedAbility.java index 62c78b67913..99cb57d335d 100644 --- a/Mage/src/main/java/mage/abilities/common/ActivateOnlyByOpponentActivatedAbility.java +++ b/Mage/src/main/java/mage/abilities/common/ActivateOnlyByOpponentActivatedAbility.java @@ -29,6 +29,6 @@ public class ActivateOnlyByOpponentActivatedAbility extends ActivatedAbilityImpl @Override public String getRule() { - return super.getRule() + " Only any opponent may activate this ability."; + return super.getRule() + " Only your opponents may activate this ability."; } } diff --git a/Mage/src/main/java/mage/abilities/common/AllianceAbility.java b/Mage/src/main/java/mage/abilities/common/AllianceAbility.java new file mode 100644 index 00000000000..c17203a2a79 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/AllianceAbility.java @@ -0,0 +1,26 @@ +package mage.abilities.common; + +import mage.abilities.effects.Effect; +import mage.constants.AbilityWord; +import mage.constants.Zone; +import mage.filter.StaticFilters; + +/** + * @author TheElk801 + */ +public class AllianceAbility extends EntersBattlefieldControlledTriggeredAbility { + + public AllianceAbility(Effect effect) { + super(Zone.BATTLEFIELD, effect, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, false); + this.setAbilityWord(AbilityWord.ALLIANCE); + } + + private AllianceAbility(final AllianceAbility ability) { + super(ability); + } + + @Override + public AllianceAbility copy() { + return new AllianceAbility(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/common/AttacksAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/AttacksAllTriggeredAbility.java index 47686abe0a6..6f6c5ee1b07 100644 --- a/Mage/src/main/java/mage/abilities/common/AttacksAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/AttacksAllTriggeredAbility.java @@ -1,6 +1,5 @@ package mage.abilities.common; -import java.util.UUID; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.constants.SetTargetPointer; @@ -11,9 +10,11 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author LevelX2 */ public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl { @@ -59,7 +60,7 @@ public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanent(event.getSourceId()); - if (filter.match(permanent, getSourceId(), getControllerId(), game)) { + if (filter.match(permanent, getControllerId(), this, game)) { if (attacksYouOrYourPlaneswalker) { boolean check = false; if (event.getTargetId().equals(getControllerId())) { @@ -74,18 +75,15 @@ public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl { return false; } } + getEffects().setValue("attacker", permanent); switch (setTargetPointer) { case PERMANENT: - for (Effect effect : getEffects()) { - effect.setTargetPointer(new FixedTarget(permanent, game)); - } + getEffects().setTargetPointer(new FixedTarget(permanent, game)); break; case PLAYER: UUID playerId = controller ? permanent.getControllerId() : game.getCombat().getDefendingPlayerId(permanent.getId(), game); if (playerId != null) { - for (Effect effect : getEffects()) { - effect.setTargetPointer(new FixedTarget(playerId)); - } + getEffects().setTargetPointer(new FixedTarget(playerId)); } break; } @@ -101,10 +99,8 @@ public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl { @Override public String getTriggerPhrase() { - return "Whenever " + (filter.getMessage().startsWith("an") ? "" : "a ") - + filter.getMessage() + " attacks" - + (attacksYouOrYourPlaneswalker ? " you or a planeswalker you control" : "") - + ", " ; + return "Whenever " + CardUtil.addArticle(filter.getMessage()) + " attacks" + + (attacksYouOrYourPlaneswalker ? " you or a planeswalker you control" : "") + ", "; } } diff --git a/Mage/src/main/java/mage/abilities/common/AttacksAloneControlledTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/AttacksAloneControlledTriggeredAbility.java index 93b64fbc433..6f48c8cccfb 100644 --- a/Mage/src/main/java/mage/abilities/common/AttacksAloneControlledTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/AttacksAloneControlledTriggeredAbility.java @@ -58,7 +58,7 @@ public class AttacksAloneControlledTriggeredAbility extends TriggeredAbilityImpl return false; } Permanent permanent = game.getPermanent(game.getCombat().getAttackers().get(0)); - if (permanent == null || !filter.match(permanent, getSourceId(), getControllerId(), game)) { + if (permanent == null || !filter.match(permanent, getControllerId(), this, game)) { return false; } if (setTargetPointer) { diff --git a/Mage/src/main/java/mage/abilities/common/AttacksCreatureYouControlTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/AttacksCreatureYouControlTriggeredAbility.java index 2545d601057..2f2171a2d42 100644 --- a/Mage/src/main/java/mage/abilities/common/AttacksCreatureYouControlTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/AttacksCreatureYouControlTriggeredAbility.java @@ -61,7 +61,7 @@ public class AttacksCreatureYouControlTriggeredAbility extends TriggeredAbilityI @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent sourcePermanent = game.getPermanent(event.getSourceId()); - if (filter.match(sourcePermanent, sourceId, controllerId, game)) { + if (filter.match(sourcePermanent, controllerId, this, game)) { if (setTargetPointer) { this.getEffects().setTargetPointer(new FixedTarget(event.getSourceId(), game)); } diff --git a/Mage/src/main/java/mage/abilities/common/AttacksWithCreaturesTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/AttacksWithCreaturesTriggeredAbility.java index 2ea2a0b5138..1578bf435f3 100644 --- a/Mage/src/main/java/mage/abilities/common/AttacksWithCreaturesTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/AttacksWithCreaturesTriggeredAbility.java @@ -57,7 +57,7 @@ public class AttacksWithCreaturesTriggeredAbility extends TriggeredAbilityImpl { .getAttackers() .stream() .map(game::getPermanent) - .filter(permanent -> filter.match(permanent, sourceId, controllerId, game)) + .filter(permanent -> filter.match(permanent, controllerId, this, game)) .mapToInt(x -> 1) .sum(); if (attackers < minAttackers) { diff --git a/Mage/src/main/java/mage/abilities/common/BecomesBlockedAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BecomesBlockedAllTriggeredAbility.java index fc6228268ec..ce84e8e227d 100644 --- a/Mage/src/main/java/mage/abilities/common/BecomesBlockedAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/BecomesBlockedAllTriggeredAbility.java @@ -42,7 +42,7 @@ public class BecomesBlockedAllTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanent(event.getTargetId()); - if (filter.match(permanent, getSourceId(), getControllerId(), game)) { + if (filter.match(permanent, getControllerId(), this, game)) { if (setTargetPointer) { this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); } diff --git a/Mage/src/main/java/mage/abilities/common/BecomesBlockedByCreatureTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BecomesBlockedByCreatureTriggeredAbility.java index 80bdb8296db..0fb76640ff3 100644 --- a/Mage/src/main/java/mage/abilities/common/BecomesBlockedByCreatureTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/BecomesBlockedByCreatureTriggeredAbility.java @@ -7,8 +7,8 @@ import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; /** * @author North @@ -41,21 +41,16 @@ public class BecomesBlockedByCreatureTriggeredAbility extends TriggeredAbilityIm if (!event.getTargetId().equals(this.getSourceId())) { return false; } - Permanent blocker = game.getPermanent(event.getSourceId()); - if (!filter.match(blocker, game)) { + if (!filter.match(game.getPermanent(event.getSourceId()), getControllerId(), this, game)) { return false; } - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getSourceId(), game)); - } + getEffects().setTargetPointer(new FixedTarget(event.getSourceId(), game)); return true; } @Override public String getTriggerPhrase() { - return "Whenever {this} becomes blocked by " - + (filter.getMessage().startsWith("an ") ? "" : "a ") - + filter.getMessage() + ", " ; + return "Whenever {this} becomes blocked by " + CardUtil.addArticle(filter.getMessage()) + ", "; } @Override diff --git a/Mage/src/main/java/mage/abilities/common/BecomesTappedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BecomesTappedTriggeredAbility.java index 0d1ead46bd0..856121d89b8 100644 --- a/Mage/src/main/java/mage/abilities/common/BecomesTappedTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/BecomesTappedTriggeredAbility.java @@ -1,20 +1,17 @@ -/* - * To change this template, choose Tools | Templates - * and open the template in the editor. - */ package mage.abilities.common; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.constants.Zone; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; /** - * * @author jeffwadsworth */ public class BecomesTappedTriggeredAbility extends TriggeredAbilityImpl { @@ -23,7 +20,7 @@ public class BecomesTappedTriggeredAbility extends TriggeredAbilityImpl { protected boolean setTargetPointer; public BecomesTappedTriggeredAbility(Effect effect, boolean optional) { - this(effect, optional, new FilterPermanent("a permanent")); + this(effect, optional, StaticFilters.FILTER_PERMANENT_A); } public BecomesTappedTriggeredAbility(Effect effect, boolean optional, FilterPermanent filter) { @@ -31,7 +28,11 @@ public class BecomesTappedTriggeredAbility extends TriggeredAbilityImpl { } public BecomesTappedTriggeredAbility(Effect effect, boolean optional, FilterPermanent filter, boolean setTargetPointer) { - super(Zone.BATTLEFIELD, effect, optional); + this(Zone.BATTLEFIELD, effect, optional, filter, setTargetPointer); + } + + public BecomesTappedTriggeredAbility(Zone zone, Effect effect, boolean optional, FilterPermanent filter, boolean setTargetPointer) { + super(zone, effect, optional); this.filter = filter; this.setTargetPointer = setTargetPointer; } @@ -55,17 +56,17 @@ public class BecomesTappedTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanent(event.getTargetId()); - if (filter.match(permanent, getSourceId(), getControllerId(), game)) { - if (setTargetPointer) { - this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); - } - return true; + if (!filter.match(permanent, getControllerId(), this, game)) { + return false; } - return false; + if (setTargetPointer) { + this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); + } + return true; } @Override public String getTriggerPhrase() { - return "Whenever " + filter.getMessage() + " becomes tapped, " ; + return "Whenever " + CardUtil.addArticle(filter.getMessage()) + " becomes tapped, "; } } diff --git a/Mage/src/main/java/mage/abilities/common/BecomesTargetAttachedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BecomesTargetAttachedTriggeredAbility.java index fef952f3a74..79d1fb27952 100644 --- a/Mage/src/main/java/mage/abilities/common/BecomesTargetAttachedTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/BecomesTargetAttachedTriggeredAbility.java @@ -6,7 +6,6 @@ import mage.constants.Zone; import mage.filter.FilterStackObject; import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.events.GameEvent.EventType; import mage.game.events.GameEvent; import mage.game.stack.StackObject; import mage.game.permanent.Permanent; @@ -56,7 +55,7 @@ public class BecomesTargetAttachedTriggeredAbility extends TriggeredAbilityImpl StackObject sourceObject = game.getStack().getStackObject(event.getSourceId()); if (enchantment != null && enchantment.getAttachedTo() != null) { if (event.getTargetId().equals(enchantment.getAttachedTo()) - && filter.match(sourceObject, getSourceId(), getControllerId(), game)) { + && filter.match(sourceObject, getControllerId(), this, game)) { return true; } } diff --git a/Mage/src/main/java/mage/abilities/common/BecomesTargetTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BecomesTargetTriggeredAbility.java index e09b74d081e..da8d10afcd0 100644 --- a/Mage/src/main/java/mage/abilities/common/BecomesTargetTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/BecomesTargetTriggeredAbility.java @@ -57,7 +57,7 @@ public class BecomesTargetTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { StackObject sourceObject = game.getStack().getStackObject(event.getSourceId()); if (!event.getTargetId().equals(getSourceId()) - || !filter.match(sourceObject, getSourceId(), getControllerId(), game)) { + || !filter.match(sourceObject, getControllerId(), this, game)) { return false; } switch (setTargetPointer) { diff --git a/Mage/src/main/java/mage/abilities/common/BeginningOfCombatTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BeginningOfCombatTriggeredAbility.java index ab997fbfdf1..9165fc03c9e 100644 --- a/Mage/src/main/java/mage/abilities/common/BeginningOfCombatTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/BeginningOfCombatTriggeredAbility.java @@ -10,8 +10,8 @@ import mage.target.targetpointer.FixedTarget; public class BeginningOfCombatTriggeredAbility extends TriggeredAbilityImpl { - private TargetController targetController; - private boolean setTargetPointer; + private final TargetController targetController; + private final boolean setTargetPointer; public BeginningOfCombatTriggeredAbility(Effect effect, TargetController targetController, boolean isOptional) { this(Zone.BATTLEFIELD, effect, targetController, isOptional, false); @@ -62,6 +62,7 @@ public class BeginningOfCombatTriggeredAbility extends TriggeredAbilityImpl { return true; } break; + case EACH_PLAYER: case ANY: if (setTargetPointer) { this.getEffects().forEach(effect -> { @@ -80,6 +81,8 @@ public class BeginningOfCombatTriggeredAbility extends TriggeredAbilityImpl { return "At the beginning of combat on your turn, " + generateZoneString(); case OPPONENT: return "At the beginning of each opponent's combat step, " + generateZoneString(); + case EACH_PLAYER: + return "At the beginning of combat on each player's turn, " + generateZoneString(); case ANY: return "At the beginning of each combat, " + generateZoneString(); } @@ -87,9 +90,8 @@ public class BeginningOfCombatTriggeredAbility extends TriggeredAbilityImpl { } private String generateZoneString() { - switch (getZone()) { - case GRAVEYARD: - return "if {this} is in your graveyard, "; + if (getZone() == Zone.GRAVEYARD) { + return "if {this} is in your graveyard, "; } return ""; } diff --git a/Mage/src/main/java/mage/abilities/common/BlocksCreatureTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BlocksCreatureTriggeredAbility.java new file mode 100644 index 00000000000..e8dc56c4c6f --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/BlocksCreatureTriggeredAbility.java @@ -0,0 +1,64 @@ +package mage.abilities.common; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +/** + * @author Hiddevb + */ +public class BlocksCreatureTriggeredAbility extends TriggeredAbilityImpl { + + private final FilterCreaturePermanent filter; + + public BlocksCreatureTriggeredAbility(Effect effect) { + this(effect, false); + } + + public BlocksCreatureTriggeredAbility(Effect effect, boolean optional) { + this(effect, StaticFilters.FILTER_PERMANENT_CREATURE, optional); + } + + public BlocksCreatureTriggeredAbility(Effect effect, FilterCreaturePermanent filter, boolean optional) { + super(Zone.BATTLEFIELD, effect, optional); + this.filter = filter; + } + + public BlocksCreatureTriggeredAbility(final BlocksCreatureTriggeredAbility 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())) { + return false; + } + if (!filter.match(game.getPermanent(event.getTargetId()), getControllerId(), this, game)) { + return false; + } + getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); + return true; + } + + @Override + public String getTriggerPhrase() { + return "Whenever {this} blocks " + CardUtil.addArticle(filter.getMessage()) + ", "; + } + + @Override + public BlocksCreatureTriggeredAbility copy() { + return new BlocksCreatureTriggeredAbility(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/common/BlocksOrBecomesBlockedSourceTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BlocksOrBecomesBlockedSourceTriggeredAbility.java index ba64cb6b26d..3cefef7c511 100644 --- a/Mage/src/main/java/mage/abilities/common/BlocksOrBecomesBlockedSourceTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/BlocksOrBecomesBlockedSourceTriggeredAbility.java @@ -21,7 +21,11 @@ public class BlocksOrBecomesBlockedSourceTriggeredAbility extends TriggeredAbili protected boolean setTargetPointer; public BlocksOrBecomesBlockedSourceTriggeredAbility(Effect effect, boolean optional) { - this(effect, StaticFilters.FILTER_PERMANENT_CREATURE, optional, null, true); + this(effect, optional, true); + } + + public BlocksOrBecomesBlockedSourceTriggeredAbility(Effect effect, boolean optional, boolean setTargetPointer) { + this(effect, StaticFilters.FILTER_PERMANENT_CREATURE, optional, null, setTargetPointer); } public BlocksOrBecomesBlockedSourceTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional) { diff --git a/Mage/src/main/java/mage/abilities/common/BlocksSourceTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BlocksSourceTriggeredAbility.java index ea59eed6ee9..98b517163e4 100644 --- a/Mage/src/main/java/mage/abilities/common/BlocksSourceTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/BlocksSourceTriggeredAbility.java @@ -1,4 +1,3 @@ - package mage.abilities.common; import mage.constants.Zone; @@ -6,7 +5,7 @@ import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.game.Game; import mage.game.events.GameEvent; -import mage.target.targetpointer.FixedTarget; +import mage.game.permanent.Permanent; /** * @@ -14,50 +13,32 @@ import mage.target.targetpointer.FixedTarget; */ public class BlocksSourceTriggeredAbility extends TriggeredAbilityImpl { - private boolean setTargetPointer; - private boolean once = false; + public BlocksSourceTriggeredAbility(Effect effect) { + this(effect, false); + } public BlocksSourceTriggeredAbility(Effect effect, boolean optional) { - this(effect, optional, false); - } - - public BlocksSourceTriggeredAbility(Effect effect, boolean optional, boolean setTargetPointer) { - this(effect, optional, setTargetPointer, false); - } - - public BlocksSourceTriggeredAbility(Effect effect, boolean optional, boolean setTargetPointer, boolean once) { super(Zone.BATTLEFIELD, effect, optional); - this.setTargetPointer = setTargetPointer; - this.once = once; } public BlocksSourceTriggeredAbility(final BlocksSourceTriggeredAbility ability) { super(ability); - this.setTargetPointer = ability.setTargetPointer; - this.once = ability.once; } @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.BLOCKER_DECLARED; + return event.getType() == GameEvent.EventType.DECLARED_BLOCKERS; } @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getSourceId().equals(this.getSourceId())) { - if (setTargetPointer) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getTargetId())); - } - } - return true; - } - return false; + Permanent permanent = game.getPermanent(getSourceId()); + return permanent != null && permanent.getBlocking() > 0; } @Override public String getTriggerPhrase() { - return "When" + (once ? "" : "ever") + " {this} blocks" + (setTargetPointer ? " a creature, " : ", ") ; + return "Whenever {this} blocks, "; } @Override diff --git a/Mage/src/main/java/mage/abilities/common/CastSecondSpellTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/CastSecondSpellTriggeredAbility.java index 6c40f07da58..a9012a8dad2 100644 --- a/Mage/src/main/java/mage/abilities/common/CastSecondSpellTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/CastSecondSpellTriggeredAbility.java @@ -6,6 +6,7 @@ import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; +import mage.constants.TargetController; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; @@ -17,19 +18,28 @@ import mage.watchers.common.CastSpellLastTurnWatcher; public class CastSecondSpellTriggeredAbility extends TriggeredAbilityImpl { private static final Hint hint = new ValueHint("Spells you cast this turn", SpellCastValue.instance); + private final TargetController targetController; public CastSecondSpellTriggeredAbility(Effect effect) { - this(Zone.BATTLEFIELD, effect, false); + this(effect, TargetController.YOU); } - public CastSecondSpellTriggeredAbility(Zone zone, Effect effect, boolean optional) { + public CastSecondSpellTriggeredAbility(Effect effect, TargetController targetController) { + this(Zone.BATTLEFIELD, effect, targetController, false); + } + + public CastSecondSpellTriggeredAbility(Zone zone, Effect effect, TargetController targetController, boolean optional) { super(zone, effect, optional); this.addWatcher(new CastSpellLastTurnWatcher()); - this.addHint(hint); + if (targetController == TargetController.YOU) { + this.addHint(hint); + } + this.targetController = targetController; } private CastSecondSpellTriggeredAbility(final CastSecondSpellTriggeredAbility ability) { super(ability); + this.targetController = ability.targetController; } @Override @@ -39,8 +49,21 @@ public class CastSecondSpellTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (!isControlledBy(event.getPlayerId())) { - return false; + switch (targetController) { + case YOU: + if (!isControlledBy(event.getPlayerId())) { + return false; + } + break; + case OPPONENT: + if (!game.getOpponents(getControllerId()).contains(event.getPlayerId())) { + return false; + } + break; + case ANY: + break; + default: + throw new IllegalArgumentException("TargetController " + targetController + " not supported"); } CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); return watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) == 2; @@ -48,7 +71,16 @@ public class CastSecondSpellTriggeredAbility extends TriggeredAbilityImpl { @Override public String getTriggerPhrase() { - return "Whenever you cast your second spell each turn, " ; + switch (targetController) { + case YOU: + return "Whenever you cast your second spell each turn, "; + case OPPONENT: + return "Whenever an opponent casts their second spell each turn, "; + case ANY: + return "Whenever a player casts their second spell each turn, "; + default: + throw new IllegalArgumentException("TargetController " + targetController + " not supported"); + } } @Override diff --git a/Mage/src/main/java/mage/abilities/common/CommanderChooseColorAbility.java b/Mage/src/main/java/mage/abilities/common/CommanderChooseColorAbility.java new file mode 100644 index 00000000000..1063dfece4c --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/CommanderChooseColorAbility.java @@ -0,0 +1,33 @@ +package mage.abilities.common; + +import mage.abilities.StaticAbility; +import mage.cards.Card; +import mage.constants.Zone; + +/** + * @author TheElk801 + */ +public class CommanderChooseColorAbility extends StaticAbility { + + public CommanderChooseColorAbility() { + super(Zone.ALL, null); + } + + private CommanderChooseColorAbility(final CommanderChooseColorAbility ability) { + super(ability); + } + + @Override + public CommanderChooseColorAbility copy() { + return new CommanderChooseColorAbility(this); + } + + @Override + public String getRule() { + return "If {this} is your commander, choose a color before the game begins. {this} is the chosen color."; + } + + public static boolean checkCard(Card card) { + return card.getAbilities().stream().anyMatch(CommanderChooseColorAbility.class::isInstance); + } +} diff --git a/Mage/src/main/java/mage/abilities/common/ControlledCreaturesDealCombatDamagePlayerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealCombatDamageControlledTriggeredAbility.java similarity index 76% rename from Mage/src/main/java/mage/abilities/common/ControlledCreaturesDealCombatDamagePlayerTriggeredAbility.java rename to Mage/src/main/java/mage/abilities/common/DealCombatDamageControlledTriggeredAbility.java index 412a580bd12..bbe23c9e11c 100644 --- a/Mage/src/main/java/mage/abilities/common/ControlledCreaturesDealCombatDamagePlayerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealCombatDamageControlledTriggeredAbility.java @@ -17,39 +17,39 @@ import java.util.UUID; /** * @author LevelX2 */ -public class ControlledCreaturesDealCombatDamagePlayerTriggeredAbility extends TriggeredAbilityImpl { +public class DealCombatDamageControlledTriggeredAbility extends TriggeredAbilityImpl { private final Set damagedPlayerIds = new HashSet<>(); private final boolean setTargetPointer; private final boolean onlyOpponents; - public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Effect effect) { + public DealCombatDamageControlledTriggeredAbility(Effect effect) { this(Zone.BATTLEFIELD, effect); } - public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Zone zone, Effect effect) { + public DealCombatDamageControlledTriggeredAbility(Zone zone, Effect effect) { this(zone, effect, false); } - public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Zone zone, Effect effect, boolean setTargetPointer) { + public DealCombatDamageControlledTriggeredAbility(Zone zone, Effect effect, boolean setTargetPointer) { this(zone, effect, setTargetPointer, false); } - public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Zone zone, Effect effect, boolean setTargetPointer, boolean onlyOpponents) { + public DealCombatDamageControlledTriggeredAbility(Zone zone, Effect effect, boolean setTargetPointer, boolean onlyOpponents) { super(zone, effect, false); this.setTargetPointer = setTargetPointer; this.onlyOpponents = onlyOpponents; } - public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(final ControlledCreaturesDealCombatDamagePlayerTriggeredAbility ability) { + public DealCombatDamageControlledTriggeredAbility(final DealCombatDamageControlledTriggeredAbility ability) { super(ability); this.setTargetPointer = ability.setTargetPointer; this.onlyOpponents = ability.onlyOpponents; } @Override - public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility copy() { - return new ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(this); + public DealCombatDamageControlledTriggeredAbility copy() { + return new DealCombatDamageControlledTriggeredAbility(this); } @Override diff --git a/Mage/src/main/java/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java index f62306e734a..1d0bfcc6565 100644 --- a/Mage/src/main/java/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java @@ -83,9 +83,9 @@ public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbility return false; } } + getAllEffects().setValue("damage", event.getAmount()); if (setTargetPointer) { getAllEffects().setTargetPointer(new FixedTarget(event.getPlayerId())); - getAllEffects().setValue("damage", event.getAmount()); } return true; } diff --git a/Mage/src/main/java/mage/abilities/common/DealsCombatDamageTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealsCombatDamageTriggeredAbility.java index b5dfec5711a..96ecbbcdd1f 100644 --- a/Mage/src/main/java/mage/abilities/common/DealsCombatDamageTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealsCombatDamageTriggeredAbility.java @@ -1,5 +1,3 @@ - - package mage.abilities.common; import mage.abilities.TriggeredAbilityImpl; @@ -26,13 +24,13 @@ public class DealsCombatDamageTriggeredAbility extends TriggeredAbilityImpl { } public DealsCombatDamageTriggeredAbility(final DealsCombatDamageTriggeredAbility ability) { - super(ability); - this.usedInPhase = ability.usedInPhase; + super(ability); + this.usedInPhase = ability.usedInPhase; } @Override public DealsCombatDamageTriggeredAbility copy() { - return new DealsCombatDamageTriggeredAbility(this); + return new DealsCombatDamageTriggeredAbility(this); } @Override @@ -47,10 +45,10 @@ public class DealsCombatDamageTriggeredAbility extends TriggeredAbilityImpl { && event.getSourceId().equals(this.sourceId) && ((DamagedEvent) event).isCombatDamage()) { usedInPhase = true; + getEffects().setValue("damage", event.getAmount()); return true; - } - if (event.getType()== GameEvent.EventType.COMBAT_DAMAGE_STEP_PRE) { + if (event.getType() == GameEvent.EventType.COMBAT_DAMAGE_STEP_PRE) { usedInPhase = false; } return false; @@ -58,7 +56,6 @@ public class DealsCombatDamageTriggeredAbility extends TriggeredAbilityImpl { @Override public String getTriggerPhrase() { - return "Whenever {this} deals combat damage, " ; + return "Whenever {this} deals combat damage, "; } - } diff --git a/Mage/src/main/java/mage/abilities/common/DealsDamageGainLifeSourceTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealsDamageGainLifeSourceTriggeredAbility.java index 50015cacfc3..564b3f37bf4 100644 --- a/Mage/src/main/java/mage/abilities/common/DealsDamageGainLifeSourceTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealsDamageGainLifeSourceTriggeredAbility.java @@ -1,16 +1,12 @@ - - package mage.abilities.common; -import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.dynamicvalue.common.SavedDamageValue; import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; -import mage.constants.Outcome; +import mage.abilities.effects.common.GainLifeEffect; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.players.Player; /** * @@ -20,7 +16,7 @@ import mage.players.Player; public class DealsDamageGainLifeSourceTriggeredAbility extends TriggeredAbilityImpl { public DealsDamageGainLifeSourceTriggeredAbility() { - super(Zone.BATTLEFIELD, new GainThatMuchLifeEffect(), false); + super(Zone.BATTLEFIELD, new GainLifeEffect(SavedDamageValue.MUCH), false); } public DealsDamageGainLifeSourceTriggeredAbility(final DealsDamageGainLifeSourceTriggeredAbility ability) { @@ -53,34 +49,3 @@ public class DealsDamageGainLifeSourceTriggeredAbility extends TriggeredAbilityI return "Whenever {this} deals damage, " ; } } - -class GainThatMuchLifeEffect extends OneShotEffect { - - public GainThatMuchLifeEffect() { - super(Outcome.GainLife); - this.staticText = "you gain that much life"; - } - - public GainThatMuchLifeEffect(final GainThatMuchLifeEffect effect) { - super(effect); - } - - @Override - public GainThatMuchLifeEffect copy() { - return new GainThatMuchLifeEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - int amount = (Integer) getValue("damage"); - if (amount > 0) { - controller.gainLife(amount, game, source); - - } - return true; - } - return false; - } -} diff --git a/Mage/src/main/java/mage/abilities/common/DealsDamageToACreatureAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealsDamageToACreatureAllTriggeredAbility.java index 70b0364d69a..713625ba41e 100644 --- a/Mage/src/main/java/mage/abilities/common/DealsDamageToACreatureAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealsDamageToACreatureAllTriggeredAbility.java @@ -69,27 +69,24 @@ public class DealsDamageToACreatureAllTriggeredAbility extends TriggeredAbilityI return false; } permanent = game.getPermanentOrLKIBattlefield(event.getSourceId()); - if (!filterPermanent.match(permanent, getSourceId(), getControllerId(), game)) { + if (!filterPermanent.match(permanent, getControllerId(), this, game)) { return false; } - for (Effect effect : this.getEffects()) { - effect.setValue("damage", event.getAmount()); - effect.setValue("sourceId", event.getSourceId()); - switch (setTargetPointer) { - case PLAYER: - effect.setTargetPointer(new FixedTarget(permanent.getControllerId())); - break; - case PERMANENT: - effect.setTargetPointer(new FixedTarget(permanent, game)); - break; - case PERMANENT_TARGET: - Permanent permanent_target = game.getPermanentOrLKIBattlefield(event.getTargetId()); - if (permanent_target != null) { - effect.setTargetPointer(new FixedTarget(permanent_target, game)); - } - break; - } - + this.getEffects().setValue("damage", event.getAmount()); + this.getEffects().setValue("sourceId", event.getSourceId()); + switch (setTargetPointer) { + case PLAYER: + this.getEffects().setTargetPointer(new FixedTarget(permanent.getControllerId())); + break; + case PERMANENT: + this.getEffects().setTargetPointer(new FixedTarget(permanent, game)); + break; + case PERMANENT_TARGET: + Permanent permanent_target = game.getPermanentOrLKIBattlefield(event.getTargetId()); + if (permanent_target != null) { + this.getEffects().setTargetPointer(new FixedTarget(permanent_target, game)); + } + break; } return true; } @@ -97,6 +94,6 @@ public class DealsDamageToACreatureAllTriggeredAbility extends TriggeredAbilityI @Override public String getTriggerPhrase() { return "Whenever " + filterPermanent.getMessage() + " deals " - + (combatDamageOnly ? "combat " : "") + "damage to a creature, " ; + + (combatDamageOnly ? "combat " : "") + "damage to a creature, "; } } diff --git a/Mage/src/main/java/mage/abilities/common/DealsDamageToACreatureTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealsDamageToACreatureTriggeredAbility.java index 1dcc7f4ec6b..b59a77ee884 100644 --- a/Mage/src/main/java/mage/abilities/common/DealsDamageToACreatureTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealsDamageToACreatureTriggeredAbility.java @@ -1,9 +1,9 @@ package mage.abilities.common; -import mage.constants.Zone; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; +import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.events.DamagedEvent; @@ -12,7 +12,6 @@ import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; /** - * * @author LevelX */ public class DealsDamageToACreatureTriggeredAbility extends TriggeredAbilityImpl { @@ -43,7 +42,7 @@ public class DealsDamageToACreatureTriggeredAbility extends TriggeredAbilityImpl public DealsDamageToACreatureTriggeredAbility copy() { return new DealsDamageToACreatureTriggeredAbility(this); } - + @Override public boolean checkEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.DAMAGED_PERMANENT; @@ -55,15 +54,13 @@ public class DealsDamageToACreatureTriggeredAbility extends TriggeredAbilityImpl && (!combatOnly || ((DamagedEvent) event).isCombatDamage())) { if (filter != null) { Permanent creature = game.getPermanentOrLKIBattlefield(event.getTargetId()); - if (!filter.match(creature, getSourceId(), getControllerId(), game)) { + if (!filter.match(creature, getControllerId(), this, game)) { return false; } } if (setTargetPointer) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getTargetId(), game)); - effect.setValue("damage", event.getAmount()); - } + this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); + this.getEffects().setValue("damage", event.getAmount()); } return true; } diff --git a/Mage/src/main/java/mage/abilities/common/DealsDamageToAPlayerAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealsDamageToAPlayerAllTriggeredAbility.java index faeb89e0d8b..668e0d41408 100644 --- a/Mage/src/main/java/mage/abilities/common/DealsDamageToAPlayerAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealsDamageToAPlayerAllTriggeredAbility.java @@ -74,7 +74,7 @@ public class DealsDamageToAPlayerAllTriggeredAbility extends TriggeredAbilityImp return false; } Permanent permanent = game.getPermanent(event.getSourceId()); - if (!filter.match(permanent, getSourceId(), getControllerId(), game)) { + if (!filter.match(permanent, getControllerId(), this, game)) { return false; } this.getEffects().setValue("damage", event.getAmount()); diff --git a/Mage/src/main/java/mage/abilities/common/DealsDamageToAPlayerAttachedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealsDamageToAPlayerAttachedTriggeredAbility.java index e8fe47c2c66..90978080273 100644 --- a/Mage/src/main/java/mage/abilities/common/DealsDamageToAPlayerAttachedTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealsDamageToAPlayerAttachedTriggeredAbility.java @@ -77,8 +77,8 @@ public class DealsDamageToAPlayerAttachedTriggeredAbility extends TriggeredAbili || p == null || !p.getAttachments().contains(this.getSourceId())) { return false; } + getEffects().setValue("damage", event.getAmount()); if (setFixedTargetPointer) { - getEffects().setValue("damage", event.getAmount()); getEffects().setTargetPointer(new FixedTarget(event.getPlayerId())); } return true; @@ -86,7 +86,11 @@ public class DealsDamageToAPlayerAttachedTriggeredAbility extends TriggeredAbili @Override public String getTriggerPhrase() { - StringBuilder sb = new StringBuilder("Whenever ").append(attachedDescription); + StringBuilder sb = new StringBuilder("Whenever "); + sb.append(attachedDescription); + if (!attachedDescription.endsWith("creature")) { + sb.append(" creature"); + } sb.append(" deals"); if (onlyCombat) { sb.append(" combat"); diff --git a/Mage/src/main/java/mage/abilities/common/DiesAttachedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DiesAttachedTriggeredAbility.java index 204d6119a4c..3b94b15b382 100644 --- a/Mage/src/main/java/mage/abilities/common/DiesAttachedTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DiesAttachedTriggeredAbility.java @@ -110,6 +110,19 @@ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl { } } } + // set targetpointer to the creature that died + if (setTargetPointer == SetTargetPointer.CARD + || setTargetPointer == SetTargetPointer.PERMANENT) { + Permanent attachment = game.getPermanentOrLKIBattlefield(getSourceId()); + if (attachment != null + && attachment.getAttachedTo() != null) { + Permanent attachedTo = (Permanent) game.getLastKnownInformation(attachment.getAttachedTo(), + Zone.BATTLEFIELD, attachment.getAttachedToZoneChangeCounter()); + if (attachedTo != null) { + getEffects().setTargetPointer(new FixedTarget(attachedTo.getId())); + } + } + } return true; } @@ -125,7 +138,7 @@ public class DiesAttachedTriggeredAbility extends TriggeredAbilityImpl { if (diesRuleText) { sb.append(" dies, "); } else { - sb.append(" is put into graveyard, "); + sb.append(" is put into a graveyard, "); } return sb.toString(); } diff --git a/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java index b4a49b2fa7c..1a9fa39f56e 100644 --- a/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java @@ -69,7 +69,7 @@ public class DiesCreatureTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (!zEvent.isDiesEvent() || !filter.match(zEvent.getTarget(), sourceId, controllerId, game)) { + if (!zEvent.isDiesEvent() || !filter.match(zEvent.getTarget(), controllerId, this, game)) { return false; } getEffects().setValue("creatureDied", zEvent.getTarget()); diff --git a/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility.java index 5d11e296373..c21e14145cd 100644 --- a/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility.java @@ -49,7 +49,7 @@ public class DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility extends Tri if (zEvent.getTarget().getId().equals(this.getSourceId())) { return true; } else { - if (filter.match(zEvent.getTarget(), getSourceId(), getControllerId(), game)) { + if (filter.match(zEvent.getTarget(), getControllerId(), this, game)) { return true; } } diff --git a/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherCreatureTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherCreatureTriggeredAbility.java index bccded75fcf..ab9ec39ce08 100644 --- a/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherCreatureTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherCreatureTriggeredAbility.java @@ -56,7 +56,7 @@ public class DiesThisOrAnotherCreatureTriggeredAbility extends TriggeredAbilityI if (!applyFilterOnSource && zEvent.getTarget().getId().equals(this.getSourceId())) { return true; } else { - if (filter.match(zEvent.getTarget(), getSourceId(), getControllerId(), game)) { + if (filter.match(zEvent.getTarget(), getControllerId(), this, game)) { return true; } } diff --git a/Mage/src/main/java/mage/abilities/common/EnchantedCreatureBlockedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/EnchantedCreatureBlockedTriggeredAbility.java deleted file mode 100644 index bcae0ec90ec..00000000000 --- a/Mage/src/main/java/mage/abilities/common/EnchantedCreatureBlockedTriggeredAbility.java +++ /dev/null @@ -1,52 +0,0 @@ -package mage.abilities.common; - -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.target.targetpointer.FixedTarget; - -/** - * - * @author L_J - */ -public class EnchantedCreatureBlockedTriggeredAbility extends TriggeredAbilityImpl { - - public EnchantedCreatureBlockedTriggeredAbility(Effect effect, boolean optional) { - super(Zone.BATTLEFIELD, effect, optional); - } - - public EnchantedCreatureBlockedTriggeredAbility(final EnchantedCreatureBlockedTriggeredAbility ability) { - super(ability); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.CREATURE_BLOCKED; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Permanent equipment = game.getPermanent(sourceId); - if (equipment != null && equipment.getAttachedTo() != null) { - Permanent equipped = game.getPermanent(equipment.getAttachedTo()); - if (equipped.getId().equals(event.getTargetId())) { - getEffects().get(1).setTargetPointer(new FixedTarget(equipped, game)); - return true; - } - } - return false; - } - - @Override - public String getTriggerPhrase() { - return "Whenever enchanted creature becomes blocked, " ; - } - - @Override - public EnchantedCreatureBlockedTriggeredAbility copy() { - return new EnchantedCreatureBlockedTriggeredAbility(this); - } -} diff --git a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAllTriggeredAbility.java index 3626a2c2b15..48ac04769b2 100644 --- a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldAllTriggeredAbility.java @@ -84,7 +84,7 @@ public class EntersBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { UUID targetId = event.getTargetId(); Permanent permanent = game.getPermanent(targetId); - if (!filter.match(permanent, getSourceId(), getControllerId(), game)) { + if (!filter.match(permanent, getControllerId(), this, game)) { return false; } this.getEffects().setValue("permanentEnteringBattlefield", permanent); diff --git a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldControlledTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldControlledTriggeredAbility.java index 0d273a2c80e..7a0f5accc27 100644 --- a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldControlledTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldControlledTriggeredAbility.java @@ -51,11 +51,11 @@ public class EntersBattlefieldControlledTriggeredAbility extends EntersBattlefie @Override public boolean checkTrigger(GameEvent event, Game game) { - if (super.checkTrigger(event, game)) { - Permanent permanent = game.getPermanent(event.getTargetId()); - return permanent != null && permanent.isControlledBy(this.getControllerId()); + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent == null || !permanent.isControlledBy(getControllerId())) { + return false; } - return false; + return super.checkTrigger(event, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldOrAttacksAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldOrAttacksAllTriggeredAbility.java index 1a92950bcd3..2168b6857d2 100644 --- a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldOrAttacksAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldOrAttacksAllTriggeredAbility.java @@ -79,7 +79,7 @@ public class EntersBattlefieldOrAttacksAllTriggeredAbility extends TriggeredAbil public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanent(event.getTargetId()); if (event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD - && filter.match(permanent, getSourceId(), getControllerId(), game)) { + && filter.match(permanent, getControllerId(), this, game)) { if (setTargetPointer != SetTargetPointer.NONE) { for (Effect effect : this.getEffects()) { switch (setTargetPointer) { @@ -98,7 +98,7 @@ public class EntersBattlefieldOrAttacksAllTriggeredAbility extends TriggeredAbil Permanent attacker = game.getPermanent(event.getSourceId()); if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED - && filter.match(attacker, getSourceId(), getControllerId(), game)) { + && filter.match(attacker, getControllerId(), this, game)) { if (setTargetPointer != SetTargetPointer.NONE) { for (Effect effect : this.getEffects()) { switch (setTargetPointer) { diff --git a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldThisOrAnotherTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldThisOrAnotherTriggeredAbility.java index ce631a0a3be..39b7be1d3ff 100644 --- a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldThisOrAnotherTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldThisOrAnotherTriggeredAbility.java @@ -52,7 +52,7 @@ public class EntersBattlefieldThisOrAnotherTriggeredAbility extends EntersBattle if (onlyControlled && !permanent.isControlledBy(this.getControllerId())) { return false; } - return filter.match(permanent, getSourceId(), getControllerId(), game); + return filter.match(permanent, getControllerId(), this, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/common/ForetellSourceControllerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/ForetellSourceControllerTriggeredAbility.java index e395a0b98cb..fc9c8cf73ca 100644 --- a/Mage/src/main/java/mage/abilities/common/ForetellSourceControllerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/ForetellSourceControllerTriggeredAbility.java @@ -2,7 +2,6 @@ package mage.abilities.common; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; -import mage.abilities.keyword.ForetellAbility; import mage.cards.Card; import mage.constants.Zone; import mage.game.Game; @@ -24,27 +23,21 @@ public class ForetellSourceControllerTriggeredAbility extends TriggeredAbilityIm @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.TAKEN_SPECIAL_ACTION; + return event.getType() == GameEvent.EventType.FORETELL; } @Override public boolean checkTrigger(GameEvent event, Game game) { - Card card = game.getCard(event.getSourceId()); + Card card = game.getCard(event.getTargetId()); Player player = game.getPlayer(event.getPlayerId()); - if (card == null || player == null) { - return false; - } - - if (!isControlledBy(player.getId())) { - return false; - } - - return card.getAbilities(game).containsClass(ForetellAbility.class); + return (card != null + && player != null + && isControlledBy(player.getId())); } @Override public String getTriggerPhrase() { - return "Whenever you foretell a card, " ; + return "Whenever you foretell a card, "; } @Override diff --git a/Mage/src/main/java/mage/abilities/common/GainLifeControllerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/GainLifeControllerTriggeredAbility.java index d1ca2460e45..90f01a19cc3 100644 --- a/Mage/src/main/java/mage/abilities/common/GainLifeControllerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/GainLifeControllerTriggeredAbility.java @@ -46,10 +46,8 @@ public class GainLifeControllerTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (event.getPlayerId().equals(this.getControllerId())) { if (setTargetPointer) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getPlayerId())); - effect.setValue("gainedLife", event.getAmount()); - } + this.getEffects().setTargetPointer(new FixedTarget(event.getPlayerId())); + this.getEffects().setValue("gainedLife", event.getAmount()); } return true; } @@ -58,6 +56,6 @@ public class GainLifeControllerTriggeredAbility extends TriggeredAbilityImpl { @Override public String getTriggerPhrase() { - return "Whenever you gain life, " ; + return "Whenever you gain life, "; } } diff --git a/Mage/src/main/java/mage/abilities/common/GiveManaAbilityAndCastSourceAbility.java b/Mage/src/main/java/mage/abilities/common/GiveManaAbilityAndCastSourceAbility.java new file mode 100644 index 00000000000..db2f5016745 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/GiveManaAbilityAndCastSourceAbility.java @@ -0,0 +1,171 @@ +package mage.abilities.common; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.ActivatedAbilityImpl; +import mage.abilities.Mode; +import mage.abilities.costs.common.ExileSourceFromHandCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.mana.*; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.target.common.TargetLandPermanent; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public class GiveManaAbilityAndCastSourceAbility extends ActivatedAbilityImpl { + + // TODO: write automated tests for this (it works in manual testing) + public GiveManaAbilityAndCastSourceAbility(String colors) { + super(Zone.HAND, new GainManaAbilitiesWhileExiledEffect(colors), new GenericManaCost(2)); + this.addCost(new ExileSourceFromHandCost()); + this.addEffect(new CastExiledFromHandCardEffect()); + this.addTarget(new TargetLandPermanent()); + this.addWatcher(new WasCastFromExileWatcher()); + } + + private GiveManaAbilityAndCastSourceAbility(final GiveManaAbilityAndCastSourceAbility ability) { + super(ability); + } + + @Override + public GiveManaAbilityAndCastSourceAbility copy() { + return new GiveManaAbilityAndCastSourceAbility(this); + } +} + +class CastExiledFromHandCardEffect extends OneShotEffect { + + CastExiledFromHandCardEffect() { + super(Outcome.Benefit); + staticText = "You may cast {this} for as long as it remains exiled"; + } + + private CastExiledFromHandCardEffect(final CastExiledFromHandCardEffect effect) { + super(effect); + } + + @Override + public CastExiledFromHandCardEffect copy() { + return new CastExiledFromHandCardEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Optional.of(getValue("exiledHandCardRef")) + .filter(Objects::nonNull) + .map(MageObjectReference.class::cast) + .map(mor -> mor.getCard(game)) + .ifPresent(card -> CardUtil.makeCardPlayable( + game, source, card, Duration.Custom, false + )); + return true; + } +} + +class GainManaAbilitiesWhileExiledEffect extends ContinuousEffectImpl { + + private final String colors; + + GainManaAbilitiesWhileExiledEffect(String colors) { + super(Duration.Custom, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + this.colors = colors; + } + + private GainManaAbilitiesWhileExiledEffect(final GainManaAbilitiesWhileExiledEffect effect) { + super(effect); + this.colors = effect.colors; + } + + @Override + public GainManaAbilitiesWhileExiledEffect copy() { + return new GainManaAbilitiesWhileExiledEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (WasCastFromExileWatcher.check((MageObjectReference) getValue("exiledHandCardRef"), game)) { + discard(); + return false; + } + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + discard(); + return false; + } + for (char c : colors.toCharArray()) { + Ability ability; + switch (c) { + case 'W': + ability = new WhiteManaAbility(); + break; + case 'U': + ability = new BlueManaAbility(); + break; + case 'B': + ability = new BlackManaAbility(); + break; + case 'R': + ability = new RedManaAbility(); + break; + case 'G': + ability = new GreenManaAbility(); + break; + default: + continue; + } + permanent.addAbility(ability, source.getSourceId(), game); + } + return true; + } + + @Override + public String getText(Mode mode) { + return "target land gains \"{T}: Add " + + CardUtil.concatWithOr( + Arrays.stream(colors.split("")) + .map(s -> '{' + s + '}') + .collect(Collectors.toList()) + ) + + "\" until {this} is cast from exile"; + } +} + +class WasCastFromExileWatcher extends Watcher { + + private final Set morSet = new HashSet<>(); + + WasCastFromExileWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() != GameEvent.EventType.SPELL_CAST || !Zone.EXILED.match(event.getZone())) { + return; + } + Spell spell = game.getSpell(event.getSourceId()); + if (spell != null) { + morSet.add(new MageObjectReference(spell.getMainCard(), game, -1)); + } + } + + static boolean check(MageObjectReference mor, Game game) { + return game + .getState() + .getWatcher(WasCastFromExileWatcher.class) + .morSet + .contains(mor); + } +} diff --git a/Mage/src/main/java/mage/abilities/common/GoadAttachedAbility.java b/Mage/src/main/java/mage/abilities/common/GoadAttachedAbility.java deleted file mode 100644 index 3f5c6b43a96..00000000000 --- a/Mage/src/main/java/mage/abilities/common/GoadAttachedAbility.java +++ /dev/null @@ -1,78 +0,0 @@ -package mage.abilities.common; - -import mage.abilities.Ability; -import mage.abilities.StaticAbility; -import mage.abilities.effects.Effect; -import mage.abilities.effects.RestrictionEffect; -import mage.abilities.effects.common.combat.AttacksIfAbleAttachedEffect; -import mage.constants.AttachmentType; -import mage.constants.Duration; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; - -import java.util.UUID; - -/** - * @author TheElk801 - */ -public class GoadAttachedAbility extends StaticAbility { - - public GoadAttachedAbility(Effect... effects) { - super(Zone.BATTLEFIELD, null); - for (Effect effect : effects) { - this.addEffect(effect); - } - this.addEffect(new AttacksIfAbleAttachedEffect( - Duration.WhileOnBattlefield, AttachmentType.AURA - ).setText((getEffects().size() > 1 ? ", " : " ") + "and is goaded. (It attacks each combat if able")); - this.addEffect(new GoadAttackEffect()); - } - - private GoadAttachedAbility(final GoadAttachedAbility ability) { - super(ability); - } - - @Override - public GoadAttachedAbility copy() { - return new GoadAttachedAbility(this); - } -} - -class GoadAttackEffect extends RestrictionEffect { - - GoadAttackEffect() { - super(Duration.WhileOnBattlefield); - staticText = "and attacks a player other than you if able.)"; - } - - private GoadAttackEffect(final GoadAttackEffect effect) { - super(effect); - } - - @Override - public GoadAttackEffect copy() { - return new GoadAttackEffect(this); - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - Permanent attachment = game.getPermanent(source.getSourceId()); - return attachment != null && attachment.getAttachedTo() != null - && permanent.getId().equals(attachment.getAttachedTo()); - } - - @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { - if (defenderId == null - || game.getState().getPlayersInRange(attacker.getControllerId(), game).size() == 2) { // just 2 players left, so it may attack you - return true; - } - // A planeswalker controlled by the controller is the defender - if (game.getPermanent(defenderId) != null) { - return !game.getPermanent(defenderId).getControllerId().equals(source.getControllerId()); - } - // The controller is the defender - return !defenderId.equals(source.getControllerId()); - } -} diff --git a/Mage/src/main/java/mage/abilities/common/LeavesBattlefieldAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/LeavesBattlefieldAllTriggeredAbility.java index 8c06dbc8a87..da979db570c 100644 --- a/Mage/src/main/java/mage/abilities/common/LeavesBattlefieldAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/LeavesBattlefieldAllTriggeredAbility.java @@ -62,7 +62,7 @@ public class LeavesBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl { if (zEvent.getFromZone() == Zone.BATTLEFIELD) { UUID targetId = event.getTargetId(); Permanent permanent = game.getPermanentOrLKIBattlefield(targetId); - if (filter.match(permanent, getSourceId(), getControllerId(), game)) { + if (filter.match(permanent, getControllerId(), this, game)) { if (setTargetPointer != SetTargetPointer.NONE) { for (Effect effect : this.getEffects()) { switch (setTargetPointer) { diff --git a/Mage/src/main/java/mage/abilities/common/PlaneswalkerEntersWithLoyaltyCountersAbility.java b/Mage/src/main/java/mage/abilities/common/PlaneswalkerEntersWithLoyaltyCountersAbility.java deleted file mode 100644 index db7355e37ab..00000000000 --- a/Mage/src/main/java/mage/abilities/common/PlaneswalkerEntersWithLoyaltyCountersAbility.java +++ /dev/null @@ -1,39 +0,0 @@ -package mage.abilities.common; - -import mage.abilities.effects.EntersBattlefieldEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.counters.CounterType; - -/** - * @author LevelX2 - */ -public class PlaneswalkerEntersWithLoyaltyCountersAbility extends EntersBattlefieldAbility { - - private int startingLoyalty; - - public PlaneswalkerEntersWithLoyaltyCountersAbility(int loyalty) { - super(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(loyalty))); - startingLoyalty = loyalty; - setRuleVisible(false); - } - - public PlaneswalkerEntersWithLoyaltyCountersAbility(final PlaneswalkerEntersWithLoyaltyCountersAbility ability) { - super(ability); - startingLoyalty = ability.startingLoyalty; - } - - public int getStartingLoyalty() { - return startingLoyalty; - } - - public void setStartingLoyalty(int startingLoyalty) { - this.startingLoyalty = startingLoyalty; - this.getEffects().clear(); - this.addEffect(new EntersBattlefieldEffect(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(startingLoyalty)))); - } - - @Override - public PlaneswalkerEntersWithLoyaltyCountersAbility copy() { - return new PlaneswalkerEntersWithLoyaltyCountersAbility(this); - } -} diff --git a/Mage/src/main/java/mage/abilities/common/PutCardIntoGraveFromAnywhereAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/PutCardIntoGraveFromAnywhereAllTriggeredAbility.java index 9fc36f87cf4..78313bcb411 100644 --- a/Mage/src/main/java/mage/abilities/common/PutCardIntoGraveFromAnywhereAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/PutCardIntoGraveFromAnywhereAllTriggeredAbility.java @@ -77,11 +77,12 @@ public class PutCardIntoGraveFromAnywhereAllTriggeredAbility extends TriggeredAb @Override public boolean checkTrigger(GameEvent event, Game game) { - if (((ZoneChangeEvent) event).getToZone() != Zone.GRAVEYARD) { + if (((ZoneChangeEvent) event).getToZone() != Zone.GRAVEYARD + || !zone.match(game.getState().getZone(getSourceId()))) { return false; } Card card = game.getCard(event.getTargetId()); - if (card == null || card.isCopy() || !filter.match(card, getSourceId(), getControllerId(), game)) { + if (card == null || card.isCopy() || !filter.match(card, getControllerId(), this, game)) { return false; } switch (setTargetPointer) { diff --git a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromAnywhereSourceAbility.java b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromAnywhereSourceAbility.java index b207de62068..70788da37e6 100644 --- a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromAnywhereSourceAbility.java +++ b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromAnywhereSourceAbility.java @@ -118,7 +118,7 @@ class PutIntoGraveFromAnywhereEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { if (optional) { Player controller = game.getPlayer(source.getControllerId()); - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (controller == null || object == null) { return false; } diff --git a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldAllTriggeredAbility.java index 341d4088259..32bc8aaf5bf 100644 --- a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldAllTriggeredAbility.java @@ -7,7 +7,6 @@ import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.events.ZoneChangeEvent; import mage.target.targetpointer.FixedTarget; @@ -49,7 +48,7 @@ public class PutIntoGraveFromBattlefieldAllTriggeredAbility extends TriggeredAbi public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; if (zEvent.isDiesEvent()) { - if (filter.match(zEvent.getTarget(), this.getSourceId(), this.getControllerId(), game)) { + if (filter.match(zEvent.getTarget(), this.getControllerId(), this, game)) { if (onlyToControllerGraveyard && !this.isControlledBy(game.getOwnerId(zEvent.getTargetId()))) { return false; } diff --git a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldSourceTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldSourceTriggeredAbility.java index d9aa0038e5d..d672f331100 100644 --- a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldSourceTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldSourceTriggeredAbility.java @@ -13,7 +13,7 @@ import mage.game.permanent.Permanent; */ public class PutIntoGraveFromBattlefieldSourceTriggeredAbility extends TriggeredAbilityImpl { - private boolean onlyToControllerGraveyard; + private final boolean onlyToControllerGraveyard; public PutIntoGraveFromBattlefieldSourceTriggeredAbility(Effect effect) { this(effect, false, false); @@ -42,19 +42,21 @@ public class PutIntoGraveFromBattlefieldSourceTriggeredAbility extends Triggered @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getTargetId().equals(getSourceId())) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - Permanent permanent = zEvent.getTarget(); - if (permanent != null - && zEvent.isDiesEvent()) { - return !onlyToControllerGraveyard || this.isControlledBy(game.getOwnerId(zEvent.getTargetId())); - } + if (!event.getTargetId().equals(getSourceId())) { + return false; } - return false; + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + Permanent permanent = zEvent.getTarget(); + if (permanent == null || !zEvent.isDiesEvent() + || (onlyToControllerGraveyard && !this.isControlledBy(game.getOwnerId(zEvent.getTargetId())))) { + return false; + } + this.getEffects().setValue("permanentWasCreature", permanent.isCreature(game)); + return true; } @Override public String getTriggerPhrase() { - return "When {this} is put into " + (onlyToControllerGraveyard ? "your" : "a") + " graveyard from the battlefield, " ; + return "When {this} is put into " + (onlyToControllerGraveyard ? "your" : "a") + " graveyard from the battlefield, "; } } diff --git a/Mage/src/main/java/mage/abilities/common/SacrificeAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/SacrificeAllTriggeredAbility.java index 98f38a68cad..589bf164a8d 100644 --- a/Mage/src/main/java/mage/abilities/common/SacrificeAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/SacrificeAllTriggeredAbility.java @@ -58,7 +58,7 @@ public class SacrificeAllTriggeredAbility extends TriggeredAbilityImpl { break; } Permanent sacrificedPermanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); - return sacrificed && filter.match(sacrificedPermanent, getSourceId(), getControllerId(), game); + return sacrificed && filter.match(sacrificedPermanent, getControllerId(), this, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/common/SacrificePermanentTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/SacrificePermanentTriggeredAbility.java index 2a0925c3340..016f5bcfea5 100644 --- a/Mage/src/main/java/mage/abilities/common/SacrificePermanentTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/SacrificePermanentTriggeredAbility.java @@ -57,7 +57,7 @@ public class SacrificePermanentTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); if (!isControlledBy(event.getPlayerId()) || permanent == null - || !filter.match(permanent, getSourceId(), getControllerId(), game)) { + || !filter.match(permanent, getControllerId(), this, game)) { return false; } this.getEffects().setValue("sacrificedPermanent", permanent); diff --git a/Mage/src/main/java/mage/abilities/common/SpellCastAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/SpellCastAllTriggeredAbility.java index fdb748f1f90..f3eedd69081 100644 --- a/Mage/src/main/java/mage/abilities/common/SpellCastAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/SpellCastAllTriggeredAbility.java @@ -59,7 +59,7 @@ public class SpellCastAllTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Spell spell = game.getStack().getSpell(event.getTargetId()); - if (!filter.match(spell, getSourceId(), getControllerId(), game)) { + if (!filter.match(spell, getControllerId(), this, game)) { return false; } getEffects().setValue("spellCast", spell); diff --git a/Mage/src/main/java/mage/abilities/common/SpellCastControllerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/SpellCastControllerTriggeredAbility.java index 775efe507ac..b49ffe73aae 100644 --- a/Mage/src/main/java/mage/abilities/common/SpellCastControllerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/SpellCastControllerTriggeredAbility.java @@ -68,7 +68,7 @@ public class SpellCastControllerTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (event.getPlayerId().equals(this.getControllerId())) { Spell spell = game.getStack().getSpell(event.getTargetId()); - if (filter.match(spell, getSourceId(), getControllerId(), game)) { + if (filter.match(spell, getControllerId(), this, game)) { this.getEffects().setValue("spellCast", spell); if (rememberSource) { if (rememberSourceAsCard) { diff --git a/Mage/src/main/java/mage/abilities/common/SpellCastOpponentTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/SpellCastOpponentTriggeredAbility.java index ad185bad4af..5845b595a9b 100644 --- a/Mage/src/main/java/mage/abilities/common/SpellCastOpponentTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/SpellCastOpponentTriggeredAbility.java @@ -61,7 +61,7 @@ public class SpellCastOpponentTriggeredAbility extends TriggeredAbilityImpl { return false; } Spell spell = game.getStack().getSpell(event.getTargetId()); - if (!filter.match(spell, getSourceId(), getControllerId(), game)) { + if (!filter.match(spell, getControllerId(), this, game)) { return false; } getEffects().setValue("spellCast", spell); diff --git a/Mage/src/main/java/mage/abilities/common/TapForManaAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/TapForManaAllTriggeredAbility.java index ca588d70d83..a28ffeaa6d1 100644 --- a/Mage/src/main/java/mage/abilities/common/TapForManaAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/TapForManaAllTriggeredAbility.java @@ -48,7 +48,7 @@ public class TapForManaAllTriggeredAbility extends TriggeredAbilityImpl { } TappedForManaEvent manaEvent = ((TappedForManaEvent) event); Permanent permanent = manaEvent.getPermanent(); - if (permanent == null || !filter.match(permanent, getSourceId(), getControllerId(), game)) { + if (permanent == null || !filter.match(permanent, getControllerId(), this, game)) { return false; } getEffects().setValue("mana", manaEvent.getMana()); diff --git a/Mage/src/main/java/mage/abilities/common/TapForManaAllTriggeredManaAbility.java b/Mage/src/main/java/mage/abilities/common/TapForManaAllTriggeredManaAbility.java index 8ddf18e7adf..3874f6ed155 100644 --- a/Mage/src/main/java/mage/abilities/common/TapForManaAllTriggeredManaAbility.java +++ b/Mage/src/main/java/mage/abilities/common/TapForManaAllTriggeredManaAbility.java @@ -42,7 +42,7 @@ public class TapForManaAllTriggeredManaAbility extends TriggeredManaAbility { public boolean checkTrigger(GameEvent event, Game game) { TappedForManaEvent manaEvent = ((TappedForManaEvent) event); Permanent permanent = manaEvent.getPermanent(); - if (permanent == null || !filter.match(permanent, getSourceId(), getControllerId(), game)) { + if (permanent == null || !filter.match(permanent, getControllerId(), this, game)) { return false; } getEffects().setValue("mana", manaEvent.getMana()); diff --git a/Mage/src/main/java/mage/abilities/common/TurnedFaceUpAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/TurnedFaceUpAllTriggeredAbility.java index f1b45368546..48dbeee10f6 100644 --- a/Mage/src/main/java/mage/abilities/common/TurnedFaceUpAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/TurnedFaceUpAllTriggeredAbility.java @@ -67,7 +67,7 @@ public class TurnedFaceUpAllTriggeredAbility extends TriggeredAbilityImpl { } } Permanent permanent = game.getPermanent(event.getTargetId()); - if (filter.match(permanent, getSourceId(), getControllerId(), game)) { + if (filter.match(permanent, getControllerId(), this, game)) { if (setTargetPointer) { for (Effect effect : getEffects()) { effect.setTargetPointer(new FixedTarget(event.getTargetId(), game)); diff --git a/Mage/src/main/java/mage/abilities/common/ZoneChangeAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/ZoneChangeAllTriggeredAbility.java index f155be848ba..ec181d81956 100644 --- a/Mage/src/main/java/mage/abilities/common/ZoneChangeAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/ZoneChangeAllTriggeredAbility.java @@ -60,7 +60,7 @@ public class ZoneChangeAllTriggeredAbility extends TriggeredAbilityImpl { } else { perm = game.getPermanent(event.getTargetId()); // LevelX2: maybe this part is not neccessary } - if (filter.match(perm, sourceId, controllerId, game)) { + if (filter.match(perm, controllerId, this, game)) { return true; } } diff --git a/Mage/src/main/java/mage/abilities/common/delayed/AtTheBeginOfMainPhaseDelayedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/delayed/AtTheBeginOfMainPhaseDelayedTriggeredAbility.java index d23bc1098fa..e311d887b50 100644 --- a/Mage/src/main/java/mage/abilities/common/delayed/AtTheBeginOfMainPhaseDelayedTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/delayed/AtTheBeginOfMainPhaseDelayedTriggeredAbility.java @@ -20,12 +20,18 @@ public class AtTheBeginOfMainPhaseDelayedTriggeredAbility extends DelayedTrigger NEXT_PRECOMBAT_MAIN("next precombat main phase"), NEXT_POSTCOMAT_MAIN("next postcombat main phase"), NEXT_MAIN("next main phase"), - NEXT_MAIN_THIS_TURN("next main phase this turn"); + NEXT_MAIN_THIS_TURN("next main phase this turn", Duration.EndOfTurn); private final String text; + private final Duration duration; PhaseSelection(String text) { + this(text, Duration.EndOfGame); + } + + PhaseSelection(String text, Duration duration) { this.text = text; + this.duration = duration; } @Override @@ -38,7 +44,7 @@ public class AtTheBeginOfMainPhaseDelayedTriggeredAbility extends DelayedTrigger private final PhaseSelection phaseSelection; public AtTheBeginOfMainPhaseDelayedTriggeredAbility(Effect effect, boolean optional, TargetController targetController, PhaseSelection phaseSelection) { - super(effect, Duration.EndOfGame, true, optional); + super(effect, phaseSelection.duration, true, optional); this.targetController = targetController; this.phaseSelection = phaseSelection; @@ -101,7 +107,7 @@ public class AtTheBeginOfMainPhaseDelayedTriggeredAbility extends DelayedTrigger } @Override - public String getRule() { + public String getTriggerPhrase() { switch (targetController) { case YOU: return "At the beginning of your " + phaseSelection + ", "; diff --git a/Mage/src/main/java/mage/abilities/common/delayed/AtTheBeginOfNextEndStepDelayedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/delayed/AtTheBeginOfNextEndStepDelayedTriggeredAbility.java index 0fff4ee32ad..5a87f0dc469 100644 --- a/Mage/src/main/java/mage/abilities/common/delayed/AtTheBeginOfNextEndStepDelayedTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/delayed/AtTheBeginOfNextEndStepDelayedTriggeredAbility.java @@ -1,4 +1,3 @@ - package mage.abilities.common.delayed; import mage.abilities.DelayedTriggeredAbility; @@ -6,34 +5,32 @@ import mage.abilities.condition.Condition; import mage.abilities.effects.Effect; import mage.constants.Duration; import mage.constants.TargetController; -import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; /** - * * @author North */ public class AtTheBeginOfNextEndStepDelayedTriggeredAbility extends DelayedTriggeredAbility { - private TargetController targetController; - private Condition condition; + private final TargetController targetController; + private final Condition condition; public AtTheBeginOfNextEndStepDelayedTriggeredAbility(Effect effect) { this(effect, TargetController.ANY); } public AtTheBeginOfNextEndStepDelayedTriggeredAbility(Effect effect, TargetController targetController) { - this(Zone.ALL, effect, targetController); + this(effect, targetController, null); } - public AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone zone, Effect effect, TargetController targetController) { - this(zone, effect, targetController, null); + public AtTheBeginOfNextEndStepDelayedTriggeredAbility(Effect effect, TargetController targetController, Condition condition) { + this(effect, targetController, condition, false); } - public AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone zone, Effect effect, TargetController targetController, Condition condition) { - super(effect, Duration.Custom); + public AtTheBeginOfNextEndStepDelayedTriggeredAbility(Effect effect, TargetController targetController, Condition condition, boolean optional) { + super(effect, Duration.Custom, true, optional); this.zone = zone; this.targetController = targetController; this.condition = condition; @@ -52,32 +49,33 @@ public class AtTheBeginOfNextEndStepDelayedTriggeredAbility extends DelayedTrigg @Override public boolean checkTrigger(GameEvent event, Game game) { - boolean correctEndPhase = false; switch (targetController) { case ANY: - correctEndPhase = true; break; case YOU: - correctEndPhase = event.getPlayerId().equals(this.controllerId); + if (!isControlledBy(event.getPlayerId())) { + return false; + } break; case OPPONENT: - if (game.getPlayer(this.getControllerId()).hasOpponent(event.getPlayerId(), game)) { - correctEndPhase = true; + if (!game.getOpponents(this.getControllerId()).contains(event.getPlayerId())) { + return false; } break; case CONTROLLER_ATTACHED_TO: - Permanent attachment = game.getPermanent(sourceId); - if (attachment != null && attachment.getAttachedTo() != null) { - Permanent attachedTo = game.getPermanent(attachment.getAttachedTo()); - if (attachedTo != null && attachedTo.isControlledBy(event.getPlayerId())) { - correctEndPhase = true; - } + Permanent attachment = game.getPermanent(getSourceId()); + if (attachment == null || attachment.getAttachedTo() == null) { + return false; } + Permanent attachedTo = game.getPermanent(attachment.getAttachedTo()); + if (attachedTo == null || !attachedTo.isControlledBy(event.getPlayerId())) { + return false; + } + break; + default: + throw new UnsupportedOperationException("TargetController not supported"); } - if (correctEndPhase) { - return !(condition != null && !condition.apply(game, this)); - } - return false; + return condition == null || condition.apply(game, this); } @Override @@ -86,23 +84,17 @@ public class AtTheBeginOfNextEndStepDelayedTriggeredAbility extends DelayedTrigg } @Override - public String getRule() { - StringBuilder sb = new StringBuilder(); + public String getTriggerPhrase() { switch (targetController) { case YOU: - sb.append("At the beginning of your next end step, "); - break; + return "At the beginning of your next end step, "; case OPPONENT: - sb.append("At the beginning of an opponent's next end step, "); - break; + return "At the beginning of an opponent's next end step, "; case ANY: - sb.append("At the beginning of the next end step, "); - break; + return "At the beginning of the next end step, "; case CONTROLLER_ATTACHED_TO: - sb.append("At the beginning of the next end step of enchanted creature's controller, "); - break; + return "At the beginning of the next end step of enchanted creature's controller, "; } - sb.append(getEffects().getText(modes.getMode())); - return sb.toString(); + throw new UnsupportedOperationException("TargetController not supported"); } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/AnyPlayerControlsCondition.java b/Mage/src/main/java/mage/abilities/condition/common/AnyPlayerControlsCondition.java index 3d32a9908c5..22bdf1741a0 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/AnyPlayerControlsCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/AnyPlayerControlsCondition.java @@ -19,6 +19,6 @@ public class AnyPlayerControlsCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0; + return game.getBattlefield().count(filter, source.getControllerId(), source, game) > 0; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/AttachedToMatchesFilterCondition.java b/Mage/src/main/java/mage/abilities/condition/common/AttachedToMatchesFilterCondition.java index 98fefd12798..eca3a8a38dd 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/AttachedToMatchesFilterCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/AttachedToMatchesFilterCondition.java @@ -29,7 +29,7 @@ public class AttachedToMatchesFilterCondition implements Condition { if (attachedTo == null) { attachedTo = (Permanent) game.getLastKnownInformation(permanent.getAttachedTo(), Zone.BATTLEFIELD); } - if (filter.match(attachedTo, attachedTo.getId(), attachedTo.getControllerId(), game)) { + if (filter.match(attachedTo, attachedTo.getControllerId(), source, game)) { return true; } diff --git a/Mage/src/main/java/mage/abilities/condition/common/BlitzedCondition.java b/Mage/src/main/java/mage/abilities/condition/common/BlitzedCondition.java new file mode 100644 index 00000000000..220410a074d --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/BlitzedCondition.java @@ -0,0 +1,21 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.keyword.BlitzAbility; +import mage.game.Game; + +import java.util.List; + +/** + * @author TheElk801 + */ +public enum BlitzedCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + List blitzActivations = (List) game.getState().getValue(BlitzAbility.BLITZ_ACTIVATION_VALUE_KEY + source.getSourceId()); + return blitzActivations != null && blitzActivations.contains(game.getState().getZoneChangeCounter(source.getSourceId())); + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/BuybackCondition.java b/Mage/src/main/java/mage/abilities/condition/common/BuybackCondition.java index e565ea72f3d..f2941a2a5f9 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/BuybackCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/BuybackCondition.java @@ -18,7 +18,7 @@ public enum BuybackCondition implements Condition { Card card = game.getCard(source.getSourceId()); if (card != null) { return card.getAbilities(game).stream() - .filter(a -> a instanceof BuybackAbility) + .filter(BuybackAbility.class::isInstance) .anyMatch(a -> ((BuybackAbility) a).isBuybackActivated(game)); } return false; diff --git a/Mage/src/main/java/mage/abilities/condition/common/CardsInControllerGraveyardCondition.java b/Mage/src/main/java/mage/abilities/condition/common/CardsInControllerGraveyardCondition.java index fa0f86c7913..90b03f8e53f 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/CardsInControllerGraveyardCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/CardsInControllerGraveyardCondition.java @@ -30,7 +30,7 @@ public class CardsInControllerGraveyardCondition implements Condition { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (filter != null) { - return player != null && player.getGraveyard().count(filter, source.getSourceId(), source.getControllerId(), game) >= value; + return player != null && player.getGraveyard().count(filter, source.getControllerId(), source, game) >= value; } return player != null && player.getGraveyard().size() >= value; } diff --git a/Mage/src/main/java/mage/abilities/condition/common/ControlledModifiedCreatureAsSpellCastCondition.java b/Mage/src/main/java/mage/abilities/condition/common/ControlledModifiedCreatureAsSpellCastCondition.java index 5000cbb92a9..4af273a385e 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/ControlledModifiedCreatureAsSpellCastCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/ControlledModifiedCreatureAsSpellCastCondition.java @@ -21,7 +21,7 @@ public enum ControlledModifiedCreatureAsSpellCastCondition implements Condition if (sourceObject == null || watcher == null) { return false; } - return watcher.checkModifiedCondition(new MageObjectReference(sourceObject, game)); + return watcher.getModifiedCreatureCount(new MageObjectReference(sourceObject, game)) > 0; } @Override diff --git a/Mage/src/main/java/mage/abilities/condition/common/ControlsCreatureGreatestPowerCondition.java b/Mage/src/main/java/mage/abilities/condition/common/ControlsCreatureGreatestPowerCondition.java index 8558104f948..f3cf48580de 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/ControlsCreatureGreatestPowerCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/ControlsCreatureGreatestPowerCondition.java @@ -28,7 +28,7 @@ public enum ControlsCreatureGreatestPowerCondition implements Condition { Set controllers = new HashSet<>(); Integer maxPower = null; - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); for (Permanent permanent : permanents) { if (permanent == null) { continue; diff --git a/Mage/src/main/java/mage/abilities/condition/common/ControlsCreatureGreatestToughnessCondition.java b/Mage/src/main/java/mage/abilities/condition/common/ControlsCreatureGreatestToughnessCondition.java index 2e5d8665a48..16ed887a4d7 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/ControlsCreatureGreatestToughnessCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/ControlsCreatureGreatestToughnessCondition.java @@ -27,7 +27,7 @@ public enum ControlsCreatureGreatestToughnessCondition implements Condition { Set controllers = new HashSet<>(); Integer maxToughness = null; - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); for (Permanent permanent : permanents) { if (permanent == null) { continue; diff --git a/Mage/src/main/java/mage/abilities/condition/common/ControlsPermanentGreatestCMCCondition.java b/Mage/src/main/java/mage/abilities/condition/common/ControlsPermanentGreatestCMCCondition.java index 291ec51fa2c..92a533b372e 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/ControlsPermanentGreatestCMCCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/ControlsPermanentGreatestCMCCondition.java @@ -32,7 +32,7 @@ public class ControlsPermanentGreatestCMCCondition implements Condition { Set controllers = new HashSet<>(); Integer maxCMC = null; - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); for (Permanent permanent : permanents) { int cmc = permanent.getManaCost().manaValue(); if (maxCMC == null || cmc > maxCMC) { diff --git a/Mage/src/main/java/mage/abilities/condition/common/CovenCondition.java b/Mage/src/main/java/mage/abilities/condition/common/CovenCondition.java index 63d20df6270..6d2b558ac0b 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/CovenCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/CovenCondition.java @@ -21,7 +21,7 @@ public enum CovenCondition implements Condition { .getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getControllerId(), source.getSourceId(), game + source.getControllerId(), source, game ) .stream() .filter(Objects::nonNull) diff --git a/Mage/src/main/java/mage/abilities/condition/common/CreatedTokenThisTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/CreatedTokenThisTurnCondition.java new file mode 100644 index 00000000000..e8b4ab934d1 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/CreatedTokenThisTurnCondition.java @@ -0,0 +1,30 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.game.Game; +import mage.watchers.common.CreatedTokenWatcher; + +/** + * @author TheElk801 + */ +public enum CreatedTokenThisTurnCondition implements Condition { + instance; + private static final Hint hint = new ConditionHint(instance, "You created a token this turn"); + + public static Hint getHint() { + return hint; + } + + @Override + public boolean apply(Game game, Ability source) { + return CreatedTokenWatcher.checkPlayer(source.getControllerId(), game); + } + + @Override + public String toString() { + return "if you created a token this turn"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/CreatureCountCondition.java b/Mage/src/main/java/mage/abilities/condition/common/CreatureCountCondition.java index 305c0775a5b..8b2faa634e8 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/CreatureCountCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/CreatureCountCondition.java @@ -43,7 +43,7 @@ public class CreatureCountCondition implements Condition { } return true; case ANY: - return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) == creatureCount; + return game.getBattlefield().count(filter, source.getControllerId(), source, game) == creatureCount; default: throw new UnsupportedOperationException("Value for targetController not supported: " + targetController.toString()); } diff --git a/Mage/src/main/java/mage/abilities/condition/common/DashedCondition.java b/Mage/src/main/java/mage/abilities/condition/common/DashedCondition.java index dd7c1e87901..553aef07dd4 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/DashedCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/DashedCondition.java @@ -1,4 +1,3 @@ - package mage.abilities.condition.common; import mage.abilities.Ability; @@ -6,24 +5,21 @@ import mage.abilities.condition.Condition; import mage.abilities.keyword.DashAbility; import mage.cards.Card; import mage.game.Game; +import mage.util.CardUtil; /** * @author LevelX2 */ - public enum DashedCondition implements Condition { - instance; @Override public boolean apply(Game game, Ability source) { Card card = game.getCard(source.getSourceId()); - if (card != null) { - return card.getAbilities(game).stream() - .filter(a -> a instanceof DashAbility) - .anyMatch(d -> ((DashAbility) d).isActivated(source, game)); - - } - return false; + return card != null + && CardUtil.castStream(card + .getAbilities(game) + .stream(), DashAbility.class) + .anyMatch(ability -> ability.isActivated(source, game)); } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/DeliriumCondition.java b/Mage/src/main/java/mage/abilities/condition/common/DeliriumCondition.java index 4e45afbc2b5..3ab16641907 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/DeliriumCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/DeliriumCondition.java @@ -19,7 +19,7 @@ public enum DeliriumCondition implements Condition { @Override public String toString() { - return "if there are four or more card types among cards in your graveyard"; + return "there are four or more card types among cards in your graveyard"; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/DesertControlledOrGraveyardCondition.java b/Mage/src/main/java/mage/abilities/condition/common/DesertControlledOrGraveyardCondition.java new file mode 100644 index 00000000000..dc65cabf0e0 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/DesertControlledOrGraveyardCondition.java @@ -0,0 +1,68 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.hint.Hint; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.game.Game; +import mage.players.Player; + +/** + * @author TheElk801 + */ +public enum DesertControlledOrGraveyardCondition implements Condition { + instance; + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.DESERT); + private static final FilterCard filter2 = new FilterCard(); + + static { + filter2.add(SubType.DESERT.getPredicate()); + } + + @Override + public boolean apply(Game game, Ability source) { + if (game.getBattlefield().contains(filter, source, game, 1)) { + return true; + } + Player player = game.getPlayer(source.getControllerId()); + return player != null && player.getGraveyard().count(filter2, game) > 0; + } + + @Override + public String toString() { + return "you control a Desert or there is a Desert card in your graveyard"; + } + + public static Hint getHint() { + return DesertControlledOrGraveyardHint.instance; + } + + enum DesertControlledOrGraveyardHint implements Hint { + instance; + + @Override + public String getText(Game game, Ability ability) { + StringBuilder sb = new StringBuilder(); + if (game.getBattlefield().contains(filter, ability, game, 1)) { + sb.append("You control a Desert"); + } + Player player = game.getPlayer(ability.getControllerId()); + if (player != null && player.getGraveyard().count(filter2, game) > 0) { + if (sb.length() > 0) { + sb.append("
"); + } + sb.append("You have a Desert card in your graveyard"); + } + return sb.toString(); + } + + @Override + public Hint copy() { + return null; + } + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/DifferentManaValuesInGraveCondition.java b/Mage/src/main/java/mage/abilities/condition/common/DifferentManaValuesInGraveCondition.java new file mode 100644 index 00000000000..7e55bdc07e1 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/DifferentManaValuesInGraveCondition.java @@ -0,0 +1,38 @@ +package mage.abilities.condition.common; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * @author TheElk801 + */ +public enum DifferentManaValuesInGraveCondition implements Condition { + FIVE(5); + private final int amount; + + DifferentManaValuesInGraveCondition(int amount) { + this.amount = amount; + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + return player != null + && player + .getGraveyard() + .getCards(game) + .stream() + .mapToInt(MageObject::getManaValue) + .distinct() + .count() >= amount; + } + + @Override + public String toString() { + return "there are " + CardUtil.numberToText(amount) + " or more mana values among cards in your graveyard"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/EnchantedCreatureColorCondition.java b/Mage/src/main/java/mage/abilities/condition/common/EnchantedCreatureColorCondition.java index 12f62254b4b..66d84ea8c72 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/EnchantedCreatureColorCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/EnchantedCreatureColorCondition.java @@ -30,7 +30,7 @@ public class EnchantedCreatureColorCondition implements Condition { Permanent enchantment = game.getPermanent(source.getSourceId()); if (enchantment != null) { Permanent creature = game.getPermanent(enchantment.getAttachedTo()); - if(filter.match(creature, source.getSourceId(), enchantment.getControllerId(), game)){ + if(filter.match(creature, enchantment.getControllerId(), source, game)){ return true; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/EnchantedCreatureSubtypeCondition.java b/Mage/src/main/java/mage/abilities/condition/common/EnchantedCreatureSubtypeCondition.java index 5aaf26241ab..d290e129e2d 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/EnchantedCreatureSubtypeCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/EnchantedCreatureSubtypeCondition.java @@ -26,7 +26,7 @@ public class EnchantedCreatureSubtypeCondition implements Condition { Permanent enchantment = game.getPermanent(source.getSourceId()); if (enchantment != null) { Permanent creature = game.getPermanent(enchantment.getAttachedTo()); - if (filter.match(creature, source.getSourceId(), enchantment.getControllerId(), game)) { + if (filter.match(creature, enchantment.getControllerId(), source, game)) { return true; } diff --git a/Mage/src/main/java/mage/abilities/condition/common/EvokedCondition.java b/Mage/src/main/java/mage/abilities/condition/common/EvokedCondition.java index 7733f475f7a..99fa5c3eaab 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/EvokedCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/EvokedCondition.java @@ -23,7 +23,7 @@ public enum EvokedCondition implements Condition { Card card = game.getCard(source.getSourceId()); if (card != null) { return card.getAbilities(game).stream() - .filter(ab -> ab instanceof EvokeAbility) + .filter(EvokeAbility.class::isInstance) .anyMatch(evoke -> ((EvokeAbility) evoke).isActivated(source, game)); } return false; diff --git a/Mage/src/main/java/mage/abilities/condition/common/FaceDownSourceCondition.java b/Mage/src/main/java/mage/abilities/condition/common/FaceDownSourceCondition.java index a71db2bb7c7..298610c8ab8 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/FaceDownSourceCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/FaceDownSourceCondition.java @@ -19,7 +19,7 @@ public enum FaceDownSourceCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { if (mageObject instanceof Permanent) { return ((Permanent)mageObject).isFaceDown(game); diff --git a/Mage/src/main/java/mage/abilities/condition/common/MeldCondition.java b/Mage/src/main/java/mage/abilities/condition/common/MeldCondition.java index a0a3f552d20..23cf52129b1 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/MeldCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/MeldCondition.java @@ -32,7 +32,7 @@ public class MeldCondition implements Condition { FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); filter.add(new NamePredicate(this.meldWithName)); filter.add(new OwnerIdPredicate(source.getControllerId())); - return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0; + return game.getBattlefield().count(filter, source.getControllerId(), source, game) > 0; } } return false; diff --git a/Mage/src/main/java/mage/abilities/condition/common/MostCommonColorCondition.java b/Mage/src/main/java/mage/abilities/condition/common/MostCommonColorCondition.java index 1b3c8157387..3992edf70d1 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/MostCommonColorCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/MostCommonColorCondition.java @@ -45,7 +45,7 @@ public class MostCommonColorCondition implements Condition { i = 0; for (ObjectColor color : ObjectColor.getAllColors()) { colorFilters[i].add(new ColorPredicate(color)); - colorCounts[i] = game.getBattlefield().count(colorFilters[i], source.getId(), source.getControllerId(), game); + colorCounts[i] = game.getBattlefield().count(colorFilters[i], source.getControllerId(), source, game); i++; } int max = 0; diff --git a/Mage/src/main/java/mage/abilities/condition/common/OathbreakerOnBattlefieldCondition.java b/Mage/src/main/java/mage/abilities/condition/common/OathbreakerOnBattlefieldCondition.java index ba27bdfbbc8..760a11d893c 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/OathbreakerOnBattlefieldCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/OathbreakerOnBattlefieldCondition.java @@ -63,7 +63,7 @@ public class OathbreakerOnBattlefieldCondition implements Condition { @Override public boolean apply(Game game, Ability source) { // source.getSourceId() is null for commander's effects - int permanentsOnBattlefield = game.getBattlefield().count(this.filter, source.getSourceId(), playerId, game); + int permanentsOnBattlefield = game.getBattlefield().count(this.filter, playerId, source, game); return permanentsOnBattlefield > 0; } diff --git a/Mage/src/main/java/mage/abilities/condition/common/OneOpponentCondition.java b/Mage/src/main/java/mage/abilities/condition/common/OneOpponentCondition.java index 21aac3c45fe..bc63a4a55a1 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/OneOpponentCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/OneOpponentCondition.java @@ -19,6 +19,7 @@ public enum OneOpponentCondition implements Condition { .stream() .map(game::getPlayer) .filter(Objects::nonNull) + .filter(player -> !player.hasLost()) .count() <= 1; } diff --git a/Mage/src/main/java/mage/abilities/condition/common/OpponentControlsPermanentCondition.java b/Mage/src/main/java/mage/abilities/condition/common/OpponentControlsPermanentCondition.java index 25b98e853ca..bf56a6694cb 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/OpponentControlsPermanentCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/OpponentControlsPermanentCondition.java @@ -53,7 +53,7 @@ public class OpponentControlsPermanentCondition implements Condition { for (UUID opponentId : game.getOpponents(source.getControllerId())) { FilterPermanent localFilter = filter.copy(); localFilter.add(new ControllerIdPredicate(opponentId)); - if (ComparisonType.compare(game.getBattlefield().count(localFilter, source.getSourceId(), source.getControllerId(), game), type, this.count)) { + if (ComparisonType.compare(game.getBattlefield().count(localFilter, source.getControllerId(), source, game), type, this.count)) { conditionApplies = true; break; } diff --git a/Mage/src/main/java/mage/abilities/condition/common/PermanentsOnTheBattlefieldCondition.java b/Mage/src/main/java/mage/abilities/condition/common/PermanentsOnTheBattlefieldCondition.java index 0643c27dd8a..d0cfc543586 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/PermanentsOnTheBattlefieldCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/PermanentsOnTheBattlefieldCondition.java @@ -68,7 +68,7 @@ public class PermanentsOnTheBattlefieldCondition implements Condition { localFilter = filter; } return ComparisonType.compare(game.getBattlefield().count( - localFilter, source.getSourceId(), source.getControllerId(), game + localFilter, source.getControllerId(), source, game ), type, count); } diff --git a/Mage/src/main/java/mage/abilities/condition/common/ProwlCostWasPaidCondition.java b/Mage/src/main/java/mage/abilities/condition/common/ProwlCostWasPaidCondition.java index e280ee7ef9b..9060d681514 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/ProwlCostWasPaidCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/ProwlCostWasPaidCondition.java @@ -32,7 +32,7 @@ public enum ProwlCostWasPaidCondition implements Condition { @Override public String toString() { - return "{this}'s prowl cost was paid"; + return "this spell's prowl cost was paid"; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceIsSpellCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceIsSpellCondition.java index 82ef4ea7352..583cedc4a30 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/SourceIsSpellCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/SourceIsSpellCondition.java @@ -17,7 +17,7 @@ instance; @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && !object.isLand(game); } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceMatchesFilterCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceMatchesFilterCondition.java index cfacae4ec2c..ebab226cc5d 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/SourceMatchesFilterCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/SourceMatchesFilterCondition.java @@ -29,7 +29,7 @@ public class SourceMatchesFilterCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId()); - if (FILTER.match(permanent, permanent.getId(), permanent.getControllerId(), game)) { + if (FILTER.match(permanent, permanent.getControllerId(), source, game)) { return true; } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceOnBattlefieldCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceOnBattlefieldCondition.java index 50c334dd2b1..d5b042add5b 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/SourceOnBattlefieldCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/SourceOnBattlefieldCondition.java @@ -1,11 +1,9 @@ - package mage.abilities.condition.common; import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.game.Game; - /** * As long as the sourceId permanent is * on the battlefield, the condition is true. @@ -13,18 +11,15 @@ import mage.game.Game; * @author LevelX2 */ public enum SourceOnBattlefieldCondition implements Condition { - instance; - + @Override public boolean apply(Game game, Ability source) { - return (game.getPermanent(source.getSourceId()) != null); + return source.getSourcePermanentIfItStillExists(game) != null; } @Override public String toString() { return "if {this} is on the battlefield"; } - - } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceTargetsPermanentCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceTargetsPermanentCondition.java index 545518e6efa..b8558deb31a 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/SourceTargetsPermanentCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/SourceTargetsPermanentCondition.java @@ -30,7 +30,7 @@ public class SourceTargetsPermanentCondition implements Condition { Iterator targets = sourceSpell.getStackAbility().getTargets().iterator(); while (targets.hasNext()) { Permanent permanent = game.getPermanentOrLKIBattlefield(targets.next().getFirstTarget()); - if (filter.match(permanent, source.getSourceId(), source.getControllerId(), game)) { + if (filter.match(permanent, source.getControllerId(), source, game)) { return true; } } diff --git a/Mage/src/main/java/mage/abilities/costs/AlternativeCost2.java b/Mage/src/main/java/mage/abilities/costs/AlternativeCost.java similarity index 91% rename from Mage/src/main/java/mage/abilities/costs/AlternativeCost2.java rename to Mage/src/main/java/mage/abilities/costs/AlternativeCost.java index 767c3d3c1b9..c951ac81a36 100644 --- a/Mage/src/main/java/mage/abilities/costs/AlternativeCost2.java +++ b/Mage/src/main/java/mage/abilities/costs/AlternativeCost.java @@ -9,8 +9,8 @@ import mage.game.Game; * * @author LevelX2 */ -public interface AlternativeCost2 extends Cost { - +public interface AlternativeCost extends Cost { + String getName(); /** @@ -41,13 +41,11 @@ public interface AlternativeCost2 extends Cost { /** * If the player intends to pay the alternate cost, the cost will be activated - * */ void activate(); /** - * Reset the activate - * + * Reset the activate */ void reset(); @@ -61,4 +59,6 @@ public interface AlternativeCost2 extends Cost { Cost getCost(); + @Override + AlternativeCost copy(); } diff --git a/Mage/src/main/java/mage/abilities/costs/AlternativeCost2Impl.java b/Mage/src/main/java/mage/abilities/costs/AlternativeCostImpl.java similarity index 67% rename from Mage/src/main/java/mage/abilities/costs/AlternativeCost2Impl.java rename to Mage/src/main/java/mage/abilities/costs/AlternativeCostImpl.java index 5b5b81c4bff..577083d2aec 100644 --- a/Mage/src/main/java/mage/abilities/costs/AlternativeCost2Impl.java +++ b/Mage/src/main/java/mage/abilities/costs/AlternativeCostImpl.java @@ -1,43 +1,36 @@ - package mage.abilities.costs; +import mage.abilities.costs.mana.ManaCost; import mage.game.Game; /** * Alternative costs * - * @author LevelX2 - * * @param + * @author LevelX2 */ -public class AlternativeCost2Impl> extends CostsImpl implements AlternativeCost2 { +public class AlternativeCostImpl> extends CostsImpl implements AlternativeCost { protected String name; - protected String reminderText; - protected String delimiter; + protected final String reminderText; + protected boolean isMana; protected boolean activated; - public AlternativeCost2Impl(String name, String reminderText, Cost cost) { - this(name, " ", reminderText, cost); - } - - public AlternativeCost2Impl(String name, String delimiter, String reminderText, Cost cost) { + public AlternativeCostImpl(String name, String reminderText, Cost cost) { this.activated = false; this.name = name; - this.delimiter = delimiter; - if (reminderText != null) { - this.reminderText = "" + reminderText + ""; - } + this.isMana = cost instanceof ManaCost; + this.reminderText = reminderText; this.add(cost); } - public AlternativeCost2Impl(final AlternativeCost2Impl cost) { + public AlternativeCostImpl(final AlternativeCostImpl cost) { super(cost); this.name = cost.name; this.reminderText = cost.reminderText; this.activated = cost.activated; - this.delimiter = cost.delimiter; + this.isMana = cost.isMana; } @Override @@ -57,7 +50,7 @@ public class AlternativeCost2Impl> extends Cos if (onlyCost) { return getText(); } else { - return (name != null ? name : "") + (delimiter != null ? delimiter : "") + getText(); + return (name != null ? name : "") + (isMana ? " " : "—") + getText() + (isMana ? "" : '.'); } } @@ -68,11 +61,10 @@ public class AlternativeCost2Impl> extends Cos */ @Override public String getReminderText() { - String replace = ""; if (reminderText != null && !reminderText.isEmpty()) { - replace = reminderText.replace("{cost}", this.getText(true)); + return "(" + reminderText.replace("{cost}", this.getText(true)) + ")"; } - return replace; + return ""; } /** @@ -80,7 +72,7 @@ public class AlternativeCost2Impl> extends Cos * message. * * @param position - if there are multiple costs, it's the postion the cost - * is set (starting with 0) + * is set (starting with 0) * @return */ @Override @@ -92,7 +84,6 @@ public class AlternativeCost2Impl> extends Cos /** * If the player intends to pay the cost, the cost will be activated - * */ @Override public void activate() { @@ -101,7 +92,6 @@ public class AlternativeCost2Impl> extends Cos /** * Reset the activate and count information - * */ @Override public void reset() { @@ -120,8 +110,8 @@ public class AlternativeCost2Impl> extends Cos } @Override - public AlternativeCost2Impl copy() { - return new AlternativeCost2Impl(this); + public AlternativeCostImpl copy() { + return new AlternativeCostImpl<>(this); } @Override @@ -131,5 +121,4 @@ public class AlternativeCost2Impl> extends Cos } return null; } - } diff --git a/Mage/src/main/java/mage/abilities/costs/AlternativeCostSourceAbility.java b/Mage/src/main/java/mage/abilities/costs/AlternativeCostSourceAbility.java index 53d22aa3918..ad40cf39052 100644 --- a/Mage/src/main/java/mage/abilities/costs/AlternativeCostSourceAbility.java +++ b/Mage/src/main/java/mage/abilities/costs/AlternativeCostSourceAbility.java @@ -16,6 +16,7 @@ import mage.util.CardUtil; import java.util.Iterator; import java.util.UUID; +import java.util.stream.Collectors; /** * @author LevelX2 @@ -24,7 +25,7 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter private static final String ALTERNATIVE_COST_ACTIVATION_KEY = "AlternativeCostActivated"; - private Costs alternateCosts = new CostsImpl<>(); + private Costs alternateCosts = new CostsImpl<>(); protected Condition condition; protected String rule; protected FilterCard filter; @@ -88,15 +89,15 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter @Override public void addCost(Cost cost) { - AlternativeCost2 alternativeCost = convertToAlternativeCost(cost); + AlternativeCost alternativeCost = convertToAlternativeCost(cost); if (alternativeCost != null) { this.alternateCosts.add(alternativeCost); } } - private AlternativeCost2 convertToAlternativeCost(Cost cost) { + private AlternativeCost convertToAlternativeCost(Cost cost) { //return cost != null ? new AlternativeCost2Impl(null, cost.getText(), cost) : null; - return cost != null ? new AlternativeCost2Impl(null, "", "", cost) : null; + return cost != null ? new AlternativeCostImpl(null, "", cost) : null; } @Override @@ -117,13 +118,13 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter if (ability != null && AbilityType.SPELL == ability.getAbilityType()) { if (filter != null) { Card card = game.getCard(ability.getSourceId()); - if (!filter.match(card, ability.getSourceId(), ability.getControllerId(), game)) { + if (!filter.match(card, ability.getControllerId(), ability, game)) { return false; } } Player player = game.getPlayer(ability.getControllerId()); if (player != null) { - Costs alternativeCostsToCheck; + Costs alternativeCostsToCheck; if (dynamicCost != null) { alternativeCostsToCheck = new CostsImpl<>(); alternativeCostsToCheck.add(convertToAlternativeCost(dynamicCost.getCost(ability, game))); @@ -140,7 +141,7 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter if (alternativeCostsToCheck.canPay(ability, ability, ability.getControllerId(), game) && player.chooseUse(Outcome.Benefit, costChoiceText, this, game)) { if (ability instanceof SpellAbility) { - ability.getManaCostsToPay().removeIf(manaCost -> manaCost instanceof VariableCost); + ability.getManaCostsToPay().removeIf(VariableCost.class::isInstance); CardUtil.reduceCost((SpellAbility) ability, ability.getManaCosts()); } else { @@ -149,7 +150,7 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter if (!onlyMana) { ability.getCosts().clear(); } - for (AlternativeCost2 alternateCost : alternativeCostsToCheck) { + for (AlternativeCost alternateCost : alternativeCostsToCheck) { alternateCost.activate(); for (Iterator it = ((Costs) alternateCost).iterator(); it.hasNext(); ) { Cost costDetailed = (Cost) it.next(); @@ -207,14 +208,14 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter @Override public boolean isActivated(Ability source, Game game) { - Costs alternativeCostsToCheck; + Costs alternativeCostsToCheck; if (dynamicCost != null) { alternativeCostsToCheck = new CostsImpl<>(); alternativeCostsToCheck.add(convertToAlternativeCost(dynamicCost.getCost(source, game))); } else { alternativeCostsToCheck = this.alternateCosts; } - for (AlternativeCost2 cost : alternativeCostsToCheck) { + for (AlternativeCost cost : alternativeCostsToCheck) { if (cost.isActivated(game)) { return true; } @@ -227,6 +228,11 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter return alternateCosts.isEmpty() ? " without paying its mana costs" : " using alternative casting costs"; } + @Override + public void resetCost() { + + } + @Override public String getRule() { if (rule != null) { @@ -245,23 +251,13 @@ public class AlternativeCostSourceAbility extends StaticAbility implements Alter } int numberCosts = 0; String remarkText = ""; - for (AlternativeCost2 alternativeCost : alternateCosts) { - if (numberCosts == 0) { - if (alternativeCost.getCost() instanceof ManaCost) { - sb.append("pay "); - } - sb.append(alternativeCost.getText(false)); - remarkText = alternativeCost.getReminderText(); - } else { - sb.append(" and "); - if (alternativeCost.getCost() instanceof ManaCost) { - sb.append("pay "); - } - String text = alternativeCost.getText(true); - sb.append(Character.toLowerCase(text.charAt(0))).append(text.substring(1)); - } - ++numberCosts; - } + sb.append(CardUtil.concatWithAnd(alternateCosts + .stream() + .map(cost -> cost.getCost() instanceof ManaCost + ? "pay " + cost.getText(true) + : cost.getText(true)) + .map(CardUtil::getTextWithFirstCharLowerCase) + .collect(Collectors.toList()))); if (condition == null || alternateCosts.size() == 1) { sb.append(" rather than pay this spell's mana cost"); } else if (alternateCosts.isEmpty()) { diff --git a/Mage/src/main/java/mage/abilities/costs/AlternativeSourceCosts.java b/Mage/src/main/java/mage/abilities/costs/AlternativeSourceCosts.java index 474bf1bfeaf..14a4737aec7 100644 --- a/Mage/src/main/java/mage/abilities/costs/AlternativeSourceCosts.java +++ b/Mage/src/main/java/mage/abilities/costs/AlternativeSourceCosts.java @@ -1,4 +1,3 @@ - package mage.abilities.costs; import mage.abilities.Ability; @@ -6,7 +5,7 @@ import mage.game.Game; /** * Interface for abilities that add alternative costs to the source. - * + *

* Example of such additional source costs: {@link mage.abilities.keyword.KickerAbility} * * @author LevelX2 @@ -15,35 +14,38 @@ public interface AlternativeSourceCosts { /** * Ask the player if they want to use the alternative costs - * + * * @param ability ability the alternative cost is activated for * @param game - * @return + * @return */ boolean askToActivateAlternativeCosts(Ability ability, Game game); - + /** * Is the alternative spell cost currently available - * + * * @param source spell ability the alternative costs can be paid for * @param game - * @return + * @return */ boolean isAvailable(Ability source, Game game); - + /** * Was the alternative cost activated + * * @param game * @param source * @return */ boolean isActivated(Ability source, Game game); - + /** * Suffix string to use for game log + * * @param game - * @return + * @return */ - String getCastMessageSuffix(Game game); - + String getCastMessageSuffix(Game game); + + void resetCost(); } \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/costs/AlternativeSourceCostsImpl.java b/Mage/src/main/java/mage/abilities/costs/AlternativeSourceCostsImpl.java new file mode 100644 index 00000000000..b3c92c197ff --- /dev/null +++ b/Mage/src/main/java/mage/abilities/costs/AlternativeSourceCostsImpl.java @@ -0,0 +1,116 @@ +package mage.abilities.costs; + +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.StaticAbility; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.cards.Card; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +import java.util.Iterator; + +/** + * @author TheElk801 + */ +public abstract class AlternativeSourceCostsImpl extends StaticAbility implements AlternativeSourceCosts { + + protected final AlternativeCost alternativeCost; + protected final String reminderText; + private int zoneChangeCounter = 0; + + protected AlternativeSourceCostsImpl(String name, String reminderText, String manaString) { + this(name, reminderText, new ManaCostsImpl<>(manaString)); + } + + protected AlternativeSourceCostsImpl(String name, String reminderText, Cost cost) { + super(Zone.ALL, null); + this.name = name; + this.reminderText = reminderText; + this.alternativeCost = new AlternativeCostImpl<>(name, reminderText, cost); + } + + protected AlternativeSourceCostsImpl(final AlternativeSourceCostsImpl ability) { + super(ability); + this.alternativeCost = ability.alternativeCost.copy(); + this.reminderText = ability.reminderText; + this.zoneChangeCounter = ability.zoneChangeCounter; + } + + @Override + public boolean askToActivateAlternativeCosts(Ability ability, Game game) { + if (ability instanceof SpellAbility) { + handleActivatingAlternativeCosts(ability, game); + } + return isActivated(ability, game); + } + + protected boolean handleActivatingAlternativeCosts(Ability ability, Game game) { + Player player = game.getPlayer(ability.getControllerId()); + if (player == null) { + return false; + } + this.resetCost(); + if (!alternativeCost.canPay(ability, this, player.getId(), game) + || !player.chooseUse(Outcome.Benefit, "Cast this for its " + this.name + " cost? (" + alternativeCost.getText(true) + ')', ability, game)) { + return false; + } + alternativeCost.activate(); + if (zoneChangeCounter == 0) { + Card card = game.getCard(getSourceId()); + if (card != null) { + zoneChangeCounter = card.getZoneChangeCounter(game); + } else { + throw new IllegalArgumentException("source card not found"); + } + } + ability.getManaCostsToPay().clear(); + ability.getCosts().clear(); + for (Iterator it = ((Costs) alternativeCost).iterator(); it.hasNext(); ) { + Cost cost = it.next(); + if (cost instanceof ManaCost) { + ability.getManaCostsToPay().add((ManaCost) cost.copy()); + } else { + ability.getCosts().add(cost.copy()); + } + } + return true; + } + + @Override + public boolean isActivated(Ability ability, Game game) { + Card card = game.getCard(sourceId); + if (card != null && card.getZoneChangeCounter(game) <= zoneChangeCounter + 1) { + return alternativeCost.isActivated(game); + } + return false; + } + + @Override + public Costs getCosts() { + return (Costs) alternativeCost; + } + + @Override + public String getRule() { + return alternativeCost.getText(false) + ' ' + alternativeCost.getReminderText(); + } + + @Override + public void resetCost() { + alternativeCost.reset(); + this.zoneChangeCounter = 0; + } + + @Override + public boolean isAvailable(Ability source, Game game) { + return true; + } + + public String getCastMessageSuffix(Game game) { + return alternativeCost.getCastSuffixMessage(0); + } +} diff --git a/Mage/src/main/java/mage/abilities/costs/CostAdjuster.java b/Mage/src/main/java/mage/abilities/costs/CostAdjuster.java index b7bc0d23a50..ea1d77449d0 100644 --- a/Mage/src/main/java/mage/abilities/costs/CostAdjuster.java +++ b/Mage/src/main/java/mage/abilities/costs/CostAdjuster.java @@ -3,10 +3,13 @@ package mage.abilities.costs; import mage.abilities.Ability; import mage.game.Game; +import java.io.Serializable; + /** * @author TheElk801 */ -public interface CostAdjuster { +@FunctionalInterface +public interface CostAdjuster extends Serializable { /** * Must check playable and real cast states. diff --git a/Mage/src/main/java/mage/abilities/costs/OrCost.java b/Mage/src/main/java/mage/abilities/costs/OrCost.java index c040438282d..9ab8c989acb 100644 --- a/Mage/src/main/java/mage/abilities/costs/OrCost.java +++ b/Mage/src/main/java/mage/abilities/costs/OrCost.java @@ -1,32 +1,32 @@ - package mage.abilities.costs; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCost; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; import mage.target.Targets; -import java.util.UUID; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; public class OrCost implements Cost { - private final Cost firstCost; - private final Cost secondCost; + private final List costs = new ArrayList<>(); private String description; // which cost was slected to pay private Cost selectedCost; - public OrCost(Cost firstCost, Cost secondCost, String description) { - this.firstCost = firstCost; - this.secondCost = secondCost; + public OrCost(String description, Cost... costs) { + Collections.addAll(this.costs, costs); this.description = description; } public OrCost(final OrCost cost) { - this.firstCost = cost.firstCost.copy(); - this.secondCost = cost.secondCost.copy(); + cost.costs.stream().map(Cost::copy).forEach(this.costs::add); this.description = cost.description; this.selectedCost = cost.selectedCost; } @@ -49,7 +49,7 @@ public class OrCost implements Cost { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return firstCost.canPay(ability, source, controllerId, game) || secondCost.canPay(ability, source, controllerId, game); + return costs.stream().anyMatch(cost -> cost.canPay(ability, source, controllerId, game)); } @Override @@ -60,28 +60,47 @@ public class OrCost implements Cost { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { selectedCost = null; - // if only one can be paid select it - if (!firstCost.canPay(ability, source, controllerId, game)) { - selectedCost = secondCost; + List usable = costs + .stream() + .filter(cost -> cost.canPay(ability, source, controllerId, game)) + .collect(Collectors.toList()); + Player controller = game.getPlayer(controllerId); + if (controller == null) { + return false; } - if (!secondCost.canPay(ability, source, controllerId, game)) { - selectedCost = firstCost; - } - // if both can be paid player has to select - if (selectedCost == null) { - Player controller = game.getPlayer(controllerId); - if (controller != null) { + switch (usable.size()) { + case 0: + return false; + case 1: + selectedCost = usable.get(0); + break; + case 2: StringBuilder sb = new StringBuilder(); - if (firstCost instanceof ManaCost) { + if (usable.get(0) instanceof ManaCost) { sb.append("Pay "); } - sb.append(firstCost.getText()).append('?'); - if (controller.chooseUse(Outcome.Detriment, sb.toString(), ability, game)) { - selectedCost = firstCost; + sb.append(usable.get(0).getText()); + sb.append(" or "); + sb.append(usable.get(1)); + sb.append('?'); + if (controller.chooseUse( + Outcome.Detriment, sb.toString(), null, + usable.get(0).getText(), usable.get(1).getText(), ability, game + )) { + selectedCost = usable.get(0); } else { - selectedCost = secondCost; + selectedCost = usable.get(1); } - } + break; + default: + Map costMap = usable + .stream() + .collect(Collectors.toMap(Cost::getText, Function.identity())); + Choice choice = new ChoiceImpl(true); + choice.setMessage("Choose a cost to pay"); + choice.setChoices(costMap.keySet()); + controller.choose(Outcome.Neutral, choice, game); + selectedCost = costMap.getOrDefault(choice.getChoice(), null); } if (selectedCost == null) { return false; @@ -92,17 +111,13 @@ public class OrCost implements Cost { @Override public boolean isPaid() { - if (selectedCost != null) { - return selectedCost.isPaid(); - } - return false; + return selectedCost != null ? selectedCost.isPaid() : false; } @Override public void clearPaid() { selectedCost = null; - firstCost.clearPaid(); - secondCost.clearPaid(); + costs.stream().forEach(Cost::clearPaid); } @Override diff --git a/Mage/src/main/java/mage/abilities/costs/UseAttachedCost.java b/Mage/src/main/java/mage/abilities/costs/UseAttachedCost.java index e0c98170d7b..785a4e278fc 100644 --- a/Mage/src/main/java/mage/abilities/costs/UseAttachedCost.java +++ b/Mage/src/main/java/mage/abilities/costs/UseAttachedCost.java @@ -41,7 +41,7 @@ public abstract class UseAttachedCost extends CostImpl { public UseAttachedCost setMageObjectReference(Ability source, Game game) { this.mageObjectReference = new MageObjectReference(source.getSourceId(), game); - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object != null) { this.name = object.getName(); } diff --git a/Mage/src/main/java/mage/abilities/costs/common/ControlPermanentCost.java b/Mage/src/main/java/mage/abilities/costs/common/ControlPermanentCost.java deleted file mode 100644 index ad5d3f50838..00000000000 --- a/Mage/src/main/java/mage/abilities/costs/common/ControlPermanentCost.java +++ /dev/null @@ -1,39 +0,0 @@ -package mage.abilities.costs.common; - -import mage.abilities.Ability; -import mage.abilities.costs.Cost; -import mage.abilities.costs.CostImpl; -import mage.filter.common.FilterControlledPermanent; -import mage.game.Game; - -import java.util.UUID; - -public class ControlPermanentCost extends CostImpl { - private final FilterControlledPermanent filter; - - public ControlPermanentCost(FilterControlledPermanent filter) { - this.filter = filter.copy(); - this.text = "Activate only if you control " + filter.getMessage(); - } - - public ControlPermanentCost(final ControlPermanentCost cost) { - super(cost); - this.filter = cost.filter.copy(); - } - - @Override - public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return game.getBattlefield().containsControlled(filter, source.getSourceId(), controllerId, game, 1); - } - - @Override - public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - this.paid = true; - return paid; - } - - @Override - public ControlPermanentCost copy() { - return new ControlPermanentCost(this); - } -} diff --git a/Mage/src/main/java/mage/abilities/costs/common/DiscardTargetCost.java b/Mage/src/main/java/mage/abilities/costs/common/DiscardTargetCost.java index 0711f3e0aad..4ff17c8dbbb 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/DiscardTargetCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/DiscardTargetCost.java @@ -50,7 +50,7 @@ public class DiscardTargetCost extends CostImpl { int amount = this.getTargets().get(0).getNumberOfTargets(); if (randomDiscard) { this.cards.addAll(player.discard(amount, true, true, source, game).getCards(game)); - } else if (targets.choose(Outcome.Discard, controllerId, source.getSourceId(), game)) { + } else if (targets.choose(Outcome.Discard, controllerId, source.getSourceId(), source, game)) { Cards toDiscard = new CardsImpl(); toDiscard.addAll(targets.get(0).getTargets()); Cards discarded = player.discard(toDiscard, true, source, game); @@ -71,7 +71,7 @@ public class DiscardTargetCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileFromGraveCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileFromGraveCost.java index e8cda8f583c..f8e810dc117 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileFromGraveCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileFromGraveCost.java @@ -78,7 +78,7 @@ public class ExileFromGraveCost extends CostImpl { public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { - if (targets.choose(Outcome.Exile, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.Exile, controllerId, source.getSourceId(), source, game)) { for (UUID targetId : targets.get(0).getTargets()) { Card card = game.getCard(targetId); if (card == null @@ -106,7 +106,7 @@ public class ExileFromGraveCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileFromHandCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileFromHandCost.java index 8d3f1a3228a..5e88fdfcd6a 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileFromHandCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileFromHandCost.java @@ -51,7 +51,7 @@ public class ExileFromHandCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - if (targets.choose(Outcome.Exile, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.Exile, controllerId, source.getSourceId(), source, game)) { Player player = game.getPlayer(controllerId); int cmc = 0; for (UUID targetId : targets.get(0).getTargets()) { @@ -81,7 +81,7 @@ public class ExileFromHandCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileSourceCost.java index 1531dfb7ae1..772ab5be3a9 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileSourceCost.java @@ -1,63 +1,47 @@ - package mage.abilities.costs.common; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.cards.Card; +import mage.constants.Zone; import mage.game.Game; import mage.players.Player; -import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public class ExileSourceCost extends CostImpl { - private boolean toUniqueExileZone; - + /** + * @param toUniqueExileZone moves the card to a source object dependant + * unique exile zone, so another effect of the same source object (e.g. + * Deadeye Navigator) can identify the card + */ public ExileSourceCost() { this.text = "exile {this}"; } - /** - * - * @param toUniqueExileZone moves the card to a source object dependant - * unique exile zone, so another effect of the same source object (e.g. - * Deadeye Navigator) can identify the card - */ - public ExileSourceCost(boolean toUniqueExileZone) { - this.text = "exile {this}"; - this.toUniqueExileZone = toUniqueExileZone; - } - public ExileSourceCost(ExileSourceCost cost) { super(cost); - this.toUniqueExileZone = cost.toUniqueExileZone; } @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { MageObject sourceObject = ability.getSourceObject(game); Player controller = game.getPlayer(controllerId); - if (controller != null && sourceObject instanceof Card) { - UUID exileZoneId = null; - String exileZoneName = ""; - if (toUniqueExileZone) { - exileZoneId = CardUtil.getExileZoneId(game, ability.getSourceId(), ability.getSourceObjectZoneChangeCounter()); - exileZoneName = sourceObject.getName(); - game.getState().setValue(sourceObject.getId().toString(), ability.getSourceObjectZoneChangeCounter()); - } - controller.moveCardToExileWithInfo((Card) sourceObject, exileZoneId, exileZoneName, source, game, game.getState().getZone(sourceObject.getId()), true); - // 117.11. The actions performed when paying a cost may be modified by effects. - // Even if they are, meaning the actions that are performed don't match the actions - // that are called for, the cost has still been paid. - // so return state here is not important because the user indended to exile the target anyway - paid = true; + if (controller == null || !(sourceObject instanceof Card)) { + return paid; } + controller.moveCards((Card) sourceObject, Zone.EXILED, source, game); + // 117.11. The actions performed when paying a cost may be modified by effects. + // Even if they are, meaning the actions that are performed don't match the actions + // that are called for, the cost has still been paid. + // so return state here is not important because the user indended to exile the target anyway + paid = true; return paid; } @@ -70,5 +54,4 @@ public class ExileSourceCost extends CostImpl { public ExileSourceCost copy() { return new ExileSourceCost(this); } - } diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileSourceFromGraveCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileSourceFromGraveCost.java index e6dcf15e195..51fad57ba09 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileSourceFromGraveCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileSourceFromGraveCost.java @@ -1,7 +1,5 @@ - package mage.abilities.costs.common; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; @@ -10,8 +8,9 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author magenoxx_at_gmail.com */ public class ExileSourceFromGraveCost extends CostImpl { @@ -20,36 +19,36 @@ public class ExileSourceFromGraveCost extends CostImpl { this.text = "exile {this} from your graveyard"; } - public ExileSourceFromGraveCost(ExileSourceFromGraveCost cost) { + private ExileSourceFromGraveCost(final ExileSourceFromGraveCost cost) { super(cost); } @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); - if (controller != null) { - Card card = game.getCard(source.getSourceId()); - if (card != null && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) { - controller.moveCardToExileWithInfo(card, null, "", source, game, Zone.GRAVEYARD, true); - // 117.11. The actions performed when paying a cost may be modified by effects. - // Even if they are, meaning the actions that are performed don't match the actions - // that are called for, the cost has still been paid. - // so return state here is not important because the user indended to exile the target anyway - paid = true; - } + if (controller == null) { + return paid; + } + Card card = game.getCard(source.getSourceId()); + if (card != null && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) { + controller.moveCards(card, Zone.EXILED, source, game); + // 117.11. The actions performed when paying a cost may be modified by effects. + // Even if they are, meaning the actions that are performed don't match the actions + // that are called for, the cost has still been paid. + // so return state here is not important because the user indended to exile the target anyway + paid = true; } return paid; } @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - Card card = game.getCard(source.getSourceId()); - return card != null && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD; + return game.getCard(source.getSourceId()) != null + && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD; } @Override public ExileSourceFromGraveCost copy() { return new ExileSourceFromGraveCost(this); } - } diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileSourceFromHandCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileSourceFromHandCost.java index 8d6ba5bc718..40ba91a5f36 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileSourceFromHandCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileSourceFromHandCost.java @@ -1,5 +1,6 @@ package mage.abilities.costs.common; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; @@ -29,6 +30,7 @@ public class ExileSourceFromHandCost extends CostImpl { Card card = game.getCard(source.getSourceId()); if (player != null && player.getHand().contains(source.getSourceId()) && card != null) { paid = player.moveCards(card, Zone.EXILED, source, game); + source.getEffects().setValue("exiledHandCardRef", new MageObjectReference(card, game)); } return paid; } diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileTargetCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileTargetCost.java index 551fd5909fc..541a63ebf86 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileTargetCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileTargetCost.java @@ -2,20 +2,23 @@ package mage.abilities.costs.common; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.Outcome; -import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.common.TargetControlledPermanent; +import mage.util.CardUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; /** - * * @author emerald000 */ public class ExileTargetCost extends CostImpl { @@ -26,41 +29,49 @@ public class ExileTargetCost extends CostImpl { this.addTarget(target); this.text = "Exile " + target.getTargetName(); } - + public ExileTargetCost(TargetControlledPermanent target, boolean noText) { this.addTarget(target); } public ExileTargetCost(ExileTargetCost cost) { super(cost); - for (Permanent permanent: cost.permanents) { + for (Permanent permanent : cost.permanents) { this.permanents.add(permanent.copy()); } } @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - if (targets.choose(Outcome.Exile, controllerId, source.getSourceId(), game)) { - for (UUID targetId: targets.get(0).getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent == null) { - return false; - } - permanents.add(permanent.copy()); - // 117.11. The actions performed when paying a cost may be modified by effects. - // Even if they are, meaning the actions that are performed don't match the actions - // that are called for, the cost has still been paid. - // so return state here is not important because the user indended to exile the target anyway - game.getPlayer(ability.getControllerId()).moveCardToExileWithInfo(permanent, null, null, source, game, Zone.BATTLEFIELD, true); - } - paid = true; + Player player = game.getPlayer(ability.getControllerId()); + if (player == null || !targets.choose(Outcome.Exile, controllerId, source.getSourceId(), source, game)) { + return paid; } + Cards cards = new CardsImpl(); + for (UUID targetId : targets.get(0).getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent == null) { + return false; + } + cards.add(permanent); + permanents.add(permanent.copy()); + // 117.11. The actions performed when paying a cost may be modified by effects. + // Even if they are, meaning the actions that are performed don't match the actions + // that are called for, the cost has still been paid. + // so return state here is not important because the user indended to exile the target anyway + } + player.moveCardsToExile( + cards.getCards(game), source, game, false, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + paid = true; return paid; } @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override @@ -71,5 +82,4 @@ public class ExileTargetCost extends CostImpl { public List getPermanents() { return permanents; } - } diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileTopCardOfGraveyardCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileTopCardOfGraveyardCost.java index 9784495831c..417910fd555 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileTopCardOfGraveyardCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileTopCardOfGraveyardCost.java @@ -1,6 +1,5 @@ package mage.abilities.costs.common; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; @@ -9,45 +8,40 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author fireshoes */ public class ExileTopCardOfGraveyardCost extends CostImpl { - private final int amount; - - public ExileTopCardOfGraveyardCost(int amount) { - this.amount = amount; + public ExileTopCardOfGraveyardCost() { this.text = "Exile the top card of your graveyard"; } - public ExileTopCardOfGraveyardCost(ExileTopCardOfGraveyardCost cost) { + private ExileTopCardOfGraveyardCost(final ExileTopCardOfGraveyardCost cost) { super(cost); - this.amount = cost.amount; } @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { Player controller = game.getPlayer(controllerId); - if(controller == null) { + if (controller == null) { return false; } - return controller.getGraveyard().size() >= amount; + return !controller.getGraveyard().isEmpty(); } @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); - if(controller != null) { - Card topCard = null; - for (Card card :controller.getGraveyard().getCards(game)) { - topCard = card; - } - if (topCard != null) { - controller.moveCardToExileWithInfo(topCard, null, "", source, game, Zone.GRAVEYARD, true); - paid = true; - } + if (controller == null) { + return paid; + } + Card topCard = controller.getGraveyard().getTopCard(game); + if (topCard != null) { + controller.moveCards(topCard, Zone.EXILED, source, game); + paid = true; } return paid; } @@ -56,4 +50,4 @@ public class ExileTopCardOfGraveyardCost extends CostImpl { public ExileTopCardOfGraveyardCost copy() { return new ExileTopCardOfGraveyardCost(this); } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileTopCreatureCardOfGraveyardCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileTopCreatureCardOfGraveyardCost.java index 94e1e91fd00..acaac231f6a 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ExileTopCreatureCardOfGraveyardCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileTopCreatureCardOfGraveyardCost.java @@ -1,6 +1,5 @@ package mage.abilities.costs.common; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; @@ -9,8 +8,9 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author fireshoes */ public class ExileTopCreatureCardOfGraveyardCost extends CostImpl { @@ -30,7 +30,7 @@ public class ExileTopCreatureCardOfGraveyardCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { Player controller = game.getPlayer(controllerId); - if(controller == null) { + if (controller == null) { return false; } return controller.getGraveyard().size() >= amount; @@ -39,17 +39,19 @@ public class ExileTopCreatureCardOfGraveyardCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); - if(controller != null) { - Card topCard = null; - for (Card card :controller.getGraveyard().getCards(game)) { - if (card.isCreature(game)) { - topCard = card; - } - } - if (topCard != null) { - controller.moveCardToExileWithInfo(topCard, null, "", source, game, Zone.GRAVEYARD, true); - paid = true; - } + if (controller == null) { + return paid; + } + Card topCard = controller + .getGraveyard() + .getCards(game) + .stream() + .filter(card -> card.isCreature(game)) + .findFirst() + .orElse(null); + if (topCard != null) { + controller.moveCards(topCard, Zone.EXILED, source, game); + paid = true; } return paid; } diff --git a/Mage/src/main/java/mage/abilities/costs/common/PayEnergyCost.java b/Mage/src/main/java/mage/abilities/costs/common/PayEnergyCost.java index e2462f3a25f..75e11fa4214 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/PayEnergyCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/PayEnergyCost.java @@ -49,7 +49,7 @@ public class PayEnergyCost extends CostImpl { } private void setText() { - StringBuilder sb = new StringBuilder("Pay "); + StringBuilder sb = new StringBuilder("pay "); for (int i = 0; i < amount; i++) { sb.append("{E}"); } diff --git a/Mage/src/main/java/mage/abilities/costs/common/PayLoyaltyCost.java b/Mage/src/main/java/mage/abilities/costs/common/PayLoyaltyCost.java index 65e5fccbbcb..2b8885471c0 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/PayLoyaltyCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/PayLoyaltyCost.java @@ -38,7 +38,7 @@ public class PayLoyaltyCost extends CostImpl { // apply cost modification if (ability instanceof LoyaltyAbility) { LoyaltyAbility copiedAbility = ((LoyaltyAbility) ability).copy(); - planeswalker.adjustCosts(copiedAbility, game); + copiedAbility.adjustCosts(game); game.getContinuousEffects().costModification(copiedAbility, game); loyaltyCost = 0; for (Cost cost : copiedAbility.getCosts()) { diff --git a/Mage/src/main/java/mage/abilities/costs/common/PayVariableLoyaltyCost.java b/Mage/src/main/java/mage/abilities/costs/common/PayVariableLoyaltyCost.java index b1cacfecfa0..ca1a04dc04d 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/PayVariableLoyaltyCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/PayVariableLoyaltyCost.java @@ -62,7 +62,7 @@ public class PayVariableLoyaltyCost extends VariableCostImpl { // apply cost modification if (source instanceof LoyaltyAbility) { LoyaltyAbility copiedAbility = ((LoyaltyAbility) source).copy(); - permanent.adjustCosts(copiedAbility, game); + copiedAbility.adjustCosts(game); game.getContinuousEffects().costModification(copiedAbility, game); for (Cost cost : copiedAbility.getCosts()) { if (cost instanceof PayVariableLoyaltyCost) { diff --git a/Mage/src/main/java/mage/abilities/costs/common/PutCardFromHandOnTopOfLibraryCost.java b/Mage/src/main/java/mage/abilities/costs/common/PutCardFromHandOnTopOfLibraryCost.java index fdb2d4cb48f..565bb66c1b0 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/PutCardFromHandOnTopOfLibraryCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/PutCardFromHandOnTopOfLibraryCost.java @@ -32,8 +32,8 @@ public class PutCardFromHandOnTopOfLibraryCost extends CostImpl { TargetCardInHand targetCardInHand = new TargetCardInHand(); targetCardInHand.setRequired(false); Card card; - if (targetCardInHand.canChoose(source.getSourceId(), controllerId, game) - && controller.choose(Outcome.PreventDamage, targetCardInHand, source.getSourceId(), game)) { + if (targetCardInHand.canChoose(controllerId, source, game) + && controller.choose(Outcome.PreventDamage, targetCardInHand, source, game)) { card = game.getCard(targetCardInHand.getFirstTarget()); paid = card != null && controller.moveCardToLibraryWithInfo(card, source, game, Zone.HAND, true, true); } diff --git a/Mage/src/main/java/mage/abilities/costs/common/RemoveCounterCost.java b/Mage/src/main/java/mage/abilities/costs/common/RemoveCounterCost.java index 63e91293e11..036f83ac51b 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/RemoveCounterCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/RemoveCounterCost.java @@ -23,10 +23,9 @@ import java.util.UUID; */ public class RemoveCounterCost extends CostImpl { - protected TargetPermanent target; - private String name; - private CounterType counterTypeToRemove; - protected int countersToRemove; + protected final TargetPermanent target; + private final CounterType counterTypeToRemove; + protected final int countersToRemove; public RemoveCounterCost(TargetPermanent target) { this(target, null); @@ -47,7 +46,6 @@ public class RemoveCounterCost extends CostImpl { public RemoveCounterCost(final RemoveCounterCost cost) { super(cost); this.target = cost.target.copy(); - this.name = cost.name; this.countersToRemove = cost.countersToRemove; this.counterTypeToRemove = cost.counterTypeToRemove; } @@ -62,7 +60,7 @@ public class RemoveCounterCost extends CostImpl { return paid = true; } target.clearChosen(); - if (target.choose(Outcome.UnboostCreature, controllerId, source.getSourceId(), game)) { + if (target.choose(Outcome.UnboostCreature, controllerId, source.getSourceId(), source, game)) { for (UUID targetId : target.getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent != null) { @@ -124,17 +122,24 @@ public class RemoveCounterCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return target.canChoose(source.getSourceId(), controllerId, game); + return target.canChoose(controllerId, source, game); } private String setText() { - StringBuilder sb = new StringBuilder("Remove "); + StringBuilder sb = new StringBuilder("remove "); if (counterTypeToRemove != null) { - sb.append(CardUtil.numberToText(countersToRemove, counterTypeToRemove.getArticle())).append(' ').append(counterTypeToRemove.getName()); + sb.append(CardUtil.numberToText(countersToRemove, counterTypeToRemove.getArticle())); + sb.append(' '); + sb.append(counterTypeToRemove.getName()); } else { sb.append(CardUtil.numberToText(countersToRemove, "a")); } - sb.append(countersToRemove == 1 ? " counter from " : " counters from ").append(target.getMaxNumberOfTargets() == 1 ? "a " : "").append(target.getTargetName()); + sb.append(countersToRemove > 1 ? " counters from " : " counter from "); + if (target.getMaxNumberOfTargets() > 1) { + sb.append(target.getTargetName()); + } else { + sb.append(CardUtil.addArticle(target.getTargetName())); + } return sb.toString(); } diff --git a/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java b/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java index d041d2368b5..e449d1158c6 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/RemoveCountersSourceCost.java @@ -3,12 +3,19 @@ package mage.abilities.costs.common; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.Outcome; import mage.counters.Counter; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.players.Player; import mage.util.CardUtil; +import mage.util.RandomUtil; +import java.util.Iterator; +import java.util.Set; import java.util.UUID; /** @@ -19,16 +26,23 @@ public class RemoveCountersSourceCost extends CostImpl { private final int amount; private final String name; + public RemoveCountersSourceCost() { + this((Counter) null); + } + public RemoveCountersSourceCost(Counter counter) { - this.amount = counter.getCount(); - this.name = counter.getName(); - this.text = new StringBuilder("remove ").append((amount == 1 ? CounterType.findArticle(counter.getName()) : CardUtil.numberToText(amount))) - .append(' ').append(name).append(" counter").append((amount != 1 ? "s" : "")) + this.amount = counter != null ? counter.getCount() : 1; + this.name = counter != null ? counter.getName() : ""; + this.text = new StringBuilder("remove ") + .append((amount == 1 ? CounterType.findArticle(name) : CardUtil.numberToText(amount))) + .append(name.isEmpty() ? "" : (' ' + name)) + .append(" counter") + .append((amount != 1 ? "s" : "")) .append(" from {this}").toString(); } - public RemoveCountersSourceCost(RemoveCountersSourceCost cost) { + private RemoveCountersSourceCost(RemoveCountersSourceCost cost) { super(cost); this.amount = cost.amount; this.name = cost.name; @@ -42,9 +56,41 @@ public class RemoveCountersSourceCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null && permanent.getCounters(game).getCount(name) >= amount) { - permanent.removeCounters(name, amount, source, game); + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (player == null || permanent == null) { + return paid; + } + String toRemove; + if (name.isEmpty()) { + Set toChoose = permanent.getCounters(game).keySet(); + switch (toChoose.size()) { + case 0: + return paid; + case 1: + toRemove = RandomUtil.randomFromCollection(toChoose); + break; + case 2: + Iterator iterator = toChoose.iterator(); + String choice1 = iterator.next(); + String choice2 = iterator.next(); + toRemove = player.chooseUse( + Outcome.UnboostCreature, "Choose a type of counter to remove", + null, choice1, choice2, source, game + ) ? choice1 : choice2; + break; + default: + Choice choice = new ChoiceImpl(true); + choice.setChoices(toChoose); + choice.setMessage("Choose a type of counter to remove"); + player.choose(Outcome.UnboostCreature, choice, game); + toRemove = choice.getChoice(); + } + } else { + toRemove = name; + } + if (permanent.getCounters(game).getCount(toRemove) >= amount) { + permanent.removeCounters(toRemove, amount, source, game); this.paid = true; } return paid; diff --git a/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandChosenControlledPermanentCost.java b/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandChosenControlledPermanentCost.java index 7bc29c35039..dd91a8ef466 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandChosenControlledPermanentCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandChosenControlledPermanentCost.java @@ -1,9 +1,6 @@ package mage.abilities.costs.common; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; @@ -16,8 +13,11 @@ import mage.players.Player; import mage.target.common.TargetControlledPermanent; import mage.util.CardUtil; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class ReturnToHandChosenControlledPermanentCost extends CostImpl { @@ -31,7 +31,7 @@ public class ReturnToHandChosenControlledPermanentCost extends CostImpl { + (target.getTargetName().endsWith(" you control") ? "" : " you control") + " to their owner's hand"; } else { - this.text = "return " + target.getTargetName() + this.text = "return " + CardUtil.addArticle(target.getTargetName()) + (target.getTargetName().endsWith(" you control") ? "" : " you control") + " to its owner's hand"; } @@ -45,7 +45,7 @@ public class ReturnToHandChosenControlledPermanentCost extends CostImpl { public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { - if (targets.choose(Outcome.ReturnToHand, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.ReturnToHand, controllerId, source.getSourceId(), source, game)) { Set permanentsToReturn = new HashSet<>(); for (UUID targetId : targets.get(0).getTargets()) { Permanent permanent = game.getPermanent(targetId); @@ -63,7 +63,7 @@ public class ReturnToHandChosenControlledPermanentCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromGraveyardCost.java b/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromGraveyardCost.java index 00187662ad1..3a3e3adfe7c 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromGraveyardCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/ReturnToHandFromGraveyardCost.java @@ -37,7 +37,7 @@ public class ReturnToHandFromGraveyardCost extends CostImpl { public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { - if (targets.choose(Outcome.ReturnToHand, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.ReturnToHand, controllerId, source.getSourceId(), source, game)) { Set cardsToMove = new LinkedHashSet<>(); for (UUID targetId : targets.get(0).getTargets()) { mage.cards.Card targetCard = game.getCard(targetId); @@ -56,7 +56,7 @@ public class ReturnToHandFromGraveyardCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/costs/common/RevealDragonFromHandCost.java b/Mage/src/main/java/mage/abilities/costs/common/RevealDragonFromHandCost.java index 26c0112f3ce..08d7782fab1 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/RevealDragonFromHandCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/RevealDragonFromHandCost.java @@ -43,7 +43,7 @@ public class RevealDragonFromHandCost extends RevealTargetFromHandCost { public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { super.pay(ability, game, source, controllerId, noMana, costToPay); revealedOrControlled = numberCardsRevealed > 0 - || game.getBattlefield().count(filter2, source.getSourceId(), controllerId, game) > 0; + || game.getBattlefield().count(filter2, controllerId, source, game) > 0; return paid = true; } diff --git a/Mage/src/main/java/mage/abilities/costs/common/RevealHandSourceControllerCost.java b/Mage/src/main/java/mage/abilities/costs/common/RevealHandSourceControllerCost.java index 88eeef728d5..cba62824fc2 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/RevealHandSourceControllerCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/RevealHandSourceControllerCost.java @@ -27,7 +27,7 @@ public class RevealHandSourceControllerCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { controller.revealCards(sourceObject.getName(), controller.getHand(), game); paid = true; diff --git a/Mage/src/main/java/mage/abilities/costs/common/RevealSecretOpponentCost.java b/Mage/src/main/java/mage/abilities/costs/common/RevealSecretOpponentCost.java index aa4ae4bdbcc..abf131ef2be 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/RevealSecretOpponentCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/RevealSecretOpponentCost.java @@ -44,7 +44,7 @@ public class RevealSecretOpponentCost extends CostImpl { ChooseSecretOpponentEffect.setSecretOwner(null, source, game); // because only once, the value is set to null Player controller = game.getPlayer(controllerId); Player opponent = game.getPlayer(opponentId); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && opponent != null && sourceObject != null) { if (sourceObject instanceof Permanent) { ((Permanent) sourceObject).addInfo(ChooseSecretOpponentEffect.SECRET_OPPONENT, null, game); diff --git a/Mage/src/main/java/mage/abilities/costs/common/RevealTargetFromHandCost.java b/Mage/src/main/java/mage/abilities/costs/common/RevealTargetFromHandCost.java index 12c206a2f4b..88b8df8416e 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/RevealTargetFromHandCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/RevealTargetFromHandCost.java @@ -40,7 +40,7 @@ public class RevealTargetFromHandCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - if (targets.choose(Outcome.Benefit, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.Benefit, controllerId, source.getSourceId(), source, game)) { manaValues = 0; numberCardsRevealed = 0; Player player = game.getPlayer(controllerId); @@ -81,7 +81,7 @@ public class RevealTargetFromHandCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/costs/common/SacrificeTargetCost.java b/Mage/src/main/java/mage/abilities/costs/common/SacrificeTargetCost.java index 08cbf858f45..8f790667d95 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/SacrificeTargetCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/SacrificeTargetCost.java @@ -53,7 +53,7 @@ public class SacrificeTargetCost extends CostImpl { activator = ((ActivatedAbilityImpl) ability).getActivatorId(); } // can be cancel by user - if (targets.choose(Outcome.Sacrifice, activator, source.getSourceId(), game)) { + if (targets.choose(Outcome.Sacrifice, activator, source.getSourceId(), source, game)) { for (UUID targetId : targets.get(0).getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent == null) { diff --git a/Mage/src/main/java/mage/abilities/costs/common/SacrificeXTargetCost.java b/Mage/src/main/java/mage/abilities/costs/common/SacrificeXTargetCost.java index 27d6a1b3f46..26839ceb901 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/SacrificeXTargetCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/SacrificeXTargetCost.java @@ -14,22 +14,29 @@ import mage.target.common.TargetControlledPermanent; */ public class SacrificeXTargetCost extends VariableCostImpl { - protected FilterControlledPermanent filter; + protected final FilterControlledPermanent filter; + private final int minValue; public SacrificeXTargetCost(FilterControlledPermanent filter) { this(filter, false); } public SacrificeXTargetCost(FilterControlledPermanent filter, boolean useAsAdditionalCost) { + this(filter, useAsAdditionalCost, 0); + } + + public SacrificeXTargetCost(FilterControlledPermanent filter, boolean useAsAdditionalCost, int minValue) { super(useAsAdditionalCost ? VariableCostType.ADDITIONAL : VariableCostType.NORMAL, filter.getMessage() + " to sacrifice"); this.text = (useAsAdditionalCost ? "as an additional cost to cast this spell, sacrifice " : "Sacrifice ") + xText + ' ' + filter.getMessage(); this.filter = filter; + this.minValue = minValue; } public SacrificeXTargetCost(final SacrificeXTargetCost cost) { super(cost); this.filter = cost.filter; + this.minValue = cost.minValue; } @Override @@ -37,9 +44,14 @@ public class SacrificeXTargetCost extends VariableCostImpl { return new SacrificeXTargetCost(this); } + @Override + public int getMinValue(Ability source, Game game) { + return minValue; + } + @Override public int getMaxValue(Ability source, Game game) { - return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + return game.getBattlefield().count(filter, source.getControllerId(), source, game); } @Override @@ -47,7 +59,7 @@ public class SacrificeXTargetCost extends VariableCostImpl { TargetControlledPermanent target = new TargetControlledPermanent(xValue, xValue, filter, true); return new SacrificeTargetCost(target); } - + public Filter getFilter() { return filter; } diff --git a/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java b/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java index 295e6b4b74b..1b4b9b11c7f 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java @@ -37,7 +37,7 @@ public class TapTargetCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { List permanents = new ArrayList<>(); - if (target.choose(Outcome.Tap, controllerId, source.getSourceId(), game)) { + if (target.choose(Outcome.Tap, controllerId, source.getSourceId(), source, game)) { for (UUID targetId : target.getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent == null) { @@ -53,7 +53,7 @@ public class TapTargetCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return target.canChoose(source.getSourceId(), controllerId, game); + return target.canChoose(controllerId, source, game); } public TargetControlledPermanent getTarget() { diff --git a/Mage/src/main/java/mage/abilities/costs/common/UntapTargetCost.java b/Mage/src/main/java/mage/abilities/costs/common/UntapTargetCost.java index 7532578d9fd..cdae3e00688 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/UntapTargetCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/UntapTargetCost.java @@ -1,29 +1,26 @@ - package mage.abilities.costs.common; -import mage.constants.Outcome; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; +import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledPermanent; - -import java.util.List; -import java.util.UUID; -import mage.abilities.costs.Cost; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public class UntapTargetCost extends CostImpl { - TargetControlledPermanent target; + private final TargetControlledPermanent target; public UntapTargetCost(TargetControlledPermanent target) { this.target = target; - this.text = "Untap " + CardUtil.numberToText(target.getMaxNumberOfTargets(), "") + ' ' + target.getTargetName(); + this.text = makeText(target); } public UntapTargetCost(final UntapTargetCost cost) { @@ -33,21 +30,22 @@ public class UntapTargetCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - if (target.choose(Outcome.Untap, controllerId, source.getSourceId(), game)) { - for (UUID targetId : (List) target.getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent == null) { - return false; - } - paid |= permanent.untap(game); + if (!target.choose(Outcome.Untap, controllerId, source.getSourceId(), source, game)) { + return paid; + } + for (UUID targetId : target.getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent == null) { + return false; } + paid |= permanent.untap(game); } return paid; } @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return target.canChoose(source.getSourceId(), controllerId, game); + return target.canChoose(controllerId, source, game); } @Override @@ -55,4 +53,15 @@ public class UntapTargetCost extends CostImpl { return new UntapTargetCost(this); } + private static String makeText(TargetControlledPermanent target) { + StringBuilder sb = new StringBuilder("untap "); + if (target.getMaxNumberOfTargets() > 1) { + sb.append(CardUtil.numberToText(target.getMaxNumberOfTargets())); + sb.append(' '); + sb.append(target.getTargetName().replace(" you control", "s you control")); + } else { + sb.append(CardUtil.addArticle(target.getTargetName())); + } + return sb.toString(); + } } diff --git a/Mage/src/main/java/mage/abilities/costs/costadjusters/ExileCardsFromHandAdjuster.java b/Mage/src/main/java/mage/abilities/costs/costadjusters/ExileCardsFromHandAdjuster.java new file mode 100644 index 00000000000..742e315efcb --- /dev/null +++ b/Mage/src/main/java/mage/abilities/costs/costadjusters/ExileCardsFromHandAdjuster.java @@ -0,0 +1,54 @@ +package mage.abilities.costs.costadjusters; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.CostAdjuster; +import mage.abilities.costs.common.ExileFromHandCost; +import mage.abilities.effects.common.InfoEffect; +import mage.cards.Card; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInHand; +import mage.util.CardUtil; + +/** + * @author TheElk801 + */ +public class ExileCardsFromHandAdjuster implements CostAdjuster { + + private final FilterCard filter; + + private ExileCardsFromHandAdjuster(FilterCard filter) { + this.filter = filter; + } + + @Override + public void adjustCosts(Ability ability, Game game) { + if (game.inCheckPlayableState()) { + return; + } + Player player = game.getPlayer(ability.getControllerId()); + if (player == null) { + return; + } + int cardCount = player.getHand().count(filter, game); + int toExile = cardCount > 0 ? player.getAmount( + 0, cardCount, "Choose how many " + filter.getMessage() + " to exile", game + ) : 0; + if (toExile > 0) { + ability.addCost(new ExileFromHandCost(new TargetCardInHand(toExile, filter))); + CardUtil.reduceCost(ability, 2 * toExile); + } + } + + public static final void addAdjusterAndMessage(Card card, FilterCard filter) { + card.addAbility(new SimpleStaticAbility( + Zone.ALL, + new InfoEffect("as an additional cost to cast this spell, you may exile any number of " + + filter.getMessage() + ". This spell costs {2} less to cast for each card exiled this way") + ).setRuleAtTheTop(true)); + card.getSpellAbility().setCostAdjuster(new ExileCardsFromHandAdjuster(filter)); + } +} diff --git a/Mage/src/main/java/mage/abilities/costs/costadjusters/LegendaryCreatureCostAdjuster.java b/Mage/src/main/java/mage/abilities/costs/costadjusters/LegendaryCreatureCostAdjuster.java index 51ef9b608a6..cd2406ed5f3 100644 --- a/Mage/src/main/java/mage/abilities/costs/costadjusters/LegendaryCreatureCostAdjuster.java +++ b/Mage/src/main/java/mage/abilities/costs/costadjusters/LegendaryCreatureCostAdjuster.java @@ -2,6 +2,9 @@ package mage.abilities.costs.costadjusters; import mage.abilities.Ability; import mage.abilities.costs.CostAdjuster; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; import mage.constants.SuperType; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; @@ -13,19 +16,29 @@ import mage.util.CardUtil; */ public enum LegendaryCreatureCostAdjuster implements CostAdjuster { instance; + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); static { filter.add(SuperType.LEGENDARY.getPredicate()); } + private static final Hint hint = new ValueHint( + "Legendary creatures you control", + new PermanentsOnBattlefieldCount(filter) + ); + @Override public void adjustCosts(Ability ability, Game game) { int count = game.getBattlefield().count( - filter, ability.getSourceId(), ability.getControllerId(), game + filter, ability.getControllerId(), ability, game ); if (count > 0) { CardUtil.reduceCost(ability, count); } } -} \ No newline at end of file + + public static Hint getHint() { + return hint; + } +} diff --git a/Mage/src/main/java/mage/abilities/costs/mana/ColoredManaCost.java b/Mage/src/main/java/mage/abilities/costs/mana/ColoredManaCost.java index 87319e0172a..6369c9dc794 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/ColoredManaCost.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/ColoredManaCost.java @@ -43,7 +43,7 @@ public class ColoredManaCost extends ManaCostImpl { @Override public String getText() { - return '{' + mana.toString() + '}'; + return '{' + mana.toString() + (this.phyrexian ? "/P" : "") + '}'; } @Override diff --git a/Mage/src/main/java/mage/abilities/costs/mana/HybridManaCost.java b/Mage/src/main/java/mage/abilities/costs/mana/HybridManaCost.java index 9c2193aa565..e15bc56054d 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/HybridManaCost.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/HybridManaCost.java @@ -1,8 +1,5 @@ - package mage.abilities.costs.mana; -import java.util.ArrayList; -import java.util.List; import mage.Mana; import mage.abilities.Ability; import mage.abilities.costs.Cost; @@ -10,6 +7,9 @@ import mage.constants.ColoredManaSymbol; import mage.game.Game; import mage.players.ManaPool; +import java.util.ArrayList; +import java.util.List; + public class HybridManaCost extends ManaCostImpl { private final ColoredManaSymbol mana1; @@ -50,7 +50,7 @@ public class HybridManaCost extends ManaCostImpl { @Override public String getText() { - return '{' + mana1.toString() + '/' + mana2.toString() + '}'; + return '{' + mana1.toString() + '/' + mana2.toString() + (this.phyrexian ? "/P" : "") + '}'; } @Override diff --git a/Mage/src/main/java/mage/abilities/costs/mana/ManaCost.java b/Mage/src/main/java/mage/abilities/costs/mana/ManaCost.java index 9f5a3ed02db..91a3f0194f4 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/ManaCost.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/ManaCost.java @@ -1,7 +1,5 @@ - package mage.abilities.costs.mana; -import java.util.List; import mage.Mana; import mage.abilities.Ability; import mage.abilities.costs.Cost; @@ -11,6 +9,8 @@ import mage.filter.Filter; import mage.game.Game; import mage.players.ManaPool; +import java.util.List; + public interface ManaCost extends Cost { int manaValue(); @@ -45,4 +45,7 @@ public interface ManaCost extends Cost { @Override ManaCost copy(); + boolean isPhyrexian(); + + void setPhyrexian(boolean phyrexian); } diff --git a/Mage/src/main/java/mage/abilities/costs/mana/ManaCostImpl.java b/Mage/src/main/java/mage/abilities/costs/mana/ManaCostImpl.java index d0503b870cb..59122a61edb 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/ManaCostImpl.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/ManaCostImpl.java @@ -25,6 +25,7 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost { protected Mana cost; protected ManaOptions options; protected Filter sourceFilter; + protected boolean phyrexian = false; public ManaCostImpl() { payment = new Mana(); @@ -41,6 +42,7 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost { if (manaCost.sourceFilter != null) { this.sourceFilter = manaCost.sourceFilter.copy(); } + this.phyrexian = manaCost.phyrexian; } @Override @@ -288,4 +290,17 @@ public abstract class ManaCostImpl extends CostImpl implements ManaCost { public String toString() { return getText(); } + + @Override + public boolean isPhyrexian() { + return phyrexian; + } + + @Override + public void setPhyrexian(boolean phyrexian) { + if (phyrexian) { + this.options.add(Mana.GenericMana(0)); + } + this.phyrexian = phyrexian; + } } diff --git a/Mage/src/main/java/mage/abilities/costs/mana/ManaCosts.java b/Mage/src/main/java/mage/abilities/costs/mana/ManaCosts.java index c1196269e3f..def7aef85c8 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/ManaCosts.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/ManaCosts.java @@ -54,4 +54,8 @@ public interface ManaCosts extends List, ManaCost { .collect(Collectors.toCollection(ManaCostsImpl::new)); } + + void incrPhyrexianPaid(); + + int getPhyrexianPaid(); } diff --git a/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java b/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java index 59e2e9dbd72..59229470ab3 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/ManaCostsImpl.java @@ -28,6 +28,8 @@ public class ManaCostsImpl extends ArrayList implements M protected final UUID id; protected String text = null; + protected boolean phyrexian = false; + private int phyrexianPaid = 0; private static final Map costsCache = new ConcurrentHashMap<>(); // must be thread safe, can't use nulls @@ -46,6 +48,7 @@ public class ManaCostsImpl extends ArrayList implements M for (T cost : costs) { this.add(cost.copy()); } + this.phyrexian = costs.phyrexian; } @Override @@ -175,58 +178,53 @@ public class ManaCostsImpl extends ArrayList implements M while (manaCostIterator.hasNext()) { ManaCost manaCost = manaCostIterator.next(); - if (manaCost instanceof PhyrexianManaCost) { - PhyrexianManaCost phyrexianManaCost = (PhyrexianManaCost) manaCost; - PayLifeCost payLifeCost = new PayLifeCost(2); - if (payLifeCost.canPay(abilityToPay, source, payingPlayer.getId(), game) - && payingPlayer.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + phyrexianManaCost.getBaseText() + '?', source, game)) { - manaCostIterator.remove(); - tempCosts.add(payLifeCost); - } + if (!manaCost.isPhyrexian()) { + continue; + } + PayLifeCost payLifeCost = new PayLifeCost(2); + if (payLifeCost.canPay(abilityToPay, source, payingPlayer.getId(), game) + && payingPlayer.chooseUse(Outcome.LoseLife, "Pay 2 life instead of " + manaCost.getText().replace("/P", "") + '?', source, game)) { + manaCostIterator.remove(); + tempCosts.add(payLifeCost); + this.incrPhyrexianPaid(); } } tempCosts.pay(source, game, source, payingPlayer.getId(), false, null); } + private void handleLikePhyrexianManaCosts(Player player, Ability source, Game game) { if (this.isEmpty()) { return; // nothing to be done without any mana costs. prevents NRE from occurring here } FilterMana phyrexianColors = player.getPhyrexianColors(); - if (player.getPhyrexianColors() != null) { - Costs tempCosts = new CostsImpl<>(); - - Iterator manaCostIterator = this.iterator(); - while (manaCostIterator.hasNext()) { - ManaCost manaCost = manaCostIterator.next(); - Mana mana = manaCost.getMana(); - PhyrexianManaCost tempPhyrexianCost = null; - - /* find which color mana is in the cost and set it in the temp Phyrexian cost */ - if (phyrexianColors.isWhite() && mana.getWhite() > 0) { - tempPhyrexianCost = new PhyrexianManaCost(ColoredManaSymbol.W); - } else if (phyrexianColors.isBlue() && mana.getBlue() > 0) { - tempPhyrexianCost = new PhyrexianManaCost(ColoredManaSymbol.U); - } else if (phyrexianColors.isBlack() && mana.getBlack() > 0) { - tempPhyrexianCost = new PhyrexianManaCost(ColoredManaSymbol.B); - } else if (phyrexianColors.isRed() && mana.getRed() > 0) { - tempPhyrexianCost = new PhyrexianManaCost(ColoredManaSymbol.R); - } else if (phyrexianColors.isGreen() && mana.getGreen() > 0) { - tempPhyrexianCost = new PhyrexianManaCost(ColoredManaSymbol.G); - } - - if (tempPhyrexianCost != null) { - PayLifeCost payLifeCost = new PayLifeCost(2); - if (payLifeCost.canPay(source, source, player.getId(), game) - && player.chooseUse(Outcome.LoseLife, "Pay 2 life (using an active ability) instead of " + tempPhyrexianCost.getBaseText() + '?', source, game)) { - manaCostIterator.remove(); - tempCosts.add(payLifeCost); - } - } - } - tempCosts.pay(source, game, source, player.getId(), false, null); + if (player.getPhyrexianColors() == null) { + return; } + Costs tempCosts = new CostsImpl<>(); + + Iterator manaCostIterator = this.iterator(); + while (manaCostIterator.hasNext()) { + ManaCost manaCost = manaCostIterator.next(); + Mana mana = manaCost.getMana(); + + /* find which color mana is in the cost and set it in the temp Phyrexian cost */ + if ((!phyrexianColors.isWhite() || mana.getWhite() <= 0) + && (!phyrexianColors.isBlue() || mana.getBlue() <= 0) + && (!phyrexianColors.isBlack() || mana.getBlack() <= 0) + && (!phyrexianColors.isRed() || mana.getRed() <= 0) + && (!phyrexianColors.isGreen() || mana.getGreen() <= 0)) { + continue; + } + PayLifeCost payLifeCost = new PayLifeCost(2); + if (payLifeCost.canPay(source, source, player.getId(), game) + && player.chooseUse(Outcome.LoseLife, "Pay 2 life (using an active ability) instead of " + manaCost.getMana() + '?', source, game)) { + manaCostIterator.remove(); + tempCosts.add(payLifeCost); + } + } + tempCosts.pay(source, game, source, player.getId(), false, null); } @Override @@ -441,55 +439,66 @@ public class ManaCostsImpl extends ArrayList implements M if (mana == null || mana.isEmpty()) { return; } + if (!mana.startsWith("{") || !mana.endsWith("}")) { + throw new IllegalArgumentException("mana costs should start and end with braces"); + } if (!extractMonoHybridGenericValue && costsCache.containsKey(mana)) { ManaCosts savedCosts = costsCache.get(mana); for (ManaCost cost : savedCosts) { this.add(cost.copy()); } - } else { - String[] symbols = mana.split("^\\{|}\\{|}$"); - int modifierForX = 0; - for (String symbol : symbols) { - if (!symbol.isEmpty()) { - if (symbol.length() == 1 || isNumeric(symbol)) { - if (Character.isDigit(symbol.charAt(0))) { - this.add(new GenericManaCost(Integer.valueOf(symbol))); - } else if (symbol.equals("S")) { - this.add(new SnowManaCost()); - } else if (symbol.equals("C")) { - this.add(new ColorlessManaCost(1)); - } else if (!symbol.equals("X")) { - this.add(new ColoredManaCost(ColoredManaSymbol.lookup(symbol.charAt(0)))); - } else // check X wasn't added before - if (modifierForX == 0) { - // count X occurence - for (String s : symbols) { - if (s.equals("X")) { - modifierForX++; - } - } - this.add(new VariableManaCost(VariableCostType.NORMAL, modifierForX)); - } //TODO: handle multiple {X} and/or {Y} symbols - } else if (Character.isDigit(symbol.charAt(0))) { - MonoHybridManaCost cost; - if (extractMonoHybridGenericValue) { - // for tests only, no usage in real game - cost = new MonoHybridManaCost(ColoredManaSymbol.lookup(symbol.charAt(2)), Integer.parseInt(symbol.substring(0, 1))); - } else { - cost = new MonoHybridManaCost(ColoredManaSymbol.lookup(symbol.charAt(2))); + return; + } + String[] symbols = mana.split("^\\{|}\\{|}$"); + int modifierForX = 0; + for (String symbol : symbols) { + if (symbol.isEmpty()) { + continue; + } + if (symbol.length() == 1 || isNumeric(symbol)) { + if (Character.isDigit(symbol.charAt(0))) { + this.add(new GenericManaCost(Integer.valueOf(symbol))); + } else if (symbol.equals("S")) { + this.add(new SnowManaCost()); + } else if (symbol.equals("C")) { + this.add(new ColorlessManaCost(1)); + } else if (!symbol.equals("X")) { + this.add(new ColoredManaCost(ColoredManaSymbol.lookup(symbol.charAt(0)))); + } else // check X wasn't added before + if (modifierForX == 0) { + // count X occurence + for (String s : symbols) { + if (s.equals("X")) { + modifierForX++; + } } - this.add(cost); - } else if (symbol.contains("P")) { - this.add(new PhyrexianManaCost(ColoredManaSymbol.lookup(symbol.charAt(0)))); - } else { - this.add(new HybridManaCost(ColoredManaSymbol.lookup(symbol.charAt(0)), ColoredManaSymbol.lookup(symbol.charAt(2)))); - } + this.add(new VariableManaCost(VariableCostType.NORMAL, modifierForX)); + } //TODO: handle multiple {X} and/or {Y} symbols + } else if (Character.isDigit(symbol.charAt(0))) { + MonoHybridManaCost cost; + if (extractMonoHybridGenericValue) { + // for tests only, no usage in real game + cost = new MonoHybridManaCost(ColoredManaSymbol.lookup(symbol.charAt(2)), Integer.parseInt(symbol.substring(0, 1))); + } else { + cost = new MonoHybridManaCost(ColoredManaSymbol.lookup(symbol.charAt(2))); } + this.add(cost); + } else { + boolean phyrexian = symbol.contains("/P"); + String without = symbol.replace("/P", ""); + ManaCost cost; + if (without.length() == 1) { + cost = new ColoredManaCost(ColoredManaSymbol.lookup(without.charAt(0))); + } else { + cost = new HybridManaCost(ColoredManaSymbol.lookup(without.charAt(0)), ColoredManaSymbol.lookup(without.charAt(2))); + } + cost.setPhyrexian(phyrexian); + this.add(cost); } - if (!extractMonoHybridGenericValue) { - costsCache.put(mana, this.copy()); - } + } + if (!extractMonoHybridGenericValue) { + costsCache.put(mana, this.copy()); } } @@ -597,6 +606,29 @@ public class ManaCostsImpl extends ArrayList implements M return new ManaCostsImpl<>(this); } + @Override + public boolean isPhyrexian() { + return phyrexian; + } + + @Override + public void setPhyrexian(boolean phyrexian) { + this.phyrexian = phyrexian; + for (T cost : this) { + cost.setPhyrexian(phyrexian); + } + } + + @Override + public void incrPhyrexianPaid() { + this.phyrexianPaid++; + } + + @Override + public int getPhyrexianPaid() { + return phyrexianPaid; + } + @Override public Filter getSourceFilter() { for (T cost : this) { diff --git a/Mage/src/main/java/mage/abilities/costs/mana/PhyrexianManaCost.java b/Mage/src/main/java/mage/abilities/costs/mana/PhyrexianManaCost.java deleted file mode 100644 index 60a196503dd..00000000000 --- a/Mage/src/main/java/mage/abilities/costs/mana/PhyrexianManaCost.java +++ /dev/null @@ -1,40 +0,0 @@ - -package mage.abilities.costs.mana; - -import mage.Mana; -import mage.constants.ColoredManaSymbol; - -/** - * - * @author nantuko - */ -public class PhyrexianManaCost extends ColoredManaCost { - - public PhyrexianManaCost(ColoredManaSymbol mana) { - super(mana); - options.add(Mana.GenericMana(0)); - } - - public PhyrexianManaCost(PhyrexianManaCost manaCost) { - super(manaCost); - } - - @Override - public String getText() { - return '{' + mana.toString() + "/P}"; - } - - public String getBaseText() { - return super.getText(); - } - - @Override - public ColoredManaCost getUnpaid() { - return new ColoredManaCost(this); - } - - @Override - public PhyrexianManaCost copy() { - return new PhyrexianManaCost(this); - } -} diff --git a/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java b/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java index e31ca94d96c..b1a0c45eb73 100644 --- a/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/decorator/ConditionalInterveningIfTriggeredAbility.java @@ -79,7 +79,7 @@ public class ConditionalInterveningIfTriggeredAbility extends TriggeredAbilityIm return ability.getRule(); } return (abilityWord != null ? abilityWord.formatWord() : "") + abilityText + - (abilityText.endsWith(".") || abilityText.endsWith("\"") ? "" : "."); + (abilityText.endsWith(".") || abilityText.endsWith("\"") || abilityText.endsWith(">") ? "" : "."); } @Override diff --git a/Mage/src/main/java/mage/abilities/decorator/ConditionalOneShotEffect.java b/Mage/src/main/java/mage/abilities/decorator/ConditionalOneShotEffect.java index 1bad5b3e2e8..d6ea8e16aff 100644 --- a/Mage/src/main/java/mage/abilities/decorator/ConditionalOneShotEffect.java +++ b/Mage/src/main/java/mage/abilities/decorator/ConditionalOneShotEffect.java @@ -50,7 +50,7 @@ public class ConditionalOneShotEffect extends OneShotEffect { // nothing to do - no problem Effects toApply = condition.apply(game, source) ? effects : otherwiseEffects; if (toApply.isEmpty()) { - return false; + return true; } toApply.setTargetPointer(this.targetPointer); toApply.stream().forEach(effect -> effect.apply(game, source)); @@ -63,7 +63,7 @@ public class ConditionalOneShotEffect extends OneShotEffect { } public ConditionalOneShotEffect addOtherwiseEffect(OneShotEffect effect) { - this.effects.add(effect); + this.otherwiseEffects.add(effect); return this; } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ArtifactYouControlCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ArtifactYouControlCount.java index 4c626a97a9c..0e1ce3478f0 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ArtifactYouControlCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ArtifactYouControlCount.java @@ -15,7 +15,7 @@ public enum ArtifactYouControlCount implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - return game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + return game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, sourceAbility.getControllerId(), sourceAbility, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/AttachedPermanentToughnessValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/AttachedPermanentToughnessValue.java deleted file mode 100644 index cfe130c50e1..00000000000 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/AttachedPermanentToughnessValue.java +++ /dev/null @@ -1,45 +0,0 @@ -package mage.abilities.dynamicvalue.common; - -import mage.abilities.Ability; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.effects.Effect; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; - -/** - * @author MTGfan - */ -public enum AttachedPermanentToughnessValue implements DynamicValue { - instance; - - @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - // In the case that the enchantment is blinked - Permanent enchantment = (Permanent) game.getLastKnownInformation(sourceAbility.getSourceId(), Zone.BATTLEFIELD); - if (enchantment == null) { - // It was not blinked, use the standard method - enchantment = game.getPermanentOrLKIBattlefield(sourceAbility.getSourceId()); - } - if (enchantment == null) { - return 0; - } - Permanent enchanted = game.getPermanentOrLKIBattlefield(enchantment.getAttachedTo()); - return enchanted.getToughness().getValue(); - } - - @Override - public AttachedPermanentToughnessValue copy() { - return AttachedPermanentToughnessValue.instance; - } - - @Override - public String toString() { - return "equal to"; - } - - @Override - public String getMessage() { - return "that creature's toughness"; - } -} diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/AttackingCreatureCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/AttackingCreatureCount.java index 315505335ac..e0c512ed772 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/AttackingCreatureCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/AttackingCreatureCount.java @@ -48,7 +48,7 @@ public class AttackingCreatureCount implements DynamicValue { for (UUID permId : combatGroup.getAttackers()) { if (filter != null) { Permanent attacker = game.getPermanent(permId); - if (filter.match(attacker, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game)) { + if (filter.match(attacker, sourceAbility.getControllerId(), sourceAbility, game)) { count++; } } else { diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInAllGraveyardsCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInAllGraveyardsCount.java index e54b7b16bfc..377c4338310 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInAllGraveyardsCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInAllGraveyardsCount.java @@ -38,8 +38,8 @@ public class CardsInAllGraveyardsCount implements DynamicValue { .filter(Objects::nonNull) .map(Player::getGraveyard) .mapToInt(graveyard -> graveyard.count( - filter, sourceAbility.getSourceId(), - sourceAbility.getControllerId(), game + filter, + sourceAbility.getControllerId(), sourceAbility, game )).sum(); } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInControllerGraveyardCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInControllerGraveyardCount.java index 6702e42e1d9..aa8a0194123 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInControllerGraveyardCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInControllerGraveyardCount.java @@ -39,7 +39,7 @@ public class CardsInControllerGraveyardCount implements DynamicValue { Player player = game.getPlayer(sourceAbility.getControllerId()); if (player != null) { return amount * player.getGraveyard().count( - filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game + filter, sourceAbility.getControllerId(), sourceAbility, game ); } return 0; diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInTargetPlayersGraveyardCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInTargetPlayersGraveyardCount.java index 2d9698e03e4..a6dfbcc5a27 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInTargetPlayersGraveyardCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInTargetPlayersGraveyardCount.java @@ -35,7 +35,7 @@ public class CardsInTargetPlayersGraveyardCount implements DynamicValue { if (filter == null) { return player.getGraveyard().size(); } else { - return player.getGraveyard().count(filter, sourceAbility.getControllerId(), sourceAbility.getSourceId(), game); + return player.getGraveyard().count(filter, sourceAbility.getSourceId(), sourceAbility, game); } } return 0; diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CountersSourceCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CountersSourceCount.java index d974ff9c622..718268aa598 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CountersSourceCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CountersSourceCount.java @@ -3,6 +3,7 @@ package mage.abilities.dynamicvalue.common; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; +import mage.counters.Counter; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; @@ -15,14 +16,25 @@ public class CountersSourceCount implements DynamicValue { this.counterType = counterType; } - public CountersSourceCount(final CountersSourceCount countersCount) { + protected CountersSourceCount(final CountersSourceCount countersCount) { this.counterType = countersCount.counterType; } @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { Permanent permanent = sourceAbility.getSourcePermanentOrLKI(game); - return permanent != null ? permanent.getCounters(game).getCount(counterType) : 0; + if (permanent == null) { + return 0; + } + return counterType != null + ? permanent + .getCounters(game) + .getCount(counterType) + : permanent + .getCounters(game) + .values() + .stream() + .mapToInt(Counter::getCount).sum(); } @Override @@ -37,6 +49,6 @@ public class CountersSourceCount implements DynamicValue { @Override public String getMessage() { - return counterType + " counter on {this}"; + return (counterType != null ? counterType.toString() + ' ' : "") + "counter on {this}"; } } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CreaturesYouControlCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CreaturesYouControlCount.java index 16ae508e8ff..a82e8d10239 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CreaturesYouControlCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CreaturesYouControlCount.java @@ -15,7 +15,7 @@ public enum CreaturesYouControlCount implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - return game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_CREATURES, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + return game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_CREATURES, sourceAbility.getControllerId(), sourceAbility, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/DomainValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/DomainValue.java index 2bbbae7b017..a7b75f4f8c0 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/DomainValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/DomainValue.java @@ -14,54 +14,31 @@ import java.util.stream.Collectors; /** * @author Loki */ -public class DomainValue implements DynamicValue { - - private final int amount; - private final boolean countTargetPlayer; - private UUID playerId; - - public DomainValue() { - this(1); - } - - public DomainValue(boolean countTargetPlayer) { - this(1, countTargetPlayer); - } - - public DomainValue(int amount) { - this(amount, false); - } - - public DomainValue(int amount, boolean countTargetPlayer) { - this.amount = amount; - this.countTargetPlayer = countTargetPlayer; - } - - public DomainValue(int amount, UUID playerId) { - this(amount, false); - this.playerId = playerId; - } - - public DomainValue(final DomainValue dynamicValue) { - this.amount = dynamicValue.amount; - this.countTargetPlayer = dynamicValue.countTargetPlayer; - this.playerId = dynamicValue.playerId; - } +public enum DomainValue implements DynamicValue { + REGULAR, + TARGET, + ACTIVE; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { UUID targetPlayer; - if (playerId != null) { - targetPlayer = playerId; - } else if (countTargetPlayer) { - targetPlayer = effect.getTargetPointer().getFirst(game, sourceAbility); - } else { - targetPlayer = sourceAbility.getControllerId(); + switch (this) { + case ACTIVE: + targetPlayer = game.getActivePlayerId(); + break; + case TARGET: + targetPlayer = effect.getTargetPointer().getFirst(game, sourceAbility); + break; + case REGULAR: + targetPlayer = sourceAbility.getControllerId(); + break; + default: + targetPlayer = null; } return game.getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_PERMANENT_LANDS, - targetPlayer, sourceAbility.getSourceId(), game + targetPlayer, sourceAbility, game ).stream() .map(permanent -> SubType .getBasicLands() @@ -70,26 +47,26 @@ public class DomainValue implements DynamicValue { .collect(Collectors.toSet())) .flatMap(Collection::stream) .distinct() - .mapToInt(x -> amount) + .mapToInt(x -> 1) .sum(); } @Override public DomainValue copy() { - return new DomainValue(this); + return this; } @Override public String toString() { - return String.valueOf(amount); + return "1"; } public int getAmount() { - return amount; + return 1; } @Override public String getMessage() { - return "basic land types among lands " + (countTargetPlayer ? "they control" : "you control"); + return "basic land type among lands " + (this == TARGET ? "they control" : "you control"); } } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/GateYouControlCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/GateYouControlCount.java index 61a06c39c93..112ef391d8f 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/GateYouControlCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/GateYouControlCount.java @@ -22,7 +22,7 @@ public enum GateYouControlCount implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - return game.getBattlefield().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + return game.getBattlefield().count(filter, sourceAbility.getControllerId(), sourceAbility, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestPowerAmongControlledCreaturesValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestPowerAmongControlledCreaturesValue.java index dca236e88e4..5fb88a388da 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestPowerAmongControlledCreaturesValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestPowerAmongControlledCreaturesValue.java @@ -1,12 +1,15 @@ package mage.abilities.dynamicvalue.common; +import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.permanent.Permanent; /** * @author Styxo @@ -14,15 +17,18 @@ import mage.game.permanent.Permanent; public enum GreatestPowerAmongControlledCreaturesValue implements DynamicValue { instance; + private static final Hint hint=new ValueHint("Greatest power among creatures you control",instance); @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - int amount = 0; - for (Permanent p : game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_CONTROLLED_CREATURE, sourceAbility.getControllerId(), game - )) { - amount = Math.max(p.getPower().getValue(), amount); - } - return amount; + return game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, + sourceAbility.getControllerId(), game + ).stream() + .map(MageObject::getPower) + .mapToInt(MageInt::getValue) + .sum(); } @Override @@ -40,4 +46,7 @@ public enum GreatestPowerAmongControlledCreaturesValue implements DynamicValue { return "X"; } + public static Hint getHint() { + return hint; + } } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestSharedCreatureTypeCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestSharedCreatureTypeCount.java index 493df46a475..7f5d86f1e2a 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestSharedCreatureTypeCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestSharedCreatureTypeCount.java @@ -26,9 +26,12 @@ public enum GreatestSharedCreatureTypeCount implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { + return getValue(sourceAbility.getControllerId(), sourceAbility, game); + } + + public static int getValue(UUID playerId, Ability source, Game game) { List permanentList = game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_CONTROLLED_CREATURE, - sourceAbility.getControllerId(), sourceAbility.getSourceId(), game + StaticFilters.FILTER_CONTROLLED_CREATURE, playerId, source, game ); permanentList.removeIf(Objects::isNull); int changelings = permanentList diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/HighestCMCOfPermanentValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/HighestCMCOfPermanentValue.java index 65bac591598..bd32b21006c 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/HighestCMCOfPermanentValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/HighestCMCOfPermanentValue.java @@ -34,7 +34,7 @@ public class HighestCMCOfPermanentValue implements DynamicValue { Player controller = game.getPlayer(sourceAbility.getControllerId()); if (controller != null) { for (Permanent permanent : game.getBattlefield() - .getActivePermanents(filter, sourceAbility.getControllerId(), sourceAbility.getSourceId(), game)) { + .getActivePermanents(filter, sourceAbility.getControllerId(), sourceAbility, game)) { if ((!onlyIfCanBeSacrificed || controller.canPaySacrificeCost(permanent, sourceAbility, sourceAbility.getControllerId(), game)) && permanent.getManaValue() > value) { value = permanent.getManaValue(); diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/LandsYouControlCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/LandsYouControlCount.java index f2439c2c4a3..e03161b676e 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/LandsYouControlCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/LandsYouControlCount.java @@ -16,7 +16,7 @@ public enum LandsYouControlCount implements DynamicValue { public int calculate(Game game, Ability sourceAbility, Effect effect) { return game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, - sourceAbility.getSourceId(), sourceAbility.getControllerId(), game + sourceAbility.getControllerId(), sourceAbility, game ); } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/PartyCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/PartyCount.java index 7c732321273..d4d6b7af37d 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/PartyCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/PartyCount.java @@ -40,7 +40,7 @@ public enum PartyCount implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { Cards cards = new CardsImpl(game.getBattlefield().getActivePermanents( - filter, sourceAbility.getControllerId(), sourceAbility.getSourceId(), game + filter, sourceAbility.getControllerId(), sourceAbility, game ).stream().collect(Collectors.toSet())); return subTypeAssigner.getRoleCount(cards, game); } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsOnBattlefieldCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsOnBattlefieldCount.java index ff959daaa48..8581096961a 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsOnBattlefieldCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsOnBattlefieldCount.java @@ -41,7 +41,7 @@ public class PermanentsOnBattlefieldCount implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - int value = game.getBattlefield().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + int value = game.getBattlefield().count(filter, sourceAbility.getControllerId(), sourceAbility, game); if (multiplier != null) { value *= multiplier; } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsYouControlCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsYouControlCount.java index 8eef2b5ca7a..eb79385dabb 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsYouControlCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsYouControlCount.java @@ -15,7 +15,7 @@ public enum PermanentsYouControlCount implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - return game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_PERMANENT, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + return game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_PERMANENT, sourceAbility.getControllerId(), sourceAbility, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/RemovedCountersForCostValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/RemovedCountersForCostValue.java index 815f664b437..7fd6808010a 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/RemovedCountersForCostValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/RemovedCountersForCostValue.java @@ -25,7 +25,7 @@ public enum RemovedCountersForCostValue implements DynamicValue { @Override public String getMessage() { - return "number of removed counters"; + return ""; } @Override @@ -37,5 +37,4 @@ public enum RemovedCountersForCostValue implements DynamicValue { public String toString() { return "X"; } - } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/SavedDamageValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/SavedDamageValue.java index 8c8428fb2ce..ac6e0cd6b8c 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/SavedDamageValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/SavedDamageValue.java @@ -9,7 +9,14 @@ import mage.game.Game; * @author TheElk801 */ public enum SavedDamageValue implements DynamicValue { - instance; + MANY("many"), + MUCH("much"); + + private final String message; + + SavedDamageValue(String message) { + this.message = "that " + message; + } @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -21,8 +28,13 @@ public enum SavedDamageValue implements DynamicValue { return this; } + @Override + public String toString() { + return message; + } + @Override public String getMessage() { - return "that much"; + return ""; } } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/UrzaTerrainValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/UrzaTerrainValue.java index 06168a722d9..57fa2b3f0ce 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/UrzaTerrainValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/UrzaTerrainValue.java @@ -34,17 +34,17 @@ public enum UrzaTerrainValue implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { if (subType != SubType.MINE && game.getBattlefield().count( - mineFilter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game + mineFilter, sourceAbility.getControllerId(), sourceAbility, game ) < 1) { return 1; } if (subType != SubType.TOWER && game.getBattlefield().count( - towerFilter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game + towerFilter, sourceAbility.getControllerId(), sourceAbility, game ) < 1) { return 1; } if (subType != SubType.POWER_PLANT && game.getBattlefield().count( - powerPlantFilter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game + powerPlantFilter, sourceAbility.getControllerId(), sourceAbility, game ) < 1) { return 1; } diff --git a/Mage/src/main/java/mage/abilities/effects/AsTurnedFaceUpEffect.java b/Mage/src/main/java/mage/abilities/effects/AsTurnedFaceUpEffect.java index ba3ec38a835..380a0f914b4 100644 --- a/Mage/src/main/java/mage/abilities/effects/AsTurnedFaceUpEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/AsTurnedFaceUpEffect.java @@ -53,7 +53,7 @@ public class AsTurnedFaceUpEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { if (optional) { Player controller = game.getPlayer(source.getControllerId()); - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (controller == null || object == null) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/AuraReplacementEffect.java b/Mage/src/main/java/mage/abilities/effects/AuraReplacementEffect.java index 0aaa523f803..15cb21e2582 100644 --- a/Mage/src/main/java/mage/abilities/effects/AuraReplacementEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/AuraReplacementEffect.java @@ -2,7 +2,6 @@ package mage.abilities.effects; import java.util.Locale; import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.effects.common.AttachEffect; @@ -14,16 +13,14 @@ import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; -import mage.game.stack.StackAbility; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInGraveyard; -import static org.apache.log4j.LogMF.info; /** * Cards with the Aura subtype don't change the zone they are in, if there is no * valid target on the battlefield. Also, when entering the battlefield and it - * was not cast (so from Zone != Hand), this effect gets the target to whitch to + * was not cast (so from Zone != Stack), this effect gets the target to which to * attach it and adds the Aura the the battlefield and attachs it to the target. * The "attachTo:" value in game state has to be set therefore. *

@@ -63,15 +60,6 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { return false; } - Card firstCardFace = null; - if (game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId()) != null) { - firstCardFace = card; - card = card.getSecondCardFace(); - if (!card.isEnchantment(game) || !card.hasSubtype(SubType.AURA, game)) { - return false; - } - } - // Aura cards that go to battlefield face down (Manifest) don't have to select targets if (card.isFaceDown(game)) { return false; @@ -93,14 +81,7 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { } UUID targetId = null; - MageObject sourceObject = game.getObject(event.getSourceId()); boolean enchantCardInGraveyard = false; - if (sourceObject instanceof StackAbility) { - StackAbility stackAbility = (StackAbility) sourceObject; - if (!stackAbility.getEffects().isEmpty()) { - targetId = stackAbility.getEffects().get(0).getTargetPointer().getFirst(game, stackAbility); - } - } game.applyEffects(); // So continuousEffects are removed if previous effect of the same ability did move objects that cause continuous effects Player controllingPlayer = null; @@ -139,7 +120,7 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { controllingPlayer = game.getPlayer(card.getOwnerId()); } - if (target != null && controllingPlayer != null && controllingPlayer.choose(auraOutcome, target, card.getId(), game)) { + if (target != null && controllingPlayer != null && controllingPlayer.choose(auraOutcome, target, source, game)) { targetId = target.getFirstTarget(); } } @@ -153,12 +134,7 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { } Player targetPlayer = game.getPlayer(targetId); if (targetCard != null || targetPermanent != null || targetPlayer != null) { - if (firstCardFace != null) { - // transforming card. remove first face (original card) from old zone - firstCardFace.removeFromZone(game, fromZone, source); - } else { - card.removeFromZone(game, fromZone, source); - } + card.removeFromZone(game, fromZone, source); PermanentCard permanent = new PermanentCard(card, (controllingPlayer == null ? card.getOwnerId() : controllingPlayer.getId()), game); ZoneChangeEvent zoneChangeEvent = new ZoneChangeEvent(permanent, event.getPlayerId(), fromZone, Zone.BATTLEFIELD); permanent.updateZoneChangeCounter(game, zoneChangeEvent); @@ -202,16 +178,19 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (((ZoneChangeEvent) event).getToZone() == Zone.BATTLEFIELD - && (((ZoneChangeEvent) event).getFromZone() != Zone.STACK)) { - Card card = game.getCard(event.getTargetId()); - return card != null && (card.isEnchantment(game) && 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(game) - && card.getSecondCardFace().hasSubtype(SubType.AURA, game))); + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getToZone() != Zone.BATTLEFIELD || zEvent.getFromZone() == Zone.STACK) { + return false; } - return false; + Card card = game.getCard(zEvent.getTargetId()); + if (card == null) { + return false; + } + // in case of transformable enchantments + if (Boolean.TRUE.equals(game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId())) + && card.getSecondCardFace() != null) { + card = card.getSecondCardFace(); + } + return card.isEnchantment(game) && card.hasSubtype(SubType.AURA, game); } } diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java index 77faf553bfb..03b551a9a71 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java @@ -25,7 +25,7 @@ public interface ContinuousEffect extends Effect { void discard(); - void setDuration(Duration duration); + ContinuousEffect setDuration(Duration duration); Duration getDuration(); @@ -67,6 +67,8 @@ public interface ContinuousEffect extends Effect { boolean isYourNextTurn(Game game); + boolean isYourNextEndStep(Game game); + @Override void newId(); diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java index cf80b5c9796..57525a7dbf6 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java @@ -4,7 +4,6 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.CompoundAbility; import mage.abilities.MageSingleton; -import mage.abilities.costs.mana.ActivationManaAbilityStep; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.DomainValue; import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; @@ -19,6 +18,7 @@ import mage.game.stack.Spell; import mage.game.stack.StackObject; import mage.players.Player; import mage.target.targetpointer.TargetPointer; +import mage.watchers.common.EndStepCountWatcher; import java.util.*; @@ -61,6 +61,7 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu private UUID startingControllerId; // player to check for turn duration (can't different with real controller ability) private boolean startingTurnWasActive; // effect started during related players turn and related players turn was already active private int effectStartingOnTurn = 0; // turn the effect started + private int effectStartingEndStep = 0; public ContinuousEffectImpl(Duration duration, Outcome outcome) { super(outcome); @@ -91,14 +92,16 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu this.startingControllerId = effect.startingControllerId; this.startingTurnWasActive = effect.startingTurnWasActive; this.effectStartingOnTurn = effect.effectStartingOnTurn; + this.effectStartingEndStep = effect.effectStartingEndStep; this.dependencyTypes = effect.dependencyTypes; this.dependendToTypes = effect.dependendToTypes; this.characterDefining = effect.characterDefining; } @Override - public void setDuration(Duration duration) { + public ContinuousEffectImpl setDuration(Duration duration) { this.duration = duration; + return this; } @Override @@ -211,6 +214,7 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu this.startingTurnWasActive = activePlayerId != null && activePlayerId.equals(startingController); // you can't use "game" for active player cause it's called from tests/cheat too this.effectStartingOnTurn = game.getTurnNum(); + this.effectStartingEndStep = EndStepCountWatcher.getCount(startingController, game); } @Override @@ -219,6 +223,11 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu && game.isActivePlayer(startingControllerId); } + @Override + public boolean isYourNextEndStep(Game game) { + return EndStepCountWatcher.getCount(startingControllerId, game) > effectStartingEndStep; + } + @Override public boolean isInactive(Ability source, Game game) { // YOUR turn checks @@ -227,6 +236,7 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu switch (duration) { case UntilYourNextTurn: case UntilEndOfYourNextTurn: + case UntilYourNextEndStep: break; default: return false; @@ -237,7 +247,7 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu return false; } - boolean canDelete = false; + boolean canDelete; Player player = game.getPlayer(startingControllerId); // discard on start of turn for leaved player @@ -247,18 +257,26 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu switch (duration) { case UntilYourNextTurn: case UntilEndOfYourNextTurn: - canDelete = player == null - || (!player.isInGame() - && player.hasReachedNextTurnAfterLeaving()); + canDelete = player == null || (!player.isInGame() && player.hasReachedNextTurnAfterLeaving()); + break; + default: + canDelete = false; + } + + if (canDelete) { + return true; } // discard on another conditions (start of your turn) switch (duration) { case UntilYourNextTurn: - if (player != null - && player.isInGame()) { - canDelete = canDelete - || this.isYourNextTurn(game); + if (player != null && player.isInGame()) { + return this.isYourNextTurn(game); + } + break; + case UntilYourNextEndStep: + if (player != null && player.isInGame()) { + return this.isYourNextEndStep(game); } } @@ -418,7 +436,7 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu // extraPredicates from some filters is player related, you don't need it here List list = new ArrayList<>(); Predicates.collectAllComponents(filter.getPredicates(), list); - if (list.stream().anyMatch(p -> p instanceof SubType.SubTypePredicate)) { + if (list.stream().anyMatch(SubType.SubTypePredicate.class::isInstance)) { this.addDependedToType(DependencyType.AddingCreatureType); } } diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java index 7697ea27acc..31bd0688ecf 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java @@ -1247,15 +1247,18 @@ public class ContinuousEffects implements Serializable { } private boolean isAbilityStillExists(final Game game, final Ability ability, ContinuousEffect effect) { - final Card card = game.getPermanentOrLKIBattlefield(ability.getSourceId()); - if (!(effect instanceof BecomesFaceDownCreatureEffect) - && (effect != null && !effect.getDuration().equals(Duration.Custom))) { // Custom effects do not depend on the creating permanent - if (card != null) { - return card.hasAbility(ability, game); - } + switch (effect.getDuration()) { // effects with fixed duration don't need an object with the source ability (e.g. a silence cast with isochronic Scepter has no more a card object + case EndOfCombat: + case EndOfGame: + case EndOfStep: + case EndOfTurn: + case OneUse: + case Custom: // custom duration means the effect ends itself if needed + return true; } - - return true; + final Card card = game.getPermanentOrLKIBattlefield(ability.getSourceId()); + return effect instanceof BecomesFaceDownCreatureEffect + || effect == null || card == null || card.hasAbility(ability, game); } public Set getLayeredEffectAbilities(ContinuousEffect effect) { @@ -1288,45 +1291,36 @@ public class ContinuousEffects implements Serializable { switch (effect.getEffectType()) { case REPLACEMENT: case REDIRECTION: - ReplacementEffect newReplacementEffect = (ReplacementEffect) effect; - replacementEffects.addEffect(newReplacementEffect, source); + replacementEffects.addEffect((ReplacementEffect) effect, source); break; case PREVENTION: - PreventionEffect newPreventionEffect = (PreventionEffect) effect; - preventionEffects.addEffect(newPreventionEffect, source); + preventionEffects.addEffect((PreventionEffect) effect, source); break; case RESTRICTION: - RestrictionEffect newRestrictionEffect = (RestrictionEffect) effect; - restrictionEffects.addEffect(newRestrictionEffect, source); + restrictionEffects.addEffect((RestrictionEffect) effect, source); break; case RESTRICTION_UNTAP_NOT_MORE_THAN: - RestrictionUntapNotMoreThanEffect newRestrictionUntapNotMoreThanEffect = (RestrictionUntapNotMoreThanEffect) effect; - restrictionUntapNotMoreThanEffects.addEffect(newRestrictionUntapNotMoreThanEffect, source); + restrictionUntapNotMoreThanEffects.addEffect((RestrictionUntapNotMoreThanEffect) effect, source); break; case REQUIREMENT: - RequirementEffect newRequirementEffect = (RequirementEffect) effect; - requirementEffects.addEffect(newRequirementEffect, source); + requirementEffects.addEffect((RequirementEffect) effect, source); break; case ASTHOUGH: AsThoughEffect newAsThoughEffect = (AsThoughEffect) effect; - if (!asThoughEffectsMap.containsKey(newAsThoughEffect.getAsThoughEffectType())) { + asThoughEffectsMap.computeIfAbsent(newAsThoughEffect.getAsThoughEffectType(), x -> { ContinuousEffectsList list = new ContinuousEffectsList<>(); allEffectsLists.add(list); - asThoughEffectsMap.put(newAsThoughEffect.getAsThoughEffectType(), list); - } - asThoughEffectsMap.get(newAsThoughEffect.getAsThoughEffectType()).addEffect(newAsThoughEffect, source); + return list; + }).addEffect(newAsThoughEffect, source); break; case COSTMODIFICATION: - CostModificationEffect newCostModificationEffect = (CostModificationEffect) effect; - costModificationEffects.addEffect(newCostModificationEffect, source); + costModificationEffects.addEffect((CostModificationEffect) effect, source); break; case SPLICE: - SpliceCardEffect newSpliceCardEffect = (SpliceCardEffect) effect; - spliceCardEffects.addEffect(newSpliceCardEffect, source); + spliceCardEffects.addEffect((SpliceCardEffect) effect, source); break; case CONTINUOUS_RULE_MODIFICATION: - ContinuousRuleModifyingEffect newContinuousRuleModifiyingEffect = (ContinuousRuleModifyingEffect) effect; - continuousRuleModifyingEffects.addEffect(newContinuousRuleModifiyingEffect, source); + continuousRuleModifyingEffects.addEffect((ContinuousRuleModifyingEffect) effect, source); break; default: layeredEffects.addEffect(effect, source); diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectsList.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectsList.java index 502bca43c54..e6ed6145201 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectsList.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectsList.java @@ -50,7 +50,7 @@ public class ContinuousEffectsList extends ArrayList // rules 514.2 for (Iterator i = this.iterator(); i.hasNext(); ) { T entry = i.next(); - boolean canRemove = false; + boolean canRemove; switch (entry.getDuration()) { case EndOfTurn: canRemove = true; @@ -58,6 +58,11 @@ public class ContinuousEffectsList extends ArrayList case UntilEndOfYourNextTurn: canRemove = entry.isYourNextTurn(game); break; + case UntilYourNextEndStep: + canRemove = entry.isYourNextEndStep(game); + break; + default: + canRemove = false; } if (canRemove) { i.remove(); @@ -149,6 +154,7 @@ public class ContinuousEffectsList extends ArrayList case Custom: case UntilYourNextTurn: case UntilEndOfYourNextTurn: + case UntilYourNextEndStep: // until your turn effects continue until real turn reached, their used it's own inactive method // 514.2 Second, the following actions happen simultaneously: all damage marked on permanents // (including phased-out permanents) is removed and all "until end of turn" and "this turn" effects end. @@ -192,24 +198,19 @@ public class ContinuousEffectsList extends ArrayList * @param source - connected ability */ public void addEffect(T effect, Ability source) { - if (effectAbilityMap.containsKey(effect.getId())) { - Set set = effectAbilityMap.get(effect.getId()); - for (Ability ability : set) { - if (ability.getId().equals(source.getId()) && ability.getSourceId().equals(source.getSourceId())) { - return; - } - } - set.add(source); + Set set = effectAbilityMap.computeIfAbsent(effect.getId(), x -> new HashSet<>()); + if (set.stream() + .filter(ability -> ability.getSourceId().equals(source.getSourceId())) + .map(Ability::getId) + .anyMatch(source.getId()::equals)) { return; } - Set set = new HashSet<>(); set.add(source); - this.effectAbilityMap.put(effect.getId(), set); this.add(effect); } public Set getAbility(UUID effectId) { - return effectAbilityMap.getOrDefault(effectId, new HashSet<>()); + return effectAbilityMap.computeIfAbsent(effectId, x -> new HashSet<>()); } public void removeTemporaryEffects() { @@ -230,7 +231,7 @@ public class ContinuousEffectsList extends ArrayList @Override public boolean contains(Object object) { - if (object == null || !(object instanceof ContinuousEffect)) { + if (!(object instanceof ContinuousEffect)) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousRuleModifyingEffectImpl.java b/Mage/src/main/java/mage/abilities/effects/ContinuousRuleModifyingEffectImpl.java index 55d5b56361f..17bec187922 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousRuleModifyingEffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousRuleModifyingEffectImpl.java @@ -85,7 +85,7 @@ public abstract class ContinuousRuleModifyingEffectImpl extends ContinuousEffect public String getInfoMessage(Ability source, GameEvent event, Game game) { if (infoMessage == null) { String message; - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object != null) { message = source.getRule(messageToUser ? object.getIdName() : object.getLogName()); } else { diff --git a/Mage/src/main/java/mage/abilities/effects/Effects.java b/Mage/src/main/java/mage/abilities/effects/Effects.java index 47bbb94eb1e..d22d0e4d663 100644 --- a/Mage/src/main/java/mage/abilities/effects/Effects.java +++ b/Mage/src/main/java/mage/abilities/effects/Effects.java @@ -107,8 +107,9 @@ public class Effects extends ArrayList { && !lastRule.endsWith(".") && !lastRule.endsWith("\"") && !lastRule.endsWith(".]") - && !lastRule.startsWith("Level ") + && !lastRule.startsWith("LEVEL ") && !lastRule.endsWith(".)") + && !lastRule.endsWith("
") && !lastRule.endsWith("
")) { sbText.append('.'); } diff --git a/Mage/src/main/java/mage/abilities/effects/EntersBattlefieldEffect.java b/Mage/src/main/java/mage/abilities/effects/EntersBattlefieldEffect.java index 52db89542d2..58d31684567 100644 --- a/Mage/src/main/java/mage/abilities/effects/EntersBattlefieldEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/EntersBattlefieldEffect.java @@ -98,7 +98,7 @@ public class EntersBattlefieldEffect extends ReplacementEffectImpl { Player controller = game.getPlayer(source.getControllerId()); MageObject object = game.getPermanentEntering(source.getSourceId()); if (object == null) { - object = game.getObject(source.getSourceId()); + object = game.getObject(source); } if (controller == null || object == null) { return false; diff --git a/Mage/src/main/java/mage/abilities/effects/EquipEffect.java b/Mage/src/main/java/mage/abilities/effects/EquipEffect.java deleted file mode 100644 index 392713bbf7b..00000000000 --- a/Mage/src/main/java/mage/abilities/effects/EquipEffect.java +++ /dev/null @@ -1,39 +0,0 @@ -package mage.abilities.effects; - -import mage.abilities.Ability; -import mage.abilities.effects.common.AttachEffect; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.game.Game; -import mage.game.permanent.Permanent; - -public class EquipEffect extends AttachEffect { - - public EquipEffect(Outcome outcome) { - super(outcome, "Equip"); - } - - public EquipEffect(EquipEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - //301.5c An Equipment that’s also a creature can’t equip a creature. An Equipment that loses the subtype - // “Equipment” can’t equip a creature. An Equipment can’t equip itself. An Equipment that equips an illegal or - // nonexistent permanent becomes unattached from that permanent but remains on the battlefield. (This is a - // state-based action. See rule 704.) An Equipment can’t equip more than one creature. If a spell or ability - // would cause an Equipment to equip more than one creature, the Equipment’s controller chooses which creature - // it equips. - if (sourcePermanent != null && sourcePermanent.hasSubtype(SubType.EQUIPMENT, game) && !sourcePermanent.isCreature(game)) { - return super.apply(game, source); - } - return false; - } - - @Override - public EquipEffect copy(){ - return new EquipEffect(this); - } -} diff --git a/Mage/src/main/java/mage/abilities/effects/PlaneswalkerRedirectionEffect.java b/Mage/src/main/java/mage/abilities/effects/PlaneswalkerRedirectionEffect.java index 6a4262deef4..617b819baac 100644 --- a/Mage/src/main/java/mage/abilities/effects/PlaneswalkerRedirectionEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/PlaneswalkerRedirectionEffect.java @@ -10,7 +10,6 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.game.stack.StackObject; import mage.players.Player; @@ -60,7 +59,7 @@ public class PlaneswalkerRedirectionEffect extends RedirectionEffect { redirectTarget.add(planeswalker.get(0).getId(), game); } } else { - player.choose(Outcome.Damage, redirectTarget, null, game); + player.choose(Outcome.Damage, redirectTarget, source, game); } if (!game.isSimulation()) { Permanent redirectTo = game.getPermanent(redirectTarget.getFirstTarget()); diff --git a/Mage/src/main/java/mage/abilities/effects/RedirectionEffect.java b/Mage/src/main/java/mage/abilities/effects/RedirectionEffect.java index 404791d020f..2804b557e27 100644 --- a/Mage/src/main/java/mage/abilities/effects/RedirectionEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/RedirectionEffect.java @@ -65,7 +65,7 @@ public abstract class RedirectionEffect extends ReplacementEffectImpl { if (damageToRedirect < 1) { // if multiple replacement effect apply, the rest damage can be 0, so the effect is not applied/replaced return false; } - String sourceLogName = source != null ? game.getObject(source.getSourceId()).getLogName() + ": " : ""; + String sourceLogName = source != null ? game.getObject(source).getLogName() + ": " : ""; DamageEvent damageEvent = (DamageEvent) event; int restDamage = 0; if (damageEvent.getAmount() > amountToRedirect) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/AddContinuousEffectToGame.java b/Mage/src/main/java/mage/abilities/effects/common/AddContinuousEffectToGame.java index 963a4fc4b81..8db76711cc7 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/AddContinuousEffectToGame.java +++ b/Mage/src/main/java/mage/abilities/effects/common/AddContinuousEffectToGame.java @@ -2,10 +2,11 @@ package mage.abilities.effects.common; -import mage.constants.Outcome; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; import mage.game.Game; /** @@ -18,7 +19,6 @@ public class AddContinuousEffectToGame extends OneShotEffect { public AddContinuousEffectToGame(ContinuousEffect effect) { super(Outcome.Benefit); this.effect = effect; - this.staticText = effect.getText(null); } public AddContinuousEffectToGame(final AddContinuousEffectToGame effect) { @@ -36,4 +36,9 @@ public class AddContinuousEffectToGame extends OneShotEffect { game.addEffect(effect, source); return true; } + + @Override + public String getText(Mode mode) { + return effect.getText(mode); + } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/AffinityEffect.java b/Mage/src/main/java/mage/abilities/effects/common/AffinityEffect.java index cf332b95df1..1d372b8b79e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/AffinityEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/AffinityEffect.java @@ -34,7 +34,7 @@ public class AffinityEffect extends CostModificationEffectImpl { @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { // abilityToModify.getControllerId() works with Sen Triplets and in multiplayer games, see https://github.com/magefree/mage/issues/5931 - int count = game.getBattlefield().getActivePermanents(filter, abilityToModify.getControllerId(), source.getId(), game).size(); + int count = game.getBattlefield().getActivePermanents(filter, abilityToModify.getControllerId(), source, game).size(); CardUtil.reduceCost(abilityToModify, count); return true; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/AmplifyEffect.java b/Mage/src/main/java/mage/abilities/effects/common/AmplifyEffect.java index 6788f5db765..91e5c45a81f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/AmplifyEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/AmplifyEffect.java @@ -116,7 +116,7 @@ public class AmplifyEffect extends ReplacementEffectImpl { filter.add(Predicates.not(new CardIdPredicate(enteringPermanent.getId()))); } - if (controller.getHand().count(filter, source.getSourceId(), source.getControllerId(), game) <= 0) { + if (controller.getHand().count(filter, source.getControllerId(), source, game) <= 0) { return false; } if (!controller.chooseUse(outcome, "Reveal cards to Amplify?", source, game)) { 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 1918bc1c6c5..9290eccbd74 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/AttachEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/AttachEffect.java @@ -10,6 +10,8 @@ import mage.players.Player; import mage.target.TargetCard; import mage.util.CardUtil; +import java.util.UUID; + /** * @author BetaSteward_at_googlemail.com */ @@ -36,30 +38,29 @@ public class AttachEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (sourcePermanent != null) { - // if it activating on the stack then allow +1 zcc - int zcc = game.getState().getZoneChangeCounter(sourcePermanent.getId()); - if (zcc == CardUtil.getActualSourceObjectZoneChangeCounter(game, source) - || zcc == CardUtil.getActualSourceObjectZoneChangeCounter(game, source) + 1) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent != null) { - return permanent.addAttachment(source.getSourceId(), source, game); - } else { - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (player != null) { - return player.addAttachment(source.getSourceId(), source, game); - } - if (!source.getTargets().isEmpty() && 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(), source, game); - } - } - } - } + if (sourcePermanent == null) { + return false; } - - return false; + // if it activating on the stack then allow +1 zcc + int zcc = game.getState().getZoneChangeCounter(sourcePermanent.getId()); + if (zcc != CardUtil.getActualSourceObjectZoneChangeCounter(game, source) + && zcc != CardUtil.getActualSourceObjectZoneChangeCounter(game, source) + 1) { + return false; + } + UUID targetId = getTargetPointer().getFirst(game, source); + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + return permanent.addAttachment(source.getSourceId(), source, game); + } + Player player = game.getPlayer(targetId); + if (player != null) { + return player.addAttachment(source.getSourceId(), source, game); + } + if (source.getTargets().isEmpty() || !(source.getTargets().get(0) instanceof TargetCard)) { + return false; + } + Card card = game.getCard(targetId); + return card != null && card.addAttachment(source.getSourceId(), source, game); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/BalanceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/BalanceEffect.java index 4b9a19756aa..e3d2e07c1d4 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/BalanceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/BalanceEffect.java @@ -78,7 +78,7 @@ public class BalanceEffect extends OneShotEffect { if (lowestHandSize > 0) { TargetCardInHand target = new TargetCardInHand(lowestHandSize, filterCardHand); - if (target.choose(Outcome.Protect, player.getId(), source.getSourceId(), game)) { + if (target.choose(Outcome.Protect, player.getId(), source.getSourceId(), source, game)) { for (Card card : allCardsInHand) { if (card != null && target.getTargets().contains(card.getId())) { cardsToKeep.add(card); @@ -136,12 +136,12 @@ public class BalanceEffect extends OneShotEffect { continue; } - List allPermanentsOfType = game.getBattlefield().getActivePermanents(filterPermanent, player.getId(), source.getSourceId(), game); + List allPermanentsOfType = game.getBattlefield().getActivePermanents(filterPermanent, player.getId(), source, game); List permanentsToKeep = new ArrayList<>(); if (lowestPermanentsCount > 0) { TargetControlledPermanent target = new TargetControlledPermanent(lowestPermanentsCount, lowestPermanentsCount, filterPermanent, true); - if (target.choose(Outcome.Protect, player.getId(), source.getSourceId(), game)) { + if (target.choose(Outcome.Protect, player.getId(), source.getSourceId(), source, game)) { for (Permanent permanent : allPermanentsOfType) { if (permanent != null && target.getTargets().contains(permanent.getId())) { permanentsToKeep.add(permanent); diff --git a/Mage/src/main/java/mage/abilities/effects/common/BrainstormEffect.java b/Mage/src/main/java/mage/abilities/effects/common/BrainstormEffect.java index 7e3c5b843c4..d962b3a0227 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/BrainstormEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/BrainstormEffect.java @@ -39,7 +39,7 @@ public class BrainstormEffect extends OneShotEffect { private boolean putOnLibrary(Player player, Ability source, Game game) { TargetCardInHand target = new TargetCardInHand(); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.ReturnToHand, target, source, game); Card card = player.getHand().get(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/CantBeCounteredControlledEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CantBeCounteredControlledEffect.java index 1b2eafcf901..9b6023211c9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CantBeCounteredControlledEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CantBeCounteredControlledEffect.java @@ -59,7 +59,7 @@ public class CantBeCounteredControlledEffect extends ContinuousRuleModifyingEffe public boolean applies(GameEvent event, Ability source, Game game) { Spell spell = game.getStack().getSpell(event.getTargetId()); if (spell != null && spell.isControlledBy(source.getControllerId()) - && filterTarget.match(spell, source.getSourceId(), source.getControllerId(), game)) { + && filterTarget.match(spell, source.getControllerId(), source, game)) { if (filterSource == null) { return true; } else { diff --git a/Mage/src/main/java/mage/abilities/effects/common/CantBeCounteredSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CantBeCounteredSourceEffect.java index a56d3744fb3..9520507800d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CantBeCounteredSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CantBeCounteredSourceEffect.java @@ -41,7 +41,7 @@ public class CantBeCounteredSourceEffect extends ContinuousRuleModifyingEffectIm @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { StackObject stackObject = game.getStack().getStackObject(event.getTargetId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (stackObject != null && sourceObject != null) { return sourceObject.getLogName() + " can't be countered by " + stackObject.getName(); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/CantBeTargetedAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CantBeTargetedAllEffect.java index a2c34d6fc8d..c32aabf7c5b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CantBeTargetedAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CantBeTargetedAllEffect.java @@ -11,7 +11,6 @@ import mage.filter.FilterPermanent; import mage.filter.FilterSpell; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.game.stack.StackAbility; import mage.game.stack.StackObject; @@ -64,7 +63,7 @@ public class CantBeTargetedAllEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null && filterTarget.match(permanent, source.getSourceId(), source.getControllerId(), game)) { + if (permanent != null && filterTarget.match(permanent, source.getControllerId(), source, game)) { StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); MageObject sourceObject; if (stackObject instanceof StackAbility) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java index 4b032cfc69c..a4c2c8dbc22 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CastCardFromOutsideTheGameEffect.java @@ -55,7 +55,7 @@ public class CastCardFromOutsideTheGameEffect extends OneShotEffect { return false; } - Set filtered = cards.getCards(filterCard, source.getSourceId(), source.getControllerId(), game); + Set filtered = cards.getCards(filterCard, source.getControllerId(), source, game); if (filtered.isEmpty()) { if (!game.isSimulation()) { game.informPlayer(player, "You have no " + filterCard.getMessage() + " outside the game."); diff --git a/Mage/src/main/java/mage/abilities/effects/common/CastSourceTriggeredAbility.java b/Mage/src/main/java/mage/abilities/effects/common/CastSourceTriggeredAbility.java index ed30c027ff7..887685a3fda 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CastSourceTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CastSourceTriggeredAbility.java @@ -14,25 +14,18 @@ import mage.game.stack.Spell; public class CastSourceTriggeredAbility extends TriggeredAbilityImpl { public static final String SOURCE_CAST_SPELL_ABILITY = "sourceCastSpellAbility"; - private final String rulePrefix; public CastSourceTriggeredAbility(Effect effect) { this(effect, false); } public CastSourceTriggeredAbility(Effect effect, boolean optional) { - this(effect, optional, ""); - } - - public CastSourceTriggeredAbility(Effect effect, boolean optional, String rulePrefix) { super(Zone.STACK, effect, optional); this.ruleAtTheTop = true; - this.rulePrefix = rulePrefix; } public CastSourceTriggeredAbility(final CastSourceTriggeredAbility ability) { super(ability); - this.rulePrefix = ability.rulePrefix; } @Override @@ -64,6 +57,6 @@ public class CastSourceTriggeredAbility extends TriggeredAbilityImpl { @Override public String getTriggerPhrase() { - return rulePrefix + "When you cast this spell, " ; + return "When you cast this spell, "; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChangeATargetOfTargetSpellAbilityToSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChangeATargetOfTargetSpellAbilityToSourceEffect.java index 530dc535f38..9cfb2c7675b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChangeATargetOfTargetSpellAbilityToSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChangeATargetOfTargetSpellAbilityToSourceEffect.java @@ -32,7 +32,7 @@ public class ChangeATargetOfTargetSpellAbilityToSourceEffect extends OneShotEffe @Override public boolean apply(Game game, Ability source) { StackObject stackObject = game.getStack().getStackObject(source.getFirstTarget()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (stackObject != null && sourceObject != null) { Targets targets = new Targets(); Ability sourceAbility; diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChooseACardNameEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChooseACardNameEffect.java index 9bcb1fb6cd9..111761e43b3 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChooseACardNameEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseACardNameEffect.java @@ -25,7 +25,7 @@ public class ChooseACardNameEffect extends OneShotEffect { public enum TypeOfName { ALL("card name", CardRepository.instance::getNames), - NOT_BASIC_LAND_NAME("card name other than a basic land card", CardRepository.instance::getNotBasicLandNames), + NOT_BASIC_LAND_NAME("card name other than a basic land card name", CardRepository.instance::getNotBasicLandNames), NONBASIC_LAND_NAME("nonbasic land card name", CardRepository.instance::getNonbasicLandNames), NON_ARTIFACT_AND_NON_LAND_NAME("nonartifact, nonland card name", CardRepository.instance::getNonArtifactAndNonLandNames), NON_LAND_AND_NON_CREATURE_NAME("nonland and non creature name", CardRepository.instance::getNonLandAndNonCreatureNames), diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChooseBasicLandTypeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChooseBasicLandTypeEffect.java index 180b5b08cf9..4ded699c7fe 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChooseBasicLandTypeEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseBasicLandTypeEffect.java @@ -38,7 +38,7 @@ public class ChooseBasicLandTypeEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } if (controller != null && mageObject != null) { ChoiceImpl choices = new ChoiceBasicLandType(); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChooseCardTypeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChooseCardTypeEffect.java index f965de8ed36..4f8404396b0 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChooseCardTypeEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseCardTypeEffect.java @@ -49,7 +49,7 @@ public class ChooseCardTypeEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } if (controller != null && mageObject != null) { Choice typeChoice = new ChoiceCardType(true, cardTypes); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChooseColorEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChooseColorEffect.java index ddda5e3e108..bb311417e07 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChooseColorEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseColorEffect.java @@ -40,7 +40,7 @@ public class ChooseColorEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } ChoiceColor choice = new ChoiceColor(); if (exceptColor != null) { 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 1f89ff5a785..8eef0bebdc6 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChooseCreatureTypeEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseCreatureTypeEffect.java @@ -33,7 +33,7 @@ public class ChooseCreatureTypeEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } if (controller != null && mageObject != null) { Choice typeChoice = new ChoiceCreatureType(mageObject); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChooseExpansionSetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChooseExpansionSetEffect.java index 8100a81ac6d..e2956dab7e0 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChooseExpansionSetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseExpansionSetEffect.java @@ -36,7 +36,7 @@ public class ChooseExpansionSetEffect extends OneShotEffect { MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } if (controller != null) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChooseLandTypeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChooseLandTypeEffect.java index 1ea0e9c123b..72017f024bc 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChooseLandTypeEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseLandTypeEffect.java @@ -33,7 +33,7 @@ public class ChooseLandTypeEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } if (controller != null && mageObject != null) { Choice typeChoice = new ChoiceImpl(true); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChooseOpponentEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChooseOpponentEffect.java index 2b3064ea026..655607fe22a 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChooseOpponentEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseOpponentEffect.java @@ -37,11 +37,11 @@ public class ChooseOpponentEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } if (controller != null && mageObject != null) { TargetOpponent target = new TargetOpponent(true); - if (controller.choose(this.outcome, target, source.getSourceId(), game)) { + if (controller.choose(this.outcome, target, source, game)) { Player chosenPlayer = game.getPlayer(target.getFirstTarget()); if (chosenPlayer != null) { game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + chosenPlayer.getLogName()); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChoosePlayerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChoosePlayerEffect.java index a7e0132e654..28046a14eb9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChoosePlayerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChoosePlayerEffect.java @@ -35,11 +35,11 @@ public class ChoosePlayerEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } if (controller != null && mageObject != null) { TargetPlayer target = new TargetPlayer(1, 1, true); - if (controller.choose(this.outcome, target, source.getSourceId(), game)) { + if (controller.choose(this.outcome, target, source, game)) { Player chosenPlayer = game.getPlayer(target.getFirstTarget()); if (chosenPlayer != null) { game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + chosenPlayer.getLogName()); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChooseSecretOpponentEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChooseSecretOpponentEffect.java index 7fedba19817..e1578b23237 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChooseSecretOpponentEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseSecretOpponentEffect.java @@ -4,7 +4,6 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; -import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -37,14 +36,14 @@ public class ChooseSecretOpponentEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getPermanentEntering(source.getSourceId()); if (mageObject == null) { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } if (controller == null || mageObject == null) { return false; } TargetOpponent targetOpponent = new TargetOpponent(true); targetOpponent.setTargetName("opponent (secretly)"); - controller.choose(outcome, targetOpponent, source.getSourceId(), game); + controller.choose(outcome, targetOpponent, source, game); if (targetOpponent.getFirstTarget() == null) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java index 8dc9bdfbfd5..1df904ad9ae 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java @@ -65,7 +65,7 @@ public class CipherEffect extends OneShotEffect { if (controller != null) { TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game) + if (target.canChoose(source.getControllerId(), source, game) && controller.chooseUse(outcome, "Cipher this spell to a creature?", source, game)) { controller.chooseTarget(outcome, target, source, game); Card sourceCard = game.getCard(source.getSourceId()); @@ -118,7 +118,7 @@ class CipherStoreEffect extends OneShotEffect { Card copyCard = game.copyCard(cipherCard, source, controller.getId()); SpellAbility ability = copyCard.getSpellAbility(); // remove the cipher effect from the copy - ability.getEffects().removeIf(effect -> effect instanceof CipherEffect); + ability.getEffects().removeIf(CipherEffect.class::isInstance); controller.cast(ability, game, true, new ApprovingObject(source, game)); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ClashEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ClashEffect.java index 0cfdb3838f0..1d5d983c28f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ClashEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ClashEffect.java @@ -95,7 +95,7 @@ public class ClashEffect extends OneShotEffect implements MageSingleton { Target target = new TargetOpponent(true); target.setTargetName("an opponent to clash with"); target.setNotTarget(true); - if (!controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + if (!controller.choose(Outcome.Benefit, target, source, game)) { return false; } Player opponent = game.getPlayer(target.getFirstTarget()); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ConjureCardEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ConjureCardEffect.java index ddb8bd59a17..60ad936be12 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ConjureCardEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ConjureCardEffect.java @@ -77,9 +77,11 @@ public class ConjureCardEffect extends OneShotEffect { StringBuilder sb = new StringBuilder("conjure "); sb.append(CardUtil.numberToText(amount, "a")); sb.append(' '); - sb.append(cardName); sb.append("card"); sb.append(amount > 1 ? "s " : " "); + sb.append("named "); + sb.append(cardName); + sb.append(' '); switch (zone) { case HAND: case GRAVEYARD: @@ -88,7 +90,8 @@ public class ConjureCardEffect extends OneShotEffect { case BATTLEFIELD: sb.append("onto the"); } - sb.append(zone); + sb.append(' '); + sb.append(zone.toString().toLowerCase()); return sb.toString(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java index 5f4f1dd5ccf..f4a585a7610 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java @@ -132,6 +132,7 @@ public class CopyEffect extends ContinuousEffectImpl { // and abilities that were chosen for this creature as it entered the battlefield. (2018-03-16) permanent.getPower().setValue(copyFromObject.getPower().getBaseValueModified()); permanent.getToughness().setValue(copyFromObject.getToughness().getBaseValueModified()); + permanent.setStartingLoyalty(copyFromObject.getStartingLoyalty()); if (copyFromObject instanceof Permanent) { Permanent targetPermanent = (Permanent) copyFromObject; permanent.setTransformed(targetPermanent.isTransformed()); diff --git a/Mage/src/main/java/mage/abilities/effects/common/CopyPermanentEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CopyPermanentEffect.java index 014f2368ec3..9b446d1fd08 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CopyPermanentEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CopyPermanentEffect.java @@ -80,7 +80,7 @@ public class CopyPermanentEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourcePermanent = game.getPermanentEntering(source.getSourceId()); if (sourcePermanent == null) { - sourcePermanent = game.getObject(source.getSourceId()); + sourcePermanent = game.getObject(source); } if (controller == null || sourcePermanent == null) { return false; @@ -91,8 +91,8 @@ public class CopyPermanentEffect extends OneShotEffect { } else { Target target = new TargetPermanent(filter); target.setNotTarget(true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { - controller.choose(Outcome.Copy, target, source.getSourceId(), game); + if (target.canChoose(controller.getId(), source, game)) { + controller.choose(Outcome.Copy, target, source, game); copyFromPermanent = game.getPermanent(target.getFirstTarget()); } } @@ -157,7 +157,7 @@ public class CopyPermanentEffect extends OneShotEffect { // select new target auraTarget.setNotTarget(true); - if (!controller.choose(auraOutcome, auraTarget, source.getSourceId(), game)) { + if (!controller.choose(auraOutcome, auraTarget, source, game)) { return true; } UUID targetId = auraTarget.getFirstTarget(); diff --git a/Mage/src/main/java/mage/abilities/effects/common/CreateDelayedTriggeredAbilityEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CreateDelayedTriggeredAbilityEffect.java index 9fe41bcabaf..543ca0539da 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CreateDelayedTriggeredAbilityEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CreateDelayedTriggeredAbilityEffect.java @@ -48,9 +48,7 @@ public class CreateDelayedTriggeredAbilityEffect extends OneShotEffect { DelayedTriggeredAbility delayedAbility = ability.copy(); if (this.copyTargets) { if (source.getTargets().isEmpty()) { - for (Effect effect : delayedAbility.getEffects()) { - effect.setTargetPointer(targetPointer); - } + delayedAbility.getEffects().setTargetPointer(targetPointer); } else { delayedAbility.getTargets().addAll(source.getTargets()); for (Effect effect : delayedAbility.getEffects()) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenAttachSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenAttachSourceEffect.java index 3f0d7fbac37..4941bed1f1c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenAttachSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenAttachSourceEffect.java @@ -6,7 +6,6 @@ import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; /** - * * @author weirddan455 */ public class CreateTokenAttachSourceEffect extends CreateTokenEffect { @@ -28,7 +27,7 @@ public class CreateTokenAttachSourceEffect extends CreateTokenEffect { @Override public boolean apply(Game game, Ability source) { super.apply(game, source); - Permanent token = game.getPermanent(this.getLastAddedTokenId()); + Permanent token = game.getPermanent(this.getLastAddedTokenIds().stream().findFirst().orElse(null)); if (token != null) { token.addAttachment(source.getSourceId(), source, game); return true; diff --git a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java index 92746ff3728..3fd986660fa 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java @@ -5,12 +5,10 @@ import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.Mode; -import mage.abilities.TriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; -import mage.abilities.effects.EffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; @@ -20,7 +18,6 @@ import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.EmptyToken; -import mage.game.turn.Step; import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTargets; import mage.util.CardUtil; @@ -289,20 +286,23 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect { if (tapped && !attacking) { sb.append("tapped "); } - sb.append("token that's a copy of target "); + sb.append("token that's a copy of "); } else { sb.append(number); sb.append(" "); if (tapped && !attacking) { sb.append("tapped "); } - sb.append("tokens that are copies of target "); + sb.append("tokens that are copies of "); } - if (!mode.getTargets().isEmpty()) { - sb.append(mode.getTargets().get(0).getTargetName()); - } else { + if (mode.getTargets().isEmpty()) { throw new UnsupportedOperationException("Using default rule generation of target effect without having a target object"); } + String targetName = mode.getTargets().get(0).getTargetName(); + if (!targetName.startsWith("another target")) { + sb.append("target "); + } + sb.append(targetName); if (attacking) { sb.append(" that are"); @@ -354,27 +354,39 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect { this.number = number; } + public void sacrificeTokensCreatedAtNextEndStep(Game game, Ability source) { + this.removeTokensCreatedAtEndOf(game, source, PhaseStep.END_TURN, false); + } + public void exileTokensCreatedAtNextEndStep(Game game, Ability source) { - this.exileTokensCreatedAtEndOf(game, source, PhaseStep.END_TURN); + this.removeTokensCreatedAtEndOf(game, source, PhaseStep.END_TURN, true); + } + + public void sacrificeTokensCreatedAtEndOfCombat(Game game, Ability source) { + this.removeTokensCreatedAtEndOf(game, source, PhaseStep.END_COMBAT, false); } public void exileTokensCreatedAtEndOfCombat(Game game, Ability source) { - this.exileTokensCreatedAtEndOf(game, source, PhaseStep.END_COMBAT); + this.removeTokensCreatedAtEndOf(game, source, PhaseStep.END_COMBAT, true); } - private void exileTokensCreatedAtEndOf(Game game, Ability source, PhaseStep phaseStepToExileCards) { - ExileTargetEffect exileEffect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD); - exileEffect.setText("exile the token copies"); - exileEffect.setTargetPointer(new FixedTargets(addedTokenPermanents, game)); + private void removeTokensCreatedAtEndOf(Game game, Ability source, PhaseStep phaseStepToExileCards, boolean exile) { + Effect effect; + if (exile) { + effect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD).setText("exile the token copies"); + } else { + effect = new SacrificeTargetEffect("sacrifice the token copies"); + } + effect.setTargetPointer(new FixedTargets(addedTokenPermanents, game)); DelayedTriggeredAbility exileAbility; switch (phaseStepToExileCards) { case END_TURN: - exileAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); + exileAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); break; case END_COMBAT: - exileAbility = new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect); + exileAbility = new AtTheEndOfCombatDelayedTriggeredAbility(effect); break; default: return; diff --git a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenEffect.java index 5eab8fc9885..b496483315e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenEffect.java @@ -24,11 +24,10 @@ import java.util.UUID; */ public class CreateTokenEffect extends OneShotEffect { - private Token token; - private DynamicValue amount; - private boolean tapped; - private boolean attacking; - private UUID lastAddedTokenId; + private final Token token; + private final DynamicValue amount; + private final boolean tapped; + private final boolean attacking; private List lastAddedTokenIds = new ArrayList<>(); public CreateTokenEffect(Token token) { @@ -62,7 +61,6 @@ public class CreateTokenEffect extends OneShotEffect { this.token = effect.token.copy(); this.tapped = effect.tapped; this.attacking = effect.attacking; - this.lastAddedTokenId = effect.lastAddedTokenId; this.lastAddedTokenIds.addAll(effect.lastAddedTokenIds); } @@ -75,16 +73,11 @@ public class CreateTokenEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { int value = amount.calculate(game, source, this); token.putOntoBattlefield(value, game, source, source.getControllerId(), tapped, attacking); - this.lastAddedTokenId = token.getLastAddedToken(); this.lastAddedTokenIds = token.getLastAddedTokenIds(); return true; } - public UUID getLastAddedTokenId() { - return lastAddedTokenId; - } - public List getLastAddedTokenIds() { return lastAddedTokenIds; } @@ -118,17 +111,18 @@ public class CreateTokenEffect extends OneShotEffect { } StringBuilder sb = new StringBuilder("create "); if (amount.toString().equals("1")) { - sb.append("a "); if (tapped && !attacking) { - sb.append("tapped "); + sb.append("a tapped "); + sb.append(token.getDescription()); + } else { + sb.append(CardUtil.addArticle(token.getDescription())); } - sb.append(token.getDescription()); } else { sb.append(CardUtil.numberToText(amount.toString())).append(' '); if (tapped && !attacking) { sb.append("tapped "); } - sb.append(token.getDescription()); + sb.append(token.getDescription().replace("token. It has", "tokens. They have")); if (token.getDescription().endsWith("token")) { sb.append("s"); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/CrewsVehicleSourceTriggeredAbility.java b/Mage/src/main/java/mage/abilities/effects/common/CrewsVehicleSourceTriggeredAbility.java index 214cb25fa15..35b2f0842dd 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CrewsVehicleSourceTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CrewsVehicleSourceTriggeredAbility.java @@ -43,6 +43,6 @@ public class CrewsVehicleSourceTriggeredAbility extends TriggeredAbilityImpl { @Override public String getTriggerPhrase() { - return "When {this} crews a Vehicle, " ; + return "Whenever {this} crews a Vehicle, " ; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageAllControlledTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageAllControlledTargetEffect.java index da0c5dd2b3c..3b30b9e8799 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DamageAllControlledTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageAllControlledTargetEffect.java @@ -1,10 +1,13 @@ - package mage.abilities.effects.common; -import mage.constants.Outcome; import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -15,20 +18,43 @@ import mage.players.Player; */ public class DamageAllControlledTargetEffect extends OneShotEffect { - private FilterPermanent filter; - private int amount; + private final DynamicValue amount; + private final FilterPermanent filter; + private String sourceName = "{this}"; + + public DamageAllControlledTargetEffect(int amount) { + this(amount, StaticFilters.FILTER_PERMANENT_CREATURE); + } + + public DamageAllControlledTargetEffect(int amount, String whoDealDamageName) { + this(amount, StaticFilters.FILTER_PERMANENT_CREATURE); + this.sourceName = whoDealDamageName; + } + + public DamageAllControlledTargetEffect(DynamicValue amount) { + this(amount, StaticFilters.FILTER_PERMANENT_CREATURE); + } + + public DamageAllControlledTargetEffect(DynamicValue amount, String whoDealDamageName) { + this(amount, StaticFilters.FILTER_PERMANENT_CREATURE); + this.sourceName = whoDealDamageName; + } public DamageAllControlledTargetEffect(int amount, FilterPermanent filter) { + this(StaticValue.get(amount), filter); + } + + public DamageAllControlledTargetEffect(DynamicValue amount, FilterPermanent filter) { super(Outcome.Damage); this.amount = amount; this.filter = filter; - getText(); } public DamageAllControlledTargetEffect(final DamageAllControlledTargetEffect effect) { super(effect); - this.amount = effect.amount; + this.amount = effect.amount.copy(); this.filter = effect.filter.copy(); + this.sourceName = effect.sourceName; } @Override @@ -38,19 +64,29 @@ public class DamageAllControlledTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayerOrPlaneswalkerController(source.getFirstTarget()); + Player player = game.getPlayerOrPlaneswalkerController(targetPointer.getFirst(game, source)); if (player == null) { return false; } for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, player.getId(), game)) { - permanent.damage(amount, source.getSourceId(), source, game, false, true); + permanent.damage(amount.calculate(game, source, this), source.getSourceId(), source, game, false, true); } return true; } - private void getText() { - StringBuilder sb = new StringBuilder("{this} deals "); - sb.append(amount).append(" damage to each ").append(filter.getMessage()).append(" controlled by target player"); - staticText = sb.toString(); + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + StringBuilder sb = new StringBuilder(sourceName); + sb.append(" deals ").append(amount).append(" damage to each ").append(filter.getMessage()); + if (mode.getTargets().isEmpty()) { + sb.append(" that player"); + } else { + sb.append(" target ").append(mode.getTargets().get(0).getTargetName()); + } + sb.append(" controls"); + return sb.toString(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageAllEffect.java index 11eaed42696..6d2172f7d07 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DamageAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageAllEffect.java @@ -54,7 +54,7 @@ public class DamageAllEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); for (Permanent permanent : permanents) { permanent.damage(amount.calculate(game, source, this), source.getSourceId(), source, game, false, true); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageAttachedControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageAttachedControllerEffect.java index 7e350a8da3a..401d8e49cba 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DamageAttachedControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageAttachedControllerEffect.java @@ -19,13 +19,13 @@ public class DamageAttachedControllerEffect extends OneShotEffect { protected DynamicValue amount; public DamageAttachedControllerEffect(int amount) { - super(Outcome.Damage); - this.amount = StaticValue.get(amount); + this(StaticValue.get(amount)); } public DamageAttachedControllerEffect(DynamicValue amount) { super(Outcome.Damage); this.amount = amount; + this.staticText = "{this} deals " + amount + " damage to that creature's controller"; } public DamageAttachedControllerEffect(final DamageAttachedControllerEffect effect) { @@ -60,15 +60,4 @@ public class DamageAttachedControllerEffect extends OneShotEffect { } return false; } - - @Override - public String getText(Mode mode) { - if (staticText != null && !staticText.isEmpty()) { - return staticText; - } - if ("equal to".equals(amount.toString())) { - return "{this} deals damage " + amount + " that creatures toughness to that creature's controller"; - } - return "{this} deals " + amount + " damage to that creature's controller"; - } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageAttachedEffect.java index 0d4e3f86bb6..2a858c8f419 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DamageAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageAttachedEffect.java @@ -1,5 +1,3 @@ - - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -19,27 +17,28 @@ import mage.game.permanent.Permanent; public class DamageAttachedEffect extends OneShotEffect { protected DynamicValue amount; - private String sourceName = "{this}"; public DamageAttachedEffect(int amount) { - super(Outcome.Damage); - this.amount = StaticValue.get(amount); + this(StaticValue.get(amount), "{this}"); } public DamageAttachedEffect(int amount, String whoDealDamageName) { - this(amount); - this.sourceName = whoDealDamageName; + this(StaticValue.get(amount), whoDealDamageName); } - + public DamageAttachedEffect(DynamicValue amount) { + this(amount, "{this}"); + } + + public DamageAttachedEffect(DynamicValue amount, String whoDealDamageName) { super(Outcome.Damage); this.amount = amount; + this.staticText = whoDealDamageName + " deals " + amount + " damage to enchanted creature"; } public DamageAttachedEffect(final DamageAttachedEffect effect) { super(effect); this.amount = effect.amount; - this.sourceName = effect.sourceName; } @Override @@ -65,23 +64,4 @@ public class DamageAttachedEffect extends OneShotEffect { enchanted.damage(amount.calculate(game, source, this), source.getSourceId(), source, game, false, true); return true; } - - @Override - public String getText(Mode mode) { - if (staticText != null && !staticText.isEmpty()) { - return staticText; - } - if ("equal to".equals(amount.toString())) { - return this.sourceName + " deals damage " + amount + " that creatures toughness to that creature"; - } - return this.sourceName + " deals " + amount + " damage to that creature"; - } - - public String getSourceName() { - return sourceName; - } - - public void setSourceName(String sourceName) { - this.sourceName = sourceName; - } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageControllerEffect.java index 15c41536dd9..616ea253b5d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DamageControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageControllerEffect.java @@ -1,5 +1,3 @@ - - package mage.abilities.effects.common; import mage.constants.Outcome; @@ -21,39 +19,35 @@ public class DamageControllerEffect extends OneShotEffect { protected boolean preventable; private String sourceName = "{this}"; - public DamageControllerEffect(int amount, String whoDealDamageName) { - this(amount, true, whoDealDamageName); - } - public DamageControllerEffect(int amount) { this(amount, true); } - public DamageControllerEffect(int amount, boolean preventable, String whoDealDamageName) { - super(Outcome.Damage); - this.amount = StaticValue.get(amount); - this.preventable = preventable; - this.sourceName = whoDealDamageName; + public DamageControllerEffect(int amount, boolean preventable) { + this(amount, preventable, "{this}"); } - public DamageControllerEffect(int amount, boolean preventable) { - super(Outcome.Damage); - this.amount = StaticValue.get(amount); - this.preventable = preventable; + public DamageControllerEffect(int amount, String whoDealDamageName) { + this(amount, true, whoDealDamageName); + } + + public DamageControllerEffect(int amount, boolean preventable, String whoDealDamageName) { + this(StaticValue.get(amount), preventable, whoDealDamageName); } public DamageControllerEffect(DynamicValue amount) { + this(amount, "{this}"); + } + + public DamageControllerEffect(DynamicValue amount, String whoDealDamageName) { + this(amount, true, whoDealDamageName); + } + + public DamageControllerEffect(DynamicValue amount, boolean preventable, String whoDealDamageName) { super(Outcome.Damage); this.amount = amount; - this.preventable = true; - } - - public int getAmount() { - if (amount instanceof StaticValue) { - return amount.calculate(null, null, this); - } else { - return 0; - } + this.preventable = preventable; + this.sourceName = whoDealDamageName; } public DamageControllerEffect(final DamageControllerEffect effect) { @@ -77,7 +71,7 @@ public class DamageControllerEffect extends OneShotEffect { } return false; } - + @Override public String getText(Mode mode) { if (staticText != null && !staticText.isEmpty()) { @@ -107,12 +101,4 @@ public class DamageControllerEffect extends OneShotEffect { } return sb.toString(); } - - public String getSourceName() { - return sourceName; - } - - public void setSourceName(String sourceName) { - this.sourceName = sourceName; - } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetEffect.java index bb4608f7bf3..e929327f0eb 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetEffect.java @@ -153,7 +153,10 @@ public class DamageTargetEffect extends OneShotEffect { String message = amount.getMessage(); sb.append(this.sourceName).append(" deals "); if (message.isEmpty() || !message.equals("1")) { - sb.append(amount).append(' '); + sb.append(amount); + } + if (!sb.toString().endsWith(" ")) { + sb.append(' '); } sb.append("damage to "); if (!targetDescription.isEmpty()) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/DestroyAllControlledTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DestroyAllControlledTargetEffect.java index 291813d9138..98cc806c651 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DestroyAllControlledTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DestroyAllControlledTargetEffect.java @@ -1,26 +1,23 @@ - - package mage.abilities.effects.common; -import mage.constants.Outcome; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author BetaSteward_at_googlemail.com */ public class DestroyAllControlledTargetEffect extends OneShotEffect { - private FilterPermanent filter; + private final FilterPermanent filter; public DestroyAllControlledTargetEffect(FilterPermanent filter) { super(Outcome.DestroyPermanent); this.filter = filter; - staticText = "Destroy all " + filter.getMessage() + " controlled by target player"; + staticText = "Destroy all " + filter.getMessage() + " target player controls"; } public DestroyAllControlledTargetEffect(final DestroyAllControlledTargetEffect effect) { @@ -35,10 +32,9 @@ public class DestroyAllControlledTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent permanent: game.getBattlefield().getAllActivePermanents(filter, source.getFirstTarget(), game)) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, source.getFirstTarget(), game)) { permanent.destroy(source, game, false); } return true; } - } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DestroyAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DestroyAllEffect.java index 8769ed1a232..e2c4d522270 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DestroyAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DestroyAllEffect.java @@ -44,7 +44,7 @@ public class DestroyAllEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanent.destroy(source, game, noRegen); } return true; diff --git a/Mage/src/main/java/mage/abilities/effects/common/DetainAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DetainAllEffect.java index 99c5c5b07bb..beaf758408b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DetainAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DetainAllEffect.java @@ -42,7 +42,7 @@ public class DetainAllEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { List detainedObjects = new ArrayList<>(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (!game.isSimulation()) { game.informPlayers("Detained permanent: " + permanent.getName()); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DetainTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DetainTargetEffect.java index b4e169e8075..a709bc94b18 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DetainTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DetainTargetEffect.java @@ -79,14 +79,14 @@ public class DetainTargetEffect extends OneShotEffect { sb.append("detain up to ").append(CardUtil.numberToText(target.getMaxNumberOfTargets())).append(" target ").append(target.getTargetName()); } sb.append(". (Until your next turn, "); - - if (target instanceof TargetCreaturePermanent) { - sb.append(target.getMaxNumberOfTargets() == 1 ? "that creature" : "those creatures"); - } else { - sb.append(target.getMaxNumberOfTargets() == 1 ? "that permanent" : "those permanents"); + boolean plural = target.getMaxNumberOfTargets() > 1; + sb.append(plural ? "those " : "that "); + sb.append(target.getTargetName().contains("creature") ? "creature" : "permanent"); + if (plural) { + sb.append('s'); } sb.append(" can't attack or block and "); - sb.append(target.getMaxNumberOfTargets() == 1 ? "its" : "their"); + sb.append(plural ? "their" : "its"); sb.append(" activated abilities can't be activated.)"); return sb.toString(); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DevourEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DevourEffect.java index 62b88f4db07..64be3fed9b6 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DevourEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DevourEffect.java @@ -77,7 +77,7 @@ public class DevourEffect extends ReplacementEffectImpl { } Target target = new TargetControlledPermanent(1, Integer.MAX_VALUE, devourFactor.getFilter(), true); target.setRequired(false); - if (!target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (!target.canChoose(source.getControllerId(), source, game)) { return false; } if (!controller.chooseUse(Outcome.Detriment, "Devour " + devourFactor.getCardType().toString().toLowerCase() + "s?", source, game)) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/DiscardCardControllerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/effects/common/DiscardCardControllerTriggeredAbility.java index 0d7a295b6cd..614abfa823d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DiscardCardControllerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DiscardCardControllerTriggeredAbility.java @@ -41,8 +41,12 @@ public class DiscardCardControllerTriggeredAbility extends TriggeredAbilityImpl @Override public boolean checkTrigger(GameEvent event, Game game) { - return event.getPlayerId().equals(getControllerId()) - && filter.match(game.getCard(event.getTargetId()), getSourceId(), getControllerId(), game); + if (isControlledBy(event.getPlayerId()) + && filter.match(game.getCard(event.getTargetId()), this.getControllerId(), this, game)) { + this.getEffects().setValue("discardedCard", game.getCard(event.getTargetId())); + return true; + } + return false; } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/DoIfClashWonEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DoIfClashWonEffect.java index 3e04f8611ba..4d2aa61f08b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DoIfClashWonEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DoIfClashWonEffect.java @@ -45,7 +45,7 @@ public class DoIfClashWonEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = getPayingPlayer(game, source); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (player != null && mageObject != null) { String message = null; if (chooseUseText != 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 418b3e0eaa4..6db6728c292 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java @@ -17,7 +17,7 @@ public class DoIfCostPaid extends OneShotEffect { protected Effects executingEffects = new Effects(); protected Effects otherwiseEffects = new Effects(); // used for Imprison - private final Cost cost; + protected final Cost cost; private final String chooseUseText; private final boolean optional; @@ -80,7 +80,7 @@ public class DoIfCostPaid extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = getPayingPlayer(game, source); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (player != null && mageObject != null) { String message; if (chooseUseText == null) { @@ -88,7 +88,7 @@ public class DoIfCostPaid extends OneShotEffect { if (!effectText.isEmpty() && effectText.charAt(effectText.length() - 1) == '.') { effectText = effectText.substring(0, effectText.length() - 1); } - message = getCostText() + (effectText.isEmpty() ? "" : " and " + effectText) + "?"; + message = CardUtil.addCostVerb(cost.getText()) + (effectText.isEmpty() ? "" : " and " + effectText) + "?"; message = Character.toUpperCase(message.charAt(0)) + message.substring(1); } else { message = chooseUseText; @@ -155,19 +155,13 @@ public class DoIfCostPaid extends OneShotEffect { if (!staticText.isEmpty()) { return staticText; } - return (optional ? "you may " : "") + getCostText() + ". If you do, " + executingEffects.getText(mode) + return (optional ? "you may " : "") + + CardUtil.addCostVerb(cost.getText()) + + ". If you do, " + + executingEffects.getText(mode) + (!otherwiseEffects.isEmpty() ? " If you don't, " + otherwiseEffects.getText(mode) : ""); } - protected String getCostText() { - StringBuilder sb = new StringBuilder(); - String costText = cost.getText(); - if (!CardUtil.checkCostWords(costText)) { - sb.append("pay "); - } - return sb.append(costText).toString(); - } - @Override public void setValue(String key, Object value) { super.setValue(key, value); diff --git a/Mage/src/main/java/mage/abilities/effects/common/DoUnlessAnyPlayerPaysEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DoUnlessAnyPlayerPaysEffect.java index 94e9dad3259..47605b3748d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DoUnlessAnyPlayerPaysEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DoUnlessAnyPlayerPaysEffect.java @@ -63,7 +63,7 @@ public class DoUnlessAnyPlayerPaysEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Cost costToPay; String costValueMessage; if (controller != null && sourceObject != null) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/DoUnlessControllerPaysEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DoUnlessControllerPaysEffect.java index 86e5c36b7dc..d92859a57ee 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DoUnlessControllerPaysEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DoUnlessControllerPaysEffect.java @@ -49,7 +49,7 @@ public class DoUnlessControllerPaysEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { String message; if (chooseUseText == null) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/DoUnlessTargetPlayerOrTargetsControllerPaysEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DoUnlessTargetPlayerOrTargetsControllerPaysEffect.java index 2ae6240858d..4a67e5ba406 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DoUnlessTargetPlayerOrTargetsControllerPaysEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DoUnlessTargetPlayerOrTargetsControllerPaysEffect.java @@ -73,7 +73,7 @@ public class DoUnlessTargetPlayerOrTargetsControllerPaysEffect extends OneShotEf if (targetPermanent != null) { player = game.getPlayer(targetPermanent.getControllerId()); } - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (player != null && sourceObject != null) { Cost costToPay; String costValueMessage; diff --git a/Mage/src/main/java/mage/abilities/effects/common/DoWhenCostPaid.java b/Mage/src/main/java/mage/abilities/effects/common/DoWhenCostPaid.java index 774da16628b..5e59c33ad69 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DoWhenCostPaid.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DoWhenCostPaid.java @@ -1,6 +1,5 @@ package mage.abilities.effects.common; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; @@ -38,23 +37,31 @@ public class DoWhenCostPaid extends OneShotEffect { this.optional = effect.optional; } + private boolean checkOptional(Player player, Game game, Ability source) { + return optional && !player.chooseUse( + ability.getEffects().getOutcome(source, this.outcome), + CardUtil.replaceSourceName( + chooseUseText, CardUtil.getSourceName(game, source) + ), source, game + ); + } + @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); - if (player == null || mageObject == null) { + if (player == null) { return false; } - String message = CardUtil.replaceSourceName(chooseUseText, mageObject.getLogName()); - Outcome payOutcome = ability.getEffects().getOutcome(source, this.outcome); if (!cost.canPay(source, source, player.getId(), game) - || (optional && !player.chooseUse(payOutcome, message, source, game))) { + || checkOptional(player, game, source)) { return false; } cost.clearPaid(); int bookmark = game.bookmarkState(); if (cost.pay(source, game, source, player.getId(), false)) { - ability.getEffects().setTargetPointer(getTargetPointer()); + if (ability.getTargets().isEmpty()) { + ability.getEffects().setTargetPointer(getTargetPointer()); + } game.fireReflexiveTriggeredAbility(ability, source); player.resetStoredBookmark(game); return true; @@ -72,16 +79,10 @@ public class DoWhenCostPaid extends OneShotEffect { if (!staticText.isEmpty()) { return staticText; } - return (optional ? "you may " : "") + getCostText() + ". When you do, " + CardUtil.getTextWithFirstCharLowerCase(ability.getRule()); - } - - private String getCostText() { - StringBuilder sb = new StringBuilder(); - String costText = cost.getText(); - if (!CardUtil.checkCostWords(costText)) { - sb.append("pay "); - } - return sb.append(costText).toString(); + return (optional ? "you may " : "") + + CardUtil.addCostVerb(cost.getText()) + + ". When you do, " + + CardUtil.getTextWithFirstCharLowerCase(ability.getRule()); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepSourceEffect.java index c5351ce1fc4..60289092c21 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepSourceEffect.java @@ -35,7 +35,7 @@ public class DontUntapInControllersNextUntapStepSourceEffect extends ContinuousR @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "{this} doesn't untap (" + mageObject.getLogName() + ')'; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java index e016b17c4dd..ff145ffa222 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java @@ -77,7 +77,7 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); Permanent permanentToUntap = game.getPermanent((event.getTargetId())); if (permanentToUntap != null && mageObject != null) { return permanentToUntap.getLogName() + " doesn't untap (" + mageObject.getLogName() + ')'; diff --git a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersUntapStepAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersUntapStepAllEffect.java index 72fa0bee8b3..372a63a9fdc 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersUntapStepAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersUntapStepAllEffect.java @@ -12,7 +12,6 @@ import mage.constants.TargetController; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; @@ -77,7 +76,7 @@ public class DontUntapInControllersUntapStepAllEffect extends ContinuousRuleModi throw new RuntimeException("Type of TargetController not supported!"); } if (game.isActivePlayer(permanent.getControllerId()) && // controller's untap step - filter.match(permanent, source.getSourceId(), source.getControllerId(), game)) { + filter.match(permanent, source.getControllerId(), source, game)) { return true; } } @@ -93,7 +92,7 @@ public class DontUntapInControllersUntapStepAllEffect extends ContinuousRuleModi StringBuilder sb = new StringBuilder(filter.getMessage()).append(" don't untap during "); switch(targetController) { case ANY: - sb.append("their controller's "); + sb.append("their controllers' "); break; default: throw new RuntimeException("Type of TargetController not supported yet!"); diff --git a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInPlayersNextUntapStepAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInPlayersNextUntapStepAllEffect.java index cd10dc9649c..5faf2d88abe 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInPlayersNextUntapStepAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInPlayersNextUntapStepAllEffect.java @@ -11,7 +11,6 @@ import mage.constants.PhaseStep; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; @@ -55,7 +54,7 @@ public class DontUntapInPlayersNextUntapStepAllEffect extends ContinuousRuleModi @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); Permanent permanentToUntap = game.getPermanent((event.getTargetId())); if (permanentToUntap != null && mageObject != null) { return permanentToUntap.getLogName() + " doesn't untap (" + mageObject.getLogName() + ')'; @@ -102,7 +101,7 @@ public class DontUntapInPlayersNextUntapStepAllEffect extends ContinuousRuleModi } if (game.isActivePlayer(permanent.getControllerId()) && // controller's untap step - filter.match(permanent, source.getSourceId(), source.getControllerId(), game)) { + filter.match(permanent, source.getControllerId(), source, game)) { return true; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DraftFromSpellbookEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DraftFromSpellbookEffect.java new file mode 100644 index 00000000000..fdc4a0d286d --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/DraftFromSpellbookEffect.java @@ -0,0 +1,78 @@ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.choices.Choice; +import mage.choices.ChoiceHintType; +import mage.choices.ChoiceImpl; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.util.RandomUtil; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * @author TheElk801 + */ +public class DraftFromSpellbookEffect extends OneShotEffect { + + private final List spellbook; + + public DraftFromSpellbookEffect(List spellbook) { + super(Outcome.DrawCard); + this.spellbook = spellbook; + staticText = "draft a card from {this}'s spellbook"; + } + + private DraftFromSpellbookEffect(final DraftFromSpellbookEffect effect) { + super(effect); + this.spellbook = effect.spellbook; + } + + @Override + public DraftFromSpellbookEffect copy() { + return new DraftFromSpellbookEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Set toSelect = new HashSet<>(); + while (toSelect.size() < 3) { + toSelect.add(RandomUtil.randomFromCollection(spellbook)); + } + Choice choice = new ChoiceImpl(true, ChoiceHintType.CARD); + choice.setMessage("Choose a card to draft"); + choice.setChoices(toSelect); + player.choose(outcome, choice, game); + String cardName = choice.getChoice(); + if (cardName == null) { + return false; + } + CardInfo cardInfo = CardRepository + .instance + .findCards(new CardCriteria().nameExact(cardName)) + .stream() + .findFirst() + .orElse(null); + if (cardInfo == null) { + return false; + } + Set cards = new HashSet<>(); + cards.add(cardInfo.getCard()); + game.loadCards(cards, player.getId()); + player.moveCards(cards, Zone.HAND, source, game); + return true; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/DrawDiscardControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DrawDiscardControllerEffect.java index 280d1107689..9f80cb3b893 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DrawDiscardControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DrawDiscardControllerEffect.java @@ -1,7 +1,7 @@ - package mage.abilities.effects.common; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.game.Game; @@ -9,19 +9,22 @@ import mage.players.Player; import mage.util.CardUtil; /** - * * @author BetaSteward_at_googlemail.com */ public class DrawDiscardControllerEffect extends OneShotEffect { - private int cardsToDraw; - private int cardsToDiscard; - private boolean optional; + private final int cardsToDraw; + private final int cardsToDiscard; + private final boolean optional; public DrawDiscardControllerEffect() { this(1, 1); } + public DrawDiscardControllerEffect(boolean optional) { + this(1, 1, optional); + } + public DrawDiscardControllerEffect(int cardsToDraw, int cardsToDiscard) { this(cardsToDraw, cardsToDiscard, false); } @@ -31,14 +34,6 @@ public class DrawDiscardControllerEffect extends OneShotEffect { this.cardsToDraw = cardsToDraw; this.cardsToDiscard = cardsToDiscard; this.optional = optional; - staticText = new StringBuilder(optional ? "you may " : "") - .append("draw ") - .append(cardsToDraw == 1 ? "a" : CardUtil.numberToText(cardsToDraw)) - .append(" card").append(cardsToDraw == 1 ? "" : "s") - .append(optional ? ", if you do" : ", then") - .append(" discard ") - .append(cardsToDiscard == 1 ? "a" : CardUtil.numberToText(cardsToDiscard)) - .append(" card").append(cardsToDiscard == 1 ? "" : "s").toString(); } public DrawDiscardControllerEffect(final DrawDiscardControllerEffect effect) { @@ -56,14 +51,31 @@ public class DrawDiscardControllerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - if (!optional || player.chooseUse(outcome, "Use draw, then discard effect?", source, game)) { - player.drawCards(cardsToDraw, source, game); - player.discard(cardsToDiscard, false, false, source, game); - } + if (player == null) { + return false; + } + if (optional && !player.chooseUse(outcome, "Draw, then discard?", source, game)) { return true; } - return false; + player.drawCards(cardsToDraw, source, game); + player.discard(cardsToDiscard, false, false, source, game); + return true; } + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + return (optional ? "you may " : "") + + "draw " + + (cardsToDraw == 1 ? "a" : CardUtil.numberToText(cardsToDraw)) + + " card" + + (cardsToDraw == 1 ? "" : "s") + + (optional ? ". If you do," : ", then") + + " discard " + + (cardsToDiscard == 1 ? "a" : CardUtil.numberToText(cardsToDiscard)) + + " card" + + (cardsToDiscard == 1 ? "" : "s"); + } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/EnterBattlefieldPayCostOrPutGraveyardEffect.java b/Mage/src/main/java/mage/abilities/effects/common/EnterBattlefieldPayCostOrPutGraveyardEffect.java index 0a02c0a162f..64d8c3fe096 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/EnterBattlefieldPayCostOrPutGraveyardEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/EnterBattlefieldPayCostOrPutGraveyardEffect.java @@ -47,7 +47,7 @@ public class EnterBattlefieldPayCostOrPutGraveyardEffect extends ReplacementEffe @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player player = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (player != null && cost != null && sourceObject != null) { boolean replace = true; if (cost.canPay(source, source, player.getId(), game)) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/EntersBattlefieldUnderControlOfOpponentOfChoiceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/EntersBattlefieldUnderControlOfOpponentOfChoiceEffect.java index 383b7e7ed5f..149732da4f3 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/EntersBattlefieldUnderControlOfOpponentOfChoiceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/EntersBattlefieldUnderControlOfOpponentOfChoiceEffect.java @@ -43,7 +43,7 @@ public class EntersBattlefieldUnderControlOfOpponentOfChoiceEffect extends OneSh } Target target = new TargetOpponent(); target.setNotTarget(true); - if (!controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + if (!controller.choose(Outcome.Benefit, target, source, game)) { return false; } Player opponent = game.getPlayer(target.getFirstTarget()); diff --git a/Mage/src/main/java/mage/abilities/effects/common/EpicEffect.java b/Mage/src/main/java/mage/abilities/effects/common/EpicEffect.java index 81b1f63db04..95b1f92a50f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/EpicEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/EpicEffect.java @@ -87,7 +87,7 @@ class EpicReplacementEffect extends ContinuousRuleModifyingEffectImpl { @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "For the rest of the game, you can't cast spells (Epic - " + mageObject.getName() + ')'; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileAllEffect.java index b6852c2c89c..a2fffcfa115 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileAllEffect.java @@ -49,7 +49,7 @@ public class ExileAllEffect extends OneShotEffect { } Cards cards = new CardsImpl(); game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game ).stream().forEach(cards::add); if (forSource) { return controller.moveCardsToExile(cards.getCards(game), source, game, true, CardUtil.getExileZoneId(game, source), CardUtil.getSourceName(game, source)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileCardYouChooseTargetOpponentEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileCardYouChooseTargetOpponentEffect.java index 656a8d387d5..b350f59e45d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileCardYouChooseTargetOpponentEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileCardYouChooseTargetOpponentEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -12,25 +11,20 @@ import mage.players.Player; import mage.target.TargetCard; /** - * * @author LevelX2 */ public class ExileCardYouChooseTargetOpponentEffect extends OneShotEffect { - private FilterCard filter; - - public ExileCardYouChooseTargetOpponentEffect() { - this(new FilterCard("a card")); - } + private final FilterCard filter; public ExileCardYouChooseTargetOpponentEffect(FilterCard filter) { super(Outcome.Discard); - staticText = new StringBuilder("Target opponent reveals their hand. You choose ") - .append(filter.getMessage()).append(" from it and exile that card").toString(); + this.staticText = "target opponent reveals their hand. You choose " + + filter.getMessage() + " from it and exile that card"; this.filter = filter; } - public ExileCardYouChooseTargetOpponentEffect(final ExileCardYouChooseTargetOpponentEffect effect) { + private ExileCardYouChooseTargetOpponentEffect(final ExileCardYouChooseTargetOpponentEffect effect) { super(effect); this.filter = effect.filter; } @@ -38,27 +32,25 @@ public class ExileCardYouChooseTargetOpponentEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Player opponent = game.getPlayer(source.getFirstTarget()); - Card sourceCard = game.getCard(source.getSourceId()); - if (controller != null && opponent != null) { - if (!opponent.getHand().isEmpty()) { - opponent.revealCards(sourceCard != null ? sourceCard.getIdName() + " (" + sourceCard.getZoneChangeCounter(game) + ')' : "Exile", opponent.getHand(), game); - TargetCard target = new TargetCard(Zone.HAND, filter); - if (controller.choose(Outcome.Exile, opponent.getHand(), target, game)) { - Card card = opponent.getHand().get(target.getFirstTarget(), game); - if (card != null) { - controller.moveCardToExileWithInfo(card, null, "", source, game, Zone.HAND, true); - } - } - } + Player opponent = game.getPlayer(targetPointer.getFirst(game, source)); + if (controller == null || opponent == null) { + return false; + } + opponent.revealCards(source, opponent.getHand(), game); + if (opponent.getHand().count(filter, game) < 1) { return true; } - return false; + TargetCard target = new TargetCard(Zone.HAND, filter); + controller.choose(Outcome.Exile, opponent.getHand(), target, game); + Card card = opponent.getHand().get(target.getFirstTarget(), game); + if (card != null) { + controller.moveCards(card, Zone.EXILED, source, game); + } + return true; } @Override public ExileCardYouChooseTargetOpponentEffect copy() { return new ExileCardYouChooseTargetOpponentEffect(this); } - } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileFromZoneTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileFromZoneTargetEffect.java index 7007493a089..9f30540539b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileFromZoneTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileFromZoneTargetEffect.java @@ -67,7 +67,7 @@ public class ExileFromZoneTargetEffect extends OneShotEffect { break; default: } - if (target == null || !target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target == null || !target.canChoose(player.getId(), source, game)) { return true; } target.chooseTarget(Outcome.Exile, player.getId(), source, game); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileGraveyardAllPlayersEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileGraveyardAllPlayersEffect.java index 58d185cbffb..699b3b79d53 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileGraveyardAllPlayersEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileGraveyardAllPlayersEffect.java @@ -63,7 +63,7 @@ public class ExileGraveyardAllPlayersEffect extends OneShotEffect { } Player player = game.getPlayer(playerId); if (player != null) { - toExile.addAll(player.getGraveyard().getCards(filter, source.getSourceId(), source.getControllerId(), game)); + toExile.addAll(player.getGraveyard().getCards(filter, source.getControllerId(), source, game)); } } controller.moveCards(toExile, Zone.EXILED, source, game); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileReturnBattlefieldOwnerNextEndStepSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileReturnBattlefieldOwnerNextEndStepSourceEffect.java index 3c12c7fc737..405223fe11d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileReturnBattlefieldOwnerNextEndStepSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileReturnBattlefieldOwnerNextEndStepSourceEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -9,69 +8,55 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.targetpointer.FixedTarget; /** - * * @author LevelX2 */ public class ExileReturnBattlefieldOwnerNextEndStepSourceEffect extends OneShotEffect { - private boolean returnAlways; - private boolean returnTapped; + private final boolean returnTapped; public ExileReturnBattlefieldOwnerNextEndStepSourceEffect() { this(false); } - public ExileReturnBattlefieldOwnerNextEndStepSourceEffect(boolean returnAlways) { - this(returnAlways, false); - } - /** - * - * @param returnAlways Return the permanent also if it does not go to exile - * but is moved to another zone (e.g. command zone by commander replacement - * effect) * @param returnTapped Does the source return tapped to the battlefield */ - public ExileReturnBattlefieldOwnerNextEndStepSourceEffect(boolean returnAlways, boolean returnTapped) { + public ExileReturnBattlefieldOwnerNextEndStepSourceEffect(boolean returnTapped) { super(Outcome.Benefit); this.returnTapped = returnTapped; - this.returnAlways = returnAlways; - staticText = "exile {this}. Return it to the battlefield " - + (returnTapped ? "tapped " : "") - + "under its owner's control at the beginning of the next end step"; + staticText = "exile {this}. Return it to the battlefield " + (returnTapped ? "tapped " : "") + + "under its owner's control at the beginning of the next end step"; } public ExileReturnBattlefieldOwnerNextEndStepSourceEffect(ExileReturnBattlefieldOwnerNextEndStepSourceEffect effect) { super(effect); - this.returnAlways = effect.returnAlways; this.returnTapped = effect.returnTapped; } @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - int zcc = game.getState().getZoneChangeCounter(permanent.getId()); - boolean exiled = controller.moveCardToExileWithInfo(permanent, source.getSourceId(), permanent.getIdName(), source, game, Zone.BATTLEFIELD, true); - if (exiled || (returnAlways && (zcc == game.getState().getZoneChangeCounter(permanent.getId()) - 1))) { - //create delayed triggered ability and return it from every public zone it was next moved to - AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility( - new ReturnToBattlefieldUnderOwnerControlSourceEffect(returnTapped, zcc + 1)); - game.addDelayedTriggeredAbility(delayedAbility, source); - } - } + if (controller == null) { + return false; + } + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null) { return true; } - return false; + controller.moveCards(permanent, Zone.EXILED, source, game); + //create delayed triggered ability and return it from every public zone it was next moved to + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new ReturnToBattlefieldUnderOwnerControlTargetEffect(returnTapped, true) + .setTargetPointer(new FixedTarget(permanent.getId(), game)) + ), source); + return true; } @Override public ExileReturnBattlefieldOwnerNextEndStepSourceEffect copy() { return new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(this); } - } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileTargetIfDiesEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileTargetIfDiesEffect.java index ceb64907ca7..d73cff9fde7 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileTargetIfDiesEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileTargetIfDiesEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.MageObjectReference; @@ -11,14 +10,17 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class ExileTargetIfDiesEffect extends OneShotEffect { public ExileTargetIfDiesEffect() { + this("creature"); + } + + public ExileTargetIfDiesEffect(String targetName) { super(Outcome.Damage); - this.staticText = "If that creature would die this turn, exile it instead"; + this.staticText = "If that " + targetName + " would die this turn, exile it instead"; } public ExileTargetIfDiesEffect(final ExileTargetIfDiesEffect effect) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/FlipCoinEffect.java b/Mage/src/main/java/mage/abilities/effects/common/FlipCoinEffect.java index 21036b14f8b..ec30a8ed804 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/FlipCoinEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/FlipCoinEffect.java @@ -59,7 +59,7 @@ public class FlipCoinEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (controller == null || mageObject == null) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/FortifyEffect.java b/Mage/src/main/java/mage/abilities/effects/common/FortifyEffect.java deleted file mode 100644 index f62836ecc9f..00000000000 --- a/Mage/src/main/java/mage/abilities/effects/common/FortifyEffect.java +++ /dev/null @@ -1,38 +0,0 @@ -package mage.abilities.effects.common; - -import mage.abilities.Ability; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.game.Game; -import mage.game.permanent.Permanent; - -public class FortifyEffect extends AttachEffect{ - - public FortifyEffect(Outcome outcome) { - super(outcome, "Fortify"); - } - - public FortifyEffect(FortifyEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - //Some artifacts have the subtype “Fortification.” A Fortification can be attached to a land. It can’t legally - // be attached to an object that isn’t a land. Fortification’s analog to the equip keyword ability is the - // fortify keyword ability. Rules 301.5a–e apply to Fortifications in relation to lands just as they apply to - // Equipment in relation to creatures, with one clarification relating to rule 301.5c: a Fortification that’s - // also a creature (not a land) can’t fortify a land. (See rule 702.66, “Fortify.”) - if (sourcePermanent != null && sourcePermanent.hasSubtype(SubType.FORTIFICATION, game) && !sourcePermanent.isCreature(game) - && !sourcePermanent.isLand(game)) { - return super.apply(game, source); - } - return false; - } - - @Override - public FortifyEffect copy(){ - return new FortifyEffect(this); - } -} diff --git a/Mage/src/main/java/mage/abilities/effects/common/GainLifeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/GainLifeEffect.java index ca4dbf1f801..9ec9404ed87 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/GainLifeEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/GainLifeEffect.java @@ -60,13 +60,11 @@ public class GainLifeEffect extends OneShotEffect { StringBuilder sb = new StringBuilder(); String message = life.getMessage(); sb.append("you gain "); - if (message.startsWith("that")) { - sb.append(message).append(' '); - } else if (message.isEmpty() || !life.toString().equals("1")) { + if (message.isEmpty() || !life.toString().equals("1")) { sb.append(life).append(' '); } sb.append("life"); - if (!message.isEmpty() && !message.startsWith("that")) { + if (!message.isEmpty()) { sb.append(life.toString().equals("1") ? " equal to the number of " : " for each "); sb.append(message); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/GetEmblemEffect.java b/Mage/src/main/java/mage/abilities/effects/common/GetEmblemEffect.java index 907dfdf70ad..e99b3799482 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/GetEmblemEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/GetEmblemEffect.java @@ -35,7 +35,7 @@ public class GetEmblemEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject == null) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/GetEmblemTargetPlayerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/GetEmblemTargetPlayerEffect.java index eb9aa7b52ed..2c9dce9eff8 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/GetEmblemTargetPlayerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/GetEmblemTargetPlayerEffect.java @@ -36,7 +36,7 @@ public class GetEmblemTargetPlayerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject == null) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/HideawayPlayEffect.java b/Mage/src/main/java/mage/abilities/effects/common/HideawayPlayEffect.java index ec54ab19a98..c9232b617cc 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/HideawayPlayEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/HideawayPlayEffect.java @@ -1,18 +1,16 @@ package mage.abilities.effects.common; +import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.constants.Outcome; import mage.game.ExileZone; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.util.CardUtil; -import java.util.Set; import java.util.UUID; -import mage.ApprovingObject; /** * @author LevelX2 @@ -21,7 +19,7 @@ public class HideawayPlayEffect extends OneShotEffect { public HideawayPlayEffect() { super(Outcome.Benefit); - staticText = "You may play the exiled card without paying its mana cost"; + staticText = "you may play the exiled card without paying its mana cost"; } public HideawayPlayEffect(final HideawayPlayEffect effect) { @@ -35,46 +33,38 @@ public class HideawayPlayEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - ExileZone zone = null; - Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (permanent != null) { - zone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), permanent.getZoneChangeCounter(game))); - } - - if (zone == null) { - return true; - } - Set cards = zone.getCards(game); - if (cards.isEmpty()) { - return true; - } - - Card card = cards.iterator().next(); Player controller = game.getPlayer(source.getControllerId()); - if (card != null && controller != null) { - if (controller.chooseUse(Outcome.PlayForFree, "Play " + card.getIdName() + " for free?", source, game)) { - card.setFaceDown(false, game); - int zcc = card.getZoneChangeCounter(game); - - /* 702.74. Hideaway, rulings: - * If the removed card is a land, you may play it as a result of the last ability only if it's your turn - * and you haven't already played a land that turn. This counts as your land play for the turn. - */ - if (card.isLand(game)) { - UUID playerId = controller.getId(); - if (!game.isActivePlayer(playerId) || !game.getPlayer(playerId).canPlayLand()) { - return false; - } - } - - if (!controller.playCard(card, game, true, new ApprovingObject(source, game))) { - if (card.getZoneChangeCounter(game) == zcc) { - card.setFaceDown(true, game); - } - } - } + ExileZone zone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + if (controller == null || zone == null || zone.isEmpty()) { return true; } - return false; + Card card = zone.getRandom(game); + if (card == null) { + return false; + } + if (!controller.chooseUse(Outcome.PlayForFree, "Play " + card.getIdName() + " for free?", source, game)) { + return false; + } + card.setFaceDown(false, game); + int zcc = card.getZoneChangeCounter(game); + + /* 702.74. Hideaway, rulings: + * If the removed card is a land, you may play it as a result of the last ability only if it's your turn + * and you haven't already played a land that turn. This counts as your land play for the turn. + * TODO: this doesn't work correctly with the back half of MDFCs + */ + if (card.isLand(game)) { + UUID playerId = controller.getId(); + if (!game.isActivePlayer(playerId) || !game.getPlayer(playerId).canPlayLand()) { + return false; + } + } + + if (!controller.playCard(card, game, true, new ApprovingObject(source, game))) { + if (card.getZoneChangeCounter(game) == zcc) { + card.setFaceDown(true, game); + } + } + return true; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/IfAbilityHasResolvedXTimesEffect.java b/Mage/src/main/java/mage/abilities/effects/common/IfAbilityHasResolvedXTimesEffect.java index b4dca380e03..cab6eee4c4f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/IfAbilityHasResolvedXTimesEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/IfAbilityHasResolvedXTimesEffect.java @@ -1,6 +1,7 @@ package mage.abilities.effects.common; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -21,8 +22,6 @@ public class IfAbilityHasResolvedXTimesEffect extends OneShotEffect { super(outcome); this.resolutionNumber = resolutionNumber; this.effect = effect; - this.staticText = "If this is the " + CardUtil.numberToOrdinalText(resolutionNumber) + " time this ability has resolved this turn, " + - effect.getText(null); } private IfAbilityHasResolvedXTimesEffect(final IfAbilityHasResolvedXTimesEffect effect) { @@ -39,7 +38,7 @@ public class IfAbilityHasResolvedXTimesEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { if (AbilityResolvedWatcher.getResolutionCount(game, source) != resolutionNumber) { - return true; + return false; } if (effect instanceof OneShotEffect) { return effect.apply(game, source); @@ -47,4 +46,13 @@ public class IfAbilityHasResolvedXTimesEffect extends OneShotEffect { game.addEffect((ContinuousEffect) effect, source); return true; } + + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + return "If this is the " + CardUtil.numberToOrdinalText(resolutionNumber) + + " time this ability has resolved this turn, " + effect.getText(mode); + } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/LivingDeathEffect.java b/Mage/src/main/java/mage/abilities/effects/common/LivingDeathEffect.java index beedd03ac87..2b346b9a835 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/LivingDeathEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/LivingDeathEffect.java @@ -32,7 +32,7 @@ public class LivingDeathEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { Map> exiledCards = new HashMap<>(); diff --git a/Mage/src/main/java/mage/abilities/effects/common/LookAtTargetPlayerHandEffect.java b/Mage/src/main/java/mage/abilities/effects/common/LookAtTargetPlayerHandEffect.java index 2425125ea55..6d3e191da93 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/LookAtTargetPlayerHandEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/LookAtTargetPlayerHandEffect.java @@ -32,7 +32,7 @@ public class LookAtTargetPlayerHandEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player you = game.getPlayer(source.getControllerId()); Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (you != null && targetPlayer != null) { you.lookAtCards(sourceObject != null ? sourceObject.getIdName() : null, targetPlayer.getHand(), game); return true; diff --git a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java index 3427d5c3e61..c2fbfd25086 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/LookLibraryAndPickControllerEffect.java @@ -35,253 +35,134 @@ import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; import mage.cards.Cards; import mage.cards.CardsImpl; -import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; import mage.util.CardUtil; -import java.util.Locale; - -import static java.lang.Integer.min; - /** - * @author LevelX + * @author LevelX, awjackson */ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEffect { - protected FilterCard filter; // which kind of cards to reveal - protected DynamicValue numberToPick; - protected boolean revealPickedCards = true; - protected Zone targetPickedCards = Zone.HAND; // HAND - protected int foundCardsToPick = 0; + protected int numberToPick; + protected PutCards putPickedCards; + protected FilterCard filter; + protected boolean revealPickedCards; protected boolean optional; - private boolean upTo; - private boolean putOnTopSelected; - private boolean anyOrder; + protected boolean upTo; - //TODO: These constructors are a mess - public LookLibraryAndPickControllerEffect(DynamicValue numberOfCards, - boolean mayShuffleAfter, DynamicValue numberToPick, - FilterCard pickFilter, boolean putOnTop) { - this(numberOfCards, mayShuffleAfter, numberToPick, pickFilter, - putOnTop, true); + public LookLibraryAndPickControllerEffect(int numberOfCards, int numberToPick, + PutCards putPickedCards, PutCards putLookedCards) { + this(numberOfCards, numberToPick, putPickedCards, putLookedCards, false); } - public LookLibraryAndPickControllerEffect(DynamicValue numberOfCards, - boolean mayShuffleAfter, DynamicValue numberToPick, - FilterCard pickFilter, boolean putOnTop, boolean reveal) { - this(numberOfCards, mayShuffleAfter, numberToPick, pickFilter, - Zone.LIBRARY, putOnTop, reveal); + public LookLibraryAndPickControllerEffect(DynamicValue numberOfCards, int numberToPick, + PutCards putPickedCards, PutCards putLookedCards) { + this(numberOfCards, numberToPick, putPickedCards, putLookedCards, false); } - public LookLibraryAndPickControllerEffect(DynamicValue numberOfCards, - boolean mayShuffleAfter, DynamicValue numberToPick, - FilterCard pickFilter, Zone targetZoneLookedCards, - boolean putOnTop, boolean reveal) { - this(numberOfCards, mayShuffleAfter, numberToPick, pickFilter, - targetZoneLookedCards, putOnTop, reveal, reveal); + public LookLibraryAndPickControllerEffect(int numberOfCards, int numberToPick, + PutCards putPickedCards, PutCards putLookedCards, boolean upTo) { + this(StaticValue.get(numberOfCards), numberToPick, putPickedCards, putLookedCards, upTo); } - public LookLibraryAndPickControllerEffect(int numberOfCards, - int numberToPick, FilterCard pickFilter, boolean upTo) { - this(StaticValue.get(numberOfCards), false, - StaticValue.get(numberToPick), pickFilter, Zone.LIBRARY, false, - true, upTo); - } - - /** - * @param numberOfCards - * @param numberToPick - * @param pickFilter - * @param reveal - * @param upTo - * @param targetZonePickedCards - * @param optional - */ - public LookLibraryAndPickControllerEffect(int numberOfCards, - int numberToPick, FilterCard pickFilter, boolean reveal, - boolean upTo, Zone targetZonePickedCards, boolean optional) { - this(StaticValue.get(numberOfCards), false, - StaticValue.get(numberToPick), pickFilter, Zone.LIBRARY, false, - reveal, upTo, targetZonePickedCards, optional, true, true); - - } - - /** - * @param numberOfCards - * @param mayShuffleAfter - * @param numberToPick - * @param pickFilter - * @param targetZoneLookedCards - * @param putOnTop if zone for the rest is library decide if cards go to top - * or bottom - * @param reveal - * @param upTo - */ - public LookLibraryAndPickControllerEffect(DynamicValue numberOfCards, - boolean mayShuffleAfter, DynamicValue numberToPick, - FilterCard pickFilter, Zone targetZoneLookedCards, - boolean putOnTop, boolean reveal, boolean upTo) { - this(numberOfCards, mayShuffleAfter, numberToPick, pickFilter, - targetZoneLookedCards, putOnTop, reveal, upTo, Zone.HAND, - false, true, true); - } - - /** - * @param numberOfCards - * @param mayShuffleAfter - * @param numberToPick - * @param pickFilter - * @param targetZoneLookedCards - * @param putOnTop if zone for the rest is library decide if cards go to top - * or bottom - * @param reveal - * @param upTo - * @param targetZonePickedCards - * @param optional - */ - public LookLibraryAndPickControllerEffect(DynamicValue numberOfCards, - boolean mayShuffleAfter, DynamicValue numberToPick, - FilterCard pickFilter, Zone targetZoneLookedCards, boolean putOnTop, - boolean reveal, boolean upTo, Zone targetZonePickedCards, - boolean optional) { - - this(numberOfCards, mayShuffleAfter, numberToPick, pickFilter, - targetZoneLookedCards, putOnTop, reveal, upTo, - targetZonePickedCards, optional, true, true); - } - - /** - * @param numberOfCards - * @param mayShuffleAfter - * @param numberToPick - * @param pickFilter - * @param targetZoneLookedCards - * @param putOnTop if zone for the rest is library decide if cards go to top - * or bottom - * @param reveal - * @param upTo - * @param targetZonePickedCards - * @param optional - * @param putOnTopSelected - * @param anyOrder - */ - public LookLibraryAndPickControllerEffect(DynamicValue numberOfCards, - boolean mayShuffleAfter, DynamicValue numberToPick, - FilterCard pickFilter, Zone targetZoneLookedCards, boolean putOnTop, - boolean reveal, boolean upTo, Zone targetZonePickedCards, - boolean optional, boolean putOnTopSelected, boolean anyOrder) { - super(Outcome.DrawCard, numberOfCards, mayShuffleAfter, - targetZoneLookedCards, putOnTop); + public LookLibraryAndPickControllerEffect(DynamicValue numberOfCards, int numberToPick, + PutCards putPickedCards, PutCards putLookedCards, boolean upTo) { + super(putPickedCards.getOutcome(), numberOfCards, putLookedCards); this.numberToPick = numberToPick; - this.filter = pickFilter; - this.revealPickedCards = reveal; - this.targetPickedCards = targetZonePickedCards; - this.upTo = upTo; + this.putPickedCards = putPickedCards; + this.filter = (numberToPick > 1) ? StaticFilters.FILTER_CARD_CARDS : StaticFilters.FILTER_CARD_A; + this.revealPickedCards = false; + this.optional = false; + this.upTo = upTo || numberToPick == Integer.MAX_VALUE; + } + + public LookLibraryAndPickControllerEffect(int numberOfCards, int numberToPick, FilterCard filter, + PutCards putPickedCards, PutCards putLookedCards) { + this(numberOfCards, numberToPick, filter, putPickedCards, putLookedCards, true); + } + + public LookLibraryAndPickControllerEffect(DynamicValue numberOfCards, int numberToPick, FilterCard filter, + PutCards putPickedCards, PutCards putLookedCards) { + this(numberOfCards, numberToPick, filter, putPickedCards, putLookedCards, true); + } + + public LookLibraryAndPickControllerEffect(int numberOfCards, int numberToPick, FilterCard filter, + PutCards putPickedCards, PutCards putLookedCards, boolean optional) { + this(StaticValue.get(numberOfCards), numberToPick, filter, putPickedCards, putLookedCards, optional); + } + + public LookLibraryAndPickControllerEffect(DynamicValue numberOfCards, int numberToPick, FilterCard filter, + PutCards putPickedCards, PutCards putLookedCards, boolean optional) { + super(putPickedCards.getOutcome(), numberOfCards, putLookedCards); + this.numberToPick = numberToPick; + this.putPickedCards = putPickedCards; + this.filter = filter; + this.revealPickedCards = !putPickedCards.getZone().isPublicZone(); this.optional = optional; - this.putOnTopSelected = putOnTopSelected; - this.anyOrder = anyOrder; + this.upTo = (numberToPick > 1); } public LookLibraryAndPickControllerEffect(final LookLibraryAndPickControllerEffect effect) { super(effect); - this.numberToPick = effect.numberToPick.copy(); + this.numberToPick = effect.numberToPick; + this.putPickedCards = effect.putPickedCards; this.filter = effect.filter.copy(); this.revealPickedCards = effect.revealPickedCards; - this.targetPickedCards = effect.targetPickedCards; - this.upTo = effect.upTo; this.optional = effect.optional; - this.putOnTopSelected = effect.putOnTopSelected; - this.anyOrder = effect.anyOrder; + this.upTo = effect.upTo; } @Override public LookLibraryAndPickControllerEffect copy() { return new LookLibraryAndPickControllerEffect(this); - } @Override - protected void actionWithSelectedCards(Cards cards, Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null && numberToPick.calculate(game, source, this) > 0 - && cards.count(filter, source.getSourceId(), source.getControllerId(), game) > 0) { - if (!optional || player.chooseUse(Outcome.DrawCard, getMayText(), source, game)) { - FilterCard pickFilter = filter.copy(); - pickFilter.setMessage(getPickText()); - int number = min(cards.size(), numberToPick.calculate(game, source, this)); - TargetCard target = new TargetCard((upTo ? 0 : number), number, Zone.LIBRARY, pickFilter); - if (player.choose(Outcome.DrawCard, cards, target, game)) { - Cards pickedCards = new CardsImpl(target.getTargets()); - cards.removeAll(pickedCards); - if (targetPickedCards == Zone.LIBRARY && !putOnTopSelected) { - player.putCardsOnBottomOfLibrary(pickedCards, game, source, anyOrder); - } else { - player.moveCards(pickedCards.getCards(game), targetPickedCards, source, game); - } - if (revealPickedCards) { - player.revealCards(source, pickedCards, game); - } - - } - } + protected boolean actionWithLookedCards(Game game, Ability source, Player player, Cards cards) { + int number = Math.min(numberToPick, cards.count(filter, source.getControllerId(), source, game)); + if (number < 1 + || optional && !player.chooseUse(putPickedCards.getOutcome(), getMayText(), source, game)) { + return actionWithPickedCards(game, source, player, new CardsImpl(), cards); } - + TargetCard target = new TargetCard((upTo ? 0 : number), number, Zone.LIBRARY, filter); + target.withChooseHint(getChooseHint()); + if (!player.chooseTarget(putPickedCards.getOutcome(), cards, target, source, game)) { + return actionWithPickedCards(game, source, player, new CardsImpl(), cards); + } + Cards pickedCards = new CardsImpl(target.getTargets()); + if (revealPickedCards) { + player.revealCards(source, pickedCards, game); + } + cards.removeAll(pickedCards); + return actionWithPickedCards(game, source, player, pickedCards, cards); } - private String getMayText() { - StringBuilder sb = new StringBuilder(); - switch (targetPickedCards) { - case HAND: - if (revealPickedCards) { - sb.append("Reveal ").append(filter.getMessage()).append(" and put into your hand"); - } else { - sb.append("Put ").append(filter.getMessage()).append(" into your hand"); - } - break; - case BATTLEFIELD: - sb.append("Put ").append(filter.getMessage()).append(" onto the battlefield"); - break; - case GRAVEYARD: - sb.append("Put ").append(filter.getMessage()).append(" into your graveyard"); - break; - } - return sb.append('?').toString(); + protected boolean actionWithPickedCards(Game game, Ability source, Player player, Cards pickedCards, Cards otherCards) { + boolean result = moveCards(game, source, player, pickedCards, putPickedCards); + result |= moveCards(game, source, player, otherCards, putLookedCards); + return result; } - private String getPickText() { - StringBuilder sb = new StringBuilder(filter.getMessage()).append(" to "); - switch (targetPickedCards) { - case LIBRARY: - if (putOnTopSelected) { - sb.append("put on the top of your library"); - } else { - sb.append("put on the bottom of your library"); - } - if (anyOrder) { - sb.append(" in any order"); - } else { - sb.append(" in a random order"); - } - break; - case HAND: - if (revealPickedCards) { - sb.append("reveal and put into your hand"); - } else { - sb.append("put into your hand"); - } - break; - case BATTLEFIELD: - sb.append("put onto the battlefield"); - break; - case GRAVEYARD: - sb.append("put into the graveyard"); - break; + protected String getMayText() { + boolean plural = numberToPick > 1; + StringBuilder sb = new StringBuilder(revealPickedCards ? "Reveal " : "Put "); + sb.append(plural ? filter.getMessage() : CardUtil.addArticle(filter.getMessage())); + if (revealPickedCards) { + sb.append(" and put "); + sb.append(plural ? "them" : "it"); } - return sb.toString(); + sb.append(" "); + sb.append(putPickedCards.getMessage(plural)); + return sb.append("?").toString(); + } + + protected String getChooseHint() { + return "to put " + putPickedCards.getMessage(numberToPick > 1); } @Override @@ -289,67 +170,57 @@ public class LookLibraryAndPickControllerEffect extends LookLibraryControllerEff if (staticText != null && !staticText.isEmpty()) { return staticText; } - StringBuilder sb = new StringBuilder(); - if (numberToPick.calculate(null, null, this) > 0) { - - if (revealPickedCards) { - sb.append(". You may reveal "); - sb.append(filter.getMessage()).append(" from among them and put it into your "); - } else if (targetPickedCards == Zone.BATTLEFIELD) { - sb.append(". "); - if (optional) { - sb.append("You may p"); - } else { - sb.append('P'); - } - sb.append("ut ").append(filter.getMessage()).append(" from among them onto the "); - } else { - sb.append(". Put "); - if (numberToPick.calculate(null, null, this) > 1) { - if (upTo) { - if (numberToPick.calculate(null, null, this) == (numberOfCards.calculate(null, null, this))) { - sb.append("any number"); - } else { - sb.append("up to ").append(CardUtil.numberToText(numberToPick.calculate(null, null, this))); - } - } else { - sb.append(CardUtil.numberToText(numberToPick.calculate(null, null, this))); - } - } else { - sb.append("one"); - } - - sb.append(" of them into your "); - } - sb.append(targetPickedCards.toString().toLowerCase(Locale.ENGLISH)); - - if (targetZoneLookedCards == Zone.LIBRARY) { - sb.append(". Put the rest "); - if (putOnTop) { - sb.append("back on top"); - } else { - sb.append("on the bottom"); - } - sb.append(" of your library in "); - if (anyOrder && !backInRandomOrder) { - sb.append("any"); - } else { - sb.append("a random"); - } - sb.append(" order"); - } else if (targetZoneLookedCards == Zone.GRAVEYARD) { - sb.append(" and the"); - if (numberOfCards instanceof StaticValue && numberToPick instanceof StaticValue - && ((StaticValue) numberToPick).getValue() + 1 == ((StaticValue) numberOfCards).getValue()) { - sb.append(" other"); - } else { - sb.append(" rest"); - } - sb.append(" into your graveyard"); - } + StringBuilder sb = new StringBuilder(". "); + if (optional) { + sb.append(revealPickedCards ? "You may reveal " : "You may put "); + } else { + sb.append(revealPickedCards ? "Reveal " : "Put "); } + boolean havePredicates = filter.hasPredicates(); + boolean plural = numberToPick > 1; + if (havePredicates && !plural && !upTo) { + sb.append(CardUtil.addArticle(filter.getMessage())); + } else if (numberToPick == Integer.MAX_VALUE) { + sb.append("any number of "); + if (havePredicates) { + sb.append(filter.getMessage()); + } + } else { + if (upTo) { + sb.append("up to "); + } + sb.append(CardUtil.numberToText(numberToPick)); + sb.append(" "); + sb.append(havePredicates ? filter.getMessage() : "of "); + } + if (havePredicates) { + sb.append(" from among "); + } + sb.append("them "); + if (revealPickedCards) { + sb.append("and put "); + sb.append(plural ? "them " : "it "); + } + sb.append(putPickedCards.getMessage(plural)); + + plural = optional + || upTo + || !(numberOfCards instanceof StaticValue) + || numberOfCards.calculate(null, null, this) - numberToPick != 1; + + // if remaining text would be "put the other on top of your library", omit it + if (!plural && putLookedCards == PutCards.TOP_ANY) { + return setText(mode, sb.toString()); + } + sb.append(havePredicates && (optional || upTo) ? ". Put" : " and"); + sb.append(" the "); + sb.append(plural ? "rest " : "other "); + if (putPickedCards == PutCards.GRAVEYARD && putLookedCards == PutCards.TOP_ANY) { + sb.append("back "); + } + sb.append(putLookedCards.getMessage(plural)); + // get text frame from super class and inject action text return setText(mode, sb.toString()); } - } diff --git a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/LookLibraryControllerEffect.java index 020f3f16731..45361da3071 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/LookLibraryControllerEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -17,61 +16,81 @@ import mage.util.CardUtil; /** * - * @author LevelX + * @author LevelX, awjackson */ public class LookLibraryControllerEffect extends OneShotEffect { + public enum PutCards { + HAND(Outcome.DrawCard, Zone.HAND, "into your hand"), + GRAVEYARD(Outcome.Discard, Zone.GRAVEYARD, "into your graveyard"), + BATTLEFIELD(Outcome.PutCardInPlay, Zone.BATTLEFIELD, "onto the battlefield"), + BATTLEFIELD_TAPPED(Outcome.PutCardInPlay, Zone.BATTLEFIELD, "onto the battlefield tapped"), + TOP_ANY(Outcome.Benefit, Zone.LIBRARY, "on top of your library", " in any order"), + BOTTOM_ANY(Outcome.Benefit, Zone.LIBRARY, "on the bottom of your library", " in any order"), + BOTTOM_RANDOM(Outcome.Benefit, Zone.LIBRARY, "on the bottom of your library", " in a random order"); + + private final Outcome outcome; + private final Zone zone; + private final String message; + private final String order; + + PutCards(Outcome outcome, Zone zone, String message) { + this(outcome, zone, message, ""); + } + + PutCards(Outcome outcome, Zone zone, String message, String order) { + this.outcome = outcome; + this.zone = zone; + this.message = message; + this.order = order; + } + + public Outcome getOutcome() { + return outcome; + } + + public Zone getZone() { + return zone; + } + + public String getMessage(boolean withOrder) { + return withOrder ? message + order : message; + } + } + protected DynamicValue numberOfCards; - protected boolean mayShuffleAfter = false; - protected boolean putOnTop = true; // if false on put rest back on bottom of library - protected Zone targetZoneLookedCards; // GRAVEYARD, LIBRARY - protected boolean backInRandomOrder = false; + protected PutCards putLookedCards; + protected boolean revealCards; public LookLibraryControllerEffect() { this(1); } public LookLibraryControllerEffect(int numberOfCards) { - this(numberOfCards, false, true); + this(StaticValue.get(numberOfCards)); } public LookLibraryControllerEffect(DynamicValue numberOfCards) { - this(numberOfCards, false, true); + this(Outcome.Benefit, numberOfCards, PutCards.TOP_ANY); } - public LookLibraryControllerEffect(int numberOfCards, boolean mayShuffleAfter) { - this(numberOfCards, mayShuffleAfter, true); - } - - public LookLibraryControllerEffect(int numberOfCards, boolean mayShuffleAfter, boolean putOnTop) { - this(StaticValue.get(numberOfCards), mayShuffleAfter, putOnTop); - } - - public LookLibraryControllerEffect(DynamicValue numberOfCards, boolean mayShuffleAfter, boolean putOnTop) { - this(Outcome.Benefit, numberOfCards, mayShuffleAfter, Zone.LIBRARY, putOnTop); - } - - public LookLibraryControllerEffect(Outcome outcome, DynamicValue numberOfCards, boolean mayShuffleAfter, Zone targetZoneLookedCards, boolean putOnTop) { + public LookLibraryControllerEffect(Outcome outcome, DynamicValue numberOfCards, PutCards putLookedCards) { super(outcome); this.numberOfCards = numberOfCards; - this.mayShuffleAfter = mayShuffleAfter; - this.targetZoneLookedCards = targetZoneLookedCards; - this.putOnTop = putOnTop; + this.putLookedCards = putLookedCards; + this.revealCards = false; } public LookLibraryControllerEffect(final LookLibraryControllerEffect effect) { super(effect); this.numberOfCards = effect.numberOfCards.copy(); - this.mayShuffleAfter = effect.mayShuffleAfter; - this.targetZoneLookedCards = effect.targetZoneLookedCards; - this.putOnTop = effect.putOnTop; - this.backInRandomOrder = effect.backInRandomOrder; + this.putLookedCards = effect.putLookedCards; + this.revealCards = effect.revealCards; } @Override public LookLibraryControllerEffect copy() { return new LookLibraryControllerEffect(this); - } @Override @@ -84,68 +103,37 @@ public class LookLibraryControllerEffect extends OneShotEffect { // take cards from library and look at them boolean topCardRevealed = controller.isTopCardRevealed(); controller.setTopCardRevealed(false); - Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, this.numberOfCards.calculate(game, source, this))); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, numberOfCards.calculate(game, source, this))); - controller.lookAtCards(source, null, cards, game); + if (revealCards) { + controller.revealCards(source, cards, game); + } else { + controller.lookAtCards(source, null, cards, game); + } - this.actionWithSelectedCards(cards, game, source); - - this.putCardsBack(source, controller, cards, game); + boolean result = actionWithLookedCards(game, source, controller, cards); controller.setTopCardRevealed(topCardRevealed); - this.mayShuffle(controller, source, game); - - return true; + return result; } - public boolean isBackInRandomOrder() { - return backInRandomOrder; + protected boolean actionWithLookedCards(Game game, Ability source, Player player, Cards cards) { + return moveCards(game, source, player, cards, putLookedCards); } - public Effect setBackInRandomOrder(boolean backInRandomOrder) { - this.backInRandomOrder = backInRandomOrder; - return this; - } - - protected void actionWithSelectedCards(Cards cards, Game game, Ability source) { - } - - /** - * Put the rest of the cards back to defined zone - * - * @param source - * @param player - * @param cards - * @param game - */ - protected void putCardsBack(Ability source, Player player, Cards cards, Game game) { - switch (targetZoneLookedCards) { - case LIBRARY: - if (putOnTop) { - player.putCardsOnTopOfLibrary(cards, game, source, !backInRandomOrder); - } else { - player.putCardsOnBottomOfLibrary(cards, game, source, !backInRandomOrder); - } - break; - case GRAVEYARD: - player.moveCards(cards, Zone.GRAVEYARD, source, game); - break; + protected static boolean moveCards(Game game, Ability source, Player player, Cards cards, PutCards putCards) { + switch (putCards) { + case TOP_ANY: + return player.putCardsOnTopOfLibrary(cards, game, source, true); + case BOTTOM_ANY: + return player.putCardsOnBottomOfLibrary(cards, game, source, true); + case BOTTOM_RANDOM: + return player.putCardsOnBottomOfLibrary(cards, game, source, false); + case BATTLEFIELD_TAPPED: + return player.moveCards(cards.getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null); default: - // not supported yet - } - } - - /** - * Check to shuffle library if allowed - * - * @param player - * @param source - * @param game - */ - protected void mayShuffle(Player player, Ability source, Game game) { - if (this.mayShuffleAfter && player.chooseUse(Outcome.Benefit, "Shuffle your library?", source, game)) { - player.shuffleLibrary(source, game); + return player.moveCards(cards, putCards.getZone(), source, game); } } @@ -158,46 +146,29 @@ public class LookLibraryControllerEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()) { return staticText; } - int numberLook; - try { - numberLook = Integer.parseInt(numberOfCards.toString()); - } catch (NumberFormatException e) { - numberLook = 0; + String numberString = numberOfCards.toString(); + boolean dynamic = !numberOfCards.getMessage().isEmpty(); + boolean oneCard = !dynamic && numberString.equals("1"); + StringBuilder sb = new StringBuilder(revealCards ? "reveal " : "look at "); + if (oneCard) { + sb.append("the top card"); + } else if (dynamic) { + sb.append("the top X cards"); + } else if (numberString.equals("that many")) { + sb.append("that many cards from the top"); + } else { + sb.append("the top ").append(CardUtil.numberToText(numberString)).append(" cards"); } - StringBuilder sb = new StringBuilder("look at the top "); - switch (numberLook) { - case 0: - sb.append(" X "); - break; - case 1: - sb.append("card "); - break; - default: - sb.append(CardUtil.numberToText(numberLook)); - break; + sb.append(" of your library"); + if (dynamic) { + sb.append(", where X is ").append(numberOfCards.getMessage()); } - if (numberLook != 1) { - sb.append(" cards "); - } - - sb.append("of your library"); - if (numberLook == 0) { - sb.append(", where {X} is the number of cards ").append(numberOfCards.getMessage()); - } - if (!middleText.isEmpty()) { sb.append(middleText); - } else if (numberLook > 1) { - if (backInRandomOrder) { - sb.append(". Put the rest on the bottom of your library in a random order"); - } else { - sb.append(", then put them back in any order"); - } + } else if (!oneCard) { + sb.append(", then put them "); + sb.append(putLookedCards == PutCards.TOP_ANY ? "back in any order" : putLookedCards.getMessage(true)); } - if (this.mayShuffleAfter) { - sb.append(". You may shuffle"); - } - return sb.toString(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryMayPutToBottomEffect.java b/Mage/src/main/java/mage/abilities/effects/common/LookLibraryMayPutToBottomEffect.java deleted file mode 100644 index 45422fca4ba..00000000000 --- a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryMayPutToBottomEffect.java +++ /dev/null @@ -1,53 +0,0 @@ -package mage.abilities.effects.common; - -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardsImpl; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.game.Game; -import mage.players.Player; - -/** - * - * @author LevelX2 - */ - -public class LookLibraryMayPutToBottomEffect extends OneShotEffect { - - public LookLibraryMayPutToBottomEffect() { - super(Outcome.DrawCard); - this.staticText = "Look at the top card of your library. You may put that card on the bottom of your library."; - } - - public LookLibraryMayPutToBottomEffect(final LookLibraryMayPutToBottomEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (sourceObject == null || controller == null) { - return false; - } - if (controller.getLibrary().hasCards()) { - Card card = controller.getLibrary().getFromTop(game); - if (card == null) { - return false; - } - controller.lookAtCards(sourceObject.getName(), new CardsImpl(card), game); - boolean toBottom = controller.chooseUse(outcome, "Put card on the bottom of your library?", source, game); - return controller.moveCardToLibraryWithInfo(card, source, game, Zone.LIBRARY, !toBottom, false); - } - return true; - } - - @Override - public LookLibraryMayPutToBottomEffect copy() { - return new LookLibraryMayPutToBottomEffect(this); - } - -} diff --git a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryTopCardTargetPlayerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/LookLibraryTopCardTargetPlayerEffect.java index 39b69998c8c..7e80342e94f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/LookLibraryTopCardTargetPlayerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/LookLibraryTopCardTargetPlayerEffect.java @@ -67,7 +67,7 @@ public class LookLibraryTopCardTargetPlayerEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); Player targetPlayer = game.getPlayer(source.getFirstTarget()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (player != null && targetPlayer != null && sourceObject != null) { Cards cards = new CardsImpl(); cards.addAll(targetPlayer.getLibrary().getTopCards(game, amount)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/LoseLifeTargetControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/LoseLifeTargetControllerEffect.java index 60258d8c0ab..e0d2a94c0ad 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/LoseLifeTargetControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/LoseLifeTargetControllerEffect.java @@ -1,12 +1,13 @@ - package mage.abilities.effects.common; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; +import mage.constants.Outcome; +import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.stack.Spell; @@ -18,9 +19,13 @@ import mage.players.Player; */ public class LoseLifeTargetControllerEffect extends OneShotEffect { - protected int amount; + private final DynamicValue amount; public LoseLifeTargetControllerEffect(int amount) { + this(StaticValue.get(amount)); + } + + public LoseLifeTargetControllerEffect(DynamicValue amount) { super(Outcome.Damage); this.amount = amount; staticText = "Its controller loses " + amount + " life"; @@ -28,7 +33,7 @@ public class LoseLifeTargetControllerEffect extends OneShotEffect { public LoseLifeTargetControllerEffect(final LoseLifeTargetControllerEffect effect) { super(effect); - this.amount = effect.amount; + this.amount = effect.amount.copy(); } @Override @@ -38,16 +43,11 @@ public class LoseLifeTargetControllerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - MageObject targetCard = game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.BATTLEFIELD); + MageObject targetCard = targetPointer.getFirstTargetPermanentOrLKI(game, source); + // if target is a countered spell if ( targetCard == null ) { - MageObject obj = game.getObject(targetPointer.getFirst(game, source)); - if ( obj instanceof Card ) { - targetCard = (Card)obj; - } else { - // if target is a countered spell - targetCard = game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.STACK); - } + targetCard = game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.STACK); } if ( targetCard != null ) { @@ -65,11 +65,10 @@ public class LoseLifeTargetControllerEffect extends OneShotEffect { } if ( controller != null ) { - controller.loseLife(amount, game, source, false); + controller.loseLife(amount.calculate(game, source, this), game, source, false); return true; } } return false; } - } diff --git a/Mage/src/main/java/mage/abilities/effects/common/MayTapOrUntapTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/MayTapOrUntapTargetEffect.java index d5407da7b0f..4ff98626cd5 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/MayTapOrUntapTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/MayTapOrUntapTargetEffect.java @@ -51,7 +51,8 @@ public class MayTapOrUntapTargetEffect extends OneShotEffect { if (mode.getTargets().isEmpty()) { return "you may tap or untap it"; } else { - return "you may tap or untap target " + mode.getTargets().get(0).getTargetName(); + String targetName = mode.getTargets().get(0).getTargetName(); + return "you may tap or untap " + (targetName.contains("target") ? "" : "target ") + targetName; } } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/MeldEffect.java b/Mage/src/main/java/mage/abilities/effects/common/MeldEffect.java index 28eb5727ea1..21cc64104ab 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/MeldEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/MeldEffect.java @@ -48,11 +48,11 @@ public class MeldEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { // Find the two permanents to meld. - UUID sourceId = source.getSourceId(); + UUID sourceId = source != null ? source.getSourceId() : null; FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature named " + meldWithName); filter.add(new NamePredicate(meldWithName)); TargetPermanent target = new TargetControlledCreaturePermanent(filter); - Set meldWithList = target.possibleTargets(sourceId, source.getControllerId(), game); + Set meldWithList = target.possibleTargets(source.getControllerId(), source, game); if (meldWithList.isEmpty()) { return false; // possible permanent has left the battlefield meanwhile } @@ -60,7 +60,7 @@ public class MeldEffect extends OneShotEffect { if (meldWithList.size() == 1) { meldWithId = meldWithList.iterator().next(); } else { - if (controller.choose(Outcome.BoostCreature, target, sourceId, game)) { + if (controller.choose(Outcome.BoostCreature, target, source, game)) { meldWithId = target.getFirstTarget(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/MillCardsTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/MillCardsTargetEffect.java index bc3d7685249..34daa5d11bf 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/MillCardsTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/MillCardsTargetEffect.java @@ -51,11 +51,12 @@ public class MillCardsTargetEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()) { return staticText; } - StringBuilder sb = new StringBuilder("target "); + StringBuilder sb = new StringBuilder(); if (!mode.getTargets().isEmpty()) { + sb.append("target "); sb.append(mode.getTargets().get(0).getTargetName()); } else { - sb.append("player"); + sb.append("that player"); } sb.append(" mills "); if (numberCards.toString().equals("1")) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/MillHalfLibraryTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/MillHalfLibraryTargetEffect.java new file mode 100644 index 00000000000..64b4ba0127c --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/MillHalfLibraryTargetEffect.java @@ -0,0 +1,50 @@ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; + +/** + * @author TheElk801 + */ +public class MillHalfLibraryTargetEffect extends OneShotEffect { + + private final boolean roundUp; + + public MillHalfLibraryTargetEffect(boolean roundUp) { + super(Outcome.Benefit); + this.roundUp = roundUp; + } + + private MillHalfLibraryTargetEffect(final MillHalfLibraryTargetEffect effect) { + super(effect); + this.roundUp = effect.roundUp; + } + + @Override + public MillHalfLibraryTargetEffect copy() { + return new MillHalfLibraryTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (player == null) { + return false; + } + int count = player.getLibrary().size(); + return player.millCards(count / 2 + (roundUp ? count % 2 : 0), source, game).size() > 0; + } + + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + return "target " + (mode.getTargets().isEmpty() ? "that player" : mode.getTargets().get(0).getTargetName()) + + " mills half their library, rounded " + (roundUp ? "up" : "down"); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/OpponentsCantCastChosenUntilNextTurnEffect.java b/Mage/src/main/java/mage/abilities/effects/common/OpponentsCantCastChosenUntilNextTurnEffect.java index 2eba8953dcd..5fed90bb224 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/OpponentsCantCastChosenUntilNextTurnEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/OpponentsCantCastChosenUntilNextTurnEffect.java @@ -30,7 +30,7 @@ public class OpponentsCantCastChosenUntilNextTurnEffect extends ContinuousRuleMo @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); if (mageObject != null && cardName != null) { return "You can't cast a card named " + cardName + " (" + mageObject.getIdName() + ")."; diff --git a/Mage/src/main/java/mage/abilities/effects/common/PermanentsEnterBattlefieldTappedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PermanentsEnterBattlefieldTappedEffect.java index dd46edbfbe1..95eb1e993fd 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PermanentsEnterBattlefieldTappedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PermanentsEnterBattlefieldTappedEffect.java @@ -49,7 +49,7 @@ public class PermanentsEnterBattlefieldTappedEffect extends ReplacementEffectImp @Override public boolean applies(GameEvent event, Ability source, Game game) { Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filter.match(permanent, source.getControllerId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/PhaseOutTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PhaseOutTargetEffect.java index 7d062fd4570..73f66434c7a 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PhaseOutTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PhaseOutTargetEffect.java @@ -6,7 +6,6 @@ import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.target.Target; import java.util.UUID; @@ -15,23 +14,20 @@ import java.util.UUID; */ public class PhaseOutTargetEffect extends OneShotEffect { - protected String targetDescription; - protected boolean useOnlyTargetPointer; + protected final String targetDescription; public PhaseOutTargetEffect() { - super(Outcome.Detriment); + this((String) null); } - public PhaseOutTargetEffect(String targetDescription, boolean useOnlyTargetPointer) { + public PhaseOutTargetEffect(String targetDescription) { super(Outcome.Detriment); this.targetDescription = targetDescription; - this.useOnlyTargetPointer = useOnlyTargetPointer; } - public PhaseOutTargetEffect(final PhaseOutTargetEffect effect) { + private PhaseOutTargetEffect(final PhaseOutTargetEffect effect) { super(effect); this.targetDescription = effect.targetDescription; - this.useOnlyTargetPointer = effect.useOnlyTargetPointer; } @Override @@ -41,17 +37,6 @@ public class PhaseOutTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - if (!useOnlyTargetPointer && source.getTargets().size() > 1) { - for (Target target : source.getTargets()) { - for (UUID targetId : target.getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null) { - permanent.phaseOut(game); - } - } - } - return true; - } for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { Permanent permanent = game.getPermanent(targetId); if (permanent != null) { @@ -64,14 +49,13 @@ public class PhaseOutTargetEffect extends OneShotEffect { @Override public String getText(Mode mode) { if (staticText != null && !staticText.isEmpty()) { - return staticText + " phases out"; + return staticText; } - StringBuilder sb = new StringBuilder(); if (targetDescription != null && !targetDescription.isEmpty()) { sb.append(targetDescription); } else { - sb.append("Target ").append(mode.getTargets().get(0).getTargetName()); + sb.append("target ").append(mode.getTargets().get(0).getTargetName()); } sb.append(" phase"); if (mode.getTargets().isEmpty() @@ -81,5 +65,4 @@ public class PhaseOutTargetEffect extends OneShotEffect { sb.append(" out"); return sb.toString(); } - } diff --git a/Mage/src/main/java/mage/abilities/effects/common/PopulateEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PopulateEffect.java index 26da099df0b..d1e7664f8fc 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PopulateEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PopulateEffect.java @@ -1,7 +1,6 @@ package mage.abilities.effects.common; import mage.abilities.Ability; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.constants.TargetController; @@ -15,6 +14,9 @@ import mage.target.Target; import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTarget; +import java.util.ArrayList; +import java.util.List; + /** * @author LevelX2 */ @@ -31,6 +33,7 @@ public class PopulateEffect extends OneShotEffect { private final boolean tappedAndAttacking; private static final FilterPermanent filter = new FilterCreaturePermanent("creature token for populate"); + private final List addedTokenPermanents = new ArrayList<>(); static { filter.add(TokenPredicate.TRUE); @@ -56,6 +59,7 @@ public class PopulateEffect extends OneShotEffect { public PopulateEffect(final PopulateEffect effect) { super(effect); this.tappedAndAttacking = effect.tappedAndAttacking; + this.addedTokenPermanents.addAll(effect.addedTokenPermanents); } @Override @@ -66,20 +70,27 @@ public class PopulateEffect extends OneShotEffect { } Target target = new TargetPermanent(filter); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (!target.canChoose(source.getControllerId(), source, game)) { return true; } - player.choose(Outcome.Copy, target, source.getSourceId(), game); + player.choose(Outcome.Copy, target, source, game); Permanent tokenToCopy = game.getPermanent(target.getFirstTarget()); if (tokenToCopy == null) { return true; } game.informPlayers("Token selected for populate: " + tokenToCopy.getLogName()); - Effect effect = new CreateTokenCopyTargetEffect( + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect( null, null, false, 1, tappedAndAttacking, tappedAndAttacking ); effect.setTargetPointer(new FixedTarget(target.getFirstTarget(), game)); - return effect.apply(game, source); + effect.apply(game, source); + this.addedTokenPermanents.clear(); + this.addedTokenPermanents.addAll(effect.getAddedPermanents()); + return true; + } + + public List getAddedPermanents() { + return addedTokenPermanents; } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageByAllObjectsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageByAllObjectsEffect.java index c8984f75d88..8644fc61e90 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageByAllObjectsEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageByAllObjectsEffect.java @@ -60,7 +60,7 @@ public class PreventAllDamageByAllObjectsEffect extends PreventionEffectImpl { return false; } if (filter instanceof FilterInPlay) { - return ((FilterInPlay) filter).match(damageSource, source.getSourceId(), source.getControllerId(), game); + return ((FilterInPlay) filter).match(damageSource, source.getControllerId(), source, game); } return filter.match(damageSource, game); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageByAllPermanentsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageByAllPermanentsEffect.java index 58d7564d4de..131abbd49c9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageByAllPermanentsEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageByAllPermanentsEffect.java @@ -5,9 +5,7 @@ import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.PreventionEffectImpl; import mage.constants.Duration; -import static mage.constants.Duration.EndOfTurn; import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.events.DamageEvent; import mage.game.events.GameEvent; @@ -29,7 +27,7 @@ public class PreventAllDamageByAllPermanentsEffect extends PreventionEffectImpl this(null, duration, onlyCombat); } - public PreventAllDamageByAllPermanentsEffect(FilterCreaturePermanent filter, Duration duration, boolean onlyCombat) { + public PreventAllDamageByAllPermanentsEffect(FilterPermanent filter, Duration duration, boolean onlyCombat) { super(duration, Integer.MAX_VALUE, onlyCombat); this.filter = filter; } @@ -55,7 +53,7 @@ public class PreventAllDamageByAllPermanentsEffect extends PreventionEffectImpl return true; } Permanent permanent = game.getPermanent(damageEvent.getSourceId()); - if (filter.match(permanent, source.getSourceId(), source.getControllerId(), game)) { + if (filter.match(permanent, source.getControllerId(), source, game)) { return true; } } @@ -68,24 +66,17 @@ public class PreventAllDamageByAllPermanentsEffect extends PreventionEffectImpl if (staticText != null && !staticText.isEmpty()) { return staticText; } - StringBuilder sb = new StringBuilder("Prevent all "); + StringBuilder sb = new StringBuilder("prevent all "); if (onlyCombat) { sb.append("combat "); } - sb.append("damage "); - if (duration == EndOfTurn) { - if (filter != null) { - sb.append(filter.getMessage()); - sb.append(" would deal this turn"); - } else { - sb.append("that would be dealt this turn"); - } - } else { - sb.append(duration.toString()); - if (filter != null) { - sb.append(" dealt by "); - sb.append(filter.getMessage()); - } + sb.append("damage that would be dealt"); + if (duration == Duration.EndOfTurn) { + sb.append(" this turn"); + } + if (filter != null) { + sb.append(" by "); + sb.append(filter.getMessage()); } return sb.toString(); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageFromChosenSourceToYouEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageFromChosenSourceToYouEffect.java index ca8f90ff46d..fc4ed76b548 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageFromChosenSourceToYouEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageFromChosenSourceToYouEffect.java @@ -44,7 +44,7 @@ public class PreventAllDamageFromChosenSourceToYouEffect extends PreventionEffec @Override public void init(Ability source, Game game) { - this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageToAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageToAllEffect.java index 413b888cdc6..c7b95c41beb 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageToAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageToAllEffect.java @@ -37,7 +37,7 @@ public class PreventAllDamageToAllEffect extends PreventionEffectImpl { public PreventAllDamageToAllEffect(Duration duration, FilterPermanentOrPlayer filter, boolean onlyCombat) { super(duration, Integer.MAX_VALUE, onlyCombat, false); this.filter = filter; - staticText = "Prevent all " + staticText = "prevent all " + (onlyCombat ? "combat " : "") + "damage that would be dealt to " + filter.getMessage() @@ -92,7 +92,7 @@ public class PreventAllDamageToAllEffect extends PreventionEffectImpl { object = game.getObject(event.getTargetId()); } if (object != null) { - return filter.match(object, source.getSourceId(), source.getControllerId(), game); + return filter.match(object, source.getControllerId(), source, game); } } return false; diff --git a/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageToPlayersEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageToPlayersEffect.java index 9817e4e3754..56fe441c809 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageToPlayersEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PreventAllDamageToPlayersEffect.java @@ -51,7 +51,7 @@ public class PreventAllDamageToPlayersEffect extends PreventionEffectImpl { } sb.append("damage that would be dealt to players"); if (duration == Duration.EndOfTurn) { - sb.append(" this turn"); + sb.append(" this turn"); } return sb.toString(); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/PreventAllNonCombatDamageToAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PreventAllNonCombatDamageToAllEffect.java index 8edf712f0c9..750207a27eb 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PreventAllNonCombatDamageToAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PreventAllNonCombatDamageToAllEffect.java @@ -49,7 +49,7 @@ public class PreventAllNonCombatDamageToAllEffect extends PreventionEffectImpl { && !((DamageEvent) event).isCombatDamage()) { Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent != null) { - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filter.match(permanent, source.getControllerId(), source, game); } return andToYou && source.getControllerId().equals(event.getTargetId()); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/PreventDamageBySourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PreventDamageBySourceEffect.java index f31559a4ef0..56409db455a 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PreventDamageBySourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PreventDamageBySourceEffect.java @@ -48,7 +48,7 @@ public class PreventDamageBySourceEffect extends PreventionEffectImpl { @Override public void init(Ability source, Game game) { - this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); mageObjectReference = new MageObjectReference(target.getFirstTarget(), game); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/PreventDamageToAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PreventDamageToAttachedEffect.java index d696229bc96..b7e5f8503b5 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PreventDamageToAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PreventDamageToAttachedEffect.java @@ -69,7 +69,7 @@ public class PreventDamageToAttachedEffect extends PreventionEffectImpl { } sb.append("damage to "); sb.append(attachmentType.verb()); - sb.append(" creature, prevent ").append(amountToPrevent);; + sb.append(" creature, prevent ").append(amountToPrevent); sb.append(" of that damage"); } return sb.toString(); diff --git a/Mage/src/main/java/mage/abilities/effects/common/PreventDamageToTargetMultiAmountEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PreventDamageToTargetMultiAmountEffect.java index 85e8cbaf888..e6324d95873 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PreventDamageToTargetMultiAmountEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PreventDamageToTargetMultiAmountEffect.java @@ -48,7 +48,7 @@ public class PreventDamageToTargetMultiAmountEffect extends PreventionEffectImpl public void init(Ability source, Game game) { super.init(source, game); Target target = source.getTargets().get(0); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (target instanceof TargetAmount && sourceObject != null) { TargetAmount multiTarget = (TargetAmount) target; for (UUID targetId : multiTarget.getTargets()) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/PreventNextDamageFromChosenSourceToTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PreventNextDamageFromChosenSourceToTargetEffect.java index 659ec194e58..68a54ea129e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PreventNextDamageFromChosenSourceToTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PreventNextDamageFromChosenSourceToTargetEffect.java @@ -48,7 +48,7 @@ public class PreventNextDamageFromChosenSourceToTargetEffect extends PreventionE @Override public void init(Ability source, Game game) { - this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/PreventNextDamageFromChosenSourceToYouEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PreventNextDamageFromChosenSourceToYouEffect.java index 86f10acf760..de451539114 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PreventNextDamageFromChosenSourceToYouEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PreventNextDamageFromChosenSourceToYouEffect.java @@ -47,7 +47,7 @@ public class PreventNextDamageFromChosenSourceToYouEffect extends PreventionEffe @Override public void init(Ability source, Game game) { - this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/PutCardFromHandOntoBattlefieldEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PutCardFromHandOntoBattlefieldEffect.java index 5b07d886218..9e9f0e83e3c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PutCardFromHandOntoBattlefieldEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PutCardFromHandOntoBattlefieldEffect.java @@ -65,7 +65,7 @@ public class PutCardFromHandOntoBattlefieldEffect extends OneShotEffect { } if (player.chooseUse(Outcome.PutCardInPlay, "Put " + filter.getMessage() + " from your hand onto the battlefield?", source, game)) { TargetCardInHand target = new TargetCardInHand(filter); - if (player.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { + if (player.choose(Outcome.PutCardInPlay, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { return player.moveCards(card, Zone.BATTLEFIELD, source, game, tapped, false, false, null); diff --git a/Mage/src/main/java/mage/abilities/effects/common/PutOnTopOrBottomLibraryTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PutOnTopOrBottomLibraryTargetEffect.java new file mode 100644 index 00000000000..4878d28e1db --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/PutOnTopOrBottomLibraryTargetEffect.java @@ -0,0 +1,54 @@ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; + +/** + * @author TheElk801 + */ +public class PutOnTopOrBottomLibraryTargetEffect extends OneShotEffect { + + public PutOnTopOrBottomLibraryTargetEffect() { + this(""); + } + + public PutOnTopOrBottomLibraryTargetEffect(String text) { + super(Outcome.Benefit); + staticText = text; + } + + private PutOnTopOrBottomLibraryTargetEffect(final PutOnTopOrBottomLibraryTargetEffect effect) { + super(effect); + } + + @Override + public PutOnTopOrBottomLibraryTargetEffect copy() { + return new PutOnTopOrBottomLibraryTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget())); + if (player == null) { + return false; + } + boolean onTop = player.chooseUse( + Outcome.Detriment, "Put the targeted object on the top or bottom of your library?", + null, "Top", "Bottom", source, game + ); + return new PutOnLibraryTargetEffect(onTop).apply(game, source); + } + + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + return "the owner of target " + mode.getTargets().get(0).getTargetName() + + " puts it on the top or bottom of their library"; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/RegenerateAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RegenerateAllEffect.java index 009d38db171..e3c4bc5540a 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/RegenerateAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/RegenerateAllEffect.java @@ -33,7 +33,7 @@ public class RegenerateAllEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { RegenerateTargetEffect regenEffect = new RegenerateTargetEffect(); regenEffect.setTargetPointer(new FixedTarget(permanent, game)); game.addEffect(regenEffect, source); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java index 617f651e263..402172e6bc1 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java @@ -84,7 +84,10 @@ public class ReturnFromGraveyardToBattlefieldTargetEffect extends OneShotEffect sb.append("target creature"); } else { Target target = mode.getTargets().get(0); - if (target.getMaxNumberOfTargets() > 1) { + if (target.getMaxNumberOfTargets() == Integer.MAX_VALUE + && target.getMinNumberOfTargets() == 0) { + sb.append("any number of "); + } else if (target.getMaxNumberOfTargets() > 1) { if (target.getMaxNumberOfTargets() != target.getNumberOfTargets()) { sb.append("up to "); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToHandTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToHandTargetEffect.java index 760633fc175..5a50db9c3ff 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToHandTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToHandTargetEffect.java @@ -3,7 +3,6 @@ package mage.abilities.effects.common; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.Outcome; @@ -14,7 +13,6 @@ import mage.target.Target; import mage.util.CardUtil; /** - * * @author jeff */ public class ReturnFromGraveyardToHandTargetEffect extends OneShotEffect { @@ -38,14 +36,9 @@ public class ReturnFromGraveyardToHandTargetEffect extends OneShotEffect { if (controller == null) { return false; } - Cards cardsInGraveyard = new CardsImpl(getTargetPointer().getTargets(game, source)); - for (Card card : cardsInGraveyard.getCards(game)) { - if (card != null - && game.getState().getZone(card.getId()) == Zone.GRAVEYARD) { - controller.moveCards(card, Zone.HAND, source, game); //verify the target card is still in the graveyard - } - } - return false; + Cards cards = new CardsImpl(getTargetPointer().getTargets(game, source)); + cards.retainZone(Zone.GRAVEYARD, game); //verify the target card is still in the graveyard + return !cards.isEmpty() && controller.moveCards(cards, Zone.HAND, source, game); } @Override @@ -62,10 +55,14 @@ public class ReturnFromGraveyardToHandTargetEffect extends OneShotEffect { } else if (target.getMaxNumberOfTargets() > 1) { sb.append(CardUtil.numberToText(target.getMaxNumberOfTargets())).append(' '); } - if (!mode.getTargets().get(0).getTargetName().startsWith("another")) { + if (!target.getTargetName().startsWith("another")) { sb.append("target "); } - sb.append(mode.getTargets().get(0).getTargetName()).append(" to your hand"); + sb.append(target.getTargetName()); + if (!target.getTargetName().endsWith("graveyard")) { + sb.append(" from your graveyard"); + } + sb.append(" to your hand"); return sb.toString(); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandChosenPermanentEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandChosenPermanentEffect.java index f9e144fd408..6d8052f3bd1 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandChosenPermanentEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandChosenPermanentEffect.java @@ -47,7 +47,7 @@ public class ReturnToHandChosenPermanentEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(this.getTargetPointer().getFirst(game, source)); if (player != null) { - int available = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + int available = game.getBattlefield().count(filter, source.getControllerId(), source, game); if (available > 0) { TargetControlledPermanent target = new TargetControlledPermanent(Math.min(number, available), number, filter, true); if (player.chooseTarget(this.outcome, target, source, game)) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandFromBattlefieldAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandFromBattlefieldAllEffect.java index 679b857829e..b8612237a5b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandFromBattlefieldAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandFromBattlefieldAllEffect.java @@ -24,7 +24,7 @@ public class ReturnToHandFromBattlefieldAllEffect extends OneShotEffect { public ReturnToHandFromBattlefieldAllEffect(FilterPermanent filter) { super(Outcome.ReturnToHand); this.filter = filter; - staticText = "Return all " + filter.getMessage() + " to their owners' hands"; + staticText = "return all " + filter.getMessage() + " to their owners' hands"; } public ReturnToHandFromBattlefieldAllEffect(final ReturnToHandFromBattlefieldAllEffect effect) { @@ -37,7 +37,7 @@ public class ReturnToHandFromBattlefieldAllEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Set permanentsToHand = new HashSet<>(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanentsToHand.add(permanent); } controller.moveCards(permanentsToHand, Zone.HAND, source, game); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandFromGraveyardAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandFromGraveyardAllEffect.java index 33b9c52c2d0..42068a28963 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandFromGraveyardAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandFromGraveyardAllEffect.java @@ -61,7 +61,7 @@ public class ReturnToHandFromGraveyardAllEffect extends OneShotEffect { continue; } player.moveCards(player.getGraveyard().getCards( - filter, source.getSourceId(), player.getId(), game + filter, player.getId(), source, game ), Zone.HAND, source, game); } return true; diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandSourceEffect.java index 8b4c04b1d5d..f30a0b3c16f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandSourceEffect.java @@ -62,7 +62,7 @@ public class ReturnToHandSourceEffect extends OneShotEffect { MageObject mageObject; if (returnFromNextZone && game.getState().getZoneChangeCounter(source.getSourceId()) == source.getSourceObjectZoneChangeCounter() + 1) { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } else { mageObject = source.getSourceObjectIfItStillExists(game); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/RevealCardsFromLibraryUntilEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RevealCardsFromLibraryUntilEffect.java index dddb343176c..fa4c695c654 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/RevealCardsFromLibraryUntilEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/RevealCardsFromLibraryUntilEffect.java @@ -1,8 +1,8 @@ - package mage.abilities.effects.common; import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.Cards; @@ -13,18 +13,18 @@ import mage.filter.FilterCard; import mage.game.Game; import mage.players.Library; import mage.players.Player; +import mage.util.CardUtil; /** - * * @author Styxo */ public class RevealCardsFromLibraryUntilEffect extends OneShotEffect { - private FilterCard filter; - private Zone zoneToPutRest; - private Zone zoneToPutCard; - private boolean shuffleRestInto; - private boolean anyOrder; + private final FilterCard filter; + private final Zone zoneToPutRest; + private final Zone zoneToPutCard; + private final boolean shuffleRestInto; + private final boolean anyOrder; public RevealCardsFromLibraryUntilEffect(FilterCard filter, Zone zoneToPutCard, Zone zoneToPutRest) { this(filter, zoneToPutCard, zoneToPutRest, false, false); @@ -41,17 +41,15 @@ public class RevealCardsFromLibraryUntilEffect extends OneShotEffect { this.zoneToPutRest = zoneToPutRest; this.shuffleRestInto = shuffleRestInto; this.anyOrder = anyOrder; - setText(); } - public RevealCardsFromLibraryUntilEffect(final RevealCardsFromLibraryUntilEffect effect) { + private RevealCardsFromLibraryUntilEffect(final RevealCardsFromLibraryUntilEffect effect) { super(effect); this.filter = effect.filter; this.zoneToPutCard = effect.zoneToPutCard; this.zoneToPutRest = effect.zoneToPutRest; this.shuffleRestInto = effect.shuffleRestInto; this.anyOrder = effect.anyOrder; - setText(); } @Override @@ -62,51 +60,55 @@ public class RevealCardsFromLibraryUntilEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller != null && controller.getLibrary().hasCards()) { - Cards cards = new CardsImpl(); - Library library = controller.getLibrary(); - Card card = null; - do { - card = library.removeFromTop(game); - if (card != null) { - cards.add(card); - } - } while (library.hasCards() && !filter.match(card, game)); - // reveal cards - if (!cards.isEmpty()) { - controller.revealCards(sourceObject.getIdName(), cards, game); - if (filter.match(card, game)) { - // put card in correct zone - controller.moveCards(card, zoneToPutCard, source, game); - // remove it from revealed card list - cards.remove(card); - } - // Put the rest in correct zone - switch (zoneToPutRest) { - case LIBRARY: { - if (!cards.isEmpty()) { - if (shuffleRestInto) { - library.addAll(cards.getCards(game), game); - } else { - controller.putCardsOnBottomOfLibrary(cards, game, source, anyOrder); - } - } - break; - } - default: - if (!cards.isEmpty()) { - controller.moveCards(cards, zoneToPutRest, source, game); - } - } + MageObject sourceObject = game.getObject(source); + if (controller == null || !controller.getLibrary().hasCards()) { + return false; + } + Cards cards = new CardsImpl(); + Library library = controller.getLibrary(); + Card card = null; + do { + card = library.removeFromTop(game); + if (card != null) { + cards.add(card); } + } while (library.hasCards() && !filter.match(card, game)); + // reveal cards + if (cards.isEmpty()) { return true; } - return false; + controller.revealCards(sourceObject.getIdName(), cards, game); + if (filter.match(card, game)) { + // put card in correct zone + controller.moveCards(card, zoneToPutCard, source, game); + // remove it from revealed card list + cards.remove(card); + } + // Put the rest in correct zone + if (zoneToPutRest == Zone.LIBRARY) { + if (!cards.isEmpty()) { + if (shuffleRestInto) { + library.addAll(cards.getCards(game), game); + } else { + controller.putCardsOnBottomOfLibrary(cards, game, source, anyOrder); + } + } + } else { + if (!cards.isEmpty()) { + controller.moveCards(cards, zoneToPutRest, source, game); + } + } + return true; } - private void setText() { - StringBuilder sb = new StringBuilder("reveal cards from the top of your library until you reveal a " + filter.getMessage() + ". Put that card "); + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + StringBuilder sb = new StringBuilder("reveal cards from the top of your library until you reveal "); + sb.append(CardUtil.addArticle(filter.getMessage())); + sb.append(". Put that card "); switch (zoneToPutCard) { case HAND: { @@ -144,6 +146,6 @@ public class RevealCardsFromLibraryUntilEffect extends OneShotEffect { break; } } - staticText = sb.toString(); + return sb.toString(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/RevealHandSourceControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RevealHandSourceControllerEffect.java index cbbff8ad398..e65fc55159a 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/RevealHandSourceControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/RevealHandSourceControllerEffect.java @@ -26,7 +26,7 @@ public class RevealHandSourceControllerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (player != null && sourceObject != null) { player.revealCards(sourceObject.getIdName(), player.getHand(), game); return true; diff --git a/Mage/src/main/java/mage/abilities/effects/common/RevealHandTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RevealHandTargetEffect.java index e17ead692c1..0aafaee0856 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/RevealHandTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/RevealHandTargetEffect.java @@ -35,7 +35,7 @@ public class RevealHandTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getFirstTarget()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (player != null && sourceObject != null) { player.revealCards(sourceObject.getIdName(), player.getHand(), game); return true; diff --git a/Mage/src/main/java/mage/abilities/effects/common/RevealLibraryPickControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RevealLibraryPickControllerEffect.java new file mode 100644 index 00000000000..e6df716914e --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/RevealLibraryPickControllerEffect.java @@ -0,0 +1,30 @@ +package mage.abilities.effects.common; + +import mage.filter.FilterCard; + +/** + * @author awjackson + */ +public class RevealLibraryPickControllerEffect extends LookLibraryAndPickControllerEffect { + + public RevealLibraryPickControllerEffect(int numberOfCards, int numberToPick, FilterCard filter, + PutCards putPickedCards, PutCards putLookedCards) { + this(numberOfCards, numberToPick, filter, putPickedCards, putLookedCards, true); + } + + public RevealLibraryPickControllerEffect(int numberOfCards, int numberToPick, FilterCard filter, + PutCards putPickedCards, PutCards putLookedCards, boolean optional) { + super(numberOfCards, numberToPick, filter, putPickedCards, putLookedCards, optional); + this.revealCards = true; + this.revealPickedCards = false; + } + + public RevealLibraryPickControllerEffect(final LookLibraryAndPickControllerEffect effect) { + super(effect); + } + + @Override + public RevealLibraryPickControllerEffect copy() { + return new RevealLibraryPickControllerEffect(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/RevealLibraryPutIntoHandEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RevealLibraryPutIntoHandEffect.java index c77e3560f4d..cd6f088d4aa 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/RevealLibraryPutIntoHandEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/RevealLibraryPutIntoHandEffect.java @@ -60,7 +60,7 @@ public class RevealLibraryPutIntoHandEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller == null || sourceObject == null) { return false; } @@ -72,7 +72,7 @@ public class RevealLibraryPutIntoHandEffect extends OneShotEffect { Set cardsList = cards.getCards(game); Cards cardsToHand = new CardsImpl(); for (Card card : cardsList) { - if (filter.match(card, source.getSourceId(), controller.getId(), game)) { + if (filter.match(card, controller.getId(), source, game)) { cardsToHand.add(card); cards.remove(card); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/RevealTopLandToBattlefieldElseHandEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RevealTopLandToBattlefieldElseHandEffect.java index 345f811de87..f60b198184e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/RevealTopLandToBattlefieldElseHandEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/RevealTopLandToBattlefieldElseHandEffect.java @@ -29,7 +29,7 @@ public class RevealTopLandToBattlefieldElseHandEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject == null || controller == null) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/RollDiceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RollDiceEffect.java index abd1ac95782..44bf5ffbbf0 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/RollDiceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/RollDiceEffect.java @@ -43,7 +43,7 @@ public class RollDiceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (controller != null && mageObject != null) { controller.rollDice(outcome, source, game, numSides); return true; diff --git a/Mage/src/main/java/mage/abilities/effects/common/RollDieWithResultTableEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RollDieWithResultTableEffect.java index 1e65c1f8d08..db73ada1f92 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/RollDieWithResultTableEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/RollDieWithResultTableEffect.java @@ -89,8 +89,8 @@ public class RollDieWithResultTableEffect extends OneShotEffect { @Override public String getText(Mode mode) { - StringBuilder sb = new StringBuilder(); - sb.append(prefixText).append('.'); + StringBuilder sb = new StringBuilder(prefixText); + sb.append('.'); for (TableEntry tableEntry : this.resultsTable) { sb.append("
"); if (tableEntry.max == Integer.MAX_VALUE) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/RollPlanarDieEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RollPlanarDieEffect.java index 836e5226a57..c47e0c39193 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/RollPlanarDieEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/RollPlanarDieEffect.java @@ -59,7 +59,7 @@ public class RollPlanarDieEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (controller != null && mageObject != null) { PlanarDieRollResult planarRoll = controller.rollPlanarDie(outcome, source, game); if (planarRoll == PlanarDieRollResult.CHAOS_ROLL && chaosEffects != null && chaosTargets != null) { @@ -78,7 +78,7 @@ public class RollPlanarDieEffect extends OneShotEffect { } boolean done = false; while (controller.canRespond() && effect != null && !done) { - if (target != null && !target.isChosen() && target.canChoose(source.getSourceId(), controller.getId(), game)) { + if (target != null && !target.isChosen() && target.canChoose(controller.getId(), source, game)) { controller.chooseTarget(Outcome.Benefit, target, source, game); source.addTarget(target); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/SacrificeAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SacrificeAllEffect.java index 6077f6174b4..27e4f9d13d3 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SacrificeAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SacrificeAllEffect.java @@ -64,9 +64,9 @@ public class SacrificeAllEffect extends OneShotEffect { if (player != null) { int numTargets = Math.min(amount.calculate(game, source, this), game.getBattlefield().countAll(filter, player.getId(), game)); TargetControlledPermanent target = new TargetControlledPermanent(numTargets, numTargets, filter, true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { while (!target.isChosen() && player.canRespond()) { - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + player.choose(Outcome.Sacrifice, target, source, game); } perms.addAll(target.getTargets()); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/SacrificeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SacrificeEffect.java index 9115e6ba862..d19843d6247 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SacrificeEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SacrificeEffect.java @@ -56,9 +56,9 @@ public class SacrificeEffect extends OneShotEffect { int realCount = game.getBattlefield().countAll(newFilter, player.getId(), game); amount = Math.min(amount, realCount); Target target = new TargetPermanent(amount, amount, newFilter, true); - if (amount > 0 && target.canChoose(source.getSourceId(), player.getId(), game)) { + if (amount > 0 && target.canChoose(player.getId(), source, game)) { while (!target.isChosen() - && target.canChoose(source.getSourceId(), player.getId(), game) + && target.canChoose(player.getId(), source, game) && player.canRespond()) { player.chooseTarget(Outcome.Sacrifice, target, source, game); } @@ -98,12 +98,12 @@ public class SacrificeEffect extends OneShotEffect { sb.append(" sacrifice "); } } - if (!filter.getMessage().startsWith("another") - && !filter.getMessage().startsWith("a ") - && !filter.getMessage().startsWith("an ")) { - sb.append(CardUtil.numberToText(count.toString(), "a")).append(' '); + if (count.toString().equals("1")) { + sb.append(CardUtil.addArticle(filter.getMessage())); + } else { + sb.append(CardUtil.numberToText(count.toString(), "a")); + sb.append(filter.getMessage()); } - sb.append(filter.getMessage()); staticText = sb.toString(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/SacrificeOpponentsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SacrificeOpponentsEffect.java index 279f5562547..a246d724ca7 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SacrificeOpponentsEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SacrificeOpponentsEffect.java @@ -1,6 +1,7 @@ package mage.abilities.effects.common; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; @@ -40,7 +41,6 @@ public class SacrificeOpponentsEffect extends OneShotEffect { this.amount = amount; this.filter = filter.copy(); this.filter.add(TargetController.YOU.getControllerPredicate()); - setText(); } public SacrificeOpponentsEffect(final SacrificeOpponentsEffect effect) { @@ -63,7 +63,7 @@ public class SacrificeOpponentsEffect extends OneShotEffect { int numTargets = Math.min(amount.calculate(game, source, this), game.getBattlefield().countAll(filter, player.getId(), game)); if (numTargets > 0) { TargetPermanent target = new TargetPermanent(numTargets, numTargets, filter, true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Sacrifice, target, source, game); perms.addAll(target.getTargets()); } @@ -79,7 +79,11 @@ public class SacrificeOpponentsEffect extends OneShotEffect { return true; } - private void setText() { + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } StringBuilder sb = new StringBuilder(); sb.append("each opponent sacrifices "); switch (amount.toString()) { @@ -92,6 +96,6 @@ public class SacrificeOpponentsEffect extends OneShotEffect { default: sb.append(CardUtil.numberToText(amount.toString())).append(' ').append(filter.getMessage()); } - staticText = sb.toString(); + return sb.toString(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/SacrificeOpponentsUnlessPayEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SacrificeOpponentsUnlessPayEffect.java index f7d199659af..d0e86cc5886 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SacrificeOpponentsUnlessPayEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SacrificeOpponentsUnlessPayEffect.java @@ -1,6 +1,7 @@ package mage.abilities.effects.common; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.costs.Cost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCost; @@ -60,7 +61,6 @@ public class SacrificeOpponentsUnlessPayEffect extends OneShotEffect { this.cost = cost; this.amount = amount; this.filter = filter; - setText(); } public SacrificeOpponentsUnlessPayEffect(DynamicValue genericMana, FilterPermanent filter, DynamicValue amount) { @@ -68,7 +68,6 @@ public class SacrificeOpponentsUnlessPayEffect extends OneShotEffect { this.genericMana = genericMana; this.amount = amount; this.filter = filter; - setText(); } public SacrificeOpponentsUnlessPayEffect(final SacrificeOpponentsUnlessPayEffect effect) { @@ -128,7 +127,7 @@ public class SacrificeOpponentsUnlessPayEffect extends OneShotEffect { if (numTargets > 0) { TargetPermanent target = new TargetPermanent(numTargets, numTargets, filter, true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { player.chooseTarget(Outcome.Sacrifice, target, source, game); permsToSacrifice.addAll(target.getTargets()); } @@ -150,31 +149,35 @@ public class SacrificeOpponentsUnlessPayEffect extends OneShotEffect { return true; } - private void setText() { + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } StringBuilder sb = new StringBuilder(); sb.append("each opponent sacrifices "); - if (amount.toString().equals("X")) { - sb.append(amount.toString()); - } else { - if (amount.toString().equals("1")) { - if (!filter.getMessage().startsWith("a ") && !filter.getMessage().startsWith("an ")) { - sb.append('a'); - } - } else { + switch (amount.toString()) { + case "1": + sb.append(CardUtil.addArticle(filter.getMessage())); + break; + case "X": + sb.append("X "); + sb.append(filter.getMessage()); + break; + default: sb.append(CardUtil.numberToText(amount.toString())); - } + sb.append(' '); + sb.append(filter.getMessage()); } - sb.append(' '); - sb.append(filter.getMessage()); - sb.append(" unless they pay "); + sb.append(" unless they "); if (cost != null) { - sb.append(cost.getText()); + sb.append(CardUtil.addCostVerb(cost.getText())); } else { - sb.append("{X}"); + sb.append("pay {X}"); } if (genericMana != null && !genericMana.getMessage().isEmpty()) { @@ -182,6 +185,6 @@ public class SacrificeOpponentsUnlessPayEffect extends OneShotEffect { sb.append(genericMana.getMessage()); } - staticText = sb.toString(); + return sb.toString(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java index 488c627d097..8b62985126e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java @@ -14,8 +14,6 @@ import mage.players.Player; import mage.util.CardUtil; import mage.util.ManaUtil; -import java.util.Locale; - /** * Created by IntelliJ IDEA. User: Loki Date: 21.12.10 Time: 9:21 */ @@ -92,17 +90,6 @@ public class SacrificeSourceUnlessPaysEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()) { return staticText; } - - StringBuilder sb = new StringBuilder("sacrifice {this} unless you "); - String costText = cost != null ? cost.getText() : "{X}"; - - if (CardUtil.checkCostWords(costText)) { - sb.append(costText.substring(0, 1).toLowerCase(Locale.ENGLISH)); - sb.append(costText.substring(1)); - } else { - sb.append("pay ").append(costText); - } - - return sb.toString(); + return "sacrifice {this} unless you " + CardUtil.addCostVerb(cost != null ? cost.getText() : "{X}"); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ShuffleLibrarySourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ShuffleLibrarySourceEffect.java index a803bd268f2..8d035262a24 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ShuffleLibrarySourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ShuffleLibrarySourceEffect.java @@ -1,5 +1,3 @@ - - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -14,13 +12,21 @@ import mage.players.Player; */ public class ShuffleLibrarySourceEffect extends OneShotEffect { + private boolean optional; + public ShuffleLibrarySourceEffect() { + this(false); + } + + public ShuffleLibrarySourceEffect(boolean optional) { super(Outcome.Neutral); - this.staticText = "Shuffle your library"; + this.optional = optional; + this.staticText = optional ? "you may shuffle" : "shuffle your library"; } public ShuffleLibrarySourceEffect(final ShuffleLibrarySourceEffect effect) { super(effect); + this.optional = effect.optional; } @Override @@ -32,7 +38,9 @@ public class ShuffleLibrarySourceEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - player.shuffleLibrary(source, game); + if (!optional || player.chooseUse(Outcome.Benefit, "Shuffle your library?", source, game)) { + player.shuffleLibrary(source, game); + } return true; } return false; diff --git a/Mage/src/main/java/mage/abilities/effects/common/TapAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/TapAllEffect.java index f2a38fcf6de..63e856998ea 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/TapAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/TapAllEffect.java @@ -1,5 +1,3 @@ - - package mage.abilities.effects.common; import mage.constants.Outcome; @@ -9,8 +7,6 @@ import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.permanent.Permanent; - - /** * * @author LevelX2 @@ -22,7 +18,7 @@ public class TapAllEffect extends OneShotEffect { public TapAllEffect(FilterPermanent filter) { super(Outcome.Tap); this.filter = filter; - setText(); + staticText = "tap all " + filter.getMessage(); } public TapAllEffect(final TapAllEffect effect) { @@ -37,14 +33,9 @@ public class TapAllEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanent.tap(source, game); } return true; } - - private void setText() { - staticText = "tap all " + filter.getMessage(); - } - } diff --git a/Mage/src/main/java/mage/abilities/effects/common/TapTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/TapTargetEffect.java index 9afaa42dd2a..5173c65fcfe 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/TapTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/TapTargetEffect.java @@ -58,11 +58,11 @@ public class TapTargetEffect extends OneShotEffect { } Target target = mode.getTargets().get(0); - if (target.getMaxNumberOfTargets() > 1) { + if (target.getMaxNumberOfTargets() > 1 || target.getNumberOfTargets() == 0) { if (target.getMaxNumberOfTargets() == target.getNumberOfTargets()) { return "tap " + CardUtil.numberToText(target.getNumberOfTargets()) + " target " + target.getTargetName() + 's'; } else { - return "tap up to " + CardUtil.numberToText(target.getMaxNumberOfTargets()) + " target " + target.getTargetName() + 's'; + return "tap up to " + CardUtil.numberToText(target.getMaxNumberOfTargets()) + " target " + target.getTargetName() + (target.getMaxNumberOfTargets() > 1 ? "s" : ""); } } else if (target.getMaxNumberOfTargets() == 0) { return "tap X target " + mode.getTargets().get(0).getTargetName(); diff --git a/Mage/src/main/java/mage/abilities/effects/common/UntapAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/UntapAllEffect.java index a265735c827..3cb389c5555 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/UntapAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/UntapAllEffect.java @@ -29,7 +29,7 @@ public class UntapAllEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanent.untap(game); } return true; diff --git a/Mage/src/main/java/mage/abilities/effects/common/UntapLandsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/UntapLandsEffect.java index c518b69802e..159f3bfad36 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/UntapLandsEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/UntapLandsEffect.java @@ -64,7 +64,7 @@ public class UntapLandsEffect extends OneShotEffect { tappedLands = game.getBattlefield().getAllActivePermanents(filter, game).size(); } TargetLandPermanent target = new TargetLandPermanent(upTo ? 0 : Math.min(tappedLands, amount), amount, filter, true); - if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (target.canChoose(source.getControllerId(), source, game)) { // UI Shortcut: Check if any lands are already tapped. If there are equal/fewer than amount, give the option to add those in to be untapped now. if (tappedLands <= amount && upTo) { @@ -74,7 +74,7 @@ public class UntapLandsEffect extends OneShotEffect { } } } - if (target.choose(Outcome.Untap, source.getControllerId(), source.getSourceId(), game)) { + if (target.choose(Outcome.Untap, source.getControllerId(), source.getSourceId(), source, game)) { for (UUID targetId : target.getTargets()) { Permanent p = game.getPermanent(targetId); if (p != null) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/UntapTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/UntapTargetEffect.java index 2c7d0601446..41595adeb20 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/UntapTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/UntapTargetEffect.java @@ -16,20 +16,19 @@ import java.util.UUID; */ public class UntapTargetEffect extends OneShotEffect { - protected boolean useOnlyTargetPointer; - public UntapTargetEffect() { - this(true); + this((String) null); } - public UntapTargetEffect(boolean useOnlyTargetPointer) { + public UntapTargetEffect(String text) { super(Outcome.Untap); - this.useOnlyTargetPointer = useOnlyTargetPointer; + if (text != null) { + this.staticText = text; + } } public UntapTargetEffect(final UntapTargetEffect effect) { super(effect); - this.useOnlyTargetPointer = effect.useOnlyTargetPointer; } @Override @@ -39,21 +38,10 @@ public class UntapTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - if (!useOnlyTargetPointer && source.getTargets().size() > 1) { - source.getTargets().forEach((target) -> { - for (UUID targetId : target.getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null) { - permanent.untap(game); - } - } - }); - } else { - for (UUID target : targetPointer.getTargets(game, source)) { - Permanent permanent = game.getPermanent(target); - if (permanent != null) { - permanent.untap(game); - } + for (UUID target : targetPointer.getTargets(game, source)) { + Permanent permanent = game.getPermanent(target); + if (permanent != null) { + permanent.untap(game); } } return true; @@ -88,4 +76,4 @@ public class UntapTargetEffect extends OneShotEffect { return sb.toString(); } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/asthought/CanPlayCardControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/asthought/CanPlayCardControllerEffect.java index 2e21df01784..4826c1d419b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/asthought/CanPlayCardControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/asthought/CanPlayCardControllerEffect.java @@ -23,9 +23,9 @@ import java.util.UUID; */ public class CanPlayCardControllerEffect extends AsThoughEffectImpl { - private final MageObjectReference mor; - private final UUID playerId; - private final Condition condition; + protected final MageObjectReference mor; + protected final UUID playerId; + protected final Condition condition; public CanPlayCardControllerEffect(Game game, UUID cardId, int cardZCC, Duration duration) { this(game, cardId, cardZCC, duration, null, null); diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/AttacksIfAbleAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/AttacksIfAbleAllEffect.java index 794918de4f9..44467a503d1 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/AttacksIfAbleAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/AttacksIfAbleAllEffect.java @@ -4,7 +4,7 @@ import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.RequirementEffect; import mage.constants.Duration; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.watchers.common.AttackedThisTurnWatcher; @@ -15,26 +15,27 @@ import mage.watchers.common.AttackedThisTurnWatcher; */ public class AttacksIfAbleAllEffect extends RequirementEffect { - private final FilterCreaturePermanent filter; + private final FilterPermanent filter; + private boolean eachCombat; - public AttacksIfAbleAllEffect(FilterCreaturePermanent filter) { + public AttacksIfAbleAllEffect(FilterPermanent filter) { this(filter, Duration.WhileOnBattlefield); } - boolean eachCombat; - - public AttacksIfAbleAllEffect(FilterCreaturePermanent filter, Duration duration) { - this(filter, duration, false); - } - - public AttacksIfAbleAllEffect(FilterCreaturePermanent filter, Duration duration, boolean eachCombat) { + public AttacksIfAbleAllEffect(FilterPermanent filter, Duration duration) { super(duration); this.filter = filter; - this.eachCombat = eachCombat; if (this.duration == Duration.EndOfTurn) { - staticText = filter.getMessage() + " attack " + (eachCombat ? "each combat" : "this turn") + " if able"; + eachCombat = false; + staticText = filter.getMessage() + " attack this turn if able"; } else { - staticText = filter.getMessage() + " attack each " + (eachCombat ? "combat" : "turn") + " if able"; + eachCombat = true; + String durationString = this.duration.toString(); + if (durationString.isEmpty()) { + staticText = filter.getMessage() + " attack each combat if able"; + } else { + staticText = durationString + ", " + filter.getMessage() + " attack each combat if able"; + } } } @@ -51,7 +52,7 @@ public class AttacksIfAbleAllEffect extends RequirementEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (filter.match(permanent, source.getSourceId(), source.getControllerId(), game)) { + if (filter.match(permanent, source.getControllerId(), source, game)) { if (eachCombat) { return true; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/BlocksIfAbleAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/BlocksIfAbleAllEffect.java index 494708e07e0..36427942acc 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/BlocksIfAbleAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/BlocksIfAbleAllEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -23,11 +22,8 @@ public class BlocksIfAbleAllEffect extends RequirementEffect { public BlocksIfAbleAllEffect(FilterCreaturePermanent filter, Duration duration) { super(duration); - staticText = new StringBuilder(filter.getMessage()) - .append(" block ") - .append(duration == Duration.EndOfTurn ? "this":"each") - .append(" turn if able").toString(); this.filter = filter; + staticText = filter.getMessage() + " block " + (duration == Duration.EndOfTurn ? "this turn" : "each combat") + " if able"; } public BlocksIfAbleAllEffect(final BlocksIfAbleAllEffect effect) { super(effect); @@ -41,7 +37,7 @@ public class BlocksIfAbleAllEffect extends RequirementEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filter.match(permanent, source.getControllerId(), source, game); } @Override @@ -58,7 +54,4 @@ public class BlocksIfAbleAllEffect extends RequirementEffect { public boolean mustAttack(Game game) { return false; } - - - } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CanAttackAsThoughItDidntHaveDefenderAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CanAttackAsThoughItDidntHaveDefenderAllEffect.java index f3a1114bae2..60b424e89ba 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CanAttackAsThoughItDidntHaveDefenderAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CanAttackAsThoughItDidntHaveDefenderAllEffect.java @@ -42,7 +42,7 @@ public class CanAttackAsThoughItDidntHaveDefenderAllEffect extends AsThoughEffec @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { Permanent permanent = game.getPermanent(objectId); - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filter.match(permanent, source.getControllerId(), source, game); } private String getText() { diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockAdditionalCreatureAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockAdditionalCreatureAllEffect.java index 041d14fe3ea..db83a18825d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockAdditionalCreatureAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockAdditionalCreatureAllEffect.java @@ -13,7 +13,6 @@ import mage.game.permanent.Permanent; import mage.util.CardUtil; /** - * * @author emerald000 */ @@ -42,13 +41,12 @@ public class CanBlockAdditionalCreatureAllEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (permanent != null) { // maxBlocks = 0 equals to "can block any number of creatures" if (amount > 0) { permanent.setMaxBlocks(permanent.getMaxBlocks() + amount); - } - else { + } else { permanent.setMaxBlocks(0); } } @@ -64,12 +62,16 @@ public class CanBlockAdditionalCreatureAllEffect extends ContinuousEffectImpl { private String setText() { StringBuilder sb = new StringBuilder(filter.getMessage()); sb.append(" can block "); - switch(amount) { + switch (amount) { case 0: sb.append("any number of creatures"); break; + case 1: + sb.append("an additional creature each combat"); + break; default: - sb.append(CardUtil.numberToText(amount, "an")).append(" additional creature").append(amount > 1 ? "s" : ""); + sb.append(CardUtil.numberToText(amount)); + sb.append(" additional creatures"); } return sb.toString(); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockAdditionalCreatureEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockAdditionalCreatureEffect.java index 242dc776035..a2e4f73f2b5 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockAdditionalCreatureEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockAdditionalCreatureEffect.java @@ -12,7 +12,6 @@ import mage.game.permanent.Permanent; import mage.util.CardUtil; /** - * * @author LevelX2 */ public class CanBlockAdditionalCreatureEffect extends ContinuousEffectImpl { @@ -69,21 +68,21 @@ public class CanBlockAdditionalCreatureEffect extends ContinuousEffectImpl { } private String setText() { - String text = "{this} can block "; - switch (amount) { - case 0: - text += "any number of creatures"; - break; - default: - text += CardUtil.numberToText(amount, "an") + " additional creature" + (amount > 1 ? "s" : ""); + StringBuilder sb = new StringBuilder("{this} can block "); + if (amount == 0) { + sb.append("any number of creatures"); + } else { + sb.append(CardUtil.numberToText(amount, "an")); + sb.append(" additional creature"); + sb.append((amount > 1 ? "s" : "")); } if (duration == Duration.EndOfTurn) { - text += " this turn"; + sb.append(" this turn"); } - if (duration == Duration.WhileOnBattlefield) { - text += " each combat"; + if (duration == Duration.WhileOnBattlefield && amount == 1) { + sb.append(" each combat"); } - return text; + return sb.toString(); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAnyPlayerAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAnyPlayerAllEffect.java index 40339821a31..adabfff371f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAnyPlayerAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAnyPlayerAllEffect.java @@ -38,7 +38,7 @@ public class CantAttackAnyPlayerAllEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filter.match(permanent, source.getControllerId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockAllEffect.java index 7e4db0db576..60f2a70d9c7 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockAllEffect.java @@ -36,7 +36,7 @@ public class CantAttackBlockAllEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filter.match(permanent, source.getControllerId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockTargetEffect.java index a1f25df21d8..6e146d01db4 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockTargetEffect.java @@ -1,6 +1,7 @@ package mage.abilities.effects.common.combat; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.effects.RestrictionEffect; import mage.constants.Duration; import mage.game.Game; @@ -9,12 +10,10 @@ import mage.game.permanent.Permanent; /** * @author LevelX2 */ - public class CantAttackBlockTargetEffect extends RestrictionEffect { public CantAttackBlockTargetEffect(Duration duration) { super(duration); - staticText = "Target creature can't attack or block this turn"; } public CantAttackBlockTargetEffect(final CantAttackBlockTargetEffect effect) { @@ -41,4 +40,23 @@ public class CantAttackBlockTargetEffect extends RestrictionEffect { return new CantAttackBlockTargetEffect(this); } -} \ No newline at end of file + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + StringBuilder sb = new StringBuilder("target "); + if (mode.getTargets().isEmpty()) { + sb.append("creature"); + } else { + sb.append(mode.getTargets().get(0).getTargetName()); + } + sb.append(" can't attack or block "); + if (duration == Duration.EndOfTurn) { + sb.append("this turn"); + } else { + sb.append(duration); + } + return sb.toString(); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackControllerDueToGoadEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackControllerDueToGoadEffect.java deleted file mode 100644 index 964bcf9a597..00000000000 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackControllerDueToGoadEffect.java +++ /dev/null @@ -1,46 +0,0 @@ -package mage.abilities.effects.common.combat; - -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.RestrictionEffect; -import mage.constants.Duration; -import mage.game.Game; -import mage.game.permanent.Permanent; - -/** - * @author TheElk801 - */ -public class CantAttackControllerDueToGoadEffect extends RestrictionEffect { - - public CantAttackControllerDueToGoadEffect(Duration duration) { - super(duration); - } - - public CantAttackControllerDueToGoadEffect(final CantAttackControllerDueToGoadEffect effect) { - super(effect); - } - - @Override - public CantAttackControllerDueToGoadEffect copy() { - return new CantAttackControllerDueToGoadEffect(this); - } - - @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - return this.getTargetPointer().getTargets(game, source).contains(permanent.getId()); - } - - @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { - if (defenderId == null - || game.getState().getPlayersInRange(attacker.getControllerId(), game).size() == 2) { // just 2 players left, so it may attack you - return true; - } - // A planeswalker controlled by the controller is the defender - if (game.getPermanent(defenderId) != null) { - return !game.getPermanent(defenderId).getControllerId().equals(source.getControllerId()); - } - // The controller is the defender - return !defenderId.equals(source.getControllerId()); - } -} diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java index b47fd8d748b..fcdac865536 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java @@ -44,7 +44,7 @@ public class CantAttackYouAllEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return filterAttacker.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filterAttacker.match(permanent, source.getControllerId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouOrPlaneswalkerAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouOrPlaneswalkerAllEffect.java index 7bc79625d7c..a5c208b1c50 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouOrPlaneswalkerAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouOrPlaneswalkerAllEffect.java @@ -34,7 +34,7 @@ public class CantAttackYouOrPlaneswalkerAllEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return filterAttacker.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filterAttacker.match(permanent, source.getControllerId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouUnlessPayManaAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouUnlessPayManaAllEffect.java index 34d21a234ef..cfd3e5e2f14 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouUnlessPayManaAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouUnlessPayManaAllEffect.java @@ -50,7 +50,7 @@ public class CantAttackYouUnlessPayManaAllEffect extends PayCostToAttackBlockEff // check if attacking creature fullfills filter criteria if (filterCreaturePermanent != null) { Permanent permanent = game.getPermanent(event.getSourceId()); - if (!filterCreaturePermanent.match(permanent, source.getSourceId(), source.getControllerId(), game)) { + if (!filterCreaturePermanent.match(permanent, source.getControllerId(), source, game)) { return false; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedAllEffect.java index 1894ad25e08..e3bd52c7b94 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedAllEffect.java @@ -41,6 +41,6 @@ public class CantBeBlockedAllEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filter.match(permanent, source.getControllerId(), source, game); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllSourceEffect.java index 67930d2c521..f1f9fa54a7e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllSourceEffect.java @@ -35,7 +35,7 @@ public class CantBeBlockedByAllSourceEffect extends RestrictionEffect { @Override public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { - return !filterBlockedBy.match(blocker, source.getSourceId(), source.getControllerId(), game); + return !filterBlockedBy.match(blocker, source.getControllerId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllTargetEffect.java index 1448aacf277..0d65d986daa 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllTargetEffect.java @@ -1,6 +1,7 @@ package mage.abilities.effects.common.combat; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.effects.RestrictionEffect; import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; @@ -19,11 +20,6 @@ public class CantBeBlockedByAllTargetEffect extends RestrictionEffect { public CantBeBlockedByAllTargetEffect(FilterCreaturePermanent filterBlockedBy, Duration duration) { super(duration); this.filterBlockedBy = filterBlockedBy; - staticText = "target creature" - + " can't be blocked " - + (duration == EndOfTurn ? "this turn " : "") - + (filterBlockedBy.getMessage().startsWith("except by") ? "" : "by ") - + filterBlockedBy.getMessage(); } public CantBeBlockedByAllTargetEffect(final CantBeBlockedByAllTargetEffect effect) { @@ -38,11 +34,24 @@ public class CantBeBlockedByAllTargetEffect extends RestrictionEffect { @Override public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { - return !filterBlockedBy.match(blocker, source.getSourceId(), source.getControllerId(), game); + return !filterBlockedBy.match(blocker, source.getControllerId(), source, game); } @Override public CantBeBlockedByAllTargetEffect copy() { return new CantBeBlockedByAllTargetEffect(this); } + + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + return "target " + + mode.getTargets().get(0).getTargetName() + + " can't be blocked " + + (duration == EndOfTurn ? "this turn " : "") + + (filterBlockedBy.getMessage().startsWith("except by") ? "" : "by ") + + filterBlockedBy.getMessage(); + } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAllEffect.java index 51a6dc95308..ca807c9fe84 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAllEffect.java @@ -32,12 +32,12 @@ public class CantBeBlockedByCreaturesAllEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return filterCreatures.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filterCreatures.match(permanent, source.getControllerId(), source, game); } @Override public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { - return !filterBlockedBy.match(blocker, source.getSourceId(), source.getControllerId(), game); + return !filterBlockedBy.match(blocker, source.getControllerId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAttachedEffect.java index 83259e873bf..2cf6dae0d13 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAttachedEffect.java @@ -36,7 +36,7 @@ public class CantBeBlockedByCreaturesAttachedEffect extends RestrictionEffect { @Override public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { - return !filter.match(blocker, source.getSourceId(), source.getControllerId(), game); + return !filter.match(blocker, source.getControllerId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesSourceEffect.java index 1f9cb728440..c858b739574 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesSourceEffect.java @@ -33,7 +33,7 @@ public class CantBeBlockedByCreaturesSourceEffect extends RestrictionEffect { @Override public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { - return !filter.match(blocker, source.getSourceId(), source.getControllerId(), game); + return !filter.match(blocker, source.getControllerId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByMoreThanOneAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByMoreThanOneAllEffect.java index dc4d48bf541..f36a37fc870 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByMoreThanOneAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByMoreThanOneAllEffect.java @@ -54,7 +54,7 @@ public class CantBeBlockedByMoreThanOneAllEffect extends ContinuousEffectImpl { public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { switch (layer) { case RulesEffects: - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { perm.setMaxBlockedBy(amount); } break; diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByOneAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByOneAllEffect.java index 4629f6ed64f..a65111d02ec 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByOneAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByOneAllEffect.java @@ -52,7 +52,7 @@ public class CantBeBlockedByOneAllEffect extends ContinuousEffectImpl { public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { switch (layer) { case RulesEffects: - for (Permanent perm: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { perm.setMinBlockedBy(amount); } break; diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByOneEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByOneEffect.java index 326af72f953..7ee7bc31c57 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByOneEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByOneEffect.java @@ -1,17 +1,16 @@ - package mage.abilities.effects.common.combat; +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffectImpl; import mage.constants.Duration; import mage.constants.Layer; import mage.constants.Outcome; import mage.constants.SubLayer; -import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffectImpl; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.util.CardUtil; /** - * * @author North */ public class CantBeBlockedByOneEffect extends ContinuousEffectImpl { @@ -23,9 +22,9 @@ public class CantBeBlockedByOneEffect extends ContinuousEffectImpl { } public CantBeBlockedByOneEffect(int amount, Duration duration) { - super(duration, Outcome.Benefit); + super(duration, Layer.RulesEffects, SubLayer.NA, Outcome.Benefit); this.amount = amount; - staticText = "{this} can't be blocked except by " + amount + " or more creatures"; + staticText = "{this} can't be blocked except by " + CardUtil.numberToText(amount) + " or more creatures"; } public CantBeBlockedByOneEffect(final CantBeBlockedByOneEffect effect) { @@ -39,26 +38,12 @@ public class CantBeBlockedByOneEffect extends ContinuousEffectImpl { } @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - Permanent perm = game.getPermanent(source.getSourceId()); + public boolean apply(Game game, Ability source) { + Permanent perm = source.getSourcePermanentIfItStillExists(game); if (perm != null) { - switch (layer) { - case RulesEffects: - perm.setMinBlockedBy(amount); - break; - } + perm.setMinBlockedBy(amount); return true; } return false; } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } - - @Override - public boolean hasLayer(Layer layer) { - return layer == Layer.RulesEffects; - } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedTargetEffect.java index 0d2a648f54a..081b87b3ef1 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedTargetEffect.java @@ -47,7 +47,7 @@ public class CantBeBlockedTargetEffect extends RestrictionEffect { @Override public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { - return !filter.match(blocker, source.getSourceId(), source.getControllerId(), game); + return !filter.match(blocker, source.getControllerId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAllEffect.java index dea9bc16ecd..9480fd30fd2 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAllEffect.java @@ -27,7 +27,7 @@ public class CantBlockAllEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filter.match(permanent, source.getControllerId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAttachedEffect.java index c3a680b7712..dc1ebe1a73b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAttachedEffect.java @@ -72,7 +72,7 @@ public class CantBlockAttachedEffect extends RestrictionEffect { if (attacker == null) { return true; } - return !filter.match(attacker, source.getSourceId(), source.getControllerId(), game); + return !filter.match(attacker, source.getControllerId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockCreaturesSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockCreaturesSourceEffect.java index 0d888e8caba..839c339f7d4 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockCreaturesSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockCreaturesSourceEffect.java @@ -40,7 +40,7 @@ public class CantBlockCreaturesSourceEffect extends RestrictionEffect { if (attacker == null) { return true; } - return !filter.match(attacker, source.getSourceId(), source.getControllerId(), game); + return !filter.match(attacker, source.getControllerId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockUnlessPayManaAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockUnlessPayManaAllEffect.java index 8c2af74b6b7..9311f78c620 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockUnlessPayManaAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockUnlessPayManaAllEffect.java @@ -47,7 +47,7 @@ public class CantBlockUnlessPayManaAllEffect extends PayCostToAttackBlockEffectI // check if blocking creature fullfills filter criteria if (filterCreaturePermanent != null) { Permanent permanent = game.getPermanent(event.getSourceId()); - if (!filterCreaturePermanent.match(permanent, source.getSourceId(), source.getControllerId(), game)) { + if (!filterCreaturePermanent.match(permanent, source.getControllerId(), source, game)) { return false; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockUnlessYouControlSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockUnlessYouControlSourceEffect.java index cba3316d96d..3e1fed9d0dd 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockUnlessYouControlSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockUnlessYouControlSourceEffect.java @@ -38,6 +38,6 @@ public class CantBlockUnlessYouControlSourceEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { return permanent.getId().equals(source.getSourceId()) - && game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) == 0; + && game.getBattlefield().count(filter, source.getControllerId(), source, game) == 0; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/GoadAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/GoadAttachedEffect.java new file mode 100644 index 00000000000..899aaa166c9 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/GoadAttachedEffect.java @@ -0,0 +1,44 @@ +package mage.abilities.effects.common.combat; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * @author TheElk801 + */ +public class GoadAttachedEffect extends ContinuousEffectImpl { + + public GoadAttachedEffect() { + super(Duration.WhileOnBattlefield, Layer.RulesEffects, SubLayer.NA, Outcome.Detriment); + staticText = "and is goaded"; + } + + private GoadAttachedEffect(final GoadAttachedEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null) { + return false; + } + Permanent attached = game.getPermanent(permanent.getAttachedTo()); + if (attached == null) { + return false; + } + attached.addGoadingPlayer(source.getControllerId()); + return true; + } + + @Override + public GoadAttachedEffect copy() { + return new GoadAttachedEffect(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/GoadTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/GoadTargetEffect.java index e2aca007012..a61b27ca12e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/GoadTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/GoadTargetEffect.java @@ -2,19 +2,19 @@ package mage.abilities.effects.common.combat; import mage.abilities.Ability; import mage.abilities.Mode; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ContinuousEffectImpl; import mage.constants.Duration; +import mage.constants.Layer; import mage.constants.Outcome; +import mage.constants.SubLayer; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.targetpointer.FixedTarget; /** * @author TheElk801 */ -public class GoadTargetEffect extends OneShotEffect { +public class GoadTargetEffect extends ContinuousEffectImpl { /** * 701.36. Goad @@ -24,10 +24,10 @@ public class GoadTargetEffect extends OneShotEffect { * each combat if able and attacks a player other than that player if able. */ public GoadTargetEffect() { - super(Outcome.Detriment); + super(Duration.UntilYourNextTurn, Layer.RulesEffects, SubLayer.NA, Outcome.Detriment); } - public GoadTargetEffect(final GoadTargetEffect effect) { + private GoadTargetEffect(final GoadTargetEffect effect) { super(effect); } @@ -37,26 +37,22 @@ public class GoadTargetEffect extends OneShotEffect { } @Override - public boolean apply(Game game, Ability source) { + public void init(Ability source, Game game) { + super.init(source, game); Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); if (targetCreature != null && controller != null) { - // TODO: Allow goad to target controller, current AttacksIfAbleTargetEffect does not support it - // https://github.com/magefree/mage/issues/5283 - /* - If the creature doesn’t meet any of the above exceptions and can attack, it must attack a player other than - the controller of the spell or ability that goaded it if able. If the creature can’t attack any of those - players but could otherwise attack, it must attack an opposing planeswalker (controlled by any opponent) - or the player that goaded it. (2016-08-23) - */ - ContinuousEffect effect = new AttacksIfAbleTargetEffect(Duration.UntilYourNextTurn); - effect.setTargetPointer(new FixedTarget(getTargetPointer().getFirst(game, source), game)); - game.addEffect(effect, source); - effect = new CantAttackControllerDueToGoadEffect(Duration.UntilYourNextTurn); // remember current controller - effect.setTargetPointer(new FixedTarget(getTargetPointer().getFirst(game, source), game)); - game.addEffect(effect, source); game.informPlayers(controller.getLogName() + " is goading " + targetCreature.getLogName()); } + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (targetCreature == null) { + return false; + } + targetCreature.addGoadingPlayer(source.getControllerId()); return true; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByTargetSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByTargetSourceEffect.java index d56b0e8b0ec..33a093eca3f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByTargetSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByTargetSourceEffect.java @@ -22,7 +22,7 @@ public class MustBeBlockedByTargetSourceEffect extends RequirementEffect { public MustBeBlockedByTargetSourceEffect(Duration duration) { super(duration); - staticText = "Target creature blocks {this} this turn if able"; + staticText = "target creature blocks {this} this turn if able"; } public MustBeBlockedByTargetSourceEffect(final MustBeBlockedByTargetSourceEffect effect) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardSubtypeAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardSubtypeAllEffect.java index a35c0a5af1c..8a994bcbb65 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardSubtypeAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardSubtypeAllEffect.java @@ -34,7 +34,7 @@ public class AddCardSubtypeAllEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (perm != null) { perm.addSubType(game, addedSubtype); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeSourceEffect.java index 0384c4b2523..384787e6a27 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCardTypeSourceEffect.java @@ -80,7 +80,7 @@ public class AddCardTypeSourceEffect extends ContinuousEffectImpl { } sb.append(cardType.toString().toLowerCase(Locale.ENGLISH)).append(" "); } - sb.append(" in addition to its other types ").append(this.getDuration().toString()); + sb.append("in addition to its other types ").append(this.getDuration().toString()); return sb.toString(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java index d73b816f046..33d5cddc00e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java @@ -6,10 +6,12 @@ import mage.abilities.mana.*; import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.util.CardUtil; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; public class BecomesBasicLandEnchantedEffect extends ContinuousEffectImpl { @@ -18,7 +20,11 @@ public class BecomesBasicLandEnchantedEffect extends ContinuousEffectImpl { public BecomesBasicLandEnchantedEffect(SubType... landNames) { super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Detriment); landTypes.addAll(Arrays.asList(landNames)); - this.staticText = setText(); + this.staticText = "enchanted land is " + CardUtil.addArticle(CardUtil.concatWithAnd(landTypes + .stream() + .map(SubType::getDescription) + .collect(Collectors.toList()) + )); } public BecomesBasicLandEnchantedEffect(final BecomesBasicLandEnchantedEffect effect) { @@ -76,21 +82,4 @@ public class BecomesBasicLandEnchantedEffect extends ContinuousEffectImpl { } return true; } - - private String setText() { - StringBuilder sb = new StringBuilder("Enchanted land is a "); - int i = 1; - for (SubType landType : landTypes) { - if (i > 1) { - if (i == landTypes.size()) { - sb.append(" and "); - } else { - sb.append(", "); - } - } - i++; - sb.append(landType); - } - return sb.toString(); - } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBasicLandTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBasicLandTargetEffect.java index 2c4adcb1d6e..af33aaa9427 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBasicLandTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBasicLandTargetEffect.java @@ -1,6 +1,8 @@ package mage.abilities.effects.common.continuous; +import mage.abilities.Abilities; import mage.abilities.Ability; +import mage.abilities.Mode; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.mana.*; import mage.choices.Choice; @@ -9,11 +11,13 @@ import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.util.CardUtil; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; /** * http://mtgsalvation.gamepedia.com/Land_changers @@ -24,7 +28,6 @@ public class BecomesBasicLandTargetEffect extends ContinuousEffectImpl { protected boolean chooseLandType; protected List landTypes = new ArrayList<>(); - private final List landTypesToAdd = new ArrayList<>(); private final boolean loseOther; // loses all other abilities, card types, and creature types public BecomesBasicLandTargetEffect(Duration duration) { @@ -58,15 +61,12 @@ public class BecomesBasicLandTargetEffect extends ContinuousEffectImpl { dependencyTypes.add(DependencyType.BecomePlains); } this.chooseLandType = chooseLandType; - this.staticText = setText(); this.loseOther = loseOther; - } public BecomesBasicLandTargetEffect(final BecomesBasicLandTargetEffect effect) { super(effect); this.landTypes.addAll(effect.landTypes); - this.landTypesToAdd.addAll(effect.landTypesToAdd); this.chooseLandType = effect.chooseLandType; this.loseOther = effect.loseOther; } @@ -90,9 +90,6 @@ public class BecomesBasicLandTargetEffect extends ContinuousEffectImpl { return; } } - if (loseOther) { - landTypesToAdd.addAll(landTypes); - } } @Override @@ -112,33 +109,37 @@ public class BecomesBasicLandTargetEffect extends ContinuousEffectImpl { land.removeAllAbilities(source.getSourceId(), game); // 305.7 land.removeAllSubTypes(game, SubTypeSet.NonBasicLandType); - land.addSubType(game, landTypes); - } else { - landTypesToAdd.clear(); - for (SubType subtype : landTypes) { - if (!land.hasSubtype(subtype, game)) { - land.addSubType(game, subtype); - landTypesToAdd.add(subtype); - } - } } + land.addSubType(game, landTypes); + // add intrinsic land abilities here not in layer 6 - for (SubType landType : landTypesToAdd) { + Abilities landAbilities = land.getAbilities(game); + for (SubType landType : landTypes) { switch (landType) { case PLAINS: - land.addAbility(new WhiteManaAbility(), source.getSourceId(), game); + if (!landAbilities.containsClass(WhiteManaAbility.class)) { + land.addAbility(new WhiteManaAbility(), source.getSourceId(), game); + } break; case ISLAND: - land.addAbility(new BlueManaAbility(), source.getSourceId(), game); + if (!landAbilities.containsClass(BlueManaAbility.class)) { + land.addAbility(new BlueManaAbility(), source.getSourceId(), game); + } break; case SWAMP: - land.addAbility(new BlackManaAbility(), source.getSourceId(), game); + if (!landAbilities.containsClass(BlackManaAbility.class)) { + land.addAbility(new BlackManaAbility(), source.getSourceId(), game); + } break; case MOUNTAIN: - land.addAbility(new RedManaAbility(), source.getSourceId(), game); + if (!landAbilities.containsClass(RedManaAbility.class)) { + land.addAbility(new RedManaAbility(), source.getSourceId(), game); + } break; case FOREST: - land.addAbility(new GreenManaAbility(), source.getSourceId(), game); + if (!landAbilities.containsClass(GreenManaAbility.class)) { + land.addAbility(new GreenManaAbility(), source.getSourceId(), game); + } break; } } @@ -146,27 +147,32 @@ public class BecomesBasicLandTargetEffect extends ContinuousEffectImpl { return true; } - private String setText() { - StringBuilder sb = new StringBuilder(); - if (chooseLandType) { - sb.append("Target land becomes the basic land type of your choice"); + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + StringBuilder sb = new StringBuilder("target "); + if (!mode.getTargets().isEmpty()) { + sb.append(mode.getTargets().get(0).getTargetName()); } else { - sb.append("Target land becomes a "); - int i = 1; - for (SubType landType : landTypes) { - if (i > 1) { - if (i == landTypes.size()) { - sb.append(" and "); - } else { - sb.append(", "); - } - } - i++; - sb.append(landType); - } + sb.append("land"); + } + sb.append(" becomes "); + if (chooseLandType) { + sb.append("the basic land type of your choice"); + } else { + sb.append(CardUtil.addArticle(CardUtil.concatWithAnd(landTypes + .stream() + .map(SubType::getDescription) + .collect(Collectors.toList()) + ))); + } + if (!loseOther) { + sb.append(" in addition to its other types"); } if (!duration.toString().isEmpty() && duration != Duration.EndOfGame) { - sb.append(' ').append(duration.toString()); + sb.append(' ').append(duration); } return sb.toString(); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesColorAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesColorAllEffect.java index 144c9c35095..3e0c8f12b14 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesColorAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesColorAllEffect.java @@ -106,7 +106,7 @@ public class BecomesColorAllEffect extends ContinuousEffectImpl { return false; } if (setColor != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (permanent != null) { switch (layer) { case ColorChangingEffects_5: diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesColorSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesColorSourceEffect.java index 948ee55a5c9..1916bb5257d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesColorSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesColorSourceEffect.java @@ -96,7 +96,7 @@ public class BecomesColorSourceEffect extends ContinuousEffectImpl { return false; } if (setColor != null) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null) { sourceObject.getColor(game).setColor(setColor); } else { diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureAllEffect.java index 57eabc7a822..065485cef8c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureAllEffect.java @@ -63,7 +63,7 @@ public class BecomesCreatureAllEffect extends ContinuousEffectImpl { super.init(source, game); if (this.affectedObjectsSet) { for (Permanent perm : game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game)) { + filter, source.getControllerId(), source, game)) { affectedObjectList.add(new MageObjectReference(perm, game)); } } @@ -83,7 +83,7 @@ public class BecomesCreatureAllEffect extends ContinuousEffectImpl { } } else { affectedPermanents = new HashSet<>(game.getBattlefield() - .getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)); + .getActivePermanents(filter, source.getControllerId(), source, game)); } for (Permanent permanent : affectedPermanents) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureTargetEffect.java index 0e200bb74cd..61249801e7b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureTargetEffect.java @@ -171,7 +171,7 @@ public class BecomesCreatureTargetEffect extends ContinuousEffectImpl { if (loseAllAbilities) { sb.append(" lose all their abilities and "); } - sb.append(" each become "); + sb.append(" each become "); } else { sb.append("target ").append(target.getTargetName()); if (loseAllAbilities && !keepAbilities) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureAllEffect.java index 35d9a79ad1f..4fca7dd9164 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesFaceDownCreatureAllEffect.java @@ -45,7 +45,7 @@ public class BecomesFaceDownCreatureAllEffect extends ContinuousEffectImpl imple @Override public void init(Ability source, Game game) { super.init(source, game); - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (!perm.isFaceDown(game) && !perm.isTransformable()) { affectedObjectList.add(new MageObjectReference(perm, game)); perm.setFaceDown(true, game); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesSubtypeAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesSubtypeAllEffect.java index d3a15c2dc67..104a4cddfb5 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesSubtypeAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesSubtypeAllEffect.java @@ -52,7 +52,7 @@ public class BecomesSubtypeAllEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { boolean flag = false; - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (permanent == null) { continue; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostAllEffect.java index f7a92d70af3..0acc9f9ed2b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostAllEffect.java @@ -88,7 +88,7 @@ public class BoostAllEffect extends ContinuousEffectImpl { super.init(source, game); setRuntimeData(source, game); if (this.affectedObjectsSet) { - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (!(excludeSource && perm.getId().equals(source.getSourceId())) && selectedByRuntimeData(perm, source, game)) { affectedObjectList.add(new MageObjectReference(perm, game)); } @@ -114,7 +114,7 @@ public class BoostAllEffect extends ContinuousEffectImpl { } } else { setRuntimeData(source, game); - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (!(excludeSource && perm.getId().equals(source.getSourceId())) && selectedByRuntimeData(perm, source, game)) { perm.addPower(power.calculate(game, source, this)); perm.addToughness(toughness.calculate(game, source, this)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostControlledEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostControlledEffect.java index f6e1f823de9..bc9136f944c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostControlledEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostControlledEffect.java @@ -91,8 +91,9 @@ public class BoostControlledEffect extends ContinuousEffectImpl { public void init(Ability source, Game game) { super.init(source, game); if (this.affectedObjectsSet) { - for (Permanent perm : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { - if (!(excludeSource && perm.getId().equals(source.getSourceId()))) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { + if (perm.isControlledBy(source.getControllerId()) + && !(excludeSource && perm.getId().equals(source.getSourceId()))) { affectedObjectList.add(new MageObjectReference(perm, game)); } } @@ -116,8 +117,9 @@ public class BoostControlledEffect extends ContinuousEffectImpl { } } } else { - for (Permanent perm : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { - if (!(excludeSource && perm.getId().equals(source.getSourceId()))) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { + if (perm.isControlledBy(source.getControllerId()) + && (!(excludeSource && perm.getId().equals(source.getSourceId())))) { perm.addPower(power.calculate(game, source, this)); perm.addToughness(toughness.calculate(game, source, this)); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostOpponentsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostOpponentsEffect.java index 1d9aecd51b5..b84b47ab7a1 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostOpponentsEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostOpponentsEffect.java @@ -51,7 +51,7 @@ public class BoostOpponentsEffect extends ContinuousEffectImpl { super.init(source, game); if (this.affectedObjectsSet) { Set opponents = game.getOpponents(source.getControllerId()); - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (opponents.contains(perm.getControllerId())) { affectedObjectList.add(new MageObjectReference(perm, game)); } @@ -75,7 +75,7 @@ public class BoostOpponentsEffect extends ContinuousEffectImpl { } } } else { - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (opponents.contains(perm.getControllerId())) { perm.addPower(power); perm.addToughness(toughness); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostSourceEffect.java index 2523c515157..1e0bdc5f33c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostSourceEffect.java @@ -23,7 +23,11 @@ public class BoostSourceEffect extends ContinuousEffectImpl implements SourceEff private final boolean lockedIn; public BoostSourceEffect(int power, int toughness, Duration duration) { - this(StaticValue.get(power), StaticValue.get(toughness), duration, false); + this(power, toughness, duration, "{this}"); + } + + public BoostSourceEffect(int power, int toughness, Duration duration, String description) { + this(StaticValue.get(power), StaticValue.get(toughness), duration, false, description); } public BoostSourceEffect(DynamicValue power, DynamicValue toughness, Duration duration) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/CastAsThoughItHadFlashAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/CastAsThoughItHadFlashAllEffect.java index de21045bd1d..8ae7458ccc9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/CastAsThoughItHadFlashAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/CastAsThoughItHadFlashAllEffect.java @@ -56,15 +56,15 @@ public class CastAsThoughItHadFlashAllEffect extends AsThoughEffectImpl { if (card != null) { //Allow lands with morph to be played at instant speed if (card.isLand(game)) { - boolean morphAbility = card.getAbilities().stream().anyMatch(ability -> ability instanceof MorphAbility); + boolean morphAbility = card.getAbilities().stream().anyMatch(MorphAbility.class::isInstance); if (morphAbility) { Card cardCopy = card.copy(); cardCopy.removeAllCardTypes(game); cardCopy.addCardType(game, CardType.CREATURE); - return filter.match(cardCopy, source.getSourceId(), affectedControllerId, game); + return filter.match(cardCopy, affectedControllerId, source, game); } } - return filter.match(card, source.getSourceId(), affectedControllerId, game); + return filter.match(card, affectedControllerId, source, game); } } return false; diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/CastFromHandWithoutPayingManaCostEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/CastFromHandWithoutPayingManaCostEffect.java index 03efc93852e..872bc6dd5d7 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/CastFromHandWithoutPayingManaCostEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/CastFromHandWithoutPayingManaCostEffect.java @@ -88,7 +88,7 @@ enum IsBeingCastFromHandCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object instanceof SplitCardHalf || object instanceof AdventureCardSpell || object instanceof ModalDoubleFacesCardHalf) { UUID mainCardId = ((Card) object).getMainCard().getId(); object = game.getObject(mainCardId); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/CreaturesCantGetOrHaveAbilityEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/CreaturesCantGetOrHaveAbilityEffect.java index 62d2c3d7d61..8f2452ea78e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/CreaturesCantGetOrHaveAbilityEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/CreaturesCantGetOrHaveAbilityEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.continuous; import mage.abilities.Ability; @@ -8,6 +7,7 @@ import mage.constants.Duration; import mage.constants.Layer; import mage.constants.Outcome; import mage.constants.SubLayer; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -22,11 +22,15 @@ public class CreaturesCantGetOrHaveAbilityEffect extends ContinuousEffectImpl { private final Ability ability; private final FilterCreaturePermanent filter; + public CreaturesCantGetOrHaveAbilityEffect(Ability ability, Duration duration) { + this(ability, duration, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES); + } + public CreaturesCantGetOrHaveAbilityEffect(Ability ability, Duration duration, FilterCreaturePermanent filter) { super(duration, Outcome.Detriment); this.ability = ability; this.filter = filter; - setText(); + staticText = filter.getMessage() + " lose " + ability.getRule() + " and can't have or gain " + ability.getRule(); addDependedToType(DependencyType.AddingAbility); } @@ -45,7 +49,7 @@ public class CreaturesCantGetOrHaveAbilityEffect extends ContinuousEffectImpl { public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (permanent != null) { permanent.removeAbility(ability, source.getSourceId(), game); } @@ -65,14 +69,4 @@ public class CreaturesCantGetOrHaveAbilityEffect extends ContinuousEffectImpl { public boolean hasLayer(Layer layer) { return layer == Layer.AbilityAddingRemovingEffects_6; } - - private void setText() { - StringBuilder sb = new StringBuilder(); - sb.append(filter.getMessage()); - sb.append(" lose "); - sb.append(ability.getRule()); - sb.append(" can't have or gain "); - sb.append(ability.getRule()); - staticText = sb.toString(); - } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityAllEffect.java index 428111ff9df..c15339bbf43 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityAllEffect.java @@ -1,12 +1,12 @@ package mage.abilities.effects.common.continuous; -import mage.MageObject; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.TriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.mana.ActivatedManaAbilityImpl; import mage.constants.*; import mage.filter.FilterPermanent; import mage.game.Game; @@ -14,8 +14,6 @@ import mage.game.permanent.Permanent; import java.util.Iterator; import java.util.Locale; -import java.util.Map; -import java.util.UUID; /** * @author Loki @@ -68,7 +66,7 @@ public class GainAbilityAllEffect extends ContinuousEffectImpl { super.init(source, game); setRuntimeData(source, game); if (this.affectedObjectsSet) { - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (!(excludeSource && perm.getId().equals(source.getSourceId())) && selectedByRuntimeData(perm, source, game)) { affectedObjectList.add(new MageObjectReference(perm, game)); } @@ -97,7 +95,7 @@ public class GainAbilityAllEffect extends ContinuousEffectImpl { } } else { setRuntimeData(source, game); - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (!(excludeSource && perm.getId().equals(source.getSourceId())) && selectedByRuntimeData(perm, source, game)) { perm.addAbility(ability, source.getSourceId(), game); } @@ -136,7 +134,10 @@ public class GainAbilityAllEffect extends ContinuousEffectImpl { StringBuilder sb = new StringBuilder(); - boolean quotes = forceQuotes || (ability instanceof SimpleActivatedAbility) || (ability instanceof TriggeredAbility); + boolean quotes = forceQuotes + || ability instanceof SimpleActivatedAbility + ||ability instanceof ActivatedManaAbilityImpl + || ability instanceof TriggeredAbility; boolean each = filter.getMessage().toLowerCase(Locale.ENGLISH).startsWith("each"); if (excludeSource && !each) { sb.append("other "); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityAttachedEffect.java index 125bf805c4c..c601bb23a05 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityAttachedEffect.java @@ -5,6 +5,7 @@ import mage.abilities.Mode; import mage.abilities.TriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.keyword.ProtectionAbility; import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; @@ -19,6 +20,7 @@ public class GainAbilityAttachedEffect extends ContinuousEffectImpl { protected AttachmentType attachmentType; protected boolean independentEffect; protected String targetObjectName; + protected boolean doesntRemoveItself = false; public GainAbilityAttachedEffect(Ability ability, AttachmentType attachmentType) { this(ability, attachmentType, Duration.WhileOnBattlefield); @@ -62,6 +64,7 @@ public class GainAbilityAttachedEffect extends ContinuousEffectImpl { this.attachmentType = effect.attachmentType; this.independentEffect = effect.independentEffect; this.targetObjectName = effect.targetObjectName; + this.doesntRemoveItself = effect.doesntRemoveItself; } @Override @@ -82,7 +85,7 @@ public class GainAbilityAttachedEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = null; + Permanent permanent; if (affectedObjectsSet) { permanent = game.getPermanent(targetPointer.getFirst(game, source)); if (permanent == null) { @@ -93,9 +96,14 @@ public class GainAbilityAttachedEffect extends ContinuousEffectImpl { Permanent equipment = game.getPermanent(source.getSourceId()); if (equipment != null && equipment.getAttachedTo() != null) { permanent = game.getPermanentOrLKIBattlefield(equipment.getAttachedTo()); + } else { + permanent = null; } } if (permanent != null) { + if (doesntRemoveItself && ability instanceof ProtectionAbility) { + ((ProtectionAbility) ability).setAuraIdNotToBeRemoved(source.getSourceId()); + } permanent.addAbility(ability, source.getSourceId(), game); afterGain(game, source, permanent, ability); } @@ -114,6 +122,11 @@ public class GainAbilityAttachedEffect extends ContinuousEffectImpl { // } + public GainAbilityAttachedEffect setDoesntRemoveItself(boolean doesntRemoveItself) { + this.doesntRemoveItself = doesntRemoveItself; + return this; + } + @Override public String getText(Mode mode) { if (staticText != null && !staticText.isEmpty()) { @@ -138,6 +151,9 @@ public class GainAbilityAttachedEffect extends ContinuousEffectImpl { if (!duration.toString().isEmpty()) { sb.append(' ').append(duration); } + if (doesntRemoveItself) { + sb.append(" This effect doesn't remove {this}."); + } return sb.toString(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityControlledEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityControlledEffect.java index 388778c935e..e7208691fa0 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityControlledEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityControlledEffect.java @@ -1,19 +1,19 @@ package mage.abilities.effects.common.continuous; -import mage.MageObject; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.CompoundAbility; import mage.abilities.effects.ContinuousEffectImpl; -import mage.constants.*; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.SubLayer; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import java.util.Iterator; -import java.util.Map; -import java.util.UUID; /** * @author BetaSteward_at_googlemail.com @@ -67,8 +67,9 @@ public class GainAbilityControlledEffect extends ContinuousEffectImpl { public void init(Ability source, Game game) { super.init(source, game); if (this.affectedObjectsSet) { - for (Permanent perm : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { - if (!(excludeSource && perm.getId().equals(source.getSourceId()))) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { + if (perm.isControlledBy(source.getControllerId()) + && !(excludeSource && perm.getId().equals(source.getSourceId()))) { affectedObjectList.add(new MageObjectReference(perm, game)); } } @@ -97,8 +98,9 @@ public class GainAbilityControlledEffect extends ContinuousEffectImpl { } } } else { - for (Permanent perm : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { - if (!(excludeSource && perm.getId().equals(source.getSourceId()))) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { + if (perm.isControlledBy(source.getControllerId()) + && !(excludeSource && perm.getId().equals(source.getSourceId()))) { for (Ability abilityToAdd : ability) { perm.addAbility(abilityToAdd, source.getSourceId(), game); } @@ -140,12 +142,12 @@ public class GainAbilityControlledEffect extends ContinuousEffectImpl { /** * Add quotes to gains abilities (by default static abilities don't have it) - * @return + * + * @return */ public GainAbilityControlledEffect withForceQuotes() { this.forceQuotes = true; setText(); return this; } - } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlAllEffect.java index 66c82fdab3f..3a1ffcdfc15 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlAllEffect.java @@ -30,7 +30,7 @@ public class GainControlAllEffect extends OneShotEffect { this.filter = filter; this.duration = duration; this.controllingPlayerId = controllingPlayerId; - this.staticText = "Gain control of " + filter.getMessage(); + this.staticText = "gain control of " + filter.getMessage(); } public GainControlAllEffect(final GainControlAllEffect effect) { @@ -49,7 +49,7 @@ public class GainControlAllEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { for (Permanent permanent : game.getBattlefield() .getActivePermanents(filter, - source.getControllerId(), source.getSourceId(), game)) { + source.getControllerId(), source, game)) { ContinuousEffect effect = new GainControlTargetEffect(Duration.Custom, controllingPlayerId); effect.setTargetPointer(new FixedTarget(permanent, game)); game.addEffect(effect, source); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlAllOwnedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlAllOwnedEffect.java index acac92fa1e4..2158438e4ba 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlAllOwnedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlAllOwnedEffect.java @@ -40,7 +40,7 @@ public class GainControlAllOwnedEffect extends ContinuousEffectImpl { public void init(Ability source, Game game) { super.init(source, game); for (Permanent permanent : game.getBattlefield().getActivePermanents( - filter, source.getControllerId(), source.getSourceId(), game + filter, source.getControllerId(), source, game )) { affectedObjectList.add(new MageObjectReference(permanent, game)); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainProtectionFromColorAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainProtectionFromColorAllEffect.java index fcf35711260..8d9f6c62fc9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainProtectionFromColorAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainProtectionFromColorAllEffect.java @@ -49,7 +49,7 @@ public class GainProtectionFromColorAllEffect extends GainAbilityAllEffect { @Override public void init(Ability source, Game game) { super.init(source, game); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Player controller = game.getPlayer(source.getControllerId()); if (sourceObject != null && controller != null) { if (!controller.choose(Outcome.Protect, choice, game)) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainProtectionFromColorTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainProtectionFromColorTargetEffect.java index dee3466f5a9..fd27ec25443 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainProtectionFromColorTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainProtectionFromColorTargetEffect.java @@ -46,7 +46,7 @@ public class GainProtectionFromColorTargetEffect extends GainAbilityTargetEffect @Override public void init(Ability source, Game game) { super.init(source, game); //To change body of generated methods, choose Tools | Templates. - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); Player controller = game.getPlayer(source.getControllerId()); if (sourceObject != null && controller != null) { if (controller.choose(Outcome.Protect, choice, game)) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/HasSubtypesSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/HasSubtypesSourceEffect.java index 35897da12f7..f981a7be24d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/HasSubtypesSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/HasSubtypesSourceEffect.java @@ -39,7 +39,7 @@ public final class HasSubtypesSourceEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject == null) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/IsAllCreatureTypesSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/IsAllCreatureTypesSourceEffect.java index 38b3ef6de37..780c1eec80d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/IsAllCreatureTypesSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/IsAllCreatureTypesSourceEffect.java @@ -30,7 +30,7 @@ public class IsAllCreatureTypesSourceEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject == null) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAbilityAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAbilityAllEffect.java index f6c7595da6e..6c4dbba200e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAbilityAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAbilityAllEffect.java @@ -1,9 +1,7 @@ package mage.abilities.effects.common.continuous; import java.util.Iterator; -import java.util.Map; -import java.util.UUID; -import mage.MageObject; + import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.CompoundAbility; @@ -12,7 +10,6 @@ import mage.constants.Duration; import mage.constants.Layer; import mage.constants.Outcome; import mage.constants.SubLayer; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.game.Game; @@ -65,7 +62,7 @@ public class LoseAbilityAllEffect extends ContinuousEffectImpl { public void init(Ability source, Game game) { super.init(source, game); if (this.affectedObjectsSet) { - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (!(excludeSource && perm.getId().equals(source.getSourceId()))) { affectedObjectList.add(new MageObjectReference(perm, game)); } @@ -93,7 +90,7 @@ public class LoseAbilityAllEffect extends ContinuousEffectImpl { } } } else { - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (!(excludeSource && perm.getId().equals(source.getSourceId()))) { System.out.println(game.getTurn() + ", " + game.getPhase() + ": " + "remove from size " + perm.getAbilities().size()); perm.removeAbilities(ability, source.getSourceId(), game); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAllAbilitiesAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAllAbilitiesAllEffect.java index 070183a217b..fb6fee997be 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAllAbilitiesAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAllAbilitiesAllEffect.java @@ -37,7 +37,7 @@ public class LoseAllAbilitiesAllEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { if (permanent != null) { permanent.removeAllAbilities(source.getSourceId(), game); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/PlayTheTopCardEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/PlayTheTopCardEffect.java index 14049f882e8..b7b9b995629 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/PlayTheTopCardEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/PlayTheTopCardEffect.java @@ -160,6 +160,6 @@ public class PlayTheTopCardEffect extends AsThoughEffectImpl { } // must be correct card - return filter.match(cardToCheck, source.getSourceId(), affectedControllerId, game); + return filter.match(cardToCheck, affectedControllerId, source, game); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerSourceEffect.java index 88d410c411f..e90d77c8dde 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerSourceEffect.java @@ -41,7 +41,7 @@ public class SetPowerSourceEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { int value = amount.calculate(game, source, this); mageObject.getPower().setValue(value); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessAllEffect.java index 677bb5cd8a8..6450a0cb3ef 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessAllEffect.java @@ -61,7 +61,7 @@ public class SetPowerToughnessAllEffect extends ContinuousEffectImpl { public void init(Ability source, Game game) { super.init(source, game); if (affectedObjectsSet) { - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { affectedObjectList.add(new MageObjectReference(perm, game)); } } @@ -86,7 +86,7 @@ public class SetPowerToughnessAllEffect extends ContinuousEffectImpl { } } } else { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanent.getPower().setValue(newPower); permanent.getToughness().setValue(newToughness); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessSourceEffect.java index bc549cb15c6..5220b2010f2 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessSourceEffect.java @@ -62,7 +62,7 @@ public class SetPowerToughnessSourceEffect extends ContinuousEffectImpl { if (duration == Duration.Custom || isTemporary()) { mageObject = game.getPermanent(source.getSourceId()); } else { - mageObject = game.getObject(source.getSourceId()); + mageObject = game.getObject(source); } } if (mageObject == null) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessTargetEffect.java index 31b08e6b2d6..a888c15697a 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessTargetEffect.java @@ -70,9 +70,11 @@ public class SetPowerToughnessTargetEffect extends ContinuousEffectImpl { } StringBuilder sb = new StringBuilder(); if (mode.getTargets().get(0).getMinNumberOfTargets() == 0) { - sb.append("up to "); - sb.append(CardUtil.numberToText(mode.getTargets().get(0).getMaxNumberOfTargets())); - sb.append(' '); + if (!mode.getTargets().get(0).getTargetName().startsWith("any")) { + sb.append("up to "); + sb.append(CardUtil.numberToText(mode.getTargets().get(0).getMaxNumberOfTargets())); + sb.append(' '); + } } if (!mode.getTargets().get(0).getTargetName().contains("target")) { sb.append("target "); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetToughnessSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetToughnessSourceEffect.java index c6c5d43f103..9dcbc345dd0 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetToughnessSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetToughnessSourceEffect.java @@ -40,7 +40,7 @@ public class SetToughnessSourceEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { int value = amount.calculate(game, source, this); mageObject.getToughness().setValue(value); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/SwitchPowerToughnessAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/SwitchPowerToughnessAllEffect.java index 0e071402269..0ee31ed0f96 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/SwitchPowerToughnessAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/SwitchPowerToughnessAllEffect.java @@ -44,7 +44,7 @@ public class SwitchPowerToughnessAllEffect extends ContinuousEffectImpl { if (this.affectedObjectsSet) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (Permanent perm :game.getState().getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent perm :game.getState().getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { affectedObjectList.add(new MageObjectReference(perm, game)); } } @@ -67,7 +67,7 @@ public class SwitchPowerToughnessAllEffect extends ContinuousEffectImpl { } } } else { - for (Permanent creature :game.getState().getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature :game.getState().getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { int power = creature.getPower().getValue(); creature.getPower().setValue(creature.getToughness().getValue()); creature.getToughness().setValue(power); diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/CastFromHandForFreeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/CastFromHandForFreeEffect.java new file mode 100644 index 00000000000..17311bbce18 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/CastFromHandForFreeEffect.java @@ -0,0 +1,48 @@ +package mage.abilities.effects.common.cost; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardsImpl; +import mage.constants.Outcome; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * @author fireshoes - Original Code + * @author JRHerlehy - Implement as seperate class + *

+ * Allows player to choose to cast as card from hand without paying its mana + * cost. + *

+ */ +public class CastFromHandForFreeEffect extends OneShotEffect { + + private final FilterCard filter; + + public CastFromHandForFreeEffect(FilterCard filter) { + super(Outcome.PlayForFree); + this.filter = filter; + this.staticText = "you may cast " + filter.getMessage() + " from your hand without paying its mana cost"; + } + + public CastFromHandForFreeEffect(final CastFromHandForFreeEffect effect) { + super(effect); + this.filter = effect.filter; + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + return CardUtil.castSpellWithAttributesForFree(controller, source, game, new CardsImpl(controller.getHand()), filter); + } + + @Override + public CastFromHandForFreeEffect copy() { + return new CastFromHandForFreeEffect(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/CastWithoutPayingManaCostEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/CastWithoutPayingManaCostEffect.java deleted file mode 100644 index a25e98fd522..00000000000 --- a/Mage/src/main/java/mage/abilities/effects/common/cost/CastWithoutPayingManaCostEffect.java +++ /dev/null @@ -1,115 +0,0 @@ -package mage.abilities.effects.common.cost; - -import mage.ApprovingObject; -import mage.abilities.Ability; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.StaticValue; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.constants.ComparisonType; -import mage.constants.Outcome; -import mage.filter.FilterCard; -import mage.filter.common.FilterNonlandCard; -import mage.filter.predicate.mageobject.ManaValuePredicate; -import mage.game.Game; -import mage.players.Player; -import mage.target.Target; -import mage.target.common.TargetCardInHand; -import mage.util.CardUtil; -import org.apache.log4j.Logger; - -/** - * @author fireshoes - Original Code - * @author JRHerlehy - Implement as seperate class - *

- * Allows player to choose to cast as card from hand without paying its mana - * cost. - *

- * TODO: this doesn't work correctly with MDFCs or Adventures (see https://github.com/magefree/mage/issues/7742) - */ -public class CastWithoutPayingManaCostEffect extends OneShotEffect { - - private final DynamicValue manaCost; - private final FilterCard filter; - private static final FilterCard defaultFilter - = new FilterNonlandCard("card with mana value %mv or less from your hand"); - - /** - * @param maxCost Maximum converted mana cost for this effect to apply to - */ - public CastWithoutPayingManaCostEffect(int maxCost) { - this(StaticValue.get(maxCost)); - } - - public CastWithoutPayingManaCostEffect(DynamicValue maxCost) { - this(maxCost, defaultFilter); - } - - public CastWithoutPayingManaCostEffect(DynamicValue maxCost, FilterCard filter) { - super(Outcome.PlayForFree); - this.manaCost = maxCost; - this.filter = filter; - this.staticText = "you may cast a spell with mana value " - + maxCost + " or less from your hand without paying its mana cost"; - } - - public CastWithoutPayingManaCostEffect(final CastWithoutPayingManaCostEffect effect) { - super(effect); - this.manaCost = effect.manaCost; - this.filter = effect.filter; - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - int cmc = manaCost.calculate(game, source, this); - FilterCard filter = this.filter.copy(); - filter.setMessage(filter.getMessage().replace("%mv", "" + cmc)); - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, cmc + 1)); - Target target = new TargetCardInHand(filter); - if (!target.canChoose( - source.getSourceId(), controller.getId(), game - ) || !controller.chooseUse( - Outcome.PlayForFree, - "Cast " + CardUtil.addArticle(filter.getMessage()) - + " without paying its mana cost?", source, game - )) { - return true; - } - Card cardToCast = null; - boolean cancel = false; - while (controller.canRespond() - && !cancel) { - if (controller.chooseTarget(Outcome.PlayForFree, target, source, game)) { - cardToCast = game.getCard(target.getFirstTarget()); - if (cardToCast != null) { - if (cardToCast.getSpellAbility() == null) { - Logger.getLogger(CastWithoutPayingManaCostEffect.class).fatal("Card: " - + cardToCast.getName() + " is no land and has no spell ability!"); - cancel = true; - } - if (cardToCast.getSpellAbility().canChooseTarget(game, controller.getId())) { - cancel = true; - } - } - } else { - cancel = true; - } - } - if (cardToCast != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(cardToCast, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), null); - } - return true; - } - - @Override - public CastWithoutPayingManaCostEffect copy() { - return new CastWithoutPayingManaCostEffect(this); - } -} diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostIncreasingAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostIncreasingAllEffect.java index 543d7d4ca86..b2054c0cf99 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostIncreasingAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostIncreasingAllEffect.java @@ -123,7 +123,7 @@ public class SpellsCostIncreasingAllEffect extends CostModificationEffectImpl { } else { // get playable and other staff without put on stack // used at least for flashback ability because Flashback ability doesn't use stack - Card sourceCard = game.getCard(abilityToModify.getSourceId()); + Card sourceCard = ((SpellAbility) abilityToModify).getCharacteristics(game); return this.filter.match(sourceCard, game); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionControllerEffect.java index b2367505fb0..5650069f91f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellsCostReductionControllerEffect.java @@ -110,9 +110,9 @@ public class SpellsCostReductionControllerEffect extends CostModificationEffectI public boolean applies(Ability abilityToModify, Ability source, Game game) { if (abilityToModify instanceof SpellAbility) { if (abilityToModify.isControlledBy(source.getControllerId())) { - Card spellCard = ((SpellAbility) abilityToModify).getCharacteristics(game);; + Card spellCard = ((SpellAbility) abilityToModify).getCharacteristics(game); if (spellCard != null) { - return this.filter.match(spellCard, source.getSourceId(), source.getControllerId(), game); + return this.filter.match(spellCard, source.getControllerId(), source, game); } } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersAllEffect.java index 912e6ca53bf..aed21748b09 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersAllEffect.java @@ -39,10 +39,10 @@ public class AddCountersAllEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { if (counter != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { permanent.addCounters(counter.copy(), source.getControllerId(), source, game); if (!game.isSimulation()) { game.informPlayers(sourceObject.getLogName() + ": " + controller.getLogName() + " puts " + counter.getCount() + ' ' + counter.getName().toLowerCase(Locale.ENGLISH) diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersTargetEffect.java index fa16864aa84..37f362d8998 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersTargetEffect.java @@ -56,7 +56,7 @@ public class AddCountersTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null && counter != null) { int affectedTargets = 0; for (UUID uuid : targetPointer.getTargets(game, source)) { @@ -119,6 +119,9 @@ public class AddCountersTargetEffect extends OneShotEffect { Target target = mode.getTargets().getEffectTarget(this.targetPointer); if (target != null) { if (target.getNumberOfTargets() == 0) { + if (target.getMaxNumberOfTargets() > 1) { + sb.append("each of "); + } sb.append("up to "); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/AddRemoveAllTimeSuspentCountersEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/AddRemoveAllTimeSuspentCountersEffect.java index 7bcfbd5a518..7c5276979b1 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/counter/AddRemoveAllTimeSuspentCountersEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/AddRemoveAllTimeSuspentCountersEffect.java @@ -46,7 +46,7 @@ public class AddRemoveAllTimeSuspentCountersEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (controller != null && sourceObject != null) { if (counter != null) { List permanents = new ArrayList<>(game.getBattlefield().getAllActivePermanents()); diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/ProliferateEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/ProliferateEffect.java index 8bc78be649f..758dfa52c7b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/counter/ProliferateEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/ProliferateEffect.java @@ -51,7 +51,7 @@ public class ProliferateEffect extends OneShotEffect { Target target = new TargetPermanentOrPlayer(0, Integer.MAX_VALUE, new FilterPermanentOrPlayerWithCounter(), true); Map options = new HashMap<>(); options.put("UI.right.btn.text", "Done"); - controller.choose(Outcome.Benefit, target, source.getSourceId(), game, options); + controller.choose(Outcome.Benefit, target, source, game, options); for (UUID chosen : target.getTargets()) { Permanent permanent = game.getPermanent(chosen); diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/RemoveCounterSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/RemoveCounterSourceEffect.java index 4050cf49d90..6b604c58d3c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/counter/RemoveCounterSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/RemoveCounterSourceEffect.java @@ -8,6 +8,7 @@ import mage.counters.Counter; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.util.CardUtil; /** * @author Loki @@ -66,7 +67,7 @@ public class RemoveCounterSourceEffect extends OneShotEffect { private void setText() { if (counter.getCount() > 1) { StringBuilder sb = new StringBuilder(); - sb.append("remove ").append(Integer.toString(counter.getCount())).append(' ').append(counter.getName()).append(" counters from {this}"); + sb.append("remove ").append(CardUtil.numberToText(counter.getCount())).append(' ').append(counter.getName()).append(" counters from {this}"); staticText = sb.toString(); } else { staticText = "remove " + CounterType.findArticle(counter.getName()) + " " + counter.getName() + " counter from {this}"; diff --git a/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardCardYouChooseTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardCardYouChooseTargetEffect.java index 02432352abc..0fb66863746 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardCardYouChooseTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardCardYouChooseTargetEffect.java @@ -30,6 +30,7 @@ public class DiscardCardYouChooseTargetEffect extends OneShotEffect { private DynamicValue numberCardsToReveal; private final DynamicValue numberCardsToDiscard; private boolean revealAllCards; + private boolean optional = false; public DiscardCardYouChooseTargetEffect() { this(StaticFilters.FILTER_CARD_A); @@ -99,6 +100,12 @@ public class DiscardCardYouChooseTargetEffect extends OneShotEffect { this.numberCardsToDiscard = effect.numberCardsToDiscard; this.numberCardsToReveal = effect.numberCardsToReveal; this.revealAllCards = effect.revealAllCards; + this.optional = effect.optional; + } + + public void setOptional(boolean optional) { + this.optional = optional; + staticText = this.setText(); } @Override @@ -121,7 +128,7 @@ public class DiscardCardYouChooseTargetEffect extends OneShotEffect { TargetCard chosenCards = new TargetCard(numberToReveal, numberToReveal, Zone.HAND, new FilterCard("card in " + player.getName() + "'s hand")); chosenCards.setNotTarget(true); - if (chosenCards.canChoose(source.getSourceId(), player.getId(), game) + if (chosenCards.canChoose(player.getId(), source, game) && player.chooseTarget(Outcome.Discard, player.getHand(), chosenCards, source, game)) { if (!chosenCards.getTargets().isEmpty()) { List targets = chosenCards.getTargets(); @@ -142,12 +149,12 @@ public class DiscardCardYouChooseTargetEffect extends OneShotEffect { + sourceCard.getZoneChangeCounter(game) + ')' : "Discard", revealedCards, game); boolean result = true; - int filteredCardsCount = revealedCards.count(filter, source.getSourceId(), source.getControllerId(), game); + int filteredCardsCount = revealedCards.count(filter, source.getControllerId(), source, game); int numberToDiscard = Math.min(this.numberCardsToDiscard.calculate(game, source, this), filteredCardsCount); if (numberToDiscard <= 0) { return result; } - TargetCard target = new TargetCard(numberToDiscard, Zone.HAND, filter); + TargetCard target = new TargetCard(optional ? 0 : numberToDiscard, numberToDiscard, Zone.HAND, filter); if (!controller.choose(Outcome.Benefit, revealedCards, target, game)) { return result; } @@ -175,7 +182,11 @@ public class DiscardCardYouChooseTargetEffect extends OneShotEffect { } sb.append(" reveals "); if (revealAllCards) { - sb.append("their hand. You choose "); + sb.append("their hand. You "); + if (optional) { + sb.append("may "); + } + sb.append("choose "); if (discardMultipleCards) { sb.append(numberCardsToDiscard).append(' ').append(filter.getMessage()); } else { @@ -194,7 +205,11 @@ public class DiscardCardYouChooseTargetEffect extends OneShotEffect { sb.append("a number of cards from their hand equal to "); sb.append(numberCardsToReveal.getMessage()); } - sb.append(". You choose "); + sb.append(". You "); + if (optional) { + sb.append("may "); + } + sb.append("choose "); if (numberCardsToDiscard instanceof StaticValue) { sb.append(CardUtil.numberToText(((StaticValue) numberCardsToDiscard).getValue())); } else { diff --git a/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardControllerEffect.java index ed032cb68cb..02c7e62ad65 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardControllerEffect.java @@ -55,18 +55,10 @@ public class DiscardControllerEffect extends OneShotEffect { private void setText() { StringBuilder sb = new StringBuilder("discard "); - if (amount.toString().equals("1")) { - sb.append('a'); + if (amount.toString().equals("1") || amount.toString().equals("a")) { + sb.append("a card"); } else { - sb.append(CardUtil.numberToText(amount.toString())); - } - sb.append(" card"); - try { - if (Integer.parseInt(amount.toString()) > 1) { - sb.append('s'); - } - } catch (Exception e) { - sb.append('s'); + sb.append(CardUtil.numberToText(amount.toString())).append(" cards"); } if (randomDiscard) { sb.append(" at random"); diff --git a/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardTargetEffect.java index f8ff05abd19..cf849c3aaf2 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardTargetEffect.java @@ -81,7 +81,7 @@ public class DiscardTargetEffect extends OneShotEffect { sb.append("target ").append(mode.getTargets().get(0).getTargetName()); } sb.append(" discards "); - if (amount.toString().equals("1")) { + if (amount.toString().equals("1") || amount.toString().equals("a")) { sb.append("a card"); } else { sb.append(CardUtil.numberToText(amount.toString())).append(" cards"); diff --git a/Mage/src/main/java/mage/abilities/effects/common/enterAttribute/EnterAttributeAddChosenSubtypeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/enterAttribute/EnterAttributeAddChosenSubtypeEffect.java index 84a0bc07514..a2f288faff3 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/enterAttribute/EnterAttributeAddChosenSubtypeEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/enterAttribute/EnterAttributeAddChosenSubtypeEffect.java @@ -18,7 +18,6 @@ public class EnterAttributeAddChosenSubtypeEffect extends OneShotEffect { public EnterAttributeAddChosenSubtypeEffect() { super(Outcome.Benefit); - this.staticText = "{this} is the chosen type in addition to its other types"; } public EnterAttributeAddChosenSubtypeEffect(final EnterAttributeAddChosenSubtypeEffect effect) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CantHaveCountersSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CantHaveCountersSourceEffect.java index 851e92d6d19..35e19fc2c2b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CantHaveCountersSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CantHaveCountersSourceEffect.java @@ -36,7 +36,7 @@ public class CantHaveCountersSourceEffect extends ContinuousRuleModifyingEffectI @Override public boolean applies(GameEvent event, Ability source, Game game) { - UUID sourceId = source.getSourceId(); + UUID sourceId = source != null ? source.getSourceId() : null; if (sourceId != null) { return sourceId.equals(event.getTargetId()); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayLandsFromGraveyardControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayLandsFromGraveyardControllerEffect.java index a4c227ae982..db243014c91 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayLandsFromGraveyardControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayLandsFromGraveyardControllerEffect.java @@ -77,6 +77,6 @@ public class PlayLandsFromGraveyardControllerEffect extends AsThoughEffectImpl { } // must be correct card - return filter.match(cardToCheck, source.getSourceId(), affectedControllerId, game); + return filter.match(cardToCheck, affectedControllerId, source, game); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/TargetsHaveToTargetPermanentIfAbleEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/TargetsHaveToTargetPermanentIfAbleEffect.java index cb1f72695a2..da9f91c7199 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/TargetsHaveToTargetPermanentIfAbleEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/TargetsHaveToTargetPermanentIfAbleEffect.java @@ -66,7 +66,7 @@ public class TargetsHaveToTargetPermanentIfAbleEffect extends ContinuousRuleModi @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You must choose at least " + this.filter.getMessage() + " on the battlefield as target if able (" + mageObject.getIdName() + ")."; } @@ -97,7 +97,7 @@ public class TargetsHaveToTargetPermanentIfAbleEffect extends ContinuousRuleModi Ability ability = (Ability) getValue("targetAbility"); if (ability != null) { // Get all the allowed permanents on the battlefield in range of the abilities controller - List allowedPermanents = game.getBattlefield().getActivePermanents(filter, event.getPlayerId(), event.getSourceId(), game); + List allowedPermanents = game.getBattlefield().getActivePermanents(filter, event.getPlayerId(), source, game); if (!allowedPermanents.isEmpty()) { boolean canTargetAllowedPermanent = false; for (UUID modeId : ability.getModes().getSelectedModes()) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryAndExileTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryAndExileTargetEffect.java new file mode 100644 index 00000000000..deda3c48dcf --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryAndExileTargetEffect.java @@ -0,0 +1,85 @@ +package mage.abilities.effects.common.search; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; + +/** + * @author TheElk801 + */ +public class SearchLibraryAndExileTargetEffect extends OneShotEffect { + + private final int amount; + private final boolean upTo; + + public SearchLibraryAndExileTargetEffect(int amount, boolean upTo) { + super(Outcome.Benefit); + this.amount = amount; + this.upTo = upTo; + } + + private SearchLibraryAndExileTargetEffect(final SearchLibraryAndExileTargetEffect effect) { + super(effect); + this.amount = effect.amount; + this.upTo = effect.upTo; + } + + @Override + public SearchLibraryAndExileTargetEffect copy() { + return new SearchLibraryAndExileTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (controller == null || player == null) { + return false; + } + TargetCardInLibrary target = new TargetCardInLibrary(upTo ? 0 : amount, amount, StaticFilters.FILTER_CARD); + controller.searchLibrary(target, source, game, player.getId()); + Cards cards = new CardsImpl(); + target.getTargets() + .stream() + .map(uuid -> player.getLibrary().getCard(uuid, game)) + .forEach(cards::add); + if (cards.isEmpty()) { + return false; + } + controller.moveCards(cards, Zone.EXILED, source, game); + player.shuffleLibrary(source, game); + return true; + } + + @Override + public String getText(Mode mode) { + StringBuilder sb = new StringBuilder("search "); + if (mode.getTargets().isEmpty()) { + sb.append("that player"); + } else { + sb.append("target "); + sb.append(mode.getTargets().get(0).getTargetName()); + } + sb.append("'s library for "); + if (amount > 1) { + if (upTo) { + sb.append("up to "); + } + sb.append(CardUtil.numberToText(amount)); + sb.append(" cards and exile them"); + } else { + sb.append("a card and exile it"); + } + sb.append(". Then that player shuffles"); + return sb.toString(); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/AmassEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/AmassEffect.java index bd57c9fe57b..10f42969471 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/AmassEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/AmassEffect.java @@ -72,7 +72,7 @@ public class AmassEffect extends OneShotEffect { } Target target = new TargetPermanent(filter); target.setNotTarget(true); - if (!player.choose(outcome, target, source.getSourceId(), game)) { + if (!player.choose(outcome, target, source, game)) { return false; } Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/ConniveSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/ConniveSourceEffect.java new file mode 100644 index 00000000000..a39dbb6d08f --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/keyword/ConniveSourceEffect.java @@ -0,0 +1,92 @@ +package mage.abilities.effects.keyword; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * @author TheElk801 + */ +public class ConniveSourceEffect extends OneShotEffect { + + private final String selfName; + private final ReflexiveTriggeredAbility ability; + + public ConniveSourceEffect() { + this("it"); + } + + public ConniveSourceEffect(String selfName) { + this(selfName, null); + } + + public ConniveSourceEffect(String selfName, ReflexiveTriggeredAbility ability) { + super(Outcome.Benefit); + this.selfName = selfName; + this.ability = ability; + } + + private ConniveSourceEffect(final ConniveSourceEffect effect) { + super(effect); + this.selfName = effect.selfName; + this.ability = effect.ability; + } + + @Override + public ConniveSourceEffect copy() { + return new ConniveSourceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent != null) { + connive(permanent, 1, source, game); + } + if (ability != null) { + game.fireReflexiveTriggeredAbility(ability, source); + } + return permanent != null || ability != null; + } + + public static boolean connive(Permanent permanent, int amount, Ability source, Game game) { + if (amount < 1) { + return false; + } + Player player = game.getPlayer(permanent.getControllerId()); + if (player == null) { + return false; + } + player.drawCards(amount, source, game); + int counters = player + .discard(amount, false, false, source, game) + .count(StaticFilters.FILTER_CARDS_NON_LAND, game); + if (counters > 0) { + permanent.addCounters(CounterType.P1P1.createInstance(counters), source, game); + } + return true; + } + + @Override + public String getText(Mode mode) { + if (staticText != null && !staticText.isEmpty()) { + return staticText; + } + if (ability == null) { + return selfName + " connives. (Draw a card, then discard a card. " + + "If you discarded a nonland card, put a +1/+1 counter on this creature.)"; + } + return selfName + " connives. When it connives this way, " + + CardUtil.getTextWithFirstCharLowerCase(ability.getRule()) + + " (To have a creature connive, draw a card, then discard a card. " + + "If you discarded a nonland card, put a +1/+1 counter on that creature.)"; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/FatesealEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/FatesealEffect.java index edc2354a213..a756483ec9e 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/FatesealEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/FatesealEffect.java @@ -44,7 +44,7 @@ public class FatesealEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Target target = new TargetOpponent(true); - if (controller.choose(outcome, target, source.getSourceId(), game)) { + if (controller.choose(outcome, target, source, game)) { Player opponent = game.getPlayer(target.getFirstTarget()); if (opponent == null) { return false; diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/ProtectionChosenColorAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/ProtectionChosenColorAttachedEffect.java index 8520d285d68..01bb7f25abb 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/ProtectionChosenColorAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/ProtectionChosenColorAttachedEffect.java @@ -27,7 +27,7 @@ public class ProtectionChosenColorAttachedEffect extends ContinuousEffectImpl { public ProtectionChosenColorAttachedEffect(boolean notRemoveItself) { super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); this.notRemoveItself = notRemoveItself; - staticText = "{this} has protection from the chosen color" + (notRemoveItself ? ". This effect doesn't remove {this}" : ""); + staticText = "enchanted creature has protection from the chosen color" + (notRemoveItself ? ". This effect doesn't remove {this}" : ""); } public ProtectionChosenColorAttachedEffect(final ProtectionChosenColorAttachedEffect effect) { diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/ShieldCounterEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/ShieldCounterEffect.java new file mode 100644 index 00000000000..07a218188bd --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/keyword/ShieldCounterEffect.java @@ -0,0 +1,67 @@ +package mage.abilities.effects.keyword; + +import mage.abilities.Ability; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author weirddan455 + */ +public class ShieldCounterEffect extends ReplacementEffectImpl { + + public ShieldCounterEffect() { + super(Duration.Custom, Outcome.PreventDamage); + this.staticText = "If it would be dealt damage or destroyed, remove a shield counter from it instead"; + } + + private ShieldCounterEffect(final ShieldCounterEffect effect) { + super(effect); + } + + @Override + public ShieldCounterEffect copy() { + return new ShieldCounterEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent == null || permanent.getCounters(game).getCount(CounterType.SHIELD) < 1) { + return false; + } + permanent.removeCounters(CounterType.SHIELD.getName(), 1, source, game); + if (!game.isSimulation()) { + game.informPlayers("Removed a shield counter from " + permanent.getLogName()); + } + // Damage should be prevented rather than replacing the event. + // Effects that say "damage can't be prevented" will have the creature both take the damage and remove a shield counter. + if (event.getType() == GameEvent.EventType.DAMAGE_PERMANENT) { + game.preventDamage(event, source, game, Integer.MAX_VALUE); + return false; + } + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + switch (event.getType()) { + case DAMAGE_PERMANENT: + case DESTROY_PERMANENT: + return true; + default: + return false; + } + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent permanent = game.getPermanent(event.getTargetId()); + return permanent != null && permanent.getCounters(game).getCount(CounterType.SHIELD) > 0; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/mana/AddManaInAnyCombinationEffect.java b/Mage/src/main/java/mage/abilities/effects/mana/AddManaInAnyCombinationEffect.java index 30490589f2c..bad7e9da6c6 100644 --- a/Mage/src/main/java/mage/abilities/effects/mana/AddManaInAnyCombinationEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/mana/AddManaInAnyCombinationEffect.java @@ -169,7 +169,7 @@ public class AddManaInAnyCombinationEffect extends ManaEffect { sb.append('{').append(coloredManaSymbol.toString()).append('}'); } } - if (amountString.equals("X")) { + if (amountString.equals("X") && !amount.getMessage().isEmpty()) { sb.append(", where X is "); sb.append(amount.getMessage()); } diff --git a/Mage/src/main/java/mage/abilities/effects/mana/AddManaOfAnyColorEffect.java b/Mage/src/main/java/mage/abilities/effects/mana/AddManaOfAnyColorEffect.java index 374bfbc53ba..8577f466eb0 100644 --- a/Mage/src/main/java/mage/abilities/effects/mana/AddManaOfAnyColorEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/mana/AddManaOfAnyColorEffect.java @@ -81,7 +81,7 @@ public class AddManaOfAnyColorEffect extends BasicManaEffect { if (controller != null) { String mes = String.format("Select a color of mana to add %d of it", this.amount); if (mes != null) { - ChoiceColor choice = new ChoiceColor(true, mes, game.getObject(source.getSourceId())); + ChoiceColor choice = new ChoiceColor(true, mes, game.getObject(source)); if (controller.choose(outcome, choice, game)) { if (choice.getColor() != null) { Mana mana = choice.getMana(amount); diff --git a/Mage/src/main/java/mage/abilities/effects/mana/DoUnlessAnyPlayerPaysManaEffect.java b/Mage/src/main/java/mage/abilities/effects/mana/DoUnlessAnyPlayerPaysManaEffect.java index 17dd216dca3..1e9fc0993e3 100644 --- a/Mage/src/main/java/mage/abilities/effects/mana/DoUnlessAnyPlayerPaysManaEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/mana/DoUnlessAnyPlayerPaysManaEffect.java @@ -45,7 +45,7 @@ public class DoUnlessAnyPlayerPaysManaEffect extends ManaEffect { Mana mana = new Mana(); if (game != null) { Player controller = getPlayer(game, source); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); String message = CardUtil.replaceSourceName(chooseUseText, sourceObject.getName()); for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); diff --git a/Mage/src/main/java/mage/abilities/hint/common/CovenHint.java b/Mage/src/main/java/mage/abilities/hint/common/CovenHint.java index b11aa75d401..556630227f4 100644 --- a/Mage/src/main/java/mage/abilities/hint/common/CovenHint.java +++ b/Mage/src/main/java/mage/abilities/hint/common/CovenHint.java @@ -23,7 +23,7 @@ public enum CovenHint implements Hint { .getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_CREATURE, - ability.getControllerId(), ability.getSourceId(), game + ability.getControllerId(), ability, game ) .stream() .filter(Objects::nonNull) diff --git a/Mage/src/main/java/mage/abilities/hint/common/DifferentManaValuesInGraveHint.java b/Mage/src/main/java/mage/abilities/hint/common/DifferentManaValuesInGraveHint.java new file mode 100644 index 00000000000..7c2dc478d9d --- /dev/null +++ b/Mage/src/main/java/mage/abilities/hint/common/DifferentManaValuesInGraveHint.java @@ -0,0 +1,40 @@ +package mage.abilities.hint.common; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.hint.Hint; +import mage.game.Game; +import mage.players.Player; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public enum DifferentManaValuesInGraveHint implements Hint { + instance; + + public String getText(Game game, Ability ability) { + Player player = game.getPlayer(ability.getControllerId()); + if (player == null) { + return null; + } + List values = player + .getGraveyard() + .getCards(game) + .stream() + .mapToInt(MageObject::getManaValue) + .distinct() + .sorted() + .mapToObj(String::valueOf) + .collect(Collectors.toList()); + return "Different mana values among cards in your graveyard: " + values.size() + + (values.size() > 0 ? " (" + String.join(", ", values) + ')' : ""); + } + + @Override + public DifferentManaValuesInGraveHint copy() { + return this; + } +} diff --git a/Mage/src/main/java/mage/abilities/hint/common/DomainHint.java b/Mage/src/main/java/mage/abilities/hint/common/DomainHint.java index 3b0233e3413..0dfc98a26d6 100644 --- a/Mage/src/main/java/mage/abilities/hint/common/DomainHint.java +++ b/Mage/src/main/java/mage/abilities/hint/common/DomainHint.java @@ -24,7 +24,7 @@ public enum DomainHint implements Hint { List landTypes = game.getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_PERMANENT_LANDS, - ability.getControllerId(), ability.getSourceId(), game + ability.getControllerId(), ability, game ).stream() .map(permanent -> SubType .getBasicLands() diff --git a/Mage/src/main/java/mage/abilities/keyword/AftermathAbility.java b/Mage/src/main/java/mage/abilities/keyword/AftermathAbility.java index 67a8b94bfd6..b63f1539fa2 100644 --- a/Mage/src/main/java/mage/abilities/keyword/AftermathAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/AftermathAbility.java @@ -6,8 +6,7 @@ import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.Card; -import mage.cards.ModalDoubleFacesCardHalf; -import mage.cards.SplitCardHalf; +import mage.cards.SubCard; import mage.constants.AsThoughEffectType; import mage.constants.Duration; import mage.constants.Outcome; @@ -154,14 +153,10 @@ class AftermathExileAsResolvesFromGraveyard extends ReplacementEffectImpl { // If branch so that we also support putting Aftermath on // non-split cards for... whatever reason, in case somebody // wants to do that in the future. - UUID sourceId = source.getSourceId(); + UUID sourceId = source != null ? source.getSourceId() : null; Card sourceCard = game.getCard(source.getSourceId()); - if (sourceCard instanceof SplitCardHalf) { - sourceCard = ((SplitCardHalf) sourceCard).getParentCard(); - sourceId = sourceCard.getId(); - } - if (sourceCard instanceof ModalDoubleFacesCardHalf) { - sourceCard = ((ModalDoubleFacesCardHalf) sourceCard).getParentCard(); + if (sourceCard instanceof SubCard) { + sourceCard = ((SubCard) sourceCard).getParentCard(); sourceId = sourceCard.getId(); } @@ -178,11 +173,8 @@ class AftermathExileAsResolvesFromGraveyard extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Card sourceCard = game.getCard(source.getSourceId()); - if (sourceCard instanceof SplitCardHalf) { - sourceCard = ((SplitCardHalf) sourceCard).getParentCard(); - } - if (sourceCard instanceof ModalDoubleFacesCardHalf) { - sourceCard = ((ModalDoubleFacesCardHalf) sourceCard).getParentCard(); + if (sourceCard instanceof SubCard) { + sourceCard = ((SubCard) sourceCard).getParentCard(); } if (sourceCard != null) { Player player = game.getPlayer(sourceCard.getOwnerId()); diff --git a/Mage/src/main/java/mage/abilities/keyword/AnnihilatorAbility.java b/Mage/src/main/java/mage/abilities/keyword/AnnihilatorAbility.java index 43d7cb060de..594b98cd1e2 100644 --- a/Mage/src/main/java/mage/abilities/keyword/AnnihilatorAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/AnnihilatorAbility.java @@ -9,7 +9,6 @@ import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetControlledPermanent; @@ -100,11 +99,11 @@ class AnnihilatorEffect extends OneShotEffect { int amount = Math.min(count, game.getBattlefield().countAll(new FilterControlledPermanent(), player.getId(), game)); if (amount > 0) { Target target = new TargetControlledPermanent(amount, amount, new FilterControlledPermanent(), true); - if (target.canChoose(source.getSourceId(), player.getId(), game)) { + if (target.canChoose(player.getId(), source, game)) { while (player.canRespond() - && target.canChoose(source.getSourceId(), player.getId(), game) + && target.canChoose(player.getId(), source, game) && !target.isChosen()) { - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + player.choose(Outcome.Sacrifice, target, source, game); } target.getTargets().stream() .map(game::getPermanent) diff --git a/Mage/src/main/java/mage/abilities/keyword/AuraSwapAbility.java b/Mage/src/main/java/mage/abilities/keyword/AuraSwapAbility.java index e81d2526dea..67d51a58634 100644 --- a/Mage/src/main/java/mage/abilities/keyword/AuraSwapAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/AuraSwapAbility.java @@ -72,7 +72,7 @@ class AuraSwapEffect extends OneShotEffect { Permanent enchantedPermanent = game.getPermanent(auraSourcePermanent.getAttachedTo()); filterCardToCheck.add(new AuraCardCanAttachToPermanentId(enchantedPermanent.getId())); TargetCardInHand target = new TargetCardInHand(filterCardToCheck); - if (controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { + if (controller.choose(Outcome.PutCardInPlay, target, source, game)) { Card auraInHand = game.getCard(target.getFirstTarget()); if (auraInHand != null) { game.getState().setValue("attachTo:" + auraInHand.getId(), enchantedPermanent); diff --git a/Mage/src/main/java/mage/abilities/keyword/BlitzAbility.java b/Mage/src/main/java/mage/abilities/keyword/BlitzAbility.java new file mode 100644 index 00000000000..4d7ccce8e7b --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/BlitzAbility.java @@ -0,0 +1,124 @@ +package mage.abilities.keyword; + +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.condition.common.BlitzedCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.cards.Card; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SpellAbilityType; +import mage.constants.TimingRule; +import mage.game.Game; +import mage.target.targetpointer.FixedTarget; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author TheElk801 + */ +public class BlitzAbility extends SpellAbility { + + public static final String BLITZ_ACTIVATION_VALUE_KEY = "blitzActivation"; + + public BlitzAbility(Card card, String manaString) { + super(new ManaCostsImpl<>(manaString), card.getName() + " with Blitz"); + this.spellAbilityType = SpellAbilityType.BASE_ALTERNATE; + Ability ability = new EntersBattlefieldAbility( + new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.Custom, false), + BlitzedCondition.instance, "", "" + ); + ability.addEffect(new GainAbilitySourceEffect(new DiesSourceTriggeredAbility( + new DrawCardSourceControllerEffect(1) + ).setTriggerPhrase("When this creature dies, "))); + ability.addEffect(new BlitzAddDelayedTriggeredAbilityEffect()); + ability.setRuleVisible(false); + addSubAbility(ability); + this.ruleAdditionalCostsVisible = false; + this.timing = TimingRule.SORCERY; + } + + private BlitzAbility(final BlitzAbility ability) { + super(ability); + } + + @Override + public BlitzAbility copy() { + return new BlitzAbility(this); + } + + @Override + public String getRule() { + StringBuilder sb = new StringBuilder("Blitz"); + if (costs.isEmpty()) { + sb.append(' '); + } else { + sb.append("—"); + } + sb.append(manaCosts.getText()); + if (!costs.isEmpty()) { + sb.append(", "); + sb.append(costs.getText()); + sb.append('.'); + } + sb.append(" (If you cast this spell for its blitz cost, it gains haste "); + sb.append("and \"When this creature dies, draw a card.\" "); + sb.append("Sacrifice it at the beginning of the next end step.)"); + return sb.toString(); + } + + @Override + public boolean activate(Game game, boolean noMana) { + if (!super.activate(game, noMana)) { + return false; + } + Object obj = game.getState().getValue(BLITZ_ACTIVATION_VALUE_KEY + getSourceId()); + List blitzActivations; + if (obj != null) { + blitzActivations = (List) obj; + } else { + blitzActivations = new ArrayList<>(); + game.getState().setValue(BLITZ_ACTIVATION_VALUE_KEY + getSourceId(), blitzActivations); + } + blitzActivations.add(game.getState().getZoneChangeCounter(getSourceId())); + return true; + } +} + +class BlitzAddDelayedTriggeredAbilityEffect extends OneShotEffect { + + BlitzAddDelayedTriggeredAbilityEffect() { + super(Outcome.Benefit); + } + + private BlitzAddDelayedTriggeredAbilityEffect(final BlitzAddDelayedTriggeredAbilityEffect effect) { + super(effect); + } + + @Override + public BlitzAddDelayedTriggeredAbilityEffect copy() { + return new BlitzAddDelayedTriggeredAbilityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (game.getPermanentEntering(source.getSourceId()) == null) { + return false; + } + // init target pointer now because the Blitzed creature will only be returned from battlefield zone (now in entering state so zone change counter is not raised yet) + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new SacrificeTargetEffect() + .setText("sacrifice the blitzed creature") + .setTargetPointer(new FixedTarget(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId()) + 1)) + ), source); + return true; + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/BoastAbility.java b/Mage/src/main/java/mage/abilities/keyword/BoastAbility.java index 6d6ccb4e5f8..843f862b067 100644 --- a/Mage/src/main/java/mage/abilities/keyword/BoastAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/BoastAbility.java @@ -60,7 +60,7 @@ public class BoastAbility extends ActivatedAbilityImpl { return game.getBattlefield() .getActivePermanents( StaticFilters.FILTER_CONTROLLED_PERMANENT, - getControllerId(), getSourceId(), game + getControllerId(), this, game ).stream() .map(p -> p.getAbilities(game)) .flatMap(Collection::stream) diff --git a/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java b/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java index 3e459f37658..c8724ab1680 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java @@ -1,23 +1,23 @@ package mage.abilities.keyword; -import mage.ApprovingObject; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.cards.Card; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.ComparisonType; import mage.constants.Outcome; import mage.constants.Zone; +import mage.filter.FilterCard; import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.players.Player; import mage.target.common.TargetCardInExile; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; +import mage.util.CardUtil; /** * Cascade A keyword ability that may let a player cast a random extra spell for @@ -152,45 +152,12 @@ class CascadeEffect extends OneShotEffect { } // You may cast that spell without paying its mana cost if its converted mana cost is less than this spell's converted mana cost. - List partsToCast = new ArrayList<>(); - if (cardToCast != null) { - if (cardToCast instanceof SplitCard) { - partsToCast.add(((SplitCard) cardToCast).getLeftHalfCard()); - partsToCast.add(((SplitCard) cardToCast).getRightHalfCard()); - partsToCast.add(cardToCast); - } else if (cardToCast instanceof AdventureCard) { - partsToCast.add(((AdventureCard) cardToCast).getSpellCard()); - partsToCast.add(cardToCast); - } else if (cardToCast instanceof ModalDoubleFacesCard) { - partsToCast.add(((ModalDoubleFacesCard) cardToCast).getLeftHalfCard()); - partsToCast.add(((ModalDoubleFacesCard) cardToCast).getRightHalfCard()); - } else { - partsToCast.add(cardToCast); - } - // remove too big cmc - partsToCast.removeIf(card -> card.getManaValue() >= sourceCost); - // remove non spells - partsToCast.removeIf(card -> card.getSpellAbility() == null); - } - - String partsInfo = partsToCast.stream() - .map(MageObject::getIdName) - .collect(Collectors.joining(" or ")); - if (cardToCast != null - && partsToCast.size() > 0 - && controller.chooseUse(outcome, "Cast spell without paying its mana cost (" + partsInfo + ")?", source, game)) { - try { - // enable free cast for all compatible parts - partsToCast.forEach(card -> game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE)); - controller.cast(controller.chooseAbilityForCast(cardToCast, game, true), - game, true, new ApprovingObject(source, game)); - } finally { - partsToCast.forEach(card -> game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null)); - } - } + FilterCard filter = new FilterCard(); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, sourceCost + 1)); + CardUtil.castSpellWithAttributesForFree(controller, source, game, new CardsImpl(cardToCast), filter); // Then put all cards exiled this way that weren't cast on the bottom of your library in a random order. - cardsToExile.removeIf(uuid -> game.getState().getZone(uuid) != Zone.EXILED); + cardsToExile.retainZone(Zone.EXILED, game); return controller.putCardsOnBottomOfLibrary(cardsToExile, game, source, false); } diff --git a/Mage/src/main/java/mage/abilities/keyword/CasualtyAbility.java b/Mage/src/main/java/mage/abilities/keyword/CasualtyAbility.java new file mode 100644 index 00000000000..39fba38fa32 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/CasualtyAbility.java @@ -0,0 +1,87 @@ +package mage.abilities.keyword; + +import mage.abilities.Ability; +import mage.abilities.StaticAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.CopySourceSpellEffect; +import mage.abilities.effects.common.InfoEffect; +import mage.cards.Card; +import mage.constants.ComparisonType; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.game.Game; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public class CasualtyAbility extends StaticAbility { + + public CasualtyAbility(Card card, int number) { + super(Zone.ALL, new InfoEffect( + "Casualty " + number + " (As you cast this spell, " + + "you may sacrifice a creature with power " + number + + " or greater. When you do, copy this spell.)" + )); + card.getSpellAbility().addCost(new CasualtyCost(number)); + this.setRuleAtTheTop(true); + } + + private CasualtyAbility(final CasualtyAbility ability) { + super(ability); + } + + @Override + public CasualtyAbility copy() { + return new CasualtyAbility(this); + } +} + +class CasualtyCost extends SacrificeTargetCost { + + CasualtyCost(int number) { + super(new TargetControlledPermanent(0, 1, makeFilter(number), true)); + this.text = ""; + } + + private CasualtyCost(final CasualtyCost cost) { + super(cost); + } + + @Override + public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { + if (!super.pay(ability, game, source, controllerId, noMana, costToPay)) { + return false; + } + if (!getPermanents().isEmpty()) { + game.fireReflexiveTriggeredAbility(new ReflexiveTriggeredAbility( + new CopySourceSpellEffect(), false, "when you do, copy this spell" + ), source); + } + return true; + } + + @Override + public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { + return true; + } + + @Override + public CasualtyCost copy() { + return new CasualtyCost(this); + } + + private static FilterControlledPermanent makeFilter(int number) { + FilterControlledPermanent filter = new FilterControlledCreaturePermanent( + "creature with power " + number + " or greater" + ); + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, number - 1)); + return filter; + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/ChampionAbility.java b/Mage/src/main/java/mage/abilities/keyword/ChampionAbility.java index c0e785dd9af..56944abcb41 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ChampionAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ChampionAbility.java @@ -1,11 +1,5 @@ - package mage.abilities.keyword; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.StaticAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -15,12 +9,11 @@ import mage.abilities.costs.CostImpl; import mage.abilities.effects.common.ReturnFromExileForSourceEffect; import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; import mage.cards.Card; -import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AnotherPredicate; import mage.game.Game; @@ -30,6 +23,10 @@ import mage.players.Player; import mage.target.common.TargetControlledPermanent; import mage.util.CardUtil; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + /* * @author LevelX2 * @@ -49,16 +46,7 @@ import mage.util.CardUtil; */ public class ChampionAbility extends StaticAbility { - protected EnumSet subtypes; - protected String objectDescription; - - public ChampionAbility(Card card, SubType subtype, boolean requiresCreature) { - this(card, EnumSet.of(subtype), requiresCreature); - } - - public ChampionAbility(Card card, boolean requiresCreature) { - this(card, EnumSet.noneOf(SubType.class), requiresCreature); - } + protected final String objectDescription; /** * Champion one or more creature types or if the subtype array is empty @@ -66,55 +54,56 @@ public class ChampionAbility extends StaticAbility { * * @param card * @param subtypes subtypes to champion with, if empty all creatures can be - * used - * @param requiresCreature for cards that specifically require championing - * another creature + * used */ - public ChampionAbility(Card card, EnumSet subtypes, boolean requiresCreature) { + public ChampionAbility(Card card, SubType... subtypes) { super(Zone.BATTLEFIELD, null); - this.subtypes = subtypes; - StringBuilder sb = new StringBuilder("another "); - List> subtypesPredicates = new ArrayList<>(); - if (!subtypes.isEmpty()) { - int i = 0; - for (SubType subtype : this.subtypes) { - subtypesPredicates.add(subtype.getPredicate()); - if (i == 0) { - sb.append(subtype); - } else { - sb.append(" or ").append(subtype); - } - i++; - } - } else { - sb.append("creature"); + List subTypes = Arrays.asList(subtypes); + FilterControlledPermanent filter; + switch (subTypes.size()) { + case 0: + this.objectDescription = "creature"; + filter = StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE; + break; + case 1: + SubType subType = subTypes.get(0); + this.objectDescription = subType.getDescription(); + filter = new FilterControlledPermanent(subType, "another " + subType + " you control"); + filter.add(AnotherPredicate.instance); + break; + case 2: + SubType subType1 = subTypes.get(0); + SubType subType2 = subTypes.get(1); + this.objectDescription = subType1.getDescription() + " or " + subType2.getDescription(); + filter = new FilterControlledPermanent(); + filter.add(Predicates.or( + subType1.getPredicate(), + subType2.getPredicate() + )); + filter.add(AnotherPredicate.instance); + break; + default: + throw new UnsupportedOperationException("can't have more than two subtypes currently"); } - this.objectDescription = sb.toString(); - FilterControlledPermanent filter = new FilterControlledPermanent(objectDescription); - if (!subtypesPredicates.isEmpty()) { - filter.add(Predicates.or(subtypesPredicates)); - } - if (requiresCreature) { - filter.add(CardType.CREATURE.getPredicate()); - } - filter.add(AnotherPredicate.instance); // When this permanent enters the battlefield, sacrifice it unless you exile another [object] you control. Ability ability1 = new EntersBattlefieldTriggeredAbility( - new SacrificeSourceUnlessPaysEffect(new ChampionExileCost(filter, card.getName() + " championed permanents")), false); + new SacrificeSourceUnlessPaysEffect(new ChampionExileCost(filter)), false + ); ability1.setRuleVisible(false); addSubAbility(ability1); // When this permanent leaves the battlefield, return the exiled card to the battlefield under its owner's control. - Ability ability2 = new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), false); + Ability ability2 = new LeavesBattlefieldTriggeredAbility( + new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), false + ); ability2.setRuleVisible(false); addSubAbility(ability2); } public ChampionAbility(final ChampionAbility ability) { super(ability); - this.subtypes = ability.subtypes; this.objectDescription = ability.objectDescription; } @@ -125,46 +114,41 @@ public class ChampionAbility extends StaticAbility { @Override public String getRule() { - StringBuilder sb = new StringBuilder("Champion ").append(objectDescription); - sb.append(" (When this enters the battlefield, sacrifice it unless you exile another "); - sb.append(objectDescription); - sb.append(" you control. When this leaves the battlefield, that card returns to the battlefield.)"); - return sb.toString(); + return "Champion " + CardUtil.addArticle(objectDescription) + + " (When this enters the battlefield, sacrifice it unless you exile another " + objectDescription + + " you control. When this leaves the battlefield, that card returns to the battlefield.)"; } } class ChampionExileCost extends CostImpl { - private String exileZone; - - public ChampionExileCost(FilterControlledPermanent filter, String exileZone) { + ChampionExileCost(FilterControlledPermanent filter) { this.addTarget(new TargetControlledPermanent(1, 1, filter, true)); this.text = "exile " + filter.getMessage() + " you control"; - this.exileZone = exileZone; } - public ChampionExileCost(ChampionExileCost cost) { + private ChampionExileCost(ChampionExileCost cost) { super(cost); - this.exileZone = cost.exileZone; } @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); - MageObject sourceObject = ability.getSourceObject(game); - if (controller != null && sourceObject != null) { - if (targets.choose(Outcome.Exile, controllerId, source.getSourceId(), game)) { - UUID exileId = CardUtil.getExileZoneId(game, ability.getSourceId(), ability.getSourceObjectZoneChangeCounter()); // exileId important for return effect - for (UUID targetId : targets.get(0).getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent == null) { - return false; - } - paid |= controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getIdName() + " championed permanents", source, game, Zone.BATTLEFIELD, true); - if (paid) { - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_CHAMPIONED, permanent.getId(), source, controllerId)); - } - } + if (controller == null || !targets.choose(Outcome.Exile, controllerId, source.getSourceId(), source, game)) { + return paid; + } + for (UUID targetId : targets.get(0).getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent == null) { + return false; + } + paid |= controller.moveCardsToExile( + permanent, source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + if (paid) { + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREATURE_CHAMPIONED, permanent.getId(), source, controllerId)); } } return paid; @@ -172,7 +156,7 @@ class ChampionExileCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/keyword/CompanionAbility.java b/Mage/src/main/java/mage/abilities/keyword/CompanionAbility.java index ca3a36fe85a..735824caeb6 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CompanionAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CompanionAbility.java @@ -41,8 +41,12 @@ public class CompanionAbility extends SpecialAction { return "Companion — " + companionCondition.getRule(); } - public boolean isLegal(Set cards, int startingHandSize) { + final public boolean isLegal(Set cards, int startingHandSize) { return companionCondition.isLegal(cards, startingHandSize); } + + final public String getLegalRule() { + return companionCondition.getRule(); + } } diff --git a/Mage/src/main/java/mage/abilities/keyword/CompleatedAbility.java b/Mage/src/main/java/mage/abilities/keyword/CompleatedAbility.java new file mode 100644 index 00000000000..3a777f6e333 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/CompleatedAbility.java @@ -0,0 +1,42 @@ +package mage.abilities.keyword; + +import mage.abilities.MageSingleton; +import mage.abilities.StaticAbility; +import mage.constants.Zone; + +import java.io.ObjectStreamException; + +/** + * @author TheElk801 + */ +public class CompleatedAbility extends StaticAbility implements MageSingleton { + + private static final CompleatedAbility instance; + + static { + instance = new CompleatedAbility(); + } + + private Object readResolve() throws ObjectStreamException { + return instance; + } + + public static CompleatedAbility getInstance() { + return instance; + } + + private CompleatedAbility() { + super(Zone.ALL, null); + } + + @Override + public String getRule() { + return "compleated"; + } + + @Override + public CompleatedAbility copy() { + return instance; + } + +} diff --git a/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java b/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java index 43332eb8b5a..8edac415e63 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java @@ -3,13 +3,11 @@ package mage.abilities.keyword; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.StaticAbility; -import mage.abilities.TriggeredAbilityImpl; import mage.abilities.costs.*; import mage.abilities.costs.common.TapTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.CastSourceTriggeredAbility; +import mage.abilities.effects.common.CopySourceSpellEffect; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -21,10 +19,10 @@ import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.players.Player; import mage.target.common.TargetControlledPermanent; +import mage.util.CardUtil; -import java.util.HashSet; import java.util.Iterator; -import java.util.Set; +import java.util.Objects; import java.util.UUID; /* @@ -45,62 +43,58 @@ import java.util.UUID; public class ConspireAbility extends StaticAbility implements OptionalAdditionalSourceCosts { private static final String keywordText = "Conspire"; - private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped creatures you control that share a color with it"); - protected static final String CONSPIRE_ACTIVATION_KEY = "ConspireActivation"; + private static final FilterControlledPermanent filter + = new FilterControlledPermanent("untapped creatures you control that share a color with it"); static { filter.add(TappedPredicate.UNTAPPED); - filter.add(new SharesColorWithSourcePredicate()); + filter.add(SharesColorWithSourcePredicate.instance); filter.add(CardType.CREATURE.getPredicate()); } public enum ConspireTargets { - NONE, - ONE, - MORE + NONE(""), + ONE(" and you may choose a new target for the copy"), + MORE(" and you may choose new targets for the copy"); + private final String message; + + ConspireTargets(String message) { + this.message = message; + } + + public String getReminder() { + return "as you cast this spell, you may tap two untapped creatures you control " + + "that share a color with it. When you do, copy it" + message; + } } private final UUID conspireId; - private String reminderText; - private OptionalAdditionalCost conspireCost; + private UUID addedById = null; + private final String reminderText; + private final OptionalAdditionalCost conspireCost; /** * Unique Id for a ConspireAbility but may not change while a continuous * effect gives Conspire * - * @param conspireId * @param conspireTargets controls the content of the reminder text */ - public ConspireAbility(UUID conspireId, ConspireTargets conspireTargets) { + public ConspireAbility(ConspireTargets conspireTargets) { super(Zone.STACK, null); - this.conspireId = conspireId; - switch (conspireTargets) { - case NONE: - reminderText = "As you cast this spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it."; - break; - case ONE: - reminderText = "As you cast this spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose a new target for the copy."; - break; - case MORE: - reminderText = "As you cast this spell, you may tap two untapped creatures you control that share a color with it. When you do, copy it and you may choose new targets for the copy."; - break; - } - - Cost cost = new TapTargetCost(new TargetControlledPermanent(2, 2, filter, true)); - cost.setText(""); - addConspireCostAndSetup(new OptionalAdditionalCostImpl(keywordText, " ", reminderText, cost)); - - addSubAbility(new ConspireTriggeredAbility(conspireId)); - } - - private void addConspireCostAndSetup(OptionalAdditionalCost newCost) { - this.conspireCost = newCost; + this.conspireId = UUID.randomUUID(); + reminderText = conspireTargets.getReminder(); + this.conspireCost = new OptionalAdditionalCostImpl( + keywordText, " ", reminderText, + new TapTargetCost(new TargetControlledPermanent(2, filter)) + ); this.conspireCost.setCostType(VariableCostType.ADDITIONAL); + this.addSubAbility(new ConspireTriggeredAbility(conspireId)); } public ConspireAbility(final ConspireAbility ability) { super(ability); this.conspireId = ability.conspireId; + this.addedById = ability.addedById; this.conspireCost = ability.conspireCost.copy(); this.reminderText = ability.reminderText; } @@ -113,107 +107,76 @@ public class ConspireAbility extends StaticAbility implements OptionalAdditional @Override public void addCost(Cost cost) { if (conspireCost != null) { - ((Costs) conspireCost).add(cost); + ((Costs) conspireCost).add(cost); } } - public UUID getConspireId() { - return conspireId; - } - @Override public boolean isActivated() { throw new UnsupportedOperationException("Use ConspireAbility.isActivated(Ability ability, Game game) method instead!"); } - public boolean isActivated(Ability ability, Game game) { - Set activations = (Set) game.getState().getValue(CONSPIRE_ACTIVATION_KEY + ability.getId()); - if (activations != null) { - return activations.contains(getConspireId()); - } - return false; - } - @Override public void addOptionalAdditionalCosts(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - Player player = game.getPlayer(getControllerId()); - if (player != null) { - resetConspire(ability, game); - // AI supports conspire - if (conspireCost.canPay(ability, this, getControllerId(), game) - && player.chooseUse(Outcome.Benefit, "Pay " + conspireCost.getText(false) + " ?", ability, game)) { - activateConspire(ability, game); - for (Iterator it = ((Costs) conspireCost).iterator(); it.hasNext(); ) { - Cost cost = (Cost) it.next(); - if (cost instanceof ManaCostsImpl) { - ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy()); - } else { - ability.getCosts().add(cost.copy()); - } - } - } + if (!(ability instanceof SpellAbility)) { + return; + } + Player player = game.getPlayer(getControllerId()); + if (player == null) { + return; + } + // AI supports conspire + if (!conspireCost.canPay(ability, this, getControllerId(), game) + || !player.chooseUse(Outcome.Benefit, "Pay " + + conspireCost.getText(false) + " ?", ability, game)) { + return; + } + ability.getEffects().setValue("ConspireActivation" + conspireId + addedById, true); + for (Iterator it = ((Costs) conspireCost).iterator(); it.hasNext(); ) { + Cost cost = (Cost) it.next(); + if (cost instanceof ManaCostsImpl) { + ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy()); + } else { + ability.getCosts().add(cost.copy()); } } } - private void activateConspire(Ability ability, Game game) { - Set activations = (Set) game.getState().getValue(CONSPIRE_ACTIVATION_KEY + ability.getId()); - if (activations == null) { - activations = new HashSet<>(); - game.getState().setValue(CONSPIRE_ACTIVATION_KEY + ability.getId(), activations); - } - activations.add(getConspireId()); - } - - private void resetConspire(Ability ability, Game game) { - Set activations = (Set) game.getState().getValue(CONSPIRE_ACTIVATION_KEY + ability.getId()); - if (activations != null) { - activations.remove(getConspireId()); - } - } - @Override public String getRule() { - StringBuilder sb = new StringBuilder(); - if (conspireCost != null) { - sb.append(conspireCost.getText(false)); - sb.append(' ').append(conspireCost.getReminderText()); - } - return sb.toString(); + return "Conspire (" + reminderText + ")"; } @Override public String getCastMessageSuffix() { - if (conspireCost != null) { - return conspireCost.getCastSuffixMessage(0); - } else { - return ""; - } + return conspireCost != null ? conspireCost.getCastSuffixMessage(0) : ""; } - public String getReminderText() { - if (conspireCost != null) { - return conspireCost.getReminderText(); - } else { - return ""; - } + public ConspireAbility setAddedById(UUID addedById) { + this.addedById = addedById; + CardUtil.castStream( + this.subAbilities.stream(), + ConspireTriggeredAbility.class + ).forEach(ability -> ability.setAddedById(addedById)); + return this; } } -class ConspireTriggeredAbility extends TriggeredAbilityImpl { +class ConspireTriggeredAbility extends CastSourceTriggeredAbility { private final UUID conspireId; + private UUID addedById = null; public ConspireTriggeredAbility(UUID conspireId) { - super(Zone.STACK, new ConspireEffect()); - this.conspireId = conspireId; + super(new CopySourceSpellEffect(), false); this.setRuleVisible(false); + this.conspireId = conspireId; } private ConspireTriggeredAbility(final ConspireTriggeredAbility ability) { super(ability); this.conspireId = ability.conspireId; + this.addedById = ability.addedById; } @Override @@ -221,74 +184,27 @@ class ConspireTriggeredAbility extends TriggeredAbilityImpl { return new ConspireTriggeredAbility(this); } - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SPELL_CAST; - } - @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getSourceId().equals(getSourceId())) { - Spell spell = game.getStack().getSpell(event.getSourceId()); - for (Ability ability : spell.getAbilities(game)) { - if (ability instanceof ConspireAbility - && ((ConspireAbility) ability).getConspireId().equals(getConspireId())) { - if (((ConspireAbility) ability).isActivated(spell.getSpellAbility(), game)) { - for (Effect effect : this.getEffects()) { - if (effect instanceof ConspireEffect) { - ((ConspireEffect) effect).setConspiredSpell(spell); - } - } - return true; - } - } - } + if (!super.checkTrigger(event, game)) { + return false; } - return false; - } - - public UUID getConspireId() { - return conspireId; + Spell spell = game.getStack().getSpell(event.getSourceId()); + return spell != null + && spell + .getSpellAbility() + .getEffects() + .stream() + .map(effect -> effect.getValue("ConspireActivation" + conspireId + addedById)) + .anyMatch(Objects::nonNull); } @Override public String getRule() { return "When you pay the conspire costs, copy it and you may choose a new target for the copy."; } -} -class ConspireEffect extends OneShotEffect { - - private Spell conspiredSpell; - - public ConspireEffect() { - super(Outcome.Copy); - } - - public ConspireEffect(final ConspireEffect effect) { - super(effect); - this.conspiredSpell = effect.conspiredSpell; - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null && conspiredSpell != null) { - Card card = game.getCard(conspiredSpell.getSourceId()); - if (card != null) { - conspiredSpell.createCopyOnStack(game, source, source.getControllerId(), true); - return true; - } - } - return false; - } - - public void setConspiredSpell(Spell conspiredSpell) { - this.conspiredSpell = conspiredSpell; - } - - @Override - public ConspireEffect copy() { - return new ConspireEffect(this); + public void setAddedById(UUID addedById) { + this.addedById = addedById; } } diff --git a/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java b/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java index 4f94a333e41..bb1d8f7c496 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java @@ -148,7 +148,7 @@ public class ConvokeAbility extends SimpleStaticAbility implements AlternateMana FilterControlledCreaturePermanent filterBasic = new FilterControlledCreaturePermanent(); // each creature can give {1} or color mana - game.getBattlefield().getActivePermanents(filterBasic, source.getControllerId(), source.getSourceId(), game) + game.getBattlefield().getActivePermanents(filterBasic, source.getControllerId(), source, game) .stream() .filter(permanent -> !permanent.isTapped()) .forEach(permanent -> { diff --git a/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java b/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java index e5f206f760d..c7793775541 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java @@ -4,8 +4,11 @@ import mage.abilities.Ability; import mage.abilities.common.CrewIncreasedPowerAbility; import mage.abilities.common.CrewWithToughnessAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect; import mage.abilities.hint.HintUtils; import mage.abilities.icon.abilities.CrewAbilityIcon; @@ -19,8 +22,10 @@ import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.Target; import mage.target.common.TargetControlledCreaturePermanent; +import mage.util.CardUtil; import java.awt.*; import java.util.Objects; @@ -34,10 +39,22 @@ public class CrewAbility extends SimpleActivatedAbility { private final int value; public CrewAbility(int value) { - super(Zone.BATTLEFIELD, new AddCardTypeSourceEffect(Duration.EndOfTurn, CardType.ARTIFACT), new CrewCost(value)); - this.addEffect(new AddCardTypeSourceEffect(Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE)); + this(value, null); + } + + public CrewAbility(int value, Cost altCost) { + super(Zone.BATTLEFIELD, new AddCardTypeSourceEffect( + Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE + ), new CrewCost(value, altCost)); + this.addEffect(new CrewEventEffect()); this.addIcon(CrewAbilityIcon.instance); this.value = value; + if (altCost != null) { + this.addSubAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect( + "you may " + CardUtil.addCostVerb(altCost.getText()) + + " rather than pay {this}'s crew cost" + ))); + } } public CrewAbility(final CrewAbility ability) { @@ -52,13 +69,43 @@ public class CrewAbility extends SimpleActivatedAbility { @Override public String getRule() { - return "Crew " + value + " (Tap any number of creatures you control with total power " + value + " or more: This Vehicle becomes an artifact creature until end of turn.)"; + return "Crew " + value + " (Tap any number of creatures you control with total power " + + value + " or more: This Vehicle becomes an artifact creature until end of turn.)"; + } +} + +class CrewEventEffect extends OneShotEffect { + + CrewEventEffect() { + super(Outcome.Benefit); + } + + private CrewEventEffect(final CrewEventEffect effect) { + super(effect); + } + + @Override + public CrewEventEffect copy() { + return new CrewEventEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (source.getSourcePermanentIfItStillExists(game) != null) { + game.fireEvent(GameEvent.getEvent( + GameEvent.EventType.VEHICLE_CREWED, + source.getSourceId(), + source, source.getControllerId() + )); + } + return true; } } class CrewCost extends CostImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another untapped creature you control"); + private static final FilterControlledCreaturePermanent filter + = new FilterControlledCreaturePermanent("another untapped creature you control"); static { filter.add(TappedPredicate.UNTAPPED); @@ -66,18 +113,38 @@ class CrewCost extends CostImpl { } private final int value; + private final Cost altCost; - CrewCost(int value) { + CrewCost(int value, Cost altCost) { this.value = value; + this.altCost = altCost; } - CrewCost(final CrewCost cost) { + private CrewCost(final CrewCost cost) { super(cost); this.value = cost.value; + this.altCost = cost.altCost != null ? cost.altCost.copy() : null; + } + + private boolean handleAltCost(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { + if (altCost == null || !altCost.canPay(ability, source, controllerId, game)) { + return false; + } + Player player = game.getPlayer(controllerId); + String message = CardUtil.getTextWithFirstCharUpperCase( + CardUtil.addCostVerb(altCost.getText()) + ) + " rather than the crew cost?"; + return player != null + && player.chooseUse(Outcome.Benefit, message, source, game) + && altCost.pay(ability, game, source, controllerId, noMana, costToPay); } @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { + if (handleAltCost(ability, game, source, controllerId, noMana, costToPay)) { + paid = true; + return true; + } Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true) { @Override public String getMessage() { @@ -96,7 +163,7 @@ class CrewCost extends CostImpl { }; // can cancel - if (target.choose(Outcome.Tap, controllerId, source.getSourceId(), game)) { + if (target.choose(Outcome.Tap, controllerId, source.getSourceId(), source, game)) { int sumPower = 0; for (UUID targetId : target.getTargets()) { GameEvent event = new GameEvent(GameEvent.EventType.CREW_VEHICLE, targetId, source, controllerId); @@ -112,7 +179,6 @@ class CrewCost extends CostImpl { for (UUID targetId : target.getTargets()) { game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREWED_VEHICLE, targetId, source, controllerId)); } - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.VEHICLE_CREWED, source.getSourceId(), source, controllerId)); } } else { return false; @@ -123,6 +189,9 @@ class CrewCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { + if (altCost != null && altCost.canPay(ability, source, controllerId, game)) { + return true; + } int sumPower = 0; for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controllerId, game)) { int powerToAdd = getCrewPower(permanent, game); diff --git a/Mage/src/main/java/mage/abilities/keyword/DashAbility.java b/Mage/src/main/java/mage/abilities/keyword/DashAbility.java index 9e89a3c160b..a7527cf57e3 100644 --- a/Mage/src/main/java/mage/abilities/keyword/DashAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/DashAbility.java @@ -1,201 +1,55 @@ package mage.abilities.keyword; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; import mage.abilities.Ability; -import mage.abilities.DelayedTriggeredAbility; -import mage.abilities.SpellAbility; -import mage.abilities.StaticAbility; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.condition.common.DashedCondition; -import mage.abilities.condition.common.SourceOnBattlefieldCondition; -import mage.abilities.costs.AlternativeCost2; -import mage.abilities.costs.AlternativeCost2Impl; -import mage.abilities.costs.AlternativeSourceCosts; -import mage.abilities.costs.Cost; -import mage.abilities.costs.Costs; -import mage.abilities.costs.CostsImpl; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.costs.AlternativeSourceCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; -import mage.cards.Card; import mage.constants.Duration; import mage.constants.Outcome; -import mage.constants.Zone; import mage.game.Game; -import mage.players.Player; import mage.target.targetpointer.FixedTarget; /** - * * @author LevelX2 */ -public class DashAbility extends StaticAbility implements AlternativeSourceCosts { +public class DashAbility extends AlternativeSourceCostsImpl { protected static final String KEYWORD = "Dash"; - protected static final String REMINDER_TEXT = "(You may cast this spell for its dash cost. " + protected static final String REMINDER_TEXT = "You may cast this spell for its dash cost. " + "If you do, it gains haste, and it's returned from the battlefield to its owner's " - + "hand at the beginning of the next end step.)"; + + "hand at the beginning of the next end step."; - protected List alternativeSourceCosts = new LinkedList<>(); - - // needed to check activation status, if card changes zone after casting it - private int zoneChangeCounter = 0; - - public DashAbility(Card card, String manaString) { - super(Zone.ALL, null); - name = KEYWORD; - this.addDashCost(manaString); + public DashAbility(String manaString) { + super(KEYWORD, REMINDER_TEXT, manaString); Ability ability = new EntersBattlefieldAbility( new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.Custom, false), DashedCondition.instance, "", ""); ability.addEffect(new DashAddDelayedTriggeredAbilityEffect()); ability.setRuleVisible(false); addSubAbility(ability); - } - public DashAbility(final DashAbility ability) { + private DashAbility(final DashAbility ability) { super(ability); - this.alternativeSourceCosts.addAll(ability.alternativeSourceCosts); - this.zoneChangeCounter = ability.zoneChangeCounter; } @Override public DashAbility copy() { return new DashAbility(this); } - - public final AlternativeCost2 addDashCost(String manaString) { - AlternativeCost2 evokeCost = new AlternativeCost2Impl(KEYWORD, REMINDER_TEXT, new ManaCostsImpl(manaString)); - alternativeSourceCosts.add(evokeCost); - return evokeCost; - } - - public void resetDash() { - for (AlternativeCost2 cost : alternativeSourceCosts) { - cost.reset(); - } - zoneChangeCounter = 0; - } - - @Override - public boolean isActivated(Ability ability, Game game) { - Card card = game.getCard(sourceId); - if (card != null - && card.getZoneChangeCounter(game) <= zoneChangeCounter + 1) { - for (AlternativeCost2 cost : alternativeSourceCosts) { - if (cost.isActivated(game)) { - return true; - } - } - } - return false; - } - - @Override - public boolean isAvailable(Ability source, Game game) { - return true; - } - - @Override - public boolean askToActivateAlternativeCosts(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - // we must use the controller of the ability here IE: Hedonist's Trove (play from not own hand when you aren't the owner) - Player player = game.getPlayer(ability.getControllerId()); - if (player != null) { - this.resetDash(); - for (AlternativeCost2 dashCost : alternativeSourceCosts) { - if (dashCost.canPay(ability, this, player.getId(), game) - && player.chooseUse(Outcome.Benefit, KEYWORD - + " the creature for " + dashCost.getText(true) + " ?", ability, game)) { - activateDash(dashCost, game); - ability.getManaCostsToPay().clear(); - ability.getCosts().clear(); - for (Iterator it = ((Costs) dashCost).iterator(); it.hasNext();) { - Cost cost = (Cost) it.next(); - if (cost instanceof ManaCostsImpl) { - ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy()); - } else { - ability.getCosts().add(cost.copy()); - } - } - } - } - } - } - return isActivated(ability, game); - } - - private void activateDash(AlternativeCost2 cost, Game game) { - cost.activate(); - // remember zone change counter - if (zoneChangeCounter == 0) { - Card card = game.getCard(getSourceId()); - if (card != null) { - zoneChangeCounter = card.getZoneChangeCounter(game); - } else { - throw new IllegalArgumentException("Dash source card not found"); - } - } - } - - @Override - public String getRule() { - StringBuilder sb = new StringBuilder(); - int numberCosts = 0; - String remarkText = ""; - for (AlternativeCost2 dashCost : alternativeSourceCosts) { - if (numberCosts == 0) { - sb.append(dashCost.getText(false)); - remarkText = dashCost.getReminderText(); - } else { - sb.append(" and/or ").append(dashCost.getText(true)); - } - ++numberCosts; - } - if (numberCosts == 1) { - sb.append(' ').append(remarkText); - } - - return sb.toString(); - } - - @Override - public String getCastMessageSuffix(Game game) { - StringBuilder sb = new StringBuilder(); - int position = 0; - for (AlternativeCost2 cost : alternativeSourceCosts) { - if (cost.isActivated(game)) { - sb.append(cost.getCastSuffixMessage(position)); - ++position; - } - } - return sb.toString(); - } - - @Override - public Costs getCosts() { - Costs alterCosts = new CostsImpl<>(); - for (AlternativeCost2 aCost : alternativeSourceCosts) { - alterCosts.add(aCost.getCost()); - } - return alterCosts; - } } class DashAddDelayedTriggeredAbilityEffect extends OneShotEffect { - public DashAddDelayedTriggeredAbilityEffect() { + DashAddDelayedTriggeredAbilityEffect() { super(Outcome.Benefit); - this.staticText = "return the dashed creature from the battlefield to its owner's hand"; } - public DashAddDelayedTriggeredAbilityEffect(final DashAddDelayedTriggeredAbilityEffect effect) { + private DashAddDelayedTriggeredAbilityEffect(final DashAddDelayedTriggeredAbilityEffect effect) { super(effect); } @@ -206,16 +60,15 @@ class DashAddDelayedTriggeredAbilityEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - if (game.getPermanentEntering(source.getSourceId()) != null) { - OneShotEffect returnToHandEffect = new ReturnToHandTargetEffect(); - ConditionalOneShotEffect mustBeOnBattlefieldToReturn = new ConditionalOneShotEffect(returnToHandEffect, SourceOnBattlefieldCondition.instance); - mustBeOnBattlefieldToReturn.setText("return the dashed creature from the battlefield to its owner's hand"); - // init target pointer now because the dashed creature will only be returned from battlefield zone (now in entering state so zone change counter is not raised yet) - mustBeOnBattlefieldToReturn.setTargetPointer(new FixedTarget(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId()) + 1)); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(mustBeOnBattlefieldToReturn); - game.addDelayedTriggeredAbility(delayedAbility, source); - return true; + if (game.getPermanentEntering(source.getSourceId()) == null) { + return false; } - return false; + // init target pointer now because the dashed creature will only be returned from battlefield zone (now in entering state so zone change counter is not raised yet) + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new ReturnToHandTargetEffect() + .setText("return the dashed creature from the battlefield to its owner's hand") + .setTargetPointer(new FixedTarget(source.getSourceId(), game.getState().getZoneChangeCounter(source.getSourceId()) + 1)) + ), source); + return true; } } diff --git a/Mage/src/main/java/mage/abilities/keyword/DemonstrateAbility.java b/Mage/src/main/java/mage/abilities/keyword/DemonstrateAbility.java index 36dc9487810..7d1644eeb40 100644 --- a/Mage/src/main/java/mage/abilities/keyword/DemonstrateAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/DemonstrateAbility.java @@ -61,7 +61,7 @@ class DemonstrateEffect extends OneShotEffect { } spell.createCopyOnStack(game, source, source.getControllerId(), true); TargetOpponent target = new TargetOpponent(true); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); if (game.getPlayer(target.getFirstTarget()) != null) { spell.createCopyOnStack(game, source, target.getFirstTarget(), true); } diff --git a/Mage/src/main/java/mage/abilities/keyword/EmbalmAbility.java b/Mage/src/main/java/mage/abilities/keyword/EmbalmAbility.java index 8ba79f0a687..05e20336ec0 100644 --- a/Mage/src/main/java/mage/abilities/keyword/EmbalmAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/EmbalmAbility.java @@ -17,6 +17,8 @@ import mage.game.permanent.token.EmptyToken; import mage.players.Player; import mage.util.CardUtil; +import java.util.stream.Collectors; + /** * @author LevelX2 */ @@ -29,7 +31,6 @@ public class EmbalmAbility extends ActivatedAbilityImpl { addCost(new ExileSourceFromGraveCost()); this.rule = setRule(cost, card); this.timing = TimingRule.SORCERY; - setRule(cost, card); } public EmbalmAbility(final EmbalmAbility ability) { @@ -48,14 +49,14 @@ public class EmbalmAbility extends ActivatedAbilityImpl { } private String setRule(Cost cost, Card card) { - StringBuilder sb = new StringBuilder("Embalm ").append(cost.getText()); - sb.append(" (").append(cost.getText()); - sb.append(", Exile this card from your graveyard: Create a token that's a copy of it, except it's a white Zombie "); - for (SubType subtype : card.getSubtype()) { - sb.append(subtype).append(" "); - } - sb.append(" with no mana cost. Embalm only as a sorcery.)"); - return sb.toString(); + return "Embalm " + cost.getText() + " (" + cost.getText() + ", Exile this card from your graveyard: " + + "Create a token that's a copy of it, except it's a white Zombie " + + card.getSubtype() + .stream() + .map(SubType::getDescription) + .map(s -> s + ' ') + .collect(Collectors.joining()) + + "with no mana cost. Embalm only as a sorcery.)"; } } diff --git a/Mage/src/main/java/mage/abilities/keyword/EmergeAbility.java b/Mage/src/main/java/mage/abilities/keyword/EmergeAbility.java index 8de7be818ff..a0f1d1dd3bf 100644 --- a/Mage/src/main/java/mage/abilities/keyword/EmergeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/EmergeAbility.java @@ -52,7 +52,7 @@ public class EmergeAbility extends SpellAbility { Player controller = game.getPlayer(this.getControllerId()); if (controller != null) { for (Permanent creature : game.getBattlefield().getActivePermanents( - new FilterControlledCreaturePermanent(), this.getControllerId(), this.getSourceId(), game)) { + new FilterControlledCreaturePermanent(), this.getControllerId(), this, game)) { ManaCost costToPay = CardUtil.reduceCost(emergeCost.copy(), creature.getManaValue()); if (costToPay.canPay(this, this, this.getControllerId(), game)) { return ActivationStatus.getTrue(this, game); @@ -66,7 +66,7 @@ public class EmergeAbility extends SpellAbility { @Override public ManaOptions getMinimumCostToActivate(UUID playerId, Game game) { int maxCMC = 0; - for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), playerId, this.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), playerId, this, game)) { int cmc = creature.getManaValue(); if (cmc > maxCMC) { maxCMC = cmc; @@ -88,7 +88,7 @@ public class EmergeAbility extends SpellAbility { Player controller = game.getPlayer(this.getControllerId()); if (controller != null) { TargetPermanent target = new TargetControlledCreaturePermanent(new FilterControlledCreaturePermanent("creature to sacrifice for emerge")); - if (controller.choose(Outcome.Sacrifice, target, this.getSourceId(), game)) { + if (controller.choose(Outcome.Sacrifice, target, this, game)) { Permanent creature = game.getPermanent(target.getFirstTarget()); if (creature != null) { CardUtil.reduceCost(this, creature.getManaValue()); diff --git a/Mage/src/main/java/mage/abilities/keyword/EquipAbility.java b/Mage/src/main/java/mage/abilities/keyword/EquipAbility.java index b108a3b440f..e3004d6d8f1 100644 --- a/Mage/src/main/java/mage/abilities/keyword/EquipAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/EquipAbility.java @@ -3,7 +3,7 @@ package mage.abilities.keyword; import mage.abilities.ActivatedAbilityImpl; import mage.abilities.costs.Cost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.EquipEffect; +import mage.abilities.effects.common.AttachEffect; import mage.constants.Outcome; import mage.constants.TimingRule; import mage.constants.Zone; @@ -39,7 +39,7 @@ public class EquipAbility extends ActivatedAbilityImpl { } public EquipAbility(Outcome outcome, Cost cost, Target target, boolean showAbilityHint) { - super(Zone.BATTLEFIELD, new EquipEffect(outcome), cost); + super(Zone.BATTLEFIELD, new AttachEffect(outcome, "Equip"), cost); this.addTarget(target); this.timing = TimingRule.SORCERY; this.showAbilityHint = showAbilityHint; diff --git a/Mage/src/main/java/mage/abilities/keyword/EternalizeAbility.java b/Mage/src/main/java/mage/abilities/keyword/EternalizeAbility.java index 4d930718fbb..5e51bf619ef 100644 --- a/Mage/src/main/java/mage/abilities/keyword/EternalizeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/EternalizeAbility.java @@ -17,24 +17,24 @@ import mage.game.permanent.token.EmptyToken; import mage.players.Player; import mage.util.CardUtil; +import java.util.stream.Collectors; + /** * @author igoudt */ public class EternalizeAbility extends ActivatedAbilityImpl { - private String rule; + private final String rule; public EternalizeAbility(Cost cost, Card card) { - super(Zone.GRAVEYARD, new EternalizeEffect(), cost); - addCost(new ExileSourceFromGraveCost()); - this.rule = setRule(cost, card); - this.timing = TimingRule.SORCERY; - setRule(cost, card); + this(cost, card, setRule(cost, card)); } public EternalizeAbility(Cost cost, Card card, String rule) { - this(cost, card); + super(Zone.GRAVEYARD, new EternalizeEffect(), cost); + addCost(new ExileSourceFromGraveCost()); this.rule = rule; + this.timing = TimingRule.SORCERY; } public EternalizeAbility(final EternalizeAbility ability) { @@ -52,15 +52,15 @@ public class EternalizeAbility extends ActivatedAbilityImpl { return rule; } - private String setRule(Cost cost, Card card) { - StringBuilder sb = new StringBuilder("Eternalize ").append(cost.getText()); - sb.append(" (").append(cost.getText()); - sb.append(", Exile this card from your graveyard: Create a token that's a copy of it, except it's a 4/4 black Zombie "); - for (SubType subtype : card.getSubtype()) { - sb.append(subtype).append(" "); - } - sb.append(" with no mana cost. Eternalize only as a sorcery.)"); - return sb.toString(); + private static String setRule(Cost cost, Card card) { + return "Eternalize " + cost.getText() + " (" + cost.getText() + ", Exile this card from your graveyard: " + + "Create a token that's a copy of it, except it's a 4/4 black Zombie " + + card.getSubtype() + .stream() + .map(SubType::getDescription) + .map(s -> s + ' ') + .collect(Collectors.joining()) + + "with no mana cost. Eternalize only as a sorcery.)"; } } diff --git a/Mage/src/main/java/mage/abilities/keyword/EvokeAbility.java b/Mage/src/main/java/mage/abilities/keyword/EvokeAbility.java index ebc021e70fb..805cd1e950a 100644 --- a/Mage/src/main/java/mage/abilities/keyword/EvokeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/EvokeAbility.java @@ -1,46 +1,29 @@ package mage.abilities.keyword; import mage.abilities.Ability; -import mage.abilities.SpellAbility; -import mage.abilities.StaticAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.EvokedCondition; -import mage.abilities.costs.*; +import mage.abilities.costs.AlternativeSourceCostsImpl; +import mage.abilities.costs.Cost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.SacrificeSourceEffect; -import mage.cards.Card; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.game.Game; -import mage.players.Player; - -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; /** * @author LevelX2 */ -public class EvokeAbility extends StaticAbility implements AlternativeSourceCosts { +public class EvokeAbility extends AlternativeSourceCostsImpl { protected static final String EVOKE_KEYWORD = "Evoke"; - protected static final String REMINDER_TEXT = "(You may cast this spell for its evoke cost. " - + "If you do, it's sacrificed when it enters the battlefield.)"; - - protected List evokeCosts = new LinkedList<>(); - - // needed to check activation status, if card changes zone after casting it - private int zoneChangeCounter = 0; + protected static final String REMINDER_TEXT = "You may cast this spell for its evoke cost. " + + "If you do, it's sacrificed when it enters the battlefield."; public EvokeAbility(String manaString) { this(new ManaCostsImpl<>(manaString)); } public EvokeAbility(Cost cost) { - super(Zone.ALL, null); - name = EVOKE_KEYWORD; - this.addEvokeCost(cost); + super(EVOKE_KEYWORD, REMINDER_TEXT, cost); Ability ability = new ConditionalInterveningIfTriggeredAbility( new EntersBattlefieldTriggeredAbility(new SacrificeSourceEffect()), EvokedCondition.instance, "Sacrifice {this} when it enters the battlefield and was evoked."); @@ -50,128 +33,10 @@ public class EvokeAbility extends StaticAbility implements AlternativeSourceCost private EvokeAbility(final EvokeAbility ability) { super(ability); - this.evokeCosts.addAll(ability.evokeCosts); - this.zoneChangeCounter = ability.zoneChangeCounter; } @Override public EvokeAbility copy() { return new EvokeAbility(this); } - - public final AlternativeCost2 addEvokeCost(Cost cost) { - AlternativeCost2 evokeCost = new AlternativeCost2Impl<>(EVOKE_KEYWORD, REMINDER_TEXT, cost); - evokeCosts.add(evokeCost); - return evokeCost; - } - - public void resetEvoke() { - for (AlternativeCost2 cost : evokeCosts) { - cost.reset(); - } - zoneChangeCounter = 0; - } - - @Override - public boolean isActivated(Ability ability, Game game) { - Card card = game.getCard(sourceId); - if (card != null - && card.getZoneChangeCounter(game) <= zoneChangeCounter + 1) { - for (AlternativeCost2 cost : evokeCosts) { - if (cost.isActivated(game)) { - return true; - } - } - } - return false; - } - - @Override - public boolean isAvailable(Ability source, Game game) { - return true; - } - - @Override - public boolean askToActivateAlternativeCosts(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - // we must use the controller of the ability here IE: Hedonist's Trove (play from not own hand when you aren't the owner) - Player player = game.getPlayer(ability.getControllerId()); - if (player != null) { - this.resetEvoke(); - for (AlternativeCost2 evokeCost : evokeCosts) { - if (evokeCost.canPay(ability, this, player.getId(), game) - && player.chooseUse(Outcome.Benefit, new StringBuilder(EVOKE_KEYWORD).append(" the creature for ").append(evokeCost.getText(true)).append(" ?").toString(), ability, game)) { - activateEvoke(evokeCost, game); - ability.getManaCostsToPay().clear(); - ability.getCosts().clear(); - for (Iterator it = ((Costs) evokeCost).iterator(); it.hasNext();) { - Cost cost = (Cost) it.next(); - if (cost instanceof ManaCostsImpl) { - ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy()); - } else { - ability.getCosts().add(cost.copy()); - } - } - } - } - } - } - return isActivated(ability, game); - } - - private void activateEvoke(AlternativeCost2 cost, Game game) { - cost.activate(); - // remember zone change counter - if (zoneChangeCounter == 0) { - Card card = game.getCard(getSourceId()); - if (card != null) { - zoneChangeCounter = card.getZoneChangeCounter(game); - } else { - throw new IllegalArgumentException("Evoke source card not found"); - } - } - } - - @Override - public String getRule() { - StringBuilder sb = new StringBuilder(); - int numberCosts = 0; - String remarkText = ""; - for (AlternativeCost2 evokeCost : evokeCosts) { - if (numberCosts == 0) { - sb.append(evokeCost.getText(false)); - remarkText = evokeCost.getReminderText(); - } else { - sb.append(" and/or ").append(evokeCost.getText(true)); - } - ++numberCosts; - } - if (numberCosts == 1) { - sb.append(' ').append(remarkText); - } - - return sb.toString(); - } - - @Override - public String getCastMessageSuffix(Game game) { - StringBuilder sb = new StringBuilder(); - int position = 0; - for (AlternativeCost2 cost : evokeCosts) { - if (cost.isActivated(game)) { - sb.append(cost.getCastSuffixMessage(position)); - ++position; - } - } - return sb.toString(); - } - - @Override - public Costs getCosts() { - Costs alterCosts = new CostsImpl<>(); - for (AlternativeCost2 aCost : evokeCosts) { - alterCosts.add(aCost.getCost()); - } - return alterCosts; - } } diff --git a/Mage/src/main/java/mage/abilities/keyword/ExploitAbility.java b/Mage/src/main/java/mage/abilities/keyword/ExploitAbility.java index b314027b7d9..9f076e5352d 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ExploitAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ExploitAbility.java @@ -72,7 +72,7 @@ class ExploitEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Target target = new TargetPermanent(1, 1, new FilterControlledCreaturePermanent("creature to exploit"), true); - if (target.canChoose(source.getSourceId(), controller.getId(), game)) { + if (target.canChoose(controller.getId(), source, game)) { controller.chooseTarget(Outcome.Sacrifice, target, source, game); Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null ) { diff --git a/Mage/src/main/java/mage/abilities/keyword/FlankingAbility.java b/Mage/src/main/java/mage/abilities/keyword/FlankingAbility.java index 3c7319a71ee..6a46885ee18 100644 --- a/Mage/src/main/java/mage/abilities/keyword/FlankingAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/FlankingAbility.java @@ -34,7 +34,7 @@ public class FlankingAbility extends TriggeredAbilityImpl { Permanent permanent = game.getPermanent(event.getSourceId()); if (permanent != null) { boolean hasFlankingAbility - = permanent.getAbilities().stream().anyMatch(ability -> ability instanceof FlankingAbility); + = permanent.getAbilities().stream().anyMatch(FlankingAbility.class::isInstance); if (!hasFlankingAbility) { for (Effect effect : this.getEffects()) { diff --git a/Mage/src/main/java/mage/abilities/keyword/ForetellAbility.java b/Mage/src/main/java/mage/abilities/keyword/ForetellAbility.java index 8a20a4bb066..8f4d5f26cb5 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ForetellAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ForetellAbility.java @@ -175,7 +175,7 @@ public class ForetellAbility extends SpecialAction { if (affectedControllerId.equals(source.getControllerId())) { Card card = game.getCard(objectId); if (card != null) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject == null) { return false; } diff --git a/Mage/src/main/java/mage/abilities/keyword/FortifyAbility.java b/Mage/src/main/java/mage/abilities/keyword/FortifyAbility.java index 14596029b34..be1b1ea368a 100644 --- a/Mage/src/main/java/mage/abilities/keyword/FortifyAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/FortifyAbility.java @@ -1,20 +1,17 @@ - - package mage.abilities.keyword; +import mage.abilities.ActivatedAbilityImpl; +import mage.abilities.costs.Cost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.common.FortifyEffect; +import mage.abilities.effects.common.AttachEffect; import mage.constants.Outcome; import mage.constants.TimingRule; import mage.constants.Zone; -import mage.abilities.ActivatedAbilityImpl; -import mage.abilities.costs.Cost; -import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.StaticFilters; import mage.target.Target; import mage.target.TargetPermanent; /** - * * @author BetaSteward_at_googlemail.com */ @@ -26,11 +23,11 @@ public class FortifyAbility extends ActivatedAbilityImpl { } public FortifyAbility(Outcome outcome, Cost cost) { - this(outcome, cost, new TargetPermanent(new FilterControlledLandPermanent())); + this(outcome, cost, new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND)); } public FortifyAbility(Outcome outcome, Cost cost, Target target) { - super(Zone.BATTLEFIELD, new FortifyEffect(outcome), cost); + super(Zone.BATTLEFIELD, new AttachEffect(outcome, "Fortify"), cost); this.addTarget(target); this.timing = TimingRule.SORCERY; } @@ -49,4 +46,4 @@ public class FortifyAbility extends ActivatedAbilityImpl { public String getRule() { return "Fortify " + costs.getText() + manaCosts.getText() + " (" + manaCosts.getText() + ": Attach to target land you control. Fortify only as a sorcery.)"; } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/keyword/GravestormAbility.java b/Mage/src/main/java/mage/abilities/keyword/GravestormAbility.java index f4f36701ff5..98dd328dedb 100644 --- a/Mage/src/main/java/mage/abilities/keyword/GravestormAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/GravestormAbility.java @@ -1,4 +1,3 @@ - package mage.abilities.keyword; import mage.MageObjectReference; @@ -10,7 +9,6 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.stack.Spell; import mage.game.stack.StackObject; import mage.watchers.common.GravestormWatcher; @@ -22,6 +20,7 @@ public class GravestormAbility extends TriggeredAbilityImpl { public GravestormAbility() { super(Zone.STACK, new GravestormEffect()); + this.addWatcher(new GravestormWatcher()); } private GravestormAbility(final GravestormAbility ability) { diff --git a/Mage/src/main/java/mage/abilities/keyword/HideawayAbility.java b/Mage/src/main/java/mage/abilities/keyword/HideawayAbility.java index 4cc3f4b1d38..17367db3054 100644 --- a/Mage/src/main/java/mage/abilities/keyword/HideawayAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/HideawayAbility.java @@ -1,28 +1,26 @@ package mage.abilities.keyword; -import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.StaticAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.EntersBattlefieldEffect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.TapSourceEffect; import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; -import mage.constants.AsThoughEffectType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; -import mage.game.ExileZone; import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetCard; +import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.*; /** * @author LevelX2 @@ -35,34 +33,26 @@ import mage.util.CardUtil; * controlled the permanent that exiled this card may look at this card in the * exile zone.'" */ -public class HideawayAbility extends StaticAbility { +public class HideawayAbility extends EntersBattlefieldTriggeredAbility { - public HideawayAbility() { - this("land"); - } + private final int amount; - public HideawayAbility(String name) { - super(Zone.ALL, new EntersBattlefieldEffect(new TapSourceEffect(true))); - Ability ability = new EntersBattlefieldTriggeredAbility(new HideawayExileEffect(), false); - ability.setRuleVisible(false); - addSubAbility(ability); - // Allow controller to look at face down card - ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new HideawayLookAtFaceDownCardEffect()); - ability.setRuleVisible(false); - addSubAbility(ability); - this.name = name; + public HideawayAbility(int amount) { + super(new HideawayExileEffect(amount)); + this.amount = amount; + this.addWatcher(new HideawayWatcher()); } private HideawayAbility(final HideawayAbility ability) { super(ability); - this.name = ability.name; + this.amount = ability.amount; } @Override public String getRule() { - return "Hideaway (This " + this.name + " enters the battlefield tapped. " - + "When it does, look at the top four cards of your library, exile " - + "one face down, then put the rest on the bottom of your library.)"; + return "Hideaway " + this.amount + " (When this permanent enters the battlefield, look at the top " + + CardUtil.numberToText(this.amount) + " cards of your library, exile one face down, " + + "then put the rest on the bottom of your library in a random order.)"; } @Override @@ -73,16 +63,17 @@ public class HideawayAbility extends StaticAbility { class HideawayExileEffect extends OneShotEffect { - private static FilterCard filter1 = new FilterCard("card to exile face down"); + private static final FilterCard filter = new FilterCard("card to exile face down"); + private final int amount; - public HideawayExileEffect() { + HideawayExileEffect(int amount) { super(Outcome.Benefit); - this.staticText = "look at the top four cards of your library, " - + "exile one face down, then put the rest on the bottom of your library"; + this.amount = amount; } - public HideawayExileEffect(final HideawayExileEffect effect) { + private HideawayExileEffect(final HideawayExileEffect effect) { super(effect); + this.amount = effect.amount; } @Override @@ -93,45 +84,36 @@ class HideawayExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - - // LKI is required for this ruling - /* - If Watcher for Tomorrow leaves the battlefield before its - triggered ability from hideaway resolves, its leaves-the-battlefield - ability resolves and does nothing. Then its enters-the-battlefield - ability resolves and you exile a card with no way to return it to your hand. - */ - Permanent hideawaySource = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (hideawaySource == null - || controller == null) { + if (controller == null) { return false; } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 4)); - if (!cards.isEmpty()) { - TargetCard target1 = new TargetCard(Zone.LIBRARY, filter1); - target1.setNotTarget(true); - if (controller.choose(Outcome.Detriment, cards, target1, game)) { - Card card = cards.get(target1.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); - controller.moveCardToExileWithInfo(card, exileId, "Hideaway (" + hideawaySource.getIdName() + ')', source, game, Zone.LIBRARY, false); - card.setFaceDown(true, game); - } - } - controller.putCardsOnBottomOfLibrary(cards, game, source, true); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, amount)); + if (cards.isEmpty()) { + return true; } - + TargetCard target = new TargetCard(Zone.LIBRARY, filter); + target.setNotTarget(true); + controller.choose(Outcome.Detriment, cards, target, game); + Card card = cards.get(target.getFirstTarget(), game); + if (card != null) { + controller.moveCardsToExile( + card, source, game, false, + CardUtil.getExileZoneId(game, source), + "Hideaway (" + CardUtil.getSourceName(game, source) + ')' + ); + game.addEffect(new HideawayLookAtFaceDownCardEffect().setTargetPointer(new FixedTarget(card, game)), source); + card.setFaceDown(true, game); + } + cards.retainZone(Zone.LIBRARY, game); + controller.putCardsOnBottomOfLibrary(cards, game, source, false); return true; } } class HideawayLookAtFaceDownCardEffect extends AsThoughEffectImpl { - public HideawayLookAtFaceDownCardEffect() { + HideawayLookAtFaceDownCardEffect() { super(AsThoughEffectType.LOOK_AT_FACE_DOWN, Duration.EndOfGame, Outcome.Benefit); - staticText = "You may look at the cards exiled with {this}"; } private HideawayLookAtFaceDownCardEffect(final HideawayLookAtFaceDownCardEffect effect) { @@ -150,24 +132,48 @@ class HideawayLookAtFaceDownCardEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (game.getState().getZone(objectId) != Zone.EXILED - || !game.getState().getCardState(objectId).isFaceDown()) { - return false; - } - // TODO: Does not handle if a player had the control of the land permanent some time before - // we would need to add a watcher to handle this - Permanent sourcePermanet = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (sourcePermanet != null && sourcePermanet.isControlledBy(affectedControllerId)) { - ExileZone exile = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); - Card card = game.getCard(objectId); - if (exile != null && exile.contains(objectId) && card != null) { - Player player = game.getPlayer(affectedControllerId); - if (player != null) { - player.lookAtCards("Hideaway by " + sourcePermanet.getIdName(), card, game); - } - } - } - // only the current or a previous controller can see the card, so always return false for reveal request - return false; + return Objects.equals(objectId, getTargetPointer().getFirst(game, source)) + && HideawayWatcher.check(affectedControllerId, source, game); + } +} + +class HideawayWatcher extends Watcher { + + private final Map> morMap = new HashMap<>(); + + HideawayWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + Permanent permanent; + UUID playerId; + switch (event.getType()) { + case GAINED_CONTROL: + permanent = game.getPermanent(event.getTargetId()); + playerId = event.getPlayerId(); + break; + case ENTERS_THE_BATTLEFIELD: + permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + playerId = permanent.getControllerId(); + break; + case BEGINNING_PHASE_PRE: + if (game.getTurnNum() == 1) { + morMap.clear(); + } + default: + return; + } + morMap.computeIfAbsent(new MageObjectReference(permanent, game), x -> new HashSet<>()).add(playerId); + } + + static boolean check(UUID playerId, Ability source, Game game) { + return game + .getState() + .getWatcher(HideawayWatcher.class) + .morMap + .getOrDefault(new MageObjectReference(source), Collections.emptySet()) + .contains(playerId); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/IntimidateAbility.java b/Mage/src/main/java/mage/abilities/keyword/IntimidateAbility.java index 0b4d247a84c..b41f53acae3 100644 --- a/Mage/src/main/java/mage/abilities/keyword/IntimidateAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/IntimidateAbility.java @@ -13,12 +13,14 @@ import mage.game.permanent.Permanent; *

* 702.13a Intimidate is an evasion ability. *

- * 702.13b A creature with intimidate can't be blocked except by artifact creatures - * and/or creatures that share a color with it. (See rule 509, "Declare Blockers Step.") # + * 702.13b A creature with intimidate can't be blocked except by artifact + * creatures and/or creatures that share a color with it. (See rule 509, + * "Declare Blockers Step.") # *

* 702.13c Multiple instances of intimidate on the same creature are redundant. */ public class IntimidateAbility extends EvasionAbility implements MageSingleton { + private static final IntimidateAbility instance = new IntimidateAbility(); public static IntimidateAbility getInstance() { @@ -31,7 +33,7 @@ public class IntimidateAbility extends EvasionAbility implements MageSingleton { @Override public String getRule() { - return "intimidate"; + return "intimidate (This creature can't be blocked except by artifact creatures and/or creatures that share a color with it.)"; } @Override @@ -41,6 +43,7 @@ public class IntimidateAbility extends EvasionAbility implements MageSingleton { } class IntimidateEffect extends RestrictionEffect implements MageSingleton { + public IntimidateEffect() { super(Duration.EndOfGame); } diff --git a/Mage/src/main/java/mage/abilities/keyword/LandwalkAbility.java b/Mage/src/main/java/mage/abilities/keyword/LandwalkAbility.java index 32bd473d13d..2436c9d6fcb 100644 --- a/Mage/src/main/java/mage/abilities/keyword/LandwalkAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/LandwalkAbility.java @@ -64,7 +64,7 @@ class LandwalkEffect extends RestrictionEffect { @Override public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { - if (game.getBattlefield().contains(filter, source.getSourceId(), blocker.getControllerId(), game, 1) + if (game.getBattlefield().contains(filter, source.getSourceId(), blocker.getControllerId(), source, game, 1) && null == game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_LANDWALK, null, blocker.getControllerId(), game)) { switch (filter.getMessage()) { case "plains": diff --git a/Mage/src/main/java/mage/abilities/keyword/LevelerCardBuilder.java b/Mage/src/main/java/mage/abilities/keyword/LevelerCardBuilder.java index 7158bd8ce37..697718d6d46 100644 --- a/Mage/src/main/java/mage/abilities/keyword/LevelerCardBuilder.java +++ b/Mage/src/main/java/mage/abilities/keyword/LevelerCardBuilder.java @@ -1,8 +1,5 @@ - package mage.abilities.keyword; -import java.util.ArrayList; -import java.util.List; import mage.abilities.Abilities; import mage.abilities.AbilitiesImpl; import mage.abilities.Ability; @@ -18,10 +15,14 @@ import mage.constants.SubLayer; import mage.constants.Zone; import mage.counters.CounterType; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + /** * The implementation by BetaSteward was discarded as requires special handling * in Mage.Core. - * + *

* Instead it was replaced by conditional continuous effects and builder * pattern. * @@ -181,19 +182,24 @@ public class LevelerCardBuilder { } public String getRule() { - StringBuilder sb = new StringBuilder(); - sb.append("Level ").append(level1); + StringBuilder sb = new StringBuilder("LEVEL "); + sb.append(level1); if (level2 == -1) { sb.append('+'); } else { - sb.append('-').append(level2); + sb.append('-'); + sb.append(level2); } - sb.append(": ").append(power).append('/').append(toughness).append(' '); - for (String rule : abilities.getRules("{this}")) { - sb.append(rule).append(' '); + sb.append("
"); + sb.append(power); + sb.append('/'); + sb.append(toughness); + List abilityText = abilities.getRules("{this}"); + if (!abilityText.isEmpty()) { + sb.append("
"); + sb.append(abilityText.stream().collect(Collectors.joining("
"))); } return sb.toString(); } - } } diff --git a/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java b/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java index 65a9352d671..509739bf113 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MadnessAbility.java @@ -1,11 +1,13 @@ package mage.abilities.keyword; +import mage.ApprovingObject; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.StaticAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.condition.Condition; +import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.effects.OneShotEffect; @@ -20,7 +22,6 @@ import mage.game.stack.Spell; import mage.players.Player; import java.util.UUID; -import mage.ApprovingObject; /** * 702.33. Madness @@ -52,14 +53,28 @@ public class MadnessAbility extends StaticAbility { private final String rule; - @SuppressWarnings("unchecked") - public MadnessAbility(Card card, ManaCosts madnessCost) { - super(Zone.HAND, new MadnessReplacementEffect((ManaCosts) madnessCost)); - addSubAbility(new MadnessTriggeredAbility((ManaCosts) madnessCost, getOriginalId())); - rule = "Madness " + madnessCost.getText() + " (If you discard this card, discard it into exile. When you do, cast it for its madness cost or put it into your graveyard.)"; + public MadnessAbility(ManaCosts madnessCost) { + this(madnessCost, 0); } - public MadnessAbility(final MadnessAbility ability) { + public MadnessAbility(ManaCosts madnessCost, int lifeCost) { + super(Zone.HAND, new MadnessReplacementEffect(madnessCost, lifeCost)); + addSubAbility(new MadnessTriggeredAbility(madnessCost, lifeCost, getOriginalId())); + + String costText; + + if (lifeCost > 0) { + costText = "Madness—" + madnessCost.getText() + ", Pay " + lifeCost + " life."; + } else { + costText = "Madness " + madnessCost.getText(); + } + + this.rule = costText + " (If you discard this card, discard it into exile. " + + "When you do, cast it for its madness cost or put it into your graveyard.)"; + } + + + private MadnessAbility(final MadnessAbility ability) { super(ability); this.rule = ability.rule; } @@ -81,12 +96,21 @@ public class MadnessAbility extends StaticAbility { class MadnessReplacementEffect extends ReplacementEffectImpl { - public MadnessReplacementEffect(ManaCosts madnessCost) { + public MadnessReplacementEffect(ManaCosts madnessCost, int lifeCost) { super(Duration.EndOfGame, Outcome.Benefit); - staticText = "Madness " + madnessCost.getText() + " (If you discard this card, you may cast it for its madness cost instead of putting it into your graveyard.)"; + + String costText; + + if (lifeCost > 0) { + costText = "Madness—" + madnessCost.getText() + ", Pay " + lifeCost + " life."; + } else { + costText = "Madness " + madnessCost.getText(); + } + + staticText = costText + " (If you discard this card, you may cast it for its madness cost instead of putting it into your graveyard.)"; } - public MadnessReplacementEffect(final MadnessReplacementEffect effect) { + private MadnessReplacementEffect(final MadnessReplacementEffect effect) { super(effect); } @@ -103,18 +127,23 @@ class MadnessReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Card card = game.getCard(event.getTargetId()); - if (card != null) { - if (controller.moveCardToExileWithInfo(card, source.getSourceId(), "Madness", source, game, ((ZoneChangeEvent) event).getFromZone(), true)) { - game.applyEffects(); // needed to add Madness ability to cards (e.g. by Falkenrath Gorger) - GameEvent gameEvent = new MadnessCardExiledEvent(card.getId(), source, controller.getId()); - game.fireEvent(gameEvent); - } - return true; - } + if (controller == null) { + return false; } - return false; + + Card card = game.getCard(event.getTargetId()); + if (card == null) { + return false; + } + + // TODO, deal with deprecated call + if (controller.moveCards(card, Zone.EXILED, source, game)) { + game.applyEffects(); // needed to add Madness ability to cards (e.g. by Falkenrath Gorger) + GameEvent gameEvent = new MadnessCardExiledEvent(card.getId(), source, controller.getId()); + game.fireEvent(gameEvent); + } + + return true; } @Override @@ -125,7 +154,8 @@ class MadnessReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { return event.getTargetId().equals(source.getSourceId()) - && ((ZoneChangeEvent) event).getFromZone() == Zone.HAND && ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD; + && ((ZoneChangeEvent) event).getFromZone() == Zone.HAND + && ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD; } } @@ -138,13 +168,13 @@ class MadnessTriggeredAbility extends TriggeredAbilityImpl { private final UUID madnessOriginalId; - MadnessTriggeredAbility(ManaCosts madnessCost, UUID madnessOriginalId) { - super(Zone.EXILED, new MadnessCastEffect(madnessCost), true); + MadnessTriggeredAbility(ManaCosts madnessCost, int lifeCost, UUID madnessOriginalId) { + super(Zone.EXILED, new MadnessCastEffect(madnessCost, lifeCost), true); this.madnessOriginalId = madnessOriginalId; this.setRuleVisible(false); } - MadnessTriggeredAbility(final MadnessTriggeredAbility ability) { + private MadnessTriggeredAbility(final MadnessTriggeredAbility ability) { super(ability); this.madnessOriginalId = ability.madnessOriginalId; } @@ -161,44 +191,67 @@ class MadnessTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return event.getSourceId().equals(madnessOriginalId); // Check that the event was from the connected replacement effect + // Check that the event was from the connected replacement effect + return event.getSourceId().equals(madnessOriginalId); } @Override public boolean resolve(Game game) { - if (!super.resolve(game)) { - Card card = game.getCard(getSourceId()); - if (card != null) { - Player owner = game.getPlayer(card.getOwnerId()); - if (owner != null) { - // if cast was not successfull, the card is moved to graveyard - owner.moveCards(card, Zone.GRAVEYARD, this, game); - } - } + if (super.resolve(game)) { + return true; + } + + Card card = game.getCard(getSourceId()); + if (card == null) { return false; } - return true; + + Player owner = game.getPlayer(card.getOwnerId()); + if (owner == null) { + return false; + } + + // if cast was not successfull, the card is moved to graveyard + owner.moveCards(card, Zone.GRAVEYARD, this, game); + return false; } @Override public String getTriggerPhrase() { - return "When this card is exiled this way, " ; + return "When this card is exiled this way, "; } } class MadnessCastEffect extends OneShotEffect { private final ManaCosts madnessCost; + private final int lifeCost; - public MadnessCastEffect(ManaCosts madnessCost) { + public MadnessCastEffect(ManaCosts madnessCost, int lifeCost) { super(Outcome.Benefit); this.madnessCost = madnessCost; - staticText = "you may cast it by paying " + madnessCost.getText() + " instead of putting it into your graveyard"; + this.lifeCost = lifeCost; + + String costText; + + if (lifeCost > 0) { + costText = madnessCost.getText() + " and " + lifeCost + " life"; + } else { + costText = madnessCost.getText(); + } + + staticText = "you may cast it by paying " + costText + " instead of putting it into your graveyard"; } - public MadnessCastEffect(final MadnessCastEffect effect) { + private MadnessCastEffect(final MadnessCastEffect effect) { super(effect); this.madnessCost = effect.madnessCost; + this.lifeCost = effect.lifeCost; + } + + @Override + public MadnessCastEffect copy() { + return new MadnessCastEffect(this); } @Override @@ -213,19 +266,17 @@ class MadnessCastEffect extends OneShotEffect { return false; } - // replace with the new cost + // Replace with the new cost SpellAbility castByMadness = card.getSpellAbility().copy(); ManaCosts costRef = castByMadness.getManaCostsToPay(); castByMadness.setSpellAbilityType(SpellAbilityType.BASE_ALTERNATE); castByMadness.setSpellAbilityCastMode(SpellAbilityCastMode.MADNESS); + castByMadness.getCosts().clear(); + castByMadness.addCost(new PayLifeCost(this.lifeCost)); costRef.clear(); costRef.add(madnessCost); - return owner.cast(castByMadness, game, false, new ApprovingObject(source, game)); - } - @Override - public MadnessCastEffect copy() { - return new MadnessCastEffect(this); + return owner.cast(castByMadness, game, false, new ApprovingObject(source, game)); } } @@ -236,12 +287,14 @@ enum MadnessCondition implements Condition { @Override public boolean apply(Game game, Ability source) { MageObject madnessSpell = game.getLastKnownInformation(source.getSourceId(), Zone.STACK, source.getSourceObjectZoneChangeCounter() - 1); - if (madnessSpell instanceof Spell) { - if (((Spell) madnessSpell).getSpellAbility() != null) { - return ((Spell) madnessSpell).getSpellAbility().getSpellAbilityCastMode() == SpellAbilityCastMode.MADNESS; - } + if (!(madnessSpell instanceof Spell)) { + return false; } - return false; - } + if (((Spell) madnessSpell).getSpellAbility() == null) { + return false; + } + + return ((Spell) madnessSpell).getSpellAbility().getSpellAbilityCastMode() == SpellAbilityCastMode.MADNESS; + } } diff --git a/Mage/src/main/java/mage/abilities/keyword/MenaceAbility.java b/Mage/src/main/java/mage/abilities/keyword/MenaceAbility.java index 412c98d48cb..b83cb1b1875 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MenaceAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MenaceAbility.java @@ -9,7 +9,7 @@ import mage.constants.Zone; */ public class MenaceAbility extends StaticAbility { // Menace may not be a Singleton because the source ability is needed in the continuous effect - private boolean showAbilityHint = true; + private final boolean showAbilityHint; public MenaceAbility() { this(true); diff --git a/Mage/src/main/java/mage/abilities/keyword/MentorAbility.java b/Mage/src/main/java/mage/abilities/keyword/MentorAbility.java index 6cfe91e6e9e..6dd3e873096 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MentorAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MentorAbility.java @@ -50,7 +50,7 @@ enum MentorAbilityPredicate implements ObjectSourcePlayerPredicate { @Override public boolean apply(ObjectSourcePlayer input, Game game) { - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(input.getSourceId()); + Permanent sourcePermanent = input.getSource().getSourcePermanentOrLKI(game); return sourcePermanent != null && input.getObject().getPower().getValue() < sourcePermanent.getPower().getValue(); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java b/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java index e853ad0ec39..3ce967fba16 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java @@ -1,42 +1,33 @@ package mage.abilities.keyword; -import java.util.Iterator; import mage.MageObject; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.StaticAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.AlternativeCost2Impl; -import mage.abilities.costs.AlternativeSourceCosts; +import mage.abilities.costs.AlternativeSourceCostsImpl; import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; import mage.abilities.costs.CostsImpl; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCost; -import mage.abilities.costs.mana.ManaCosts; import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect; import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect.FaceDownType; -import mage.cards.Card; -import mage.constants.AbilityType; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Rarity; -import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.stack.Spell; -import mage.players.Player; /** * 702.36. Morph - * + *

* 702.36a Morph is a static ability that functions in any zone from which you * could play the card it’s on, and the morph effect works any time the card is * face down. "Morph [cost]" means "You may cast this card as a 2/2 face-down * creature, with no text, no name, no subtypes, and no mana cost by paying {3} * rather than paying its mana cost." (See rule 707, "Face-Down Spells and * Permanents.") - * + *

* 702.36b To cast a card using its morph ability, turn it face down. It becomes * a 2/2 face-down creature card, with no text, no name, no subtypes, and no * mana cost. Any effects or prohibitions that would apply to casting a card @@ -50,9 +41,9 @@ import mage.players.Player; * spell resolves, it enters the battlefield with the same characteristics the * spell had. The morph effect applies to the face-down object wherever it is, * and it ends when the permanent is turned face up. # - * + *

* 702.36c You can't cast a card face down if it doesn't have morph. - * + *

* 702.36d If you have priority, you may turn a face-down permanent you control * face up. This is a special action; it doesn't use the stack (see rule 115). * To do this, show all players what the permanent’s morph cost would be if it @@ -62,223 +53,84 @@ import mage.players.Player; * characteristics. Any abilities relating to the permanent entering the * battlefield don’t trigger when it’s turned face up and don’t have any effect, * because the permanent has already entered the battlefield. - * + *

* 702.36e See rule 707, "Face-Down Spells and Permanents," for more information * on how to cast cards with morph. * * @author LevelX2 */ -public class MorphAbility extends StaticAbility implements AlternativeSourceCosts { +public class MorphAbility extends AlternativeSourceCostsImpl { protected static final String ABILITY_KEYWORD = "Morph"; protected static final String ABILITY_KEYWORD_MEGA = "Megamorph"; - protected static final String REMINDER_TEXT = "(You may cast this card face down as a " - + "2/2 creature for {3}. Turn it face up any time for its morph cost.)"; - protected static final String REMINDER_TEXT_MEGA = "(You may cast this card face down " + protected static final String REMINDER_TEXT = "You may cast this card face down as a " + + "2/2 creature for {3}. Turn it face up any time for its morph cost."; + protected static final String REMINDER_TEXT_MEGA = "You may cast this card face down " + "as a 2/2 creature for {3}. Turn it face up any time for its megamorph " - + "cost and put a +1/+1 counter on it.)"; - protected String ruleText; - protected AlternativeCost2Impl alternateCosts = new AlternativeCost2Impl( - ABILITY_KEYWORD, REMINDER_TEXT, new GenericManaCost(3)); + + "cost and put a +1/+1 counter on it."; protected Costs morphCosts; // needed to check activation status, if card changes zone after casting it - private int zoneChangeCounter = 0; - private boolean megamorph; + private final boolean megamorph; - public MorphAbility(Card card, Cost morphCost) { - this(card, createCosts(morphCost)); + public MorphAbility(Cost morphCost) { + this(morphCost, false); } - public MorphAbility(Card card, Cost morphCost, boolean megamorph) { - this(card, createCosts(morphCost), megamorph); - } - - public MorphAbility(Card card, Costs morphCosts) { - this(card, morphCosts, false); - } - - public MorphAbility(Card card, Costs morphCosts, boolean megamorph) { - super(Zone.HAND, null); - this.morphCosts = morphCosts; + public MorphAbility(Cost morphCost, boolean megamorph) { + super(megamorph ? ABILITY_KEYWORD_MEGA : ABILITY_KEYWORD, megamorph ? REMINDER_TEXT_MEGA : REMINDER_TEXT, new GenericManaCost(3)); + this.morphCosts = new CostsImpl<>(); + this.morphCosts.add(morphCost); this.megamorph = megamorph; this.setWorksFaceDown(true); - StringBuilder sb = new StringBuilder(); - if (megamorph) { - sb.append(ABILITY_KEYWORD_MEGA).append(' '); - } else { - sb.append(ABILITY_KEYWORD).append(' '); - } - name = ABILITY_KEYWORD; - for (Cost cost : morphCosts) { - if (!(cost instanceof ManaCosts)) { - sb.setLength(sb.length() - 1); - sb.append("—"); - break; - } - } - sb.append(morphCosts.getText()); - if (!(morphCosts.get(morphCosts.size() - 1) instanceof ManaCosts)) { - sb.append('.'); - } - sb.append(' '); - if (megamorph) { - sb.append(REMINDER_TEXT_MEGA); - } else { - sb.append(REMINDER_TEXT); - } - - ruleText = sb.toString(); - - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BecomesFaceDownCreatureEffect( + Ability ability = new SimpleStaticAbility(new BecomesFaceDownCreatureEffect( morphCosts, (megamorph ? FaceDownType.MEGAMORPHED : FaceDownType.MORPHED))); ability.setWorksFaceDown(true); ability.setRuleVisible(false); addSubAbility(ability); - } public MorphAbility(final MorphAbility ability) { super(ability); - this.zoneChangeCounter = ability.zoneChangeCounter; - this.ruleText = ability.ruleText; - this.alternateCosts = ability.alternateCosts.copy(); this.morphCosts = ability.morphCosts; // can't be changed this.megamorph = ability.megamorph; } - private static Costs createCosts(Cost cost) { - Costs costs = new CostsImpl<>(); - costs.add(cost); - return costs; - } - @Override public MorphAbility copy() { return new MorphAbility(this); } - public void resetMorph() { - alternateCosts.reset(); - zoneChangeCounter = 0; + @Override + public boolean askToActivateAlternativeCosts(Ability ability, Game game) { + switch (ability.getAbilityType()) { + case SPELL: + Spell spell = game.getStack().getSpell(ability.getId()); + if (spell != null) { + spell.setFaceDown(true, game); + if (handleActivatingAlternativeCosts(ability, game)) { + game.getState().setValue("MorphAbility" + ability.getSourceId(), "activated"); + spell.getColor(game).setColor(null); + game.getState().getCreateMageObjectAttribute(spell.getCard(), game).getSubtype().clear(); + } else { + spell.setFaceDown(false, game); + } + } + break; + case PLAY_LAND: + handleActivatingAlternativeCosts(ability, game); + } + return isActivated(ability, game); } public Costs getMorphCosts() { return morphCosts; } - @Override - public boolean isActivated(Ability ability, Game game) { - Card card = game.getCard(sourceId); - if (card != null - && card.getZoneChangeCounter(game) <= zoneChangeCounter + 1) { - return alternateCosts.isActivated(game); - } - return false; - } - - @Override - public boolean isAvailable(Ability source, Game game) { - return true; - } - - @Override - public boolean askToActivateAlternativeCosts(Ability ability, Game game) { - if (ability.getAbilityType() == AbilityType.SPELL) { - Player player = game.getPlayer(ability.getControllerId()); - Spell spell = game.getStack().getSpell(ability.getId()); - if (player != null - && spell != null) { - this.resetMorph(); - spell.setFaceDown(true, game); // so only the back is visible - if (alternateCosts.canPay(ability, this, ability.getControllerId(), game)) { - if (player.chooseUse(Outcome.Benefit, "Cast this card as a 2/2 " - + "face-down creature for " + getCosts().getText() + " ?", ability, game)) { - game.getState().setValue("MorphAbility" - + ability.getSourceId(), "activated"); // Gift of Doom - activateMorph(game); - // change mana costs - ability.getManaCostsToPay().clear(); - ability.getCosts().clear(); - for (Iterator it = this.alternateCosts.iterator(); it.hasNext();) { - Cost cost = (Cost) it.next(); - if (cost instanceof ManaCost) { - ability.getManaCostsToPay().add((ManaCost) cost.copy()); - } else { - ability.getCosts().add(cost.copy()); - } - } - // change spell colors and subtype *TODO probably this needs to be done by continuous effect (while on the stack) - ObjectColor spellColor = spell.getColor(game); - spellColor.setBlack(false); - spellColor.setRed(false); - spellColor.setGreen(false); - spellColor.setWhite(false); - spellColor.setBlue(false); - game.getState().getCreateMageObjectAttribute(spell.getCard(), game).getSubtype().clear(); - } else { - spell.setFaceDown(false, game); - } - } - } - } - if (ability.getAbilityType() == AbilityType.PLAY_LAND) { - Player player = game.getPlayer(ability.getControllerId()); - if (player != null) { - this.resetMorph(); - if (alternateCosts.canPay(ability, this, ability.getControllerId(), game)) { - if (player.chooseUse(Outcome.Benefit, "Cast this card as a 2/2 " - + "face-down creature for " + getCosts().getText() + " ?", ability, game)) { - activateMorph(game); - // change mana costs - ability.getManaCostsToPay().clear(); - ability.getCosts().clear(); - for (Iterator it = this.alternateCosts.iterator(); it.hasNext();) { - Cost cost = (Cost) it.next(); - if (cost instanceof ManaCost) { - ability.getManaCostsToPay().add((ManaCost) cost.copy()); - } else { - ability.getCosts().add(cost.copy()); - } - } - } - } - } - } - return isActivated(ability, game); - } - - private void activateMorph(Game game) { - alternateCosts.activate(); - // remember zone change counter - if (zoneChangeCounter == 0) { - Card card = game.getCard(getSourceId()); - if (card != null) { - zoneChangeCounter = card.getZoneChangeCounter(game); - } else { - throw new IllegalArgumentException("Morph source card not found"); - } - } - } - - @Override - public String getRule(boolean all) { - return getRule(); - } - @Override public String getRule() { - return ruleText; - } - - @Override - public String getCastMessageSuffix(Game game) { - return alternateCosts.getCastSuffixMessage(0); - } - - @Override - @SuppressWarnings({"unchecked"}) - public Costs getCosts() { - return alternateCosts; + boolean isMana = morphCosts.get(0) instanceof ManaCost; + return alternativeCost.getName() + (isMana ? " " : "—") + + morphCosts.getText() + (isMana ? ' ' : ". ") + alternativeCost.getReminderText(); } public static void setPermanentToFaceDownCreature(MageObject mageObject, Game game) { @@ -296,6 +148,5 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost ((Permanent) mageObject).setExpansionSetCode(""); ((Permanent) mageObject).setRarity(Rarity.SPECIAL); } - } } diff --git a/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java b/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java index 0a43464b9dc..9032e9f5098 100644 --- a/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java @@ -148,7 +148,7 @@ class ReturnAttackerToHandTargetCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { - if (targets.choose(Outcome.ReturnToHand, controllerId, source.getSourceId(), game)) { + if (targets.choose(Outcome.ReturnToHand, controllerId, source.getSourceId(), source, game)) { for (UUID targetId : targets.get(0).getTargets()) { Permanent permanent = game.getPermanent(targetId); Player controller = game.getPlayer(controllerId); @@ -165,7 +165,7 @@ class ReturnAttackerToHandTargetCost extends CostImpl { @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - return targets.canChoose(source.getSourceId(), controllerId, game); + return targets.canChoose(controllerId, source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/keyword/OfferingAbility.java b/Mage/src/main/java/mage/abilities/keyword/OfferingAbility.java index ed88abc7aaf..ad13d488752 100644 --- a/Mage/src/main/java/mage/abilities/keyword/OfferingAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/OfferingAbility.java @@ -95,7 +95,7 @@ public class OfferingAbility extends StaticAbility implements AlternateManaPayme ManaOptions additionalManaOptionsForThisAbility = new ManaOptions(); // Creatures from the offerd type - game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game) + game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game) .stream() .map(Card::getSpellAbility) .filter(Objects::nonNull) @@ -164,7 +164,7 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl { game.getState().setValue("offering_Id_" + card.getId(), null); } - if (game.getBattlefield().count(((OfferingAbility) source).getFilter(), source.getSourceId(), source.getControllerId(), game) > 0) { + if (game.getBattlefield().count(((OfferingAbility) source).getFilter(), source.getControllerId(), source, game) > 0) { if (game.inCheckPlayableState()) { return true; diff --git a/Mage/src/main/java/mage/abilities/keyword/PersistAbility.java b/Mage/src/main/java/mage/abilities/keyword/PersistAbility.java index adf31aceaf7..3f0aabeaf5a 100644 --- a/Mage/src/main/java/mage/abilities/keyword/PersistAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/PersistAbility.java @@ -47,7 +47,7 @@ public class PersistAbility extends DiesSourceTriggeredAbility { @Override public String getRule() { - return "Persist (When this creature dies, if it had no -1/-1 counters on it, return it to the battlefield under its owner's control with a -1/-1 counter on it.)"; + return "persist (When this creature dies, if it had no -1/-1 counters on it, return it to the battlefield under its owner's control with a -1/-1 counter on it.)"; } } diff --git a/Mage/src/main/java/mage/abilities/keyword/ProtectionAbility.java b/Mage/src/main/java/mage/abilities/keyword/ProtectionAbility.java index 8715c2072a1..835f133f7cd 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ProtectionAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ProtectionAbility.java @@ -15,7 +15,6 @@ import mage.game.stack.StackObject; import mage.players.Player; import mage.util.CardUtil; -import java.util.List; import java.util.UUID; import java.util.stream.Collectors; @@ -88,9 +87,9 @@ public class ProtectionAbility extends StaticAbility { if (filter instanceof FilterCard) { if (source instanceof Permanent) { - return !((FilterCard) filter).match((Card) source, getSourceId(), ((Permanent) source).getControllerId(), game); + return !((FilterCard) filter).match((Card) source, ((Permanent) source).getControllerId(), this, game); } else if (source instanceof Card) { - return !((FilterCard) filter).match((Card) source, getSourceId(), ((Card) source).getOwnerId(), game); + return !((FilterCard) filter).match((Card) source, ((Card) source).getOwnerId(), this, game); } return true; } @@ -126,7 +125,7 @@ public class ProtectionAbility extends StaticAbility { } else if (source instanceof Card) { player = game.getPlayer(((Card) source).getOwnerId()); } - return !((FilterPlayer) filter).match(player, getSourceId(), this.getControllerId(), game); + return !((FilterPlayer) filter).match(player, this.getControllerId(), this, game); } return true; diff --git a/Mage/src/main/java/mage/abilities/keyword/ProwlAbility.java b/Mage/src/main/java/mage/abilities/keyword/ProwlAbility.java index d145363f498..7973850eeea 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ProwlAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ProwlAbility.java @@ -1,23 +1,13 @@ package mage.abilities.keyword; import mage.abilities.Ability; -import mage.abilities.SpellAbility; -import mage.abilities.StaticAbility; import mage.abilities.condition.common.ProwlCondition; -import mage.abilities.costs.*; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.AlternativeSourceCostsImpl; import mage.abilities.hint.common.ProwlHint; import mage.cards.Card; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.game.Game; -import mage.players.Player; import mage.watchers.common.ProwlWatcher; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - /** * 702.74. Prowl # *

@@ -30,26 +20,21 @@ import java.util.List; * * @author LevelX2 */ -public class ProwlAbility extends StaticAbility implements AlternativeSourceCosts { +public class ProwlAbility extends AlternativeSourceCostsImpl { private static final String PROWL_KEYWORD = "Prowl"; - private final List prowlCosts = new LinkedList<>(); - private String reminderText; + private static final String reminderText = "You may cast this for its prowl cost if you dealt combat damage to a " + + "player this turn with a creature that shared a creature type with {this}"; public ProwlAbility(Card card, String manaString) { - super(Zone.ALL, null); + super(PROWL_KEYWORD, reminderText, manaString); this.setRuleAtTheTop(true); - this.name = PROWL_KEYWORD; - this.setReminderText(card); - this.addProwlCost(manaString); this.addWatcher(new ProwlWatcher()); this.addHint(ProwlHint.instance); } - public ProwlAbility(final ProwlAbility ability) { + private ProwlAbility(final ProwlAbility ability) { super(ability); - this.prowlCosts.addAll(ability.prowlCosts); - this.reminderText = ability.reminderText; } @Override @@ -57,112 +42,8 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost return new ProwlAbility(this); } - public final AlternativeCost2 addProwlCost(String manaString) { - AlternativeCost2 prowlCost = new AlternativeCost2Impl(PROWL_KEYWORD, - reminderText, new ManaCostsImpl(manaString)); - prowlCosts.add(prowlCost); - return prowlCost; - } - - public void resetProwl() { - for (AlternativeCost2 cost : prowlCosts) { - cost.reset(); - } - } - - @Override - public boolean isActivated(Ability ability, Game game) { - for (AlternativeCost2 cost : prowlCosts) { - if (cost.isActivated(game)) { - return true; - } - } - return false; - } - @Override public boolean isAvailable(Ability source, Game game) { return ProwlCondition.instance.apply(game, source); } - - @Override - public boolean askToActivateAlternativeCosts(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - Player player = game.getPlayer(ability.getControllerId()); - if (player == null) { - return false; - } - if (ProwlCondition.instance.apply(game, ability)) { - this.resetProwl(); - for (AlternativeCost2 prowlCost : prowlCosts) { - if (prowlCost.canPay(ability, this, ability.getControllerId(), game) - && player.chooseUse(Outcome.Benefit, "Cast for " - + PROWL_KEYWORD + " cost " + prowlCost.getText(true) - + " ?", ability, game)) { - prowlCost.activate(); - ability.getManaCostsToPay().clear(); - ability.getCosts().clear(); - for (Iterator it = ((Costs) prowlCost).iterator(); it.hasNext();) { - Cost cost = (Cost) it.next(); - if (cost instanceof ManaCostsImpl) { - ability.getManaCostsToPay().add((ManaCostsImpl) cost.copy()); - } else { - ability.getCosts().add(cost.copy()); - } - } - } - } - } - } - return isActivated(ability, game); - } - - @Override - public String getRule() { - StringBuilder sb = new StringBuilder(); - int numberCosts = 0; - String remarkText = ""; - for (AlternativeCost2 prowlCost : prowlCosts) { - if (numberCosts == 0) { - sb.append(prowlCost.getText(false)); - remarkText = prowlCost.getReminderText(); - } else { - sb.append(" and/or ").append(prowlCost.getText(true)); - } - ++numberCosts; - } - if (numberCosts == 1) { - sb.append(' ').append(remarkText); - } - - return sb.toString(); - } - - @Override - public String getCastMessageSuffix(Game game) { - StringBuilder sb = new StringBuilder(); - int position = 0; - for (AlternativeCost2 cost : prowlCosts) { - if (cost.isActivated(game)) { - sb.append(cost.getCastSuffixMessage(position)); - ++position; - } - } - return sb.toString(); - } - - private void setReminderText(Card card) { - reminderText - = "(You may cast this for its prowl cost if you dealt combat damage to a " - + "player this turn with a creature that shared a creature type with {this})"; - } - - @Override - public Costs getCosts() { - Costs alterCosts = new CostsImpl<>(); - for (AlternativeCost2 aCost : prowlCosts) { - alterCosts.add(aCost.getCost()); - } - return alterCosts; - } } diff --git a/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java b/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java index f3a6c0f5f37..5898f19bba8 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java @@ -3,22 +3,21 @@ package mage.abilities.keyword; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.Card; +import mage.cards.CardsImpl; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Zone; -import mage.game.ExileZone; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.stack.Spell; import mage.players.Player; - -import java.util.UUID; -import mage.ApprovingObject; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; /** * This ability has no effect by default and will always return false on the @@ -49,7 +48,7 @@ public class ReboundAbility extends SimpleStaticAbility { super(Zone.STACK, new ReboundCastFromHandReplacementEffect()); } - public ReboundAbility(ReboundAbility ability) { + public ReboundAbility(final ReboundAbility ability) { super(ability); } @@ -57,18 +56,22 @@ public class ReboundAbility extends SimpleStaticAbility { public ReboundAbility copy() { return new ReboundAbility(this); } + + @Override + public String getRule() { + return "Rebound (If you cast this spell from your hand, " + + "exile it as it resolves. At the beginning of your next upkeep, " + + "you may cast this card from exile without paying its mana cost.)"; + } } class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { ReboundCastFromHandReplacementEffect() { super(Duration.WhileOnStack, Outcome.Benefit); - this.staticText = "Rebound (If you cast this spell from your hand, " - + "exile it as it resolves. At the beginning of your next upkeep, " - + "you may cast this card from exile without paying its mana cost.)"; } - ReboundCastFromHandReplacementEffect(ReboundCastFromHandReplacementEffect effect) { + private ReboundCastFromHandReplacementEffect(final ReboundCastFromHandReplacementEffect effect) { super(effect); } @@ -84,17 +87,14 @@ class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { // by a spell like Cancel, or because all of its targets are illegal), rebound has no effect. // The spell is simply put into your graveyard. You won’t get to cast it again next turn. // (2010-06-15) - if (((ZoneChangeEvent) event).getFromZone() == Zone.STACK - && ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD - && event.getSourceId() != null - && event.getSourceId().equals(source.getSourceId())) { // if countered the source.sourceId is different or null if it fizzles - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null - && spell.getFromZone() == Zone.HAND) { - return true; - } - } - return false; + if (((ZoneChangeEvent) event).getFromZone() != Zone.STACK + || ((ZoneChangeEvent) event).getToZone() != Zone.GRAVEYARD + || event.getSourceId() == null + || !event.getSourceId().equals(source.getSourceId())) { + return false; + } // if countered the source.sourceId is different or null if it fizzles + Spell spell = game.getStack().getSpell(event.getTargetId()); + return spell != null && spell.getFromZone() == Zone.HAND; } @Override @@ -102,23 +102,19 @@ class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { Spell sourceSpell = game.getStack().getSpell(source.getSourceId()); if (sourceSpell != null && sourceSpell.isCopy()) { return false; - } else { - Card sourceCard = game.getCard(source.getSourceId()); - if (sourceCard != null) { - Player player = game.getPlayer(sourceCard.getOwnerId()); - if (player != null) { - // Add the delayed triggered effect - ReboundEffectCastFromExileDelayedTrigger trigger - = new ReboundEffectCastFromExileDelayedTrigger(source.getSourceId(), source.getSourceId()); - game.addDelayedTriggeredAbility(trigger, source); - - player.moveCardToExileWithInfo(sourceCard, sourceCard.getId(), - player.getName() + " Rebound", source, game, Zone.STACK, true); - return true; - } - } } - return false; + Card sourceCard = game.getCard(source.getSourceId()); + if (sourceCard == null) { + return false; + } + Player player = game.getPlayer(sourceCard.getOwnerId()); + if (player == null) { + return false; + } + // Add the delayed triggered effect + player.moveCardsToExile(sourceCard, source, game, true, null, "Rebound"); + game.addDelayedTriggeredAbility(new ReboundEffectCastFromExileDelayedTrigger(sourceCard, game), source); + return true; } @Override @@ -130,13 +126,11 @@ class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { class ReboundEffectCastFromExileDelayedTrigger extends DelayedTriggeredAbility { - ReboundEffectCastFromExileDelayedTrigger(UUID cardId, UUID sourceId) { - super(new ReboundCastSpellFromExileEffect()); - setSourceId(sourceId); // TODO: WTF?! - this.optional = true; + ReboundEffectCastFromExileDelayedTrigger(Card card, Game game) { + super(new ReboundCastSpellFromExileEffect().setTargetPointer(new FixedTarget(card, game)), Duration.Custom, true, true); } - ReboundEffectCastFromExileDelayedTrigger(ReboundEffectCastFromExileDelayedTrigger ability) { + private ReboundEffectCastFromExileDelayedTrigger(final ReboundEffectCastFromExileDelayedTrigger ability) { super(ability); } @@ -152,7 +146,7 @@ class ReboundEffectCastFromExileDelayedTrigger extends DelayedTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - return MyTurnCondition.instance.apply(game, this); + return game.isActivePlayer(getControllerId()); } @Override @@ -169,41 +163,25 @@ class ReboundEffectCastFromExileDelayedTrigger extends DelayedTriggeredAbility { */ class ReboundCastSpellFromExileEffect extends OneShotEffect { - private static String castFromExileText = "Rebound - You may cast {this} " - + "from exile without paying its mana cost"; - ReboundCastSpellFromExileEffect() { super(Outcome.PlayForFree); - staticText = castFromExileText; } - ReboundCastSpellFromExileEffect(ReboundCastSpellFromExileEffect effect) { + private ReboundCastSpellFromExileEffect(final ReboundCastSpellFromExileEffect effect) { super(effect); } @Override public boolean apply(Game game, Ability source) { - ExileZone zone = game.getExile().getExileZone(source.getSourceId()); - if (zone == null - || zone.isEmpty()) { - return false; - } - Card reboundCard = zone.get(source.getSourceId(), game); Player player = game.getPlayer(source.getControllerId()); - if (player != null - && reboundCard != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + reboundCard.getId(), Boolean.TRUE); - Boolean cardWasCast = player.cast(player.chooseAbilityForCast(reboundCard, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + reboundCard.getId(), null); - return cardWasCast; - } - return false; + Card reboundCard = game.getCard(getTargetPointer().getFirst(game, source)); + return player != null && reboundCard != null && CardUtil.castSpellWithAttributesForFree( + player, source, game, new CardsImpl(reboundCard), StaticFilters.FILTER_CARD + ); } @Override public ReboundCastSpellFromExileEffect copy() { return new ReboundCastSpellFromExileEffect(this); } - } diff --git a/Mage/src/main/java/mage/abilities/keyword/ReconfigureAbility.java b/Mage/src/main/java/mage/abilities/keyword/ReconfigureAbility.java index 15cfaa9a392..61d672923a8 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ReconfigureAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ReconfigureAbility.java @@ -1,7 +1,16 @@ package mage.abilities.keyword; +import mage.abilities.Ability; import mage.abilities.ActivatedAbilityImpl; -import mage.constants.Zone; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledCreaturePermanent; /** * @author TheElk801 @@ -11,9 +20,14 @@ public class ReconfigureAbility extends ActivatedAbilityImpl { private final String manaString; public ReconfigureAbility(String manaString) { - super(Zone.BATTLEFIELD, null); + super(Zone.BATTLEFIELD, new AttachEffect(Outcome.BoostCreature), new ManaCostsImpl<>(manaString)); this.manaString = manaString; - // TODO: Implement this + this.timing = TimingRule.SORCERY; + this.addTarget(new TargetControlledCreaturePermanent()); + this.addSubAbility(new ReconfigureUnattachAbility(manaString)); + Ability ability = new SimpleStaticAbility(new ReconfigureTypeEffect()); + ability.setRuleVisible(false); + this.addSubAbility(ability); } private ReconfigureAbility(final ReconfigureAbility ability) { @@ -31,6 +45,91 @@ public class ReconfigureAbility extends ActivatedAbilityImpl { return "Reconfigure " + manaString + " (" + manaString + ": Attach to target creature you control; " + "or unattach from a creature. Reconfigure only as a sorcery. " + - "While attached, this isn’t a creature.)"; + "While attached, this isn't a creature.)"; + } +} + +class ReconfigureUnattachAbility extends ActivatedAbilityImpl { + + protected ReconfigureUnattachAbility(String manaString) { + super(Zone.BATTLEFIELD, new ReconfigureUnattachEffect(), new ManaCostsImpl<>(manaString)); + this.condition = ReconfigureUnattachAbility::checkForCreature; + this.timing = TimingRule.SORCERY; + this.setRuleVisible(false); + } + + private ReconfigureUnattachAbility(final ReconfigureUnattachAbility ability) { + super(ability); + } + + @Override + public ReconfigureUnattachAbility copy() { + return new ReconfigureUnattachAbility(this); + } + + @Override + public String getRule() { + return super.getRule() + " Activate only if this permanent is attached to a creature and only as a sorcery."; + } + + private static boolean checkForCreature(Game game, Ability source) { + Permanent equipment = source.getSourcePermanentIfItStillExists(game); + if (equipment == null) { + return false; + } + Permanent permanent = game.getPermanent(equipment.getAttachedTo()); + return permanent != null && permanent.isCreature(game); + } +} + +class ReconfigureUnattachEffect extends OneShotEffect { + + ReconfigureUnattachEffect() { + super(Outcome.Benefit); + staticText = "unattach this permanent"; + } + + private ReconfigureUnattachEffect(final ReconfigureUnattachEffect effect) { + super(effect); + } + + @Override + public ReconfigureUnattachEffect copy() { + return new ReconfigureUnattachEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent != null) { + permanent.unattach(game); + } + return true; + } +} + +class ReconfigureTypeEffect extends ContinuousEffectImpl { + + ReconfigureTypeEffect() { + super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); + } + + private ReconfigureTypeEffect(final ReconfigureTypeEffect effect) { + super(effect); + } + + @Override + public ReconfigureTypeEffect copy() { + return new ReconfigureTypeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + if (permanent == null || game.getPermanent(permanent.getAttachedTo()) == null) { + return false; + } + permanent.removeCardType(game, CardType.CREATURE); + return true; } } diff --git a/Mage/src/main/java/mage/abilities/keyword/ReplicateAbility.java b/Mage/src/main/java/mage/abilities/keyword/ReplicateAbility.java index 0e52e0a5e18..fc57cccc528 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ReplicateAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ReplicateAbility.java @@ -30,7 +30,7 @@ public class ReplicateAbility extends StaticAbility implements OptionalAdditiona + " You may choose new targets for the copies."; protected OptionalAdditionalCost additionalCost; - public ReplicateAbility(Card card, String manaString) { + public ReplicateAbility(String manaString) { super(Zone.STACK, null); this.additionalCost = new OptionalAdditionalCostImpl(keywordText, reminderTextMana, new ManaCostsImpl(manaString)); diff --git a/Mage/src/main/java/mage/abilities/keyword/RippleAbility.java b/Mage/src/main/java/mage/abilities/keyword/RippleAbility.java index d1c9ef37cc5..02e51cd8a84 100644 --- a/Mage/src/main/java/mage/abilities/keyword/RippleAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/RippleAbility.java @@ -83,7 +83,7 @@ class RippleEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (player != null) { if (!player.chooseUse(Outcome.Neutral, "Reveal " + rippleNumber + " cards from the top of your library?", source, game)) { return true; //fizzle diff --git a/Mage/src/main/java/mage/abilities/keyword/SoulbondAbility.java b/Mage/src/main/java/mage/abilities/keyword/SoulbondAbility.java index 4cc6e7f4bf2..e606fbffcb9 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SoulbondAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SoulbondAbility.java @@ -136,8 +136,8 @@ class SoulboundEntersSelfEffect extends OneShotEffect { if (controller != null) { TargetControlledPermanent target = new TargetControlledPermanent(filter); target.setNotTarget(true); - if (target.canChoose(permanent.getId(), controller.getId(), game)) { - if (controller.choose(Outcome.Benefit, target, permanent.getId(), game)) { + if (target.canChoose(controller.getId(), source, game)) { + if (controller.choose(Outcome.Benefit, target, source, game)) { Permanent chosen = game.getPermanent(target.getFirstTarget()); if (chosen != null) { chosen.setPairedCard(new MageObjectReference(permanent, game)); diff --git a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java index ea752b29bb5..f3ae5a2748b 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java @@ -126,8 +126,6 @@ public class SuspendAbility extends SpecialAction { public SuspendAbility(int suspend, ManaCost cost, Card card, boolean shortRule) { super(Zone.HAND); this.addCost(cost); - // suspend uses both sorcery/instant timing depends on object, so it checks with object, see canActivate - this.setTiming(TimingRule.SORCERY); this.addEffect(new SuspendExileEffect(suspend)); this.usesStack = false; if (suspend == Integer.MAX_VALUE) { @@ -210,7 +208,14 @@ public class SuspendAbility extends SpecialAction { if (game.getState().getZone(getSourceId()) != Zone.HAND) { return ActivationStatus.getFalse(); } - + // suspend uses card's timing restriction + Card card = game.getCard(getSourceId()); + if (card == null) { + return ActivationStatus.getFalse(); + } + if (!card.getSpellAbility().spellCanBeActivatedRegularlyNow(playerId, game)) { + return ActivationStatus.getFalse(); + } return super.canActivate(playerId, game); } diff --git a/Mage/src/main/java/mage/abilities/keyword/TotemArmorAbility.java b/Mage/src/main/java/mage/abilities/keyword/TotemArmorAbility.java index be6d8b442ae..3d63f2f1100 100644 --- a/Mage/src/main/java/mage/abilities/keyword/TotemArmorAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/TotemArmorAbility.java @@ -1,5 +1,3 @@ - - package mage.abilities.keyword; import mage.abilities.Ability; @@ -24,47 +22,48 @@ import mage.game.permanent.Permanent; */ public class TotemArmorAbility extends SimpleStaticAbility { + public TotemArmorAbility() { super(Zone.BATTLEFIELD, new TotemArmorEffect()); } - public TotemArmorAbility(final TotemArmorAbility ability) { + private TotemArmorAbility(final TotemArmorAbility ability) { super(ability); } @Override - public SimpleStaticAbility copy() { + public TotemArmorAbility copy() { return new TotemArmorAbility(this); } @Override public String getRule() { - return "Totem armor (If enchanted creature would be destroyed, instead remove all damage from it and destroy this Aura.)"; + return "totem armor (If enchanted creature would be destroyed, instead remove all damage from it and destroy this Aura.)"; } } class TotemArmorEffect extends ReplacementEffectImpl { + TotemArmorEffect() { super(Duration.WhileOnBattlefield, Outcome.Benefit); } - TotemArmorEffect(final TotemArmorEffect effect) { + private TotemArmorEffect(final TotemArmorEffect effect) { super(effect); } @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (sourcePermanent != null) { - Permanent equipedPermanent = game.getPermanent(event.getTargetId()); - if (equipedPermanent != null) { - equipedPermanent.removeAllDamage(game); - sourcePermanent.destroy(source, game, false); - return true; - } + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + Permanent enchantedPermanent = game.getPermanent(event.getTargetId()); + if (sourcePermanent == null || enchantedPermanent == null) { + return false; } - return false; + enchantedPermanent.removeAllDamage(game); + sourcePermanent.destroy(source, game, false); + return true; } + @Override public boolean checksEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.DESTROY_PERMANENT; @@ -72,7 +71,7 @@ class TotemArmorEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); return sourcePermanent != null && event.getTargetId().equals(sourcePermanent.getAttachedTo()); } diff --git a/Mage/src/main/java/mage/abilities/keyword/TransformAbility.java b/Mage/src/main/java/mage/abilities/keyword/TransformAbility.java index 8a73bf88808..2990baa62eb 100644 --- a/Mage/src/main/java/mage/abilities/keyword/TransformAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/TransformAbility.java @@ -66,6 +66,7 @@ public class TransformAbility extends SimpleStaticAbility { } permanent.getPower().modifyBaseValue(sourceCard.getPower().getValue()); permanent.getToughness().modifyBaseValue(sourceCard.getToughness().getValue()); + permanent.setStartingLoyalty(sourceCard.getStartingLoyalty()); } public static Card transformCardSpellStatic(Card mainSide, Card otherSide, Game game) { diff --git a/Mage/src/main/java/mage/abilities/keyword/TransmuteAbility.java b/Mage/src/main/java/mage/abilities/keyword/TransmuteAbility.java index da0f50e807b..cc246c48044 100644 --- a/Mage/src/main/java/mage/abilities/keyword/TransmuteAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/TransmuteAbility.java @@ -75,7 +75,7 @@ class TransmuteEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null && controller != null) { FilterCard filter = new FilterCard("card with mana value " + sourceObject.getManaValue()); filter.add(new ManaValuePredicate(ComparisonType.EQUAL_TO, sourceObject.getManaValue())); diff --git a/Mage/src/main/java/mage/abilities/keyword/TributeAbility.java b/Mage/src/main/java/mage/abilities/keyword/TributeAbility.java index bc46c09fd2c..980c93f3c85 100644 --- a/Mage/src/main/java/mage/abilities/keyword/TributeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/TributeAbility.java @@ -5,7 +5,6 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.constants.Outcome; import mage.counters.CounterType; import mage.game.Game; @@ -74,7 +73,7 @@ class TributeEffect extends OneShotEffect { opponentId = game.getOpponents(controller.getId()).iterator().next(); } else { Target target = new TargetOpponent(); - controller.choose(outcome, target, source.getSourceId(), game); + controller.choose(outcome, target, source, game); opponentId = target.getFirstTarget(); } if (opponentId != null) { diff --git a/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java b/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java index 39d26048415..76ab7371156 100644 --- a/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java +++ b/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java @@ -155,7 +155,7 @@ class AnyColorLandsProduceManaEffect extends ManaEffect { return types; } inManaTypeCalculation = true; - List lands = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List lands = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); for (Permanent land : lands) { if (!land.getId().equals(source.getSourceId())) { types.addAll(AnyColorLandsProduceManaAbility.getManaTypesFromPermanent(land, game)); diff --git a/Mage/src/main/java/mage/abilities/mana/AnyColorPermanentTypesManaAbility.java b/Mage/src/main/java/mage/abilities/mana/AnyColorPermanentTypesManaAbility.java index fb8f9e9a1a2..c72bc21b2ed 100644 --- a/Mage/src/main/java/mage/abilities/mana/AnyColorPermanentTypesManaAbility.java +++ b/Mage/src/main/java/mage/abilities/mana/AnyColorPermanentTypesManaAbility.java @@ -189,7 +189,7 @@ class AnyColorPermanentTypesManaEffect extends ManaEffect { ObjectColor permanentColor; - List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); for (Permanent permanent : permanents) { permanentColor = permanent.getColor(game); diff --git a/Mage/src/main/java/mage/abilities/mana/builder/common/InstantOrSorcerySpellManaBuilder.java b/Mage/src/main/java/mage/abilities/mana/builder/common/InstantOrSorcerySpellManaBuilder.java index d2018fe9748..5f52b90ef6a 100644 --- a/Mage/src/main/java/mage/abilities/mana/builder/common/InstantOrSorcerySpellManaBuilder.java +++ b/Mage/src/main/java/mage/abilities/mana/builder/common/InstantOrSorcerySpellManaBuilder.java @@ -43,7 +43,7 @@ class InstantOrSorceryCastManaCondition extends ManaCondition implements Conditi @Override public boolean apply(Game game, Ability source) { if (source instanceof SpellAbility) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); return object != null && object.isInstantOrSorcery(game); } return false; diff --git a/Mage/src/main/java/mage/abilities/mana/conditional/ArtifactCastManaCondition.java b/Mage/src/main/java/mage/abilities/mana/conditional/ArtifactCastManaCondition.java index f41f9f1fc9f..573e130da16 100644 --- a/Mage/src/main/java/mage/abilities/mana/conditional/ArtifactCastManaCondition.java +++ b/Mage/src/main/java/mage/abilities/mana/conditional/ArtifactCastManaCondition.java @@ -18,7 +18,7 @@ public class ArtifactCastManaCondition extends ManaCondition implements Conditio @Override public boolean apply(Game game, Ability source) { if (source instanceof SpellAbility) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object != null && object.isArtifact(game)) { return true; } diff --git a/Mage/src/main/java/mage/abilities/mana/conditional/ConditionalSpellManaBuilder.java b/Mage/src/main/java/mage/abilities/mana/conditional/ConditionalSpellManaBuilder.java index a39e9d95cfa..b9d2ad51193 100644 --- a/Mage/src/main/java/mage/abilities/mana/conditional/ConditionalSpellManaBuilder.java +++ b/Mage/src/main/java/mage/abilities/mana/conditional/ConditionalSpellManaBuilder.java @@ -60,9 +60,9 @@ class SpellCastManaCondition extends ManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { if (source instanceof SpellAbility) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if ((object instanceof StackObject)) { - return filter.match((StackObject) object, source.getSourceId(), source.getControllerId(), game); + return filter.match((StackObject) object, source.getControllerId(), source, game); } // checking mana without real cast @@ -73,7 +73,7 @@ class SpellCastManaCondition extends ManaCondition implements Condition { } else if (object instanceof Commander) { spell = new Spell(((Commander) object).getSourceObject(), (SpellAbility) source, source.getControllerId(), game.getState().getZone(source.getSourceId()), game); } - return filter.match(spell, source.getSourceId(), source.getControllerId(), game); + return filter.match(spell, source.getControllerId(), source, game); } } return false; diff --git a/Mage/src/main/java/mage/abilities/mana/conditional/CreatureCastManaCondition.java b/Mage/src/main/java/mage/abilities/mana/conditional/CreatureCastManaCondition.java index 82bcc479d4c..76a1881a3bb 100644 --- a/Mage/src/main/java/mage/abilities/mana/conditional/CreatureCastManaCondition.java +++ b/Mage/src/main/java/mage/abilities/mana/conditional/CreatureCastManaCondition.java @@ -17,7 +17,7 @@ public class CreatureCastManaCondition extends ManaCondition implements Conditio @Override public boolean apply(Game game, Ability source) { if (source instanceof SpellAbility) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object != null && object.isCreature(game)) { return true; } diff --git a/Mage/src/main/java/mage/abilities/mana/conditional/PlaneswalkerCastManaCondition.java b/Mage/src/main/java/mage/abilities/mana/conditional/PlaneswalkerCastManaCondition.java index 7448b92ad98..c826ff8f0e5 100644 --- a/Mage/src/main/java/mage/abilities/mana/conditional/PlaneswalkerCastManaCondition.java +++ b/Mage/src/main/java/mage/abilities/mana/conditional/PlaneswalkerCastManaCondition.java @@ -18,7 +18,7 @@ public class PlaneswalkerCastManaCondition extends ManaCondition implements Cond @Override public boolean apply(Game game, Ability source) { if (source instanceof SpellAbility) { - MageObject object = game.getObject(source.getSourceId()); + MageObject object = game.getObject(source); if (object != null && object.isPlaneswalker(game)) { return true; } diff --git a/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java b/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java index 5b278552106..0c9a502888d 100644 --- a/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java @@ -1,17 +1,20 @@ package mage.abilities.meta; +import mage.abilities.Ability; import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; +import mage.util.CardUtil; import mage.watchers.Watcher; import java.util.ArrayList; +import java.util.Collections; import java.util.List; -import java.util.Locale; import java.util.UUID; +import java.util.stream.Collectors; /** * A triggered ability that combines several others and triggers whenever one or @@ -25,8 +28,7 @@ import java.util.UUID; public class OrTriggeredAbility extends TriggeredAbilityImpl { private final String ruleTrigger; - private TriggeredAbility[] triggeredAbilities; - private List triggeringAbilities; + private final List triggeredAbilities = new ArrayList<>(); public OrTriggeredAbility(Zone zone, Effect effect, TriggeredAbility... abilities) { this(zone, effect, false, null, abilities); @@ -34,9 +36,8 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl { public OrTriggeredAbility(Zone zone, Effect effect, boolean optional, String ruleTrigger, TriggeredAbility... abilities) { super(zone, effect, optional); - this.triggeredAbilities = abilities; this.ruleTrigger = ruleTrigger; - this.triggeringAbilities = new ArrayList<>(); + Collections.addAll(this.triggeredAbilities, abilities); for (TriggeredAbility ability : triggeredAbilities) { //Remove useless data ability.getEffects().clear(); @@ -45,12 +46,10 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl { public OrTriggeredAbility(OrTriggeredAbility ability) { super(ability); - this.triggeredAbilities = new TriggeredAbility[ability.triggeredAbilities.length]; - for (int i = 0; i < this.triggeredAbilities.length; i++) { - this.triggeredAbilities[i] = ability.triggeredAbilities[i].copy(); - } - this.triggeringAbilities = new ArrayList<>(ability.triggeringAbilities); this.ruleTrigger = ability.ruleTrigger; + for (TriggeredAbility triggeredAbility : ability.triggeredAbilities) { + this.triggeredAbilities.add(triggeredAbility.copy()); + } } @Override @@ -66,10 +65,8 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { boolean toRet = false; - for (int i = 0; i < triggeredAbilities.length; i++) { - TriggeredAbility ability = triggeredAbilities[i]; + for (TriggeredAbility ability : triggeredAbilities) { if (ability.checkEventType(event, game) && ability.checkTrigger(event, game)) { - triggeringAbilities.add(i); toRet = true; } } @@ -86,18 +83,12 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl { if (ruleTrigger != null && !ruleTrigger.isEmpty()) { return ruleTrigger; } - StringBuilder sb = new StringBuilder(); - if (triggeredAbilities[0].getRule().length() > 0) { - sb.append(triggeredAbilities[0].getRule().substring(0, 1).toUpperCase(Locale.ENGLISH)) - .append(triggeredAbilities[0].getRule().substring(1).toLowerCase(Locale.ENGLISH)); - } - - for (int i = 1; i < (triggeredAbilities.length - 1); i++) { - sb.append(triggeredAbilities[i].getRule().toLowerCase(Locale.ENGLISH)); - } - - sb.append(" or ").append(triggeredAbilities[triggeredAbilities.length - 1].getRule().toLowerCase(Locale.ENGLISH)); - return sb.toString(); + return triggeredAbilities + .stream() + .map(Ability::getRule) + .map(CardUtil::getTextWithFirstCharLowerCase) + .map(s -> s.substring(0, s.length() - 2)) + .collect(Collectors.joining(" or ")) + ", "; } @Override @@ -123,5 +114,4 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl { ability.addWatcher(watcher); } } - } diff --git a/Mage/src/main/java/mage/abilities/text/TextPart.java b/Mage/src/main/java/mage/abilities/text/TextPart.java deleted file mode 100644 index 87431fd1d64..00000000000 --- a/Mage/src/main/java/mage/abilities/text/TextPart.java +++ /dev/null @@ -1,26 +0,0 @@ - -package mage.abilities.text; - -import java.io.Serializable; -import java.util.UUID; -import mage.util.Copyable; - -/** - * - * @author LevelX2 - * @param - */ -public interface TextPart extends Serializable, Copyable { - - UUID getId(); - - String getText(); - - E getBaseValue(); - - E getCurrentValue(); - - void replaceWith(E o); - - void reset(); -} diff --git a/Mage/src/main/java/mage/abilities/text/TextPartColor.java b/Mage/src/main/java/mage/abilities/text/TextPartColor.java deleted file mode 100644 index c32527291f1..00000000000 --- a/Mage/src/main/java/mage/abilities/text/TextPartColor.java +++ /dev/null @@ -1,64 +0,0 @@ - -package mage.abilities.text; - -import mage.ObjectColor; - -/** - * - * This implementation is not finished yet. There is no support to also change - * the rules text of an object. - * - * @author LevelX2 - */ -public class TextPartColor extends TextPartImpl { - - private final ObjectColor objectColorBase; - private ObjectColor objectColorCurrent; - - public TextPartColor(ObjectColor objectColor) { - this.objectColorBase = objectColor; - this.objectColorCurrent = objectColor; - } - - public TextPartColor(final TextPartColor textPartColor) { - super(); - this.objectColorBase = textPartColor.objectColorBase; - this.objectColorCurrent = textPartColor.objectColorCurrent; - } - - @Override - public String getText() { - return objectColorCurrent.getDescription(); - } - - @Override - public ObjectColor getCurrentValue() { - return objectColorCurrent; - } - - @Override - public ObjectColor getBaseValue() { - return objectColorBase; - } - - @Override - public void replaceWith(ObjectColor objectColor) { - this.objectColorCurrent = objectColor; - } - - @Override - public void reset() { - this.objectColorCurrent = this.objectColorBase; - } - - @Override - public TextPartColor copy() { - return new TextPartColor(this); - } - - @Override - public String toString() { - return objectColorCurrent.toString(); - } - -} diff --git a/Mage/src/main/java/mage/abilities/text/TextPartImpl.java b/Mage/src/main/java/mage/abilities/text/TextPartImpl.java deleted file mode 100644 index a14b9bb088e..00000000000 --- a/Mage/src/main/java/mage/abilities/text/TextPartImpl.java +++ /dev/null @@ -1,27 +0,0 @@ -package mage.abilities.text; - -import java.util.UUID; - -/** - * - * @author LevelX2 - * @param - */ -public abstract class TextPartImpl implements TextPart { - - private final UUID id; - - public TextPartImpl() { - this.id = UUID.randomUUID(); - } - - public TextPartImpl(final TextPartImpl textPartimpl) { - this.id = textPartimpl.id; - } - - @Override - public UUID getId() { - return id; - } - -} diff --git a/Mage/src/main/java/mage/abilities/text/TextPartSubType.java b/Mage/src/main/java/mage/abilities/text/TextPartSubType.java deleted file mode 100644 index 8335613e7a6..00000000000 --- a/Mage/src/main/java/mage/abilities/text/TextPartSubType.java +++ /dev/null @@ -1,64 +0,0 @@ - -package mage.abilities.text; - -import mage.constants.SubType; - -/** - * This implementation is not finished yet. There is no support to also change - * the rules text of an object. Also all the cards that user subtypes in the - * text have to be updated with the new elements. - * - * @author LevelX2 - */ -public class TextPartSubType extends TextPartImpl { - - private final SubType subTypeBase; - private SubType subTypeCurrent; - - public TextPartSubType(SubType subType) { - this.subTypeBase = subType; - this.subTypeCurrent = subType; - } - - public TextPartSubType(final TextPartSubType textPartSubType) { - super(); - this.subTypeBase = textPartSubType.subTypeBase; - this.subTypeCurrent = textPartSubType.subTypeCurrent; - } - - @Override - public String getText() { - return subTypeCurrent.getDescription(); - } - - @Override - public SubType getCurrentValue() { - return subTypeCurrent; - } - - @Override - public SubType getBaseValue() { - return subTypeBase; - } - - @Override - public void replaceWith(SubType subType) { - this.subTypeCurrent = subType; - } - - @Override - public void reset() { - this.subTypeCurrent = this.subTypeBase; - } - - @Override - public TextPartSubType copy() { - return new TextPartSubType(this); - } - - @Override - public String toString() { - return subTypeCurrent.toString(); - } - -} diff --git a/Mage/src/main/java/mage/cards/AdventureCard.java b/Mage/src/main/java/mage/cards/AdventureCard.java index bc3bab17758..3f556598b9d 100644 --- a/Mage/src/main/java/mage/cards/AdventureCard.java +++ b/Mage/src/main/java/mage/cards/AdventureCard.java @@ -5,6 +5,7 @@ import mage.abilities.AbilitiesImpl; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.constants.CardType; +import mage.constants.SpellAbilityType; import mage.constants.Zone; import mage.game.Game; import mage.game.events.ZoneChangeEvent; @@ -13,7 +14,7 @@ import java.util.List; import java.util.UUID; /** - * @author TheElk801 + * @author phulin */ public abstract class AdventureCard extends CardImpl { @@ -90,13 +91,11 @@ public abstract class AdventureCard extends CardImpl { @Override public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) { - switch (ability.getSpellAbilityType()) { - case ADVENTURE_SPELL: - return this.getSpellCard().cast(game, fromZone, ability, controllerId); - default: - this.getSpellCard().getSpellAbility().setControllerId(controllerId); - return super.cast(game, fromZone, ability, controllerId); + if (ability.getSpellAbilityType() == SpellAbilityType.ADVENTURE_SPELL) { + return this.getSpellCard().cast(game, fromZone, ability, controllerId); } + this.getSpellCard().getSpellAbility().setControllerId(controllerId); + return super.cast(game, fromZone, ability, controllerId); } @Override diff --git a/Mage/src/main/java/mage/cards/AdventureCardSpell.java b/Mage/src/main/java/mage/cards/AdventureCardSpell.java index 6e75792c949..c274c54aa9a 100644 --- a/Mage/src/main/java/mage/cards/AdventureCardSpell.java +++ b/Mage/src/main/java/mage/cards/AdventureCardSpell.java @@ -1,15 +1,10 @@ package mage.cards; /** - * * @author phulin */ -public interface AdventureCardSpell extends Card { +public interface AdventureCardSpell extends SubCard { @Override AdventureCardSpell copy(); - - void setParentCard(AdventureCard card); - - AdventureCard getParentCard(); } diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index a06431ed075..c4b16358daf 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -8,6 +8,7 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.HasSubtypesSourceEffect; import mage.abilities.keyword.ChangelingAbility; import mage.abilities.keyword.FlashbackAbility; +import mage.abilities.keyword.ReconfigureAbility; import mage.abilities.mana.ActivatedManaAbilityImpl; import mage.cards.repository.PluginClassloaderRegistery; import mage.constants.*; @@ -328,12 +329,6 @@ public abstract class CardImpl extends MageObjectImpl implements Card { } } - protected void addAbilities(List abilities) { - for (Ability ability : abilities) { - addAbility(ability); - } - } - protected void addAbility(Ability ability, Watcher watcher) { addAbility(ability); ability.addWatcher(watcher); @@ -549,7 +544,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { removed = true; break; default: - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); logger.fatal("Invalid from zone [" + fromZone + "] for card [" + this.getIdName() + "] source [" + (sourceObject != null ? sourceObject.getName() : "null") + ']'); break; @@ -813,21 +808,35 @@ public abstract class CardImpl extends MageObjectImpl implements Card { @Override public boolean addAttachment(UUID permanentId, Ability source, 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 AttachEvent(objectId, attachment, source))) { - this.attachments.add(permanentId); - attachment.attachTo(objectId, source, game); - game.fireEvent(new AttachedEvent(objectId, attachment, source)); - return true; - } - } + if (permanentId == null + || this.attachments.contains(permanentId) + || permanentId.equals(this.getId())) { + return false; } - return false; + Permanent attachment = game.getPermanent(permanentId); + if (attachment == null) { + attachment = game.getPermanentEntering(permanentId); + } + if (attachment == null) { + return false; + } + if (attachment.hasSubtype(SubType.EQUIPMENT, game) + && (attachment.isCreature(game) + && !attachment.getAbilities(game).containsClass(ReconfigureAbility.class) + || !this.isCreature(game))) { + return false; + } + if (attachment.hasSubtype(SubType.FORTIFICATION, game) + && (attachment.isCreature(game) || !this.isLand(game))) { + return false; + } + if (game.replaceEvent(new AttachEvent(objectId, attachment, source))) { + return false; + } + this.attachments.add(permanentId); + attachment.attachTo(objectId, source, game); + game.fireEvent(new AttachedEvent(objectId, attachment, source)); + return true; } @Override diff --git a/Mage/src/main/java/mage/cards/CardWithHalves.java b/Mage/src/main/java/mage/cards/CardWithHalves.java new file mode 100644 index 00000000000..a37c6c1a6e3 --- /dev/null +++ b/Mage/src/main/java/mage/cards/CardWithHalves.java @@ -0,0 +1,11 @@ +package mage.cards; + +/** + * @author TheElk801 + */ +public interface CardWithHalves extends Card { + + Card getLeftHalfCard(); + + Card getRightHalfCard(); +} diff --git a/Mage/src/main/java/mage/cards/Cards.java b/Mage/src/main/java/mage/cards/Cards.java index 44e0ea223da..d61b1bfea0e 100644 --- a/Mage/src/main/java/mage/cards/Cards.java +++ b/Mage/src/main/java/mage/cards/Cards.java @@ -1,5 +1,6 @@ package mage.cards; +import mage.abilities.Ability; import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; @@ -28,7 +29,7 @@ public interface Cards extends Set, Serializable { Set getCards(FilterCard filter, Game game); - Set getCards(FilterCard filter, UUID sourceId, UUID playerId, Game game); + Set getCards(FilterCard filter, UUID playerId, Ability source, Game game); String getValue(Game game); @@ -40,9 +41,11 @@ public interface Cards extends Set, Serializable { int count(FilterCard filter, UUID playerId, Game game); - int count(FilterCard filter, UUID sourceId, UUID playerId, Game game); + int count(FilterCard filter, UUID playerId, Ability source, Game game); Cards copy(); void retainZone(Zone zone, Game game); + + void removeZone(Zone zone, Game game); } diff --git a/Mage/src/main/java/mage/cards/CardsImpl.java b/Mage/src/main/java/mage/cards/CardsImpl.java index b0f45e4ab9c..76d843e716b 100644 --- a/Mage/src/main/java/mage/cards/CardsImpl.java +++ b/Mage/src/main/java/mage/cards/CardsImpl.java @@ -2,6 +2,7 @@ package mage.cards; import mage.MageItem; import mage.MageObject; +import mage.abilities.Ability; import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; @@ -110,21 +111,21 @@ public class CardsImpl extends LinkedHashSet implements Cards, Serializabl } @Override - public int count(FilterCard filter, UUID sourceId, UUID playerId, Game game) { - if (sourceId == null) { + public int count(FilterCard filter, UUID playerId, Ability source, Game game) { + if (source == null) { return count(filter, playerId, game); } - return (int) this.stream().filter(card -> filter.match(game.getCard(card), sourceId, playerId, game)).count(); + return (int) this.stream().filter(card -> filter.match(game.getCard(card), playerId, source, game)).count(); } @Override - public Set getCards(FilterCard filter, UUID sourceId, UUID playerId, Game game) { + public Set getCards(FilterCard filter, UUID playerId, Ability source, Game game) { Set cards = new LinkedHashSet<>(); for (UUID cardId : this) { Card card = game.getCard(cardId); if (card != null) { - boolean match = filter.match(card, sourceId, playerId, game); + boolean match = filter.match(card, playerId, source, game); if (match) { cards.add(game.getCard(cardId)); } @@ -210,4 +211,9 @@ public class CardsImpl extends LinkedHashSet implements Cards, Serializabl public void retainZone(Zone zone, Game game) { removeIf(uuid -> game.getState().getZone(uuid) != zone); } + + @Override + public void removeZone(Zone zone, Game game) { + removeIf(uuid -> game.getState().getZone(uuid) == zone); + } } diff --git a/Mage/src/main/java/mage/cards/LevelerCard.java b/Mage/src/main/java/mage/cards/LevelerCard.java index 2c3912f2f6c..a17ab793f95 100644 --- a/Mage/src/main/java/mage/cards/LevelerCard.java +++ b/Mage/src/main/java/mage/cards/LevelerCard.java @@ -2,11 +2,13 @@ package mage.cards; -import java.util.UUID; +import mage.abilities.Ability; import mage.constants.CardType; +import java.util.List; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public abstract class LevelerCard extends CardImpl { @@ -30,4 +32,9 @@ public abstract class LevelerCard extends CardImpl { this.maxLevelCounters = maxLevelCounters; } + protected void addAbilities(List abilities) { + for (Ability ability : abilities) { + addAbility(ability); + } + } } diff --git a/Mage/src/main/java/mage/cards/ModalDoubleFacesCard.java b/Mage/src/main/java/mage/cards/ModalDoubleFacesCard.java index db7062b9313..b5ab8f42828 100644 --- a/Mage/src/main/java/mage/cards/ModalDoubleFacesCard.java +++ b/Mage/src/main/java/mage/cards/ModalDoubleFacesCard.java @@ -22,7 +22,7 @@ import java.util.UUID; /** * @author JayDi85 */ -public abstract class ModalDoubleFacesCard extends CardImpl { +public abstract class ModalDoubleFacesCard extends CardImpl implements CardWithHalves { protected Card leftHalfCard; // main card in all zone protected Card rightHalfCard; // second side card, can be only in stack and battlefield zones diff --git a/Mage/src/main/java/mage/cards/ModalDoubleFacesCardHalf.java b/Mage/src/main/java/mage/cards/ModalDoubleFacesCardHalf.java index d7dee2090bd..7ebbf338fd8 100644 --- a/Mage/src/main/java/mage/cards/ModalDoubleFacesCardHalf.java +++ b/Mage/src/main/java/mage/cards/ModalDoubleFacesCardHalf.java @@ -5,15 +5,11 @@ import mage.MageInt; /** * @author JayDi85 */ -public interface ModalDoubleFacesCardHalf extends Card { +public interface ModalDoubleFacesCardHalf extends SubCard { @Override ModalDoubleFacesCardHalf copy(); - void setParentCard(ModalDoubleFacesCard card); - - ModalDoubleFacesCard getParentCard(); - void setPT(int power, int toughness); void setPT(MageInt power, MageInt toughness); diff --git a/Mage/src/main/java/mage/cards/SplitCard.java b/Mage/src/main/java/mage/cards/SplitCard.java index b1d0c9a1763..36e799b21ac 100644 --- a/Mage/src/main/java/mage/cards/SplitCard.java +++ b/Mage/src/main/java/mage/cards/SplitCard.java @@ -18,7 +18,7 @@ import java.util.UUID; /** * @author LevelX2 */ -public abstract class SplitCard extends CardImpl { +public abstract class SplitCard extends CardImpl implements CardWithHalves { protected Card leftHalfCard; protected Card rightHalfCard; diff --git a/Mage/src/main/java/mage/cards/SplitCardHalf.java b/Mage/src/main/java/mage/cards/SplitCardHalf.java index 76db56ce603..957d97999f9 100644 --- a/Mage/src/main/java/mage/cards/SplitCardHalf.java +++ b/Mage/src/main/java/mage/cards/SplitCardHalf.java @@ -3,12 +3,8 @@ package mage.cards; /** * @author LevelX2 */ -public interface SplitCardHalf extends Card { +public interface SplitCardHalf extends SubCard { @Override SplitCardHalf copy(); - - void setParentCard(SplitCard card); - - SplitCard getParentCard(); } diff --git a/Mage/src/main/java/mage/cards/SubCard.java b/Mage/src/main/java/mage/cards/SubCard.java new file mode 100644 index 00000000000..92127541bb8 --- /dev/null +++ b/Mage/src/main/java/mage/cards/SubCard.java @@ -0,0 +1,8 @@ +package mage.cards; + +public interface SubCard extends Card { + + void setParentCard(T card); + + T getParentCard(); +} diff --git a/Mage/src/main/java/mage/cards/decks/Constructed.java b/Mage/src/main/java/mage/cards/decks/Constructed.java index 27390a1dda0..911f66bc4d4 100644 --- a/Mage/src/main/java/mage/cards/decks/Constructed.java +++ b/Mage/src/main/java/mage/cards/decks/Constructed.java @@ -14,7 +14,7 @@ import java.util.Map.Entry; */ public class Constructed extends DeckValidator { - private static final Logger logger = Logger.getLogger(DeckValidator.class); + private static final Logger logger = Logger.getLogger(Constructed.class); private static final List anyNumberCardsAllowed = new ArrayList<>(Arrays.asList( "Relentless Rats", "Shadowborn Apostle", "Rat Colony", @@ -30,16 +30,65 @@ public class Constructed extends DeckValidator { protected List rarities = new ArrayList<>(); protected Set singleCards = new HashSet<>(); - public Constructed() { - super("Constructed"); - } - protected Constructed(String name) { - super(name); + this(name, null); } protected Constructed(String name, String shortName) { super(name, shortName); + // Conspiracy cards are banned + banned.add("Adriana's Valor"); + banned.add("Advantageous Proclamation"); + banned.add("Assemble the Rank and Vile"); + banned.add("Backup Plan"); + banned.add("Brago's Favor"); + banned.add("Double Stroke"); + banned.add("Echoing Boon"); + banned.add("Emissary's Ploy"); + banned.add("Hired Heist"); + banned.add("Hold the Perimeter"); + banned.add("Hymn of the Wilds"); + banned.add("Immediate Action"); + banned.add("Incendiary Dissent"); + banned.add("Iterative Analysis"); + banned.add("Muzzio's Preparations"); + banned.add("Natural Unity"); + banned.add("Power Play"); + banned.add("Secrets of Paradise"); + banned.add("Secret Summoning"); + banned.add("Sentinel Dispatch"); + banned.add("Sovereign's Realm"); + banned.add("Summoner's Bond"); + banned.add("Unexpected Potential"); + banned.add("Weight Advantage"); + banned.add("Worldknit"); + + // Dexterity cards are banned + banned.add("Chaos Orb"); + banned.add("Falling Star"); + + // Sub-game cards are banned + banned.add("Shahrazad"); + + // Ante cards are banned + banned.add("Amulet of Quoz"); + banned.add("Bronze Tablet"); + banned.add("Contract from Below"); + banned.add("Darkpact"); + banned.add("Demonic Attorney"); + banned.add("Jeweled Bird"); + banned.add("Rebirth"); + banned.add("Tempest Efreet"); + banned.add("Timmerian Fiends"); + + // Potentially offensive cards are banned + banned.add("Cleanse"); + banned.add("Crusade"); + banned.add("Imprison"); + banned.add("Invoke Prejudice"); + banned.add("Jihad"); + banned.add("Pradesh Gypsies"); + banned.add("Stone-Throwing Devils"); } public List getSetCodes() { diff --git a/Mage/src/main/java/mage/cards/decks/DeckValidator.java b/Mage/src/main/java/mage/cards/decks/DeckValidator.java index 8457f835698..07c51cdb334 100644 --- a/Mage/src/main/java/mage/cards/decks/DeckValidator.java +++ b/Mage/src/main/java/mage/cards/decks/DeckValidator.java @@ -15,10 +15,6 @@ public abstract class DeckValidator implements Serializable { protected String shortName; protected List errorsList = new ArrayList<>(); - public DeckValidator(String name) { - setName(name); - } - public DeckValidator(String name, String shortName) { setName(name, shortName); } @@ -33,14 +29,13 @@ public abstract class DeckValidator implements Serializable { return shortName; } - protected void setName(String name) { - this.name = name; - this.shortName = name.contains("-") ? name.substring(name.indexOf("-") + 1).trim() : name; - } - protected void setName(String name, String shortName) { this.name = name; - this.shortName = shortName; + if (shortName != null) { + this.shortName = shortName; + } else { + this.shortName = name.contains("-") ? name.substring(name.indexOf("-") + 1).trim() : name; + } } protected void setShortName(String shortName) { diff --git a/Mage/src/main/java/mage/cards/mock/MockCard.java b/Mage/src/main/java/mage/cards/mock/MockCard.java index cb763203f53..d8c2e22ed0d 100644 --- a/Mage/src/main/java/mage/cards/mock/MockCard.java +++ b/Mage/src/main/java/mage/cards/mock/MockCard.java @@ -8,7 +8,6 @@ import mage.cards.CardImpl; import mage.cards.ModalDoubleFacesCard; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; -import org.apache.log4j.Logger; import java.util.ArrayList; import java.util.List; @@ -26,7 +25,7 @@ public class MockCard extends CardImpl { // Needs to be here, as it is normally calculated from the // PlaneswalkerEntersWithLoyaltyAbility of the card... but the MockCard // only has MockAbilities. - private int startingLoyalty; + private final int startingLoyalty; // mana cost extra info for multiple mana drawing // warning, don't use ManaCost objects here due too much memory consumptions @@ -79,18 +78,16 @@ public class MockCard extends CardImpl { this.isModalDoubleFacesCard = true; } - if (this.isPlaneswalker()) { - String startingLoyaltyString = card.getStartingLoyalty(); - if (startingLoyaltyString.isEmpty()) { - } else { - try { - this.startingLoyalty = Integer.parseInt(startingLoyaltyString); - } catch (NumberFormatException e) { - Logger.getLogger(MockCard.class).warn("Planeswalker `" + this.name + "` starting loyalty in bad format: `" + startingLoyaltyString + "`."); - } - } + switch (card.getStartingLoyalty()) { + case "X": + this.startingLoyalty = -2; + break; + case "": + this.startingLoyalty = -1; + break; + default: + this.startingLoyalty = Integer.parseInt(card.getStartingLoyalty()); } - this.flipCardName = card.getFlipCardName(); for (String ruleText : card.getRules()) { this.addAbility(textAbilityFromString(ruleText)); diff --git a/Mage/src/main/java/mage/cards/repository/CardInfo.java b/Mage/src/main/java/mage/cards/repository/CardInfo.java index 995bf776e92..135358e2689 100644 --- a/Mage/src/main/java/mage/cards/repository/CardInfo.java +++ b/Mage/src/main/java/mage/cards/repository/CardInfo.java @@ -4,9 +4,7 @@ import com.j256.ormlite.field.DataType; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; import mage.ObjectColor; -import mage.abilities.Ability; import mage.abilities.SpellAbility; -import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.cards.*; import mage.cards.mock.MockCard; import mage.cards.mock.MockSplitCard; @@ -245,18 +243,7 @@ public class CardInfo { } // Starting loyalty - if (card.isPlaneswalker()) { - for (Ability ab : card.getAbilities()) { - if (ab instanceof PlaneswalkerEntersWithLoyaltyCountersAbility) { - this.startingLoyalty = "" + ((PlaneswalkerEntersWithLoyaltyCountersAbility) ab).getStartingLoyalty(); - } - } - if (this.startingLoyalty == null) { - this.startingLoyalty = ""; - } - } else { - this.startingLoyalty = ""; - } + this.startingLoyalty = CardUtil.convertStartingLoyalty(card.getStartingLoyalty()); } public Card getCard() { @@ -491,8 +478,8 @@ public class CardInfo { if (o == null || !(o instanceof CardInfo)) return false; CardInfo other = (CardInfo) o; return (this.name.equals(other.name) - && this.setCode.equals(other.setCode) - && this.cardNumber.equals(other.cardNumber)); + && this.setCode.equals(other.setCode) + && this.cardNumber.equals(other.cardNumber)); } @Override diff --git a/Mage/src/main/java/mage/cards/repository/CardScanner.java b/Mage/src/main/java/mage/cards/repository/CardScanner.java index 678f1924a57..b9e3b621180 100644 --- a/Mage/src/main/java/mage/cards/repository/CardScanner.java +++ b/Mage/src/main/java/mage/cards/repository/CardScanner.java @@ -69,6 +69,11 @@ public final class CardScanner { // downloads unknown cards from the server as texts (images, hints and all other works fine with it) cardsToAdd.add(new CardInfo(card)); + if (card instanceof SplitCard) { + SplitCard splitCard = (SplitCard) card; + cardsToAdd.add(new CardInfo(splitCard.getLeftHalfCard())); + cardsToAdd.add(new CardInfo(splitCard.getRightHalfCard())); + } } } } diff --git a/Mage/src/main/java/mage/constants/AbilityWord.java b/Mage/src/main/java/mage/constants/AbilityWord.java index d81c8d6e09e..14b5a2528af 100644 --- a/Mage/src/main/java/mage/constants/AbilityWord.java +++ b/Mage/src/main/java/mage/constants/AbilityWord.java @@ -9,6 +9,7 @@ public enum AbilityWord { ADDENDUM("Addendum"), ADAMANT("Adamant"), + ALLIANCE("Alliance"), BATTALION("Battalion"), BLOODRUSH("Bloodrush"), CHANNEL("Channel"), @@ -16,6 +17,7 @@ public enum AbilityWord { COHORT("Cohort"), CONSTELLATION("Constellation"), CONVERGE("Converge"), + COUNCILS_DILEMMA("Council's dilemma"), COVEN("Coven"), DELIRIUM("Delirium"), DOMAIN("Domain"), diff --git a/Mage/src/main/java/mage/constants/Duration.java b/Mage/src/main/java/mage/constants/Duration.java index 243cb7b28e5..84bf0aa1fb0 100644 --- a/Mage/src/main/java/mage/constants/Duration.java +++ b/Mage/src/main/java/mage/constants/Duration.java @@ -12,6 +12,7 @@ public enum Duration { WhileInGraveyard("", false, false), EndOfTurn("until end of turn", true, true), UntilYourNextTurn("until your next turn", true, true), + UntilYourNextEndStep("until your next end step", true, true), UntilEndOfYourNextTurn("until the end of your next turn", true, true), UntilSourceLeavesBattlefield("until {this} leaves the battlefield", true, false), // supported for continuous layered effects EndOfCombat("until end of combat", true, true), diff --git a/Mage/src/main/java/mage/constants/SubType.java b/Mage/src/main/java/mage/constants/SubType.java index 31cb8739ffa..a016f6f9c8c 100644 --- a/Mage/src/main/java/mage/constants/SubType.java +++ b/Mage/src/main/java/mage/constants/SubType.java @@ -293,6 +293,7 @@ public enum SubType { QUARREN("Quarren", SubTypeSet.CreatureType, true), // Star Wars // R RABBIT("Rabbit", SubTypeSet.CreatureType), + RACCOON("Raccoon", SubTypeSet.CreatureType), RAIDER("Raider", SubTypeSet.CreatureType, true), // Star Wars RANGER("Ranger", SubTypeSet.CreatureType), RAT("Rat", SubTypeSet.CreatureType), @@ -436,6 +437,7 @@ public enum SubType { LILIANA("Liliana", SubTypeSet.PlaneswalkerType), LUKKA("Lukka", SubTypeSet.PlaneswalkerType), LOLTH("Lolth", SubTypeSet.PlaneswalkerType), + MINSC("Minsc", SubTypeSet.PlaneswalkerType), MORDENKAINEN("Mordenkainen", SubTypeSet.PlaneswalkerType), NAHIRI("Nahiri", SubTypeSet.PlaneswalkerType), NARSET("Narset", SubTypeSet.PlaneswalkerType), diff --git a/Mage/src/main/java/mage/constants/TargetController.java b/Mage/src/main/java/mage/constants/TargetController.java index a81c3610c87..1d3f932e1c4 100644 --- a/Mage/src/main/java/mage/constants/TargetController.java +++ b/Mage/src/main/java/mage/constants/TargetController.java @@ -68,29 +68,22 @@ public enum TargetController { switch (targetOwner) { case YOU: - if (card.isOwnedBy(playerId)) { - return true; - } - break; + return card.isOwnedBy(playerId); case OPPONENT: - if (!card.isOwnedBy(playerId) - && game.getPlayer(playerId).hasOpponent(card.getOwnerId(), game)) { - return true; - } - break; + return !card.isOwnedBy(playerId) + && game.getPlayer(playerId).hasOpponent(card.getOwnerId(), game); case NOT_YOU: - if (!card.isOwnedBy(playerId)) { - return true; - } - break; + return !card.isOwnedBy(playerId); case ENCHANTED: - Permanent permanent = game.getPermanent(input.getSourceId()); + Permanent permanent = input.getSource().getSourcePermanentIfItStillExists(game); return permanent != null && input.getObject().isOwnedBy(permanent.getAttachedTo()); + case SOURCE_TARGETS: + return card.isOwnedBy(input.getSource().getFirstTarget()); case ANY: return true; + default: + throw new UnsupportedOperationException("TargetController not supported"); } - - return false; } @Override @@ -117,24 +110,17 @@ public enum TargetController { switch (targetPlayer) { case YOU: - if (player.getId().equals(playerId)) { - return true; - } - break; + return player.getId().equals(playerId); case OPPONENT: - if (!player.getId().equals(playerId) && - game.getPlayer(playerId).hasOpponent(player.getId(), game)) { - return true; - } - break; + return !player.getId().equals(playerId) && + game.getPlayer(playerId).hasOpponent(player.getId(), game); case NOT_YOU: - if (!player.getId().equals(playerId)) { - return true; - } - break; + return !player.getId().equals(playerId); + case SOURCE_TARGETS: + return player.equals(input.getSource().getFirstTarget()); + default: + throw new UnsupportedOperationException("TargetController not supported"); } - - return false; } @Override @@ -158,39 +144,26 @@ public enum TargetController { switch (controller) { case YOU: - if (object.isControlledBy(playerId)) { - return true; - } - break; + return object.isControlledBy(playerId); case TEAM: - if (!game.getPlayer(playerId).hasOpponent(object.getControllerId(), game)) { - return true; - } - break; + return !game.getPlayer(playerId).hasOpponent(object.getControllerId(), game); case OPPONENT: - if (!object.isControlledBy(playerId) - && game.getPlayer(playerId).hasOpponent(object.getControllerId(), game)) { - return true; - } - break; + return !object.isControlledBy(playerId) + && game.getPlayer(playerId).hasOpponent(object.getControllerId(), game); case NOT_YOU: - if (!object.isControlledBy(playerId)) { - return true; - } - break; + return !object.isControlledBy(playerId); case ACTIVE: - if (object.isControlledBy(game.getActivePlayerId())) { - return true; - } - break; + return object.isControlledBy(game.getActivePlayerId()); case ENCHANTED: - Permanent permanent = game.getPermanent(input.getSourceId()); + Permanent permanent = input.getSource().getSourcePermanentIfItStillExists(game); return permanent != null && input.getObject().isControlledBy(permanent.getAttachedTo()); + case SOURCE_TARGETS: + return object.isControlledBy(input.getSource().getFirstTarget()); case ANY: return true; + default: + throw new UnsupportedOperationException("TargetController not supported"); } - - return false; } @Override diff --git a/Mage/src/main/java/mage/counters/CounterType.java b/Mage/src/main/java/mage/counters/CounterType.java index 88a0ab2566d..dfbc922f8e7 100644 --- a/Mage/src/main/java/mage/counters/CounterType.java +++ b/Mage/src/main/java/mage/counters/CounterType.java @@ -31,6 +31,7 @@ public enum CounterType { CHARGE("charge"), CHIP("chip"), COIN("coin"), + COLLECTION("collection"), COMPONENT("component"), CORPSE("corpse"), CORRUPTION("corruption"), @@ -99,6 +100,7 @@ public enum CounterType { JUDGMENT("judgment"), KNOWLEDGE("knowledge"), KI("ki"), + KICK("kick"), LANDMARK("landmark"), LEVEL("level"), LIFELINK("lifelink"), @@ -131,6 +133,7 @@ public enum CounterType { P2P2(new BoostCounter(2, 2).name), PAGE("page"), PAIN("pain"), + PALLIATION("palliation"), PARALYZATION("paralyzation"), PETAL("petal"), PETRIFICATION("petrification"), @@ -161,6 +164,7 @@ public enum CounterType { SOUL("soul"), SPITE("spite"), SPORE("spore"), + STASH("stash"), STORAGE("storage"), STRIFE("strife"), STUDY("study"), diff --git a/Mage/src/main/java/mage/designations/Designation.java b/Mage/src/main/java/mage/designations/Designation.java index 02dfb6abd11..bc4584fff85 100644 --- a/Mage/src/main/java/mage/designations/Designation.java +++ b/Mage/src/main/java/mage/designations/Designation.java @@ -9,7 +9,6 @@ import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.text.TextPart; import mage.cards.FrameStyle; import mage.constants.CardType; import mage.constants.SubType; @@ -223,14 +222,6 @@ public abstract class Designation implements MageObject { public void setStartingLoyalty(int startingLoyalty) { } - @Override - public void adjustCosts(Ability ability, Game game) { - } - - @Override - public void adjustTargets(Ability ability, Game game) { - } - @Override public int getZoneChangeCounter(Game game) { return 1; // Emblems can't move zones until now so return always 1 @@ -271,16 +262,6 @@ public abstract class Designation implements MageObject { public void setIsAllCreatureTypes(Game game, boolean value) { } - @Override - public List getTextParts() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public TextPart addTextPart(TextPart textPart) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - public boolean isUnique() { return unique; } diff --git a/Mage/src/main/java/mage/filter/FilterCard.java b/Mage/src/main/java/mage/filter/FilterCard.java index bae5bcd3de9..d62326d0045 100644 --- a/Mage/src/main/java/mage/filter/FilterCard.java +++ b/Mage/src/main/java/mage/filter/FilterCard.java @@ -1,5 +1,6 @@ package mage.filter; +import mage.abilities.Ability; import mage.cards.Card; import mage.constants.TargetController; import mage.filter.predicate.ObjectSourcePlayer; @@ -23,7 +24,7 @@ import java.util.stream.Collectors; public class FilterCard extends FilterObject { private static final long serialVersionUID = 1L; - protected List> extraPredicates = new ArrayList<>(); + protected final List> extraPredicates = new ArrayList<>(); public FilterCard() { super("card"); @@ -35,7 +36,7 @@ public class FilterCard extends FilterObject { public FilterCard(FilterCard filter) { super(filter); - this.extraPredicates = new ArrayList<>(filter.extraPredicates); + this.extraPredicates.addAll(filter.extraPredicates); } //20130711 708.6c @@ -56,14 +57,15 @@ public class FilterCard extends FilterObject { } public boolean match(Card card, UUID playerId, Game game) { - return match(card, null, playerId, game); + return match(card, playerId, null, game); } - public boolean match(Card card, UUID sourceId, UUID playerId, Game game) { + public boolean match(Card card, UUID playerId, Ability source, Game game) { if (!this.match(card, game)) { return false; } - return Predicates.and(extraPredicates).apply(new ObjectSourcePlayer(card, sourceId, playerId), game); + ObjectSourcePlayer osp = new ObjectSourcePlayer<>(card, playerId, source); + return extraPredicates.stream().allMatch(p -> p.apply(osp, game)); } public final void add(ObjectSourcePlayerPredicate predicate) { @@ -93,7 +95,7 @@ public class FilterCard extends FilterObject { // card filter can't contain controller predicate (only permanents on battlefield have controller) List list = new ArrayList<>(); Predicates.collectAllComponents(predicate, list); - if (list.stream().anyMatch(p -> p instanceof TargetController.ControllerPredicate)) { + if (list.stream().anyMatch(TargetController.ControllerPredicate.class::isInstance)) { throw new IllegalArgumentException("Card filter doesn't support controller predicate"); } } diff --git a/Mage/src/main/java/mage/filter/FilterInPlay.java b/Mage/src/main/java/mage/filter/FilterInPlay.java index db4b65b2c69..ba0b9979a7e 100644 --- a/Mage/src/main/java/mage/filter/FilterInPlay.java +++ b/Mage/src/main/java/mage/filter/FilterInPlay.java @@ -1,19 +1,18 @@ - - package mage.filter; -import java.util.UUID; +import mage.abilities.Ability; import mage.game.Game; +import java.util.UUID; + /** - * - * @author BetaSteward_at_googlemail.com * @param + * @author BetaSteward_at_googlemail.com */ public interface FilterInPlay extends Filter { - boolean match(E o, UUID sourceId, UUID playerId, Game game); + boolean match(E o, UUID playerId, Ability source, Game game); + @Override FilterInPlay copy(); - } diff --git a/Mage/src/main/java/mage/filter/FilterMana.java b/Mage/src/main/java/mage/filter/FilterMana.java index f714321c312..a8584e7fcd8 100644 --- a/Mage/src/main/java/mage/filter/FilterMana.java +++ b/Mage/src/main/java/mage/filter/FilterMana.java @@ -1,6 +1,10 @@ package mage.filter; +import mage.ObjectColor; + import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; /** * @author nantuko @@ -108,6 +112,62 @@ public class FilterMana implements Serializable { return colorCount; } + public void addAll(FilterMana filterMana) { + if (filterMana.white) { + this.white = true; + } + if (filterMana.blue) { + this.blue = true; + } + if (filterMana.black) { + this.black = true; + } + if (filterMana.red) { + this.red = true; + } + if (filterMana.green) { + this.green = true; + } + } + + public void removeAll(FilterMana filterMana) { + if (filterMana.white) { + this.white = false; + } + if (filterMana.blue) { + this.blue = false; + } + if (filterMana.black) { + this.black = false; + } + if (filterMana.red) { + this.red = false; + } + if (filterMana.green) { + this.green = false; + } + } + + public List getColors() { + List colors = new ArrayList<>(); + if (this.white) { + colors.add(ObjectColor.WHITE); + } + if (this.blue) { + colors.add(ObjectColor.BLUE); + } + if (this.black) { + colors.add(ObjectColor.BLACK); + } + if (this.red) { + colors.add(ObjectColor.RED); + } + if (this.green) { + colors.add(ObjectColor.GREEN); + } + return colors; + } + public FilterMana copy() { return new FilterMana(this); } diff --git a/Mage/src/main/java/mage/filter/FilterPermanent.java b/Mage/src/main/java/mage/filter/FilterPermanent.java index fa995d8a7dd..3c0d8dc30ec 100644 --- a/Mage/src/main/java/mage/filter/FilterPermanent.java +++ b/Mage/src/main/java/mage/filter/FilterPermanent.java @@ -1,9 +1,9 @@ package mage.filter; +import mage.abilities.Ability; import mage.constants.SubType; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; -import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.permanent.Permanent; @@ -17,7 +17,7 @@ import java.util.UUID; */ public class FilterPermanent extends FilterObject implements FilterInPlay { - protected List> extraPredicates = new ArrayList<>(); + protected final List> extraPredicates = new ArrayList<>(); public FilterPermanent() { super("permanent"); @@ -41,7 +41,7 @@ public class FilterPermanent extends FilterObject implements FilterIn public FilterPermanent(final FilterPermanent filter) { super(filter); - this.extraPredicates = new ArrayList<>(filter.extraPredicates); + this.extraPredicates.addAll(filter.extraPredicates); } @Override @@ -50,12 +50,12 @@ public class FilterPermanent extends FilterObject implements FilterIn } @Override - public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { + public boolean match(Permanent permanent, UUID playerId, Ability source, Game game) { if (!this.match(permanent, game) || !permanent.isPhasedIn()) { return false; } - - return Predicates.and(extraPredicates).apply(new ObjectSourcePlayer(permanent, sourceId, playerId), game); + ObjectSourcePlayer osp = new ObjectSourcePlayer(permanent, playerId, source); + return extraPredicates.stream().allMatch(p -> p.apply(osp, game)); } public final void add(ObjectSourcePlayerPredicate predicate) { diff --git a/Mage/src/main/java/mage/filter/FilterPlayer.java b/Mage/src/main/java/mage/filter/FilterPlayer.java index 7a4e0c726e1..025433028f0 100644 --- a/Mage/src/main/java/mage/filter/FilterPlayer.java +++ b/Mage/src/main/java/mage/filter/FilterPlayer.java @@ -1,8 +1,8 @@ package mage.filter; +import mage.abilities.Ability; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; -import mage.filter.predicate.Predicates; import mage.game.Game; import mage.players.Player; @@ -16,7 +16,7 @@ import java.util.UUID; */ public class FilterPlayer extends FilterImpl { - protected List> extraPredicates = new ArrayList<>(); + protected final List> extraPredicates = new ArrayList<>(); public FilterPlayer() { this("player"); @@ -28,7 +28,7 @@ public class FilterPlayer extends FilterImpl { public FilterPlayer(final FilterPlayer filter) { super(filter); - this.extraPredicates = new ArrayList<>(filter.extraPredicates); + this.extraPredicates.addAll(filter.extraPredicates); } public void add(ObjectSourcePlayerPredicate predicate) { @@ -43,12 +43,12 @@ public class FilterPlayer extends FilterImpl { return object instanceof Player; } - public boolean match(Player checkPlayer, UUID sourceId, UUID sourceControllerId, Game game) { + public boolean match(Player checkPlayer, UUID sourceControllerId, Ability source, Game game) { if (!this.match(checkPlayer, game)) { return false; } - - return Predicates.and(extraPredicates).apply(new ObjectSourcePlayer(checkPlayer, sourceId, sourceControllerId), game); + ObjectSourcePlayer osp = new ObjectSourcePlayer<>(checkPlayer, sourceControllerId, source); + return extraPredicates.stream().allMatch(p -> p.apply(osp, game)); } @Override diff --git a/Mage/src/main/java/mage/filter/FilterSpell.java b/Mage/src/main/java/mage/filter/FilterSpell.java index 377ea63b0b7..e2baa8f5ba9 100644 --- a/Mage/src/main/java/mage/filter/FilterSpell.java +++ b/Mage/src/main/java/mage/filter/FilterSpell.java @@ -2,6 +2,8 @@ package mage.filter; import java.util.UUID; + +import mage.abilities.Ability; import mage.game.Game; import mage.game.stack.Spell; import mage.game.stack.StackObject; @@ -25,11 +27,11 @@ public class FilterSpell extends FilterStackObject { } @Override - public boolean match(StackObject stackObject, UUID sourceId, UUID playerId, Game game) { + public boolean match(StackObject stackObject, UUID playerId, Ability source, Game game) { if (!(stackObject instanceof Spell)) { return false; } - return super.match(stackObject, sourceId, playerId, game); + return super.match(stackObject, playerId, source, game); } @Override diff --git a/Mage/src/main/java/mage/filter/FilterStackObject.java b/Mage/src/main/java/mage/filter/FilterStackObject.java index f6099773dd1..6f79cbf725c 100644 --- a/Mage/src/main/java/mage/filter/FilterStackObject.java +++ b/Mage/src/main/java/mage/filter/FilterStackObject.java @@ -1,8 +1,8 @@ package mage.filter; +import mage.abilities.Ability; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; -import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.stack.StackObject; @@ -15,7 +15,7 @@ import java.util.UUID; */ public class FilterStackObject extends FilterObject { - protected List> extraPredicates = new ArrayList<>(); + protected final List> extraPredicates = new ArrayList<>(); public FilterStackObject() { this("spell or ability"); @@ -27,15 +27,15 @@ public class FilterStackObject extends FilterObject { public FilterStackObject(final FilterStackObject filter) { super(filter); - this.extraPredicates = new ArrayList<>(filter.extraPredicates); + this.extraPredicates.addAll(filter.extraPredicates); } - public boolean match(StackObject stackObject, UUID sourceId, UUID playerId, Game game) { + public boolean match(StackObject stackObject, UUID playerId, Ability source, Game game) { if (!this.match(stackObject, game)) { return false; } - - return Predicates.and(extraPredicates).apply(new ObjectSourcePlayer(stackObject, sourceId, playerId), game); + ObjectSourcePlayer osp = new ObjectSourcePlayer<>(stackObject, playerId, source); + return extraPredicates.stream().allMatch(p -> p.apply(osp, game)); } public final void add(ObjectSourcePlayerPredicate predicate) { diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java index 70ce960cf5a..d4d03cb0aee 100644 --- a/Mage/src/main/java/mage/filter/StaticFilters.java +++ b/Mage/src/main/java/mage/filter/StaticFilters.java @@ -64,6 +64,12 @@ public final class StaticFilters { FILTER_CARD_ARTIFACT.setLockedFilter(true); } + public static final FilterArtifactCard FILTER_CARD_ARTIFACTS = new FilterArtifactCard("artifact cards"); + + static { + FILTER_CARD_ARTIFACTS.setLockedFilter(true); + } + public static final FilterArtifactCard FILTER_CARD_ARTIFACT_AN = new FilterArtifactCard("an artifact card"); static { @@ -124,6 +130,12 @@ public final class StaticFilters { FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD.setLockedFilter(true); } + public static final FilterCard FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD = new FilterArtifactCard("artifact card from your graveyard"); + + static { + FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD.setLockedFilter(true); + } + public static final FilterNoncreatureCard FILTER_CARD_NON_CREATURE = new FilterNoncreatureCard(); static { @@ -396,6 +408,12 @@ public final class StaticFilters { FILTER_CONTROLLED_PERMANENT_LAND.setLockedFilter(true); } + public static final FilterControlledPermanent FILTER_CONTROLLED_PERMANENT_A_LAND = new FilterControlledLandPermanent("a land you control"); + + static { + FILTER_CONTROLLED_PERMANENT_A_LAND.setLockedFilter(true); + } + public static final FilterControlledPermanent FILTER_CONTROLLED_PERMANENT_LANDS = new FilterControlledLandPermanent("lands you control"); static { @@ -415,13 +433,18 @@ public final class StaticFilters { FILTER_OPPONENTS_PERMANENT.setLockedFilter(true); } - public static final FilterCreaturePermanent FILTER_OPPONENTS_PERMANENT_CREATURE = new FilterCreaturePermanent("creature an opponent controls"); + public static final FilterCreaturePermanent FILTER_OPPONENTS_PERMANENT_CREATURE = new FilterOpponentsCreaturePermanent(); static { - FILTER_OPPONENTS_PERMANENT_CREATURE.add(TargetController.OPPONENT.getControllerPredicate()); FILTER_OPPONENTS_PERMANENT_CREATURE.setLockedFilter(true); } + public static final FilterCreaturePermanent FILTER_OPPONENTS_PERMANENT_CREATURES = new FilterOpponentsCreaturePermanent("creatures your opponents control"); + + static { + FILTER_OPPONENTS_PERMANENT_CREATURES.setLockedFilter(true); + } + public static final FilterCreaturePermanent FILTER_OPPONENTS_PERMANENT_A_CREATURE = new FilterCreaturePermanent("a creature an opponent controls"); static { @@ -628,10 +651,16 @@ public final class StaticFilters { FILTER_PERMANENT_CREATURE_GOBLINS.setLockedFilter(true); } - public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE_SLIVERS = new FilterCreaturePermanent(SubType.SLIVER, "all Sliver creatures"); + public static final FilterCreaturePermanent FILTER_PERMANENT_SLIVERS = new FilterCreaturePermanent(SubType.SLIVER, "Sliver creatures"); static { - FILTER_PERMANENT_CREATURE_SLIVERS.setLockedFilter(true); + FILTER_PERMANENT_SLIVERS.setLockedFilter(true); + } + + public static final FilterCreaturePermanent FILTER_PERMANENT_ALL_SLIVERS = new FilterCreaturePermanent(SubType.SLIVER, "all Sliver creatures"); + + static { + FILTER_PERMANENT_ALL_SLIVERS.setLockedFilter(true); } public static final FilterControlledPermanent FILTER_CONTROLLED_SAMURAI_OR_WARRIOR = new FilterControlledPermanent("a Samurai or Warrior you control"); @@ -780,6 +809,13 @@ public final class StaticFilters { FILTER_SPELL_INSTANT_SORCERY_WIZARD.setLockedFilter(true); } + public static final FilterSpell FILTER_SPELL_AN_ENCHANTMENT = new FilterSpell("an enchantment spell"); + + static { + FILTER_SPELL_AN_ENCHANTMENT.add(CardType.ENCHANTMENT.getPredicate()); + FILTER_SPELL_AN_ENCHANTMENT.setLockedFilter(true); + } + public static final FilterSpell FILTER_SPELL_KICKED_A = new FilterSpell("a kicked spell"); static { @@ -850,6 +886,12 @@ public final class StaticFilters { FILTER_ATTACKING_CREATURES.setLockedFilter(true); } + public static final FilterAttackingOrBlockingCreature FILTER_ATTACKING_OR_BLOCKING_CREATURE = new FilterAttackingOrBlockingCreature(); + + static { + FILTER_ATTACKING_OR_BLOCKING_CREATURE.setLockedFilter(true); + } + public static final FilterAttackingOrBlockingCreature FILTER_ATTACKING_OR_BLOCKING_CREATURES = new FilterAttackingOrBlockingCreature("attacking or blocking creatures"); static { @@ -901,6 +943,16 @@ public final class StaticFilters { FILTER_CARD_ARTIFACT_OR_CREATURE.setLockedFilter(true); } + public static final FilterCard FILTER_CARD_CREATURE_OR_LAND = new FilterCard("creature or land card"); + + static { + FILTER_CARD_CREATURE_OR_LAND.add(Predicates.or( + CardType.CREATURE.getPredicate(), + CardType.LAND.getPredicate() + )); + FILTER_CARD_CREATURE_OR_LAND.setLockedFilter(true); + } + public static final FilterPlayer FILTER_PLAYER_CONTROLLER = new FilterPlayer("you"); static { diff --git a/Mage/src/main/java/mage/filter/common/FilterBasicLandCard.java b/Mage/src/main/java/mage/filter/common/FilterBasicLandCard.java index 815419817c2..aa24dff0e5a 100644 --- a/Mage/src/main/java/mage/filter/common/FilterBasicLandCard.java +++ b/Mage/src/main/java/mage/filter/common/FilterBasicLandCard.java @@ -2,11 +2,11 @@ package mage.filter.common; import mage.constants.CardType; +import mage.constants.SubType; import mage.constants.SuperType; import mage.filter.FilterCard; /** - * * @author BetaSteward_at_googlemail.com */ public class FilterBasicLandCard extends FilterCard { @@ -15,6 +15,11 @@ public class FilterBasicLandCard extends FilterCard { this("basic land card"); } + public FilterBasicLandCard(SubType subType) { + this("basic " + subType + " card"); + this.add(subType.getPredicate()); + } + public FilterBasicLandCard(String name) { super(name); this.add(CardType.LAND.getPredicate()); diff --git a/Mage/src/main/java/mage/filter/common/FilterCreatureAttackingYou.java b/Mage/src/main/java/mage/filter/common/FilterCreatureAttackingYou.java index abe2d05ac80..10b68412a3f 100644 --- a/Mage/src/main/java/mage/filter/common/FilterCreatureAttackingYou.java +++ b/Mage/src/main/java/mage/filter/common/FilterCreatureAttackingYou.java @@ -2,7 +2,8 @@ package mage.filter.common; import java.util.UUID; -import mage.filter.common.FilterAttackingCreature; + +import mage.abilities.Ability; import mage.game.Game; import mage.game.permanent.Permanent; @@ -42,13 +43,13 @@ public class FilterCreatureAttackingYou extends FilterAttackingCreature { } @Override - public boolean match(Permanent permanent, UUID sourceId, UUID playerId, Game game) { + public boolean match(Permanent permanent, UUID playerId, Ability source, Game game) { if (orWalker) { - return super.match(permanent, sourceId, playerId, game) + return super.match(permanent, playerId, source, game) && permanent.isAttacking() // to prevent unneccessary combat checking if not attacking && playerId.equals(game.getCombat().getDefendingPlayerId(permanent.getId(), game)); } else { - return super.match(permanent, sourceId, playerId, game) + return super.match(permanent, playerId, source, game) && permanent.isAttacking() // to prevent unneccessary combat checking if not attacking && playerId.equals(game.getCombat().getDefenderId(permanent.getId())); } diff --git a/Mage/src/main/java/mage/filter/common/FilterCreatureOrPlayer.java b/Mage/src/main/java/mage/filter/common/FilterCreatureOrPlayer.java index c89ad32d6b3..f80da2f6c3d 100644 --- a/Mage/src/main/java/mage/filter/common/FilterCreatureOrPlayer.java +++ b/Mage/src/main/java/mage/filter/common/FilterCreatureOrPlayer.java @@ -1,6 +1,7 @@ package mage.filter.common; import mage.MageItem; +import mage.abilities.Ability; import mage.filter.FilterImpl; import mage.filter.FilterInPlay; import mage.filter.FilterPlayer; @@ -52,12 +53,12 @@ public class FilterCreatureOrPlayer extends FilterImpl implements Filt } @Override - public boolean match(MageItem o, UUID sourceId, UUID playerId, Game game) { + public boolean match(MageItem o, UUID playerId, Ability source, Game game) { if (super.match(o, game)) { // process predicates if (o instanceof Player) { - return playerFilter.match((Player) o, sourceId, playerId, game); + return playerFilter.match((Player) o, playerId, source, game); } else if (o instanceof Permanent) { - return creatureFilter.match((Permanent) o, sourceId, playerId, game); + return creatureFilter.match((Permanent) o, playerId, source, game); } } return false; diff --git a/Mage/src/main/java/mage/filter/common/FilterPermanentOrPlayer.java b/Mage/src/main/java/mage/filter/common/FilterPermanentOrPlayer.java index b6b6d18be11..60bd5b075b6 100644 --- a/Mage/src/main/java/mage/filter/common/FilterPermanentOrPlayer.java +++ b/Mage/src/main/java/mage/filter/common/FilterPermanentOrPlayer.java @@ -1,6 +1,7 @@ package mage.filter.common; import mage.MageItem; +import mage.abilities.Ability; import mage.filter.FilterImpl; import mage.filter.FilterInPlay; import mage.filter.FilterPermanent; @@ -64,12 +65,12 @@ public class FilterPermanentOrPlayer extends FilterImpl implements Fil } @Override - public boolean match(MageItem o, UUID sourceId, UUID playerId, Game game) { + public boolean match(MageItem o, UUID playerId, Ability source, Game game) { if (super.match(o, game)) { // process predicates if (o instanceof Player) { - return playerFilter.match((Player) o, sourceId, playerId, game); + return playerFilter.match((Player) o, playerId, source, game); } else if (o instanceof Permanent) { - return permanentFilter.match((Permanent) o, sourceId, playerId, game); + return permanentFilter.match((Permanent) o, playerId, source, game); } } return false; diff --git a/Mage/src/main/java/mage/filter/common/FilterPermanentOrPlayerWithCounter.java b/Mage/src/main/java/mage/filter/common/FilterPermanentOrPlayerWithCounter.java index e2ffcfa07f8..de468f83830 100644 --- a/Mage/src/main/java/mage/filter/common/FilterPermanentOrPlayerWithCounter.java +++ b/Mage/src/main/java/mage/filter/common/FilterPermanentOrPlayerWithCounter.java @@ -1,6 +1,7 @@ package mage.filter.common; import mage.MageItem; +import mage.abilities.Ability; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -37,8 +38,8 @@ public class FilterPermanentOrPlayerWithCounter extends FilterPermanentOrPlayer } @Override - public boolean match(MageItem o, UUID sourceId, UUID playerId, Game game) { - if (super.match(o, sourceId, playerId, game)) { // same as parent class, so can call with full params + public boolean match(MageItem o, UUID playerId, Ability source, Game game) { + if (super.match(o, playerId, source, game)) { // same as parent class, so can call with full params if (o instanceof Player) { return !((Player) o).getCounters().isEmpty(); } else if (o instanceof Permanent) { diff --git a/Mage/src/main/java/mage/filter/common/FilterPermanentOrSuspendedCard.java b/Mage/src/main/java/mage/filter/common/FilterPermanentOrSuspendedCard.java index e8e047ec006..db3150851ee 100644 --- a/Mage/src/main/java/mage/filter/common/FilterPermanentOrSuspendedCard.java +++ b/Mage/src/main/java/mage/filter/common/FilterPermanentOrSuspendedCard.java @@ -32,6 +32,7 @@ package mage.filter.common; import java.util.UUID; import mage.MageObject; +import mage.abilities.Ability; import mage.abilities.keyword.SuspendAbility; import mage.cards.Card; import mage.counters.CounterType; @@ -86,11 +87,11 @@ public class FilterPermanentOrSuspendedCard extends FilterImpl imple } @Override - public boolean match(MageObject o, UUID sourceId, UUID playerId, Game game) { + public boolean match(MageObject o, UUID playerId, Ability source, Game game) { if (o instanceof Permanent) { - return permanentFilter.match((Permanent) o, sourceId, playerId, game); + return permanentFilter.match((Permanent) o, playerId, source, game); } else if (o instanceof Card) { - return cardFilter.match((Card) o, sourceId, playerId, game); + return cardFilter.match((Card) o, playerId, source, game); } return false; } diff --git a/Mage/src/main/java/mage/filter/common/FilterSpellOrPermanent.java b/Mage/src/main/java/mage/filter/common/FilterSpellOrPermanent.java index e15fa68b20f..0f9a647f341 100644 --- a/Mage/src/main/java/mage/filter/common/FilterSpellOrPermanent.java +++ b/Mage/src/main/java/mage/filter/common/FilterSpellOrPermanent.java @@ -1,6 +1,7 @@ package mage.filter.common; import mage.MageObject; +import mage.abilities.Ability; import mage.filter.FilterImpl; import mage.filter.FilterInPlay; import mage.filter.FilterPermanent; @@ -51,11 +52,11 @@ public class FilterSpellOrPermanent extends FilterImpl implements Fi } @Override - public boolean match(MageObject o, UUID sourceId, UUID playerId, Game game) { + public boolean match(MageObject o, UUID playerId, Ability source, Game game) { if (o instanceof Spell) { - return spellFilter.match((Spell) o, sourceId, playerId, game); + return spellFilter.match((Spell) o, playerId, source, game); } else if (o instanceof Permanent) { - return permanentFilter.match((Permanent) o, sourceId, playerId, game); + return permanentFilter.match((Permanent) o, playerId, source, game); } return false; } diff --git a/Mage/src/main/java/mage/filter/predicate/ObjectSourcePlayer.java b/Mage/src/main/java/mage/filter/predicate/ObjectSourcePlayer.java index b5019768bdd..a080c55bfe2 100644 --- a/Mage/src/main/java/mage/filter/predicate/ObjectSourcePlayer.java +++ b/Mage/src/main/java/mage/filter/predicate/ObjectSourcePlayer.java @@ -1,5 +1,7 @@ package mage.filter.predicate; +import mage.abilities.Ability; + import java.util.UUID; /** @@ -11,11 +13,13 @@ public class ObjectSourcePlayer { protected final T object; protected final UUID playerId; protected final UUID sourceId; + protected final Ability source; - public ObjectSourcePlayer(T object, UUID sourceId, UUID sourceControllerId) { + public ObjectSourcePlayer(T object, UUID sourceControllerId, Ability source) { this.object = object; this.playerId = sourceControllerId; - this.sourceId = sourceId; + this.sourceId = source != null ? source.getSourceId() : null; + this.source = source; } public T getObject() { @@ -29,4 +33,8 @@ public class ObjectSourcePlayer { public UUID getSourceId() { return sourceId; } + + public Ability getSource() { + return source; + } } diff --git a/Mage/src/main/java/mage/filter/predicate/card/DefendingPlayerOwnsCardPredicate.java b/Mage/src/main/java/mage/filter/predicate/card/DefendingPlayerOwnsCardPredicate.java index a863a65c2fd..b158d3df078 100644 --- a/Mage/src/main/java/mage/filter/predicate/card/DefendingPlayerOwnsCardPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/card/DefendingPlayerOwnsCardPredicate.java @@ -13,7 +13,7 @@ public enum DefendingPlayerOwnsCardPredicate implements ObjectSourcePlayerPredic @Override public boolean apply(ObjectSourcePlayer input, Game game) { - return game.getCombat().getPlayerDefenders(game, false).contains(input.getObject().getOwnerId()); + return input.getObject().isOwnedBy(game.getCombat().getDefendingPlayerId(input.getSourceId(), game)); } @Override diff --git a/Mage/src/main/java/mage/filter/predicate/card/PutIntoGraveFromAnywhereThisTurnPredicate.java b/Mage/src/main/java/mage/filter/predicate/card/PutIntoGraveFromAnywhereThisTurnPredicate.java new file mode 100644 index 00000000000..a6fdaab53d7 --- /dev/null +++ b/Mage/src/main/java/mage/filter/predicate/card/PutIntoGraveFromAnywhereThisTurnPredicate.java @@ -0,0 +1,20 @@ +package mage.filter.predicate.card; + +import mage.cards.Card; +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.watchers.common.CardsPutIntoGraveyardWatcher; + +/** + * @author Alex-Vasile + */ +public enum PutIntoGraveFromAnywhereThisTurnPredicate implements Predicate { + instance; + + @Override + public boolean apply(Card input, Game game) { + CardsPutIntoGraveyardWatcher watcher = game.getState().getWatcher(CardsPutIntoGraveyardWatcher.class); + + return watcher != null && watcher.checkCardFromAnywhere(input, game); + } +} diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherCardPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherCardPredicate.java deleted file mode 100644 index 6bc62682bca..00000000000 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherCardPredicate.java +++ /dev/null @@ -1,24 +0,0 @@ - -package mage.filter.predicate.mageobject; - -import mage.MageObject; -import mage.filter.predicate.ObjectSourcePlayer; -import mage.filter.predicate.ObjectSourcePlayerPredicate; -import mage.game.Game; - -/** - * - * @author North - */ -public class AnotherCardPredicate implements ObjectSourcePlayerPredicate { - - @Override - public boolean apply(ObjectSourcePlayer input, Game game) { - return !input.getSourceId().equals(input.getObject().getId()); - } - - @Override - public String toString() { - return "Another card"; - } -} \ No newline at end of file diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherPredicate.java index a7ce4548085..cca9260b1e7 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/AnotherPredicate.java @@ -1,4 +1,3 @@ - package mage.filter.predicate.mageobject; import mage.MageObject; @@ -14,7 +13,11 @@ public enum AnotherPredicate implements ObjectSourcePlayerPredicate @Override public boolean apply(ObjectSourcePlayer input, Game game) { - return !input.getObject().getId().equals(input.getSourceId()); + if (!input.getObject().getId().equals(input.getSourceId())) { + return true; + } + int zcc = input.getSource().getSourceObjectZoneChangeCounter(); + return zcc != 0 && zcc != input.getObject().getZoneChangeCounter(game); } @Override diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/MageObjectReferencePredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/MageObjectReferencePredicate.java index f438b24e950..411360b5f6b 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/MageObjectReferencePredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/MageObjectReferencePredicate.java @@ -8,6 +8,8 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** * @author TheElk801 */ @@ -15,6 +17,10 @@ public class MageObjectReferencePredicate implements Predicate { private final MageObjectReference mor; + public MageObjectReferencePredicate(UUID sourceId, Game game) { + this(new MageObjectReference(sourceId, game)); + } + public MageObjectReferencePredicate(MageObject mageObject, Game game) { this(new MageObjectReference(mageObject, game)); } diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java index cb89353be36..e88d60bd304 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java @@ -1,7 +1,7 @@ package mage.filter.predicate.mageobject; import mage.MageObject; -import mage.cards.ModalDoubleFacesCard; +import mage.cards.CardWithHalves; import mage.cards.SplitCard; import mage.constants.SpellAbilityType; import mage.filter.predicate.Predicate; @@ -34,13 +34,9 @@ public class NamePredicate implements Predicate { // If a player names a card, the player may name either half of a split card, but not both. // A split card has the chosen name if one of its two names matches the chosen name. // Same for modal double faces cards - if (input instanceof SplitCard) { - return CardUtil.haveSameNames(name, ((SplitCard) input).getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || - CardUtil.haveSameNames(name, ((SplitCard) input).getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || - CardUtil.haveSameNames(name, input.getName(), this.ignoreMtgRuleForEmptyNames); - } else if (input instanceof ModalDoubleFacesCard) { - return CardUtil.haveSameNames(name, ((ModalDoubleFacesCard) input).getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || - CardUtil.haveSameNames(name, ((ModalDoubleFacesCard) input).getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || + if (input instanceof CardWithHalves) { + return CardUtil.haveSameNames(name, ((CardWithHalves) input).getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || + CardUtil.haveSameNames(name, ((CardWithHalves) input).getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || CardUtil.haveSameNames(name, input.getName(), this.ignoreMtgRuleForEmptyNames); } else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) { SplitCard card = (SplitCard) ((Spell) input).getCard(); diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/SharesColorWithSourcePredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/SharesColorWithSourcePredicate.java index 3beae46614e..14fd70349ca 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/SharesColorWithSourcePredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/SharesColorWithSourcePredicate.java @@ -6,24 +6,20 @@ import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; /** - * * @author LevelX2 */ -public class SharesColorWithSourcePredicate implements ObjectSourcePlayerPredicate { +public enum SharesColorWithSourcePredicate implements ObjectSourcePlayerPredicate { + instance; @Override public boolean apply(ObjectSourcePlayer input, Game game) { - MageObject sourceObject = game.getObject(input.getSourceId()); - if (sourceObject != null) { - return input.getObject().getColor(game).shares(sourceObject.getColor(game)); - } - return false; - + MageObject sourceObject = input.getSource().getSourceObject(game); + return sourceObject != null && input.getObject().getColor(game).shares(sourceObject.getColor(game)); } @Override public String toString() { return "shares a color"; } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/TargetsPermanentPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/TargetsPermanentPredicate.java index ccb8adea32e..7d2f9fe9dca 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/TargetsPermanentPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/TargetsPermanentPredicate.java @@ -35,7 +35,7 @@ public class TargetsPermanentPredicate implements ObjectSourcePlayerPredicate { - - private final TextPartSubType textPartSubtype; - - public TextPartSubtypePredicate(TextPartSubType textPartSubtype) { - this.textPartSubtype = textPartSubtype; - } - - @Override - public boolean apply(MageObject input, Game game) { - return input.hasSubtype(textPartSubtype.getCurrentValue(), game); - } - - @Override - public String toString() { - return "Subtype(" + textPartSubtype.getCurrentValue() + ')'; - } -} diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/AnotherEnchantedPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/AnotherEnchantedPredicate.java index 12bbdd5edbc..e232528c7d8 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/AnotherEnchantedPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/AnotherEnchantedPredicate.java @@ -14,7 +14,7 @@ public class AnotherEnchantedPredicate implements ObjectSourcePlayerPredicate input, Game game) { - Permanent enchantment = game.getPermanentOrLKIBattlefield(input.getSourceId()); + Permanent enchantment = input.getSource().getSourcePermanentIfItStillExists(game); return enchantment != null && !input.getObject().getId().equals(enchantment.getAttachedTo()); } diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/BlockingOrBlockedBySourcePredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/BlockingOrBlockedBySourcePredicate.java index 4e5af9d9dd6..59a7e6da33e 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/BlockingOrBlockedBySourcePredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/BlockingOrBlockedBySourcePredicate.java @@ -3,8 +3,8 @@ package mage.filter.predicate.permanent; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; -import mage.game.combat.CombatGroup; import mage.game.permanent.Permanent; +import mage.watchers.common.BlockingOrBlockedWatcher; import java.util.UUID; @@ -18,30 +18,20 @@ public enum BlockingOrBlockedBySourcePredicate implements ObjectSourcePlayerPred @Override public boolean apply(ObjectSourcePlayer input, Game game) { - return game - .getCombat() - .getGroups() - .stream() - .anyMatch(combatGroup -> checkBlocks(combatGroup, input.getSourceId(), input.getObject().getId())); - } - - private boolean checkBlocks(CombatGroup combatGroup, UUID thisCreature, UUID otherCreature) { + Permanent thisCreature = input.getSource().getSourcePermanentOrLKI(game); + Permanent otherCreature = input.getObject(); switch (this) { case BLOCKING: - return isBlocking(combatGroup, otherCreature, thisCreature); + return BlockingOrBlockedWatcher.check(thisCreature, otherCreature, game); case BLOCKED_BY: - return isBlocking(combatGroup, thisCreature, otherCreature); + return BlockingOrBlockedWatcher.check(otherCreature, thisCreature, game); case EITHER: - return isBlocking(combatGroup, otherCreature, thisCreature) - || isBlocking(combatGroup, thisCreature, otherCreature); + return BlockingOrBlockedWatcher.check(otherCreature, thisCreature, game) + || BlockingOrBlockedWatcher.check(thisCreature, otherCreature, game); } return false; } - private static final boolean isBlocking(CombatGroup combatGroup, UUID id1, UUID id2) { - return combatGroup.getBlockers().contains(id1) && combatGroup.getAttackers().contains(id2); - } - @Override public String toString() { return "Blocking or blocked by"; diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/ControllerControlsIslandPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/ControllerControlsIslandPredicate.java index ab9f182c049..dcac4f1c9f9 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/ControllerControlsIslandPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/ControllerControlsIslandPredicate.java @@ -1,4 +1,3 @@ - package mage.filter.predicate.permanent; import mage.constants.SubType; @@ -8,20 +7,21 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author KholdFuzion */ -public class ControllerControlsIslandPredicate implements Predicate { +public enum ControllerControlsIslandPredicate implements Predicate { + instance; + + private static final FilterLandPermanent filter = new FilterLandPermanent("Island"); - public static final FilterLandPermanent filter = new FilterLandPermanent("Island"); static { filter.add(SubType.ISLAND.getPredicate()); } @Override public boolean apply(Permanent input, Game game) { - return (game.getBattlefield().countAll(filter, input.getControllerId(), game) > 0); + return game.getBattlefield().countAll(filter, input.getControllerId(), game) > 0; } @Override diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/MaxManaValueControlledPermanentPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/MaxManaValueControlledPermanentPredicate.java new file mode 100644 index 00000000000..bcb91d8a465 --- /dev/null +++ b/Mage/src/main/java/mage/filter/predicate/permanent/MaxManaValueControlledPermanentPredicate.java @@ -0,0 +1,37 @@ +package mage.filter.predicate.permanent; + +import mage.MageObject; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.Objects; + +/** + * @author TheElk801 + */ +public enum MaxManaValueControlledPermanentPredicate implements ObjectSourcePlayerPredicate { + instance; + + private static final FilterPermanent filter = new FilterCreatureOrPlaneswalkerPermanent(); + + static { + filter.add(TargetController.YOU.getControllerPredicate()); + } + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + int cmc = game.getBattlefield() + .getActivePermanents(filter, input.getPlayerId(), input.getSource(), game) + .stream() + .filter(Objects::nonNull) + .mapToInt(MageObject::getManaValue) + .max() + .orElse(0); + return input.getObject().getManaValue() >= cmc; + } +} diff --git a/Mage/src/main/java/mage/game/Exile.java b/Mage/src/main/java/mage/game/Exile.java index 2c9a73fd7dd..bc0427ffe5d 100644 --- a/Mage/src/main/java/mage/game/Exile.java +++ b/Mage/src/main/java/mage/game/Exile.java @@ -49,8 +49,7 @@ public class Exile implements Serializable, Copyable { } private ExileZone createZone(UUID id, String name, boolean hidden) { - exileZones.putIfAbsent(id, new ExileZone(id, name, hidden)); - return exileZones.get(id); + return exileZones.computeIfAbsent(id, x -> new ExileZone(id, name, hidden)); } public ExileZone getExileZone(UUID id) { diff --git a/Mage/src/main/java/mage/game/Game.java b/Mage/src/main/java/mage/game/Game.java index 1ec9f2439fa..1aa9eb4afb3 100644 --- a/Mage/src/main/java/mage/game/Game.java +++ b/Mage/src/main/java/mage/game/Game.java @@ -80,6 +80,8 @@ public interface Game extends MageItem, Serializable, Copyable { */ MageObject getObject(UUID objectId); + MageObject getObject(Ability source); + MageObject getBaseObject(UUID objectId); MageObject getEmblem(UUID objectId); diff --git a/Mage/src/main/java/mage/game/GameCommanderImpl.java b/Mage/src/main/java/mage/game/GameCommanderImpl.java index 4457b139721..a17bc98e9f7 100644 --- a/Mage/src/main/java/mage/game/GameCommanderImpl.java +++ b/Mage/src/main/java/mage/game/GameCommanderImpl.java @@ -1,21 +1,25 @@ package mage.game; +import mage.ObjectColor; import mage.abilities.Ability; +import mage.abilities.common.CommanderChooseColorAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.continuous.CommanderReplacementEffect; import mage.abilities.effects.common.cost.CommanderCostModification; import mage.abilities.keyword.CompanionAbility; import mage.cards.Card; +import mage.choices.ChoiceColor; import mage.constants.*; +import mage.filter.FilterMana; import mage.game.mulligan.Mulligan; import mage.game.turn.TurnMod; import mage.players.Player; import mage.watchers.common.CommanderInfoWatcher; import mage.watchers.common.CommanderPlaysCountWatcher; -import java.util.Map; -import java.util.UUID; +import java.util.*; +import java.util.stream.Stream; public abstract class GameCommanderImpl extends GameImpl { @@ -40,6 +44,49 @@ public abstract class GameCommanderImpl extends GameImpl { this.checkCommanderDamage = game.checkCommanderDamage; } + private void handlePipers(Player player, Set commanders) { + int piperCount = commanders + .stream() + .filter(CommanderChooseColorAbility::checkCard) + .mapToInt(x -> 1) + .sum(); + if (piperCount < 1) { + return; + } + FilterMana leftoverColors = new FilterMana(); + Stream.concat( + player.getLibrary().getCards(this).stream(), + player.getSideboard().getCards(this).stream() + ).map(Card::getColorIdentity).forEach(leftoverColors::addAll); + FilterMana nonPiperIdentity = new FilterMana(); + commanders + .stream() + .filter(card -> !CommanderChooseColorAbility.checkCard(card)) + .map(Card::getColorIdentity) + .forEach(nonPiperIdentity::addAll); + leftoverColors.removeAll(nonPiperIdentity); + if (piperCount < leftoverColors.getColorCount()) { + throw new UnsupportedOperationException("This deck should not be legal, something went wrong"); + } + Iterator iterator = leftoverColors.getColors().listIterator(); + for (Card commander : commanders) { + if (!CommanderChooseColorAbility.checkCard(commander)) { + continue; + } + ObjectColor color; + if (!iterator.hasNext()) { + ChoiceColor choiceColor = new ChoiceColor( + true, "Choose a color for " + commander.getName() + ); + player.choose(Outcome.Neutral, choiceColor, this); + color = choiceColor.getColor(); + } else { + color = iterator.next(); + } + commander.getColor().addColor(color); + } + } + @Override protected void init(UUID choosingPlayerId) { // Karn Liberated calls it to restart game, all data and commanders must be re-initialized @@ -50,25 +97,31 @@ public abstract class GameCommanderImpl extends GameImpl { // move commanders to command zone for (UUID playerId : state.getPlayerList(startingPlayerId)) { Player player = getPlayer(playerId); - if (player != null) { - // add new commanders - for (UUID cardId : player.getSideboard()) { - Card card = this.getCard(cardId); - if (card != null) { - // Check for companions. If it is the only card in the sideboard, it is the commander, not a companion. - if (player.getSideboard().size() > 1 && card.getAbilities(this).stream().anyMatch(ability -> ability instanceof CompanionAbility)) { - continue; - } - addCommander(card, player); - } + if (player == null) { + continue; + } + // add new commanders + Set commanders = new HashSet<>(); + for (UUID cardId : player.getSideboard()) { + Card card = this.getCard(cardId); + if (card == null) { + continue; } + // Check for companions. If it is the only card in the sideboard, it is the commander, not a companion. + if (player.getSideboard().size() > 1 && card.getAbilities(this).stream().anyMatch(CompanionAbility.class::isInstance)) { + continue; + } + commanders.add(card); + addCommander(card, player); + } - // init commanders - for (UUID commanderId : this.getCommandersIds(player, CommanderCardType.ANY, false)) { - Card commander = this.getCard(commanderId); - if (commander != null) { - initCommander(commander, player); - } + handlePipers(player, commanders); + + // init commanders + for (UUID commanderId : this.getCommandersIds(player, CommanderCardType.ANY, false)) { + Card commander = this.getCard(commanderId); + if (commander != null) { + initCommander(commander, player); } } } diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 4d188c997c6..0fc53f56a88 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -14,6 +14,7 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.PreventionEffectData; import mage.abilities.effects.common.CopyEffect; import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.keyword.ShieldCounterEffect; import mage.abilities.keyword.*; import mage.abilities.mana.DelayedTriggeredManaAbility; import mage.abilities.mana.TriggeredManaAbility; @@ -30,7 +31,6 @@ import mage.filter.Filter; import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.permanent.ControllerIdPredicate; @@ -442,6 +442,11 @@ public abstract class GameImpl implements Game { return object; } + @Override + public MageObject getObject(Ability source) { + return source != null ? getObject(source.getSourceId()) : null; + } + /** * Get permanent, card or command object (not spell or ability on the stack) * @@ -1126,16 +1131,20 @@ public abstract class GameImpl implements Game { return; } + // Apply shield counter mechanic from SNC + state.addAbility(new SimpleStaticAbility(Zone.ALL, new ShieldCounterEffect()), null); + // Handle companions Map playerCompanionMap = new HashMap<>(); for (Player player : state.getPlayers().values()) { // Make a list of legal companions present in the sideboard + Set cards = new HashSet<>(player.getLibrary().getCards(this)); Set potentialCompanions = new HashSet<>(); for (Card card : player.getSideboard().getUniqueCards(this)) { for (Ability ability : card.getAbilities(this)) { if (ability instanceof CompanionAbility) { CompanionAbility companionAbility = (CompanionAbility) ability; - if (companionAbility.isLegal(new HashSet<>(player.getLibrary().getCards(this)), startingHandSize)) { + if (companionAbility.isLegal(cards, startingHandSize)) { potentialCompanions.add(card); break; } @@ -1293,6 +1302,8 @@ public abstract class GameImpl implements Game { newWatchers.add(new CardsDrawnThisTurnWatcher()); newWatchers.add(new ManaSpentToCastWatcher()); newWatchers.add(new ManaPaidSourceWatcher()); + newWatchers.add(new BlockingOrBlockedWatcher()); + newWatchers.add(new EndStepCountWatcher()); newWatchers.add(new CommanderPlaysCountWatcher()); // commander plays count uses in non commander games by some cards // runtime check - allows only GAME scope (one watcher per game) @@ -2386,10 +2397,16 @@ public abstract class GameImpl implements Game { } } else { Filter auraFilter = spellAbility.getTargets().get(0).getFilter(); - if (auraFilter instanceof FilterControlledPermanent) { - if (!((FilterControlledPermanent) auraFilter).match(attachedTo, perm.getId(), perm.getControllerId(), this) + if (auraFilter instanceof FilterPermanent) { + if (!((FilterPermanent) auraFilter).match(attachedTo, perm.getControllerId(), perm.getSpellAbility(), this) || attachedTo.cantBeAttachedBy(perm, null, this, true)) { - if (movePermanentToGraveyardWithInfo(perm)) { + Card card = this.getCard(perm.getId()); + if (card != null && card.isCreature(this)) { + UUID wasAttachedTo = perm.getAttachedTo(); + perm.attachTo(null, null, this); + BestowAbility.becomeCreature(perm, this); + fireEvent(new UnattachedEvent(wasAttachedTo, perm.getId(), perm, null)); + } else if (movePermanentToGraveyardWithInfo(perm)) { somethingHappened = true; } } @@ -2561,7 +2578,7 @@ public abstract class GameImpl implements Game { filterLegendName.add(SuperType.LEGENDARY.getPredicate()); filterLegendName.add(new NamePredicate(legend.getName())); filterLegendName.add(new ControllerIdPredicate(legend.getControllerId())); - if (getBattlefield().contains(filterLegendName, null, legend.getControllerId(), this, 2)) { + if (getBattlefield().contains(filterLegendName, null, legend.getControllerId(), null, this, 2)) { if (!replaceEvent(GameEvent.getEvent(GameEvent.EventType.DESTROY_PERMANENT_BY_LEGENDARY_RULE, legend.getId(), legend.getControllerId()))) { Player controller = this.getPlayer(legend.getControllerId()); if (controller != null) { @@ -3140,7 +3157,7 @@ public abstract class GameImpl implements Game { result.setRemainingAmount(amountToPrevent - result.getPreventedDamage()); } MageObject damageSource = game.getObject(damageEvent.getSourceId()); - MageObject preventionSource = game.getObject(source.getSourceId()); + MageObject preventionSource = game.getObject(source); if (damageSource != null && preventionSource != null) { MageObject targetObject = game.getObject(event.getTargetId()); diff --git a/Mage/src/main/java/mage/game/combat/Combat.java b/Mage/src/main/java/mage/game/combat/Combat.java index 482d8059a16..2b109a1af4f 100644 --- a/Mage/src/main/java/mage/game/combat/Combat.java +++ b/Mage/src/main/java/mage/game/combat/Combat.java @@ -384,7 +384,7 @@ public class Combat implements Serializable, Copyable { } } - if (target.choose(Outcome.Benefit, attackingPlayerId, null, game)) { + if (target.choose(Outcome.Benefit, attackingPlayerId, null, null, game)) { isBanded = true; for (UUID targetId : target.getTargets()) { Permanent permanent = game.getPermanent(targetId); @@ -440,65 +440,76 @@ public class Combat implements Serializable, Copyable { for (Permanent creature : player.getAvailableAttackers(game)) { boolean mustAttack = false; Set defendersForcedToAttack = new HashSet<>(); - - // check if a creature has to attack - for (Map.Entry> entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, false, game).entrySet()) { - RequirementEffect effect = entry.getKey(); - if (effect.mustAttack(game) - && checkAttackRestrictions(player, game)) { // needed for Goad Effect + if (creature.getGoadingPlayers().isEmpty()) { + // check if a creature has to attack + for (Map.Entry> entry : game.getContinuousEffects().getApplicableRequirementEffects(creature, false, game).entrySet()) { + RequirementEffect effect = entry.getKey(); + if (!effect.mustAttack(game)) { + continue; + } mustAttack = true; for (Ability ability : entry.getValue()) { UUID defenderId = effect.mustAttackDefender(ability, game); - if (defenderId != null) { - if (defenders.contains(defenderId)) { - defendersForcedToAttack.add(defenderId); - } + if (defenderId != null && defenders.contains(defenderId)) { + defendersForcedToAttack.add(defenderId); } break; } } + } else { + // if creature is goaded then we start with assumption that it needs to attack any player + mustAttack = true; + defendersForcedToAttack.addAll(defenders); } - if (mustAttack) { - // check which defenders the forced to attack creature can attack without paying a cost - Set defendersCostlessAttackable = new HashSet<>(defenders); - for (UUID defenderId : defenders) { - if (game.getContinuousEffects().checkIfThereArePayCostToAttackBlockEffects( - new DeclareAttackerEvent(defenderId, creature.getId(), creature.getControllerId()), game)) { - defendersCostlessAttackable.remove(defenderId); - defendersForcedToAttack.remove(defenderId); - } - } - // force attack only if a defender can be attacked without paying a cost - if (!defendersCostlessAttackable.isEmpty()) { - creaturesForcedToAttack.put(creature.getId(), defendersForcedToAttack); - // No need to attack a special defender - if (defendersForcedToAttack.isEmpty()) { - if (defendersCostlessAttackable.size() == 1) { - player.declareAttacker(creature.getId(), defendersCostlessAttackable.iterator().next(), game, false); - } else { - TargetDefender target = new TargetDefender(defendersCostlessAttackable, creature.getId()); - target.setRequired(true); - target.setTargetName("planeswalker or player for " + creature.getLogName() + " to attack (must attack effect)"); - if (player.chooseTarget(Outcome.Damage, target, null, game)) { - player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false); - } - } - } else { - if (defendersForcedToAttack.size() == 1) { - player.declareAttacker(creature.getId(), defendersForcedToAttack.iterator().next(), game, false); - } else { - TargetDefender target = new TargetDefender(defendersForcedToAttack, creature.getId()); - target.setRequired(true); - target.setTargetName("planeswalker or player for " + creature.getLogName() + " to attack (must attack effect)"); - if (player.chooseTarget(Outcome.Damage, target, null, game)) { - player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false); - } - } - } - } - + if (!mustAttack) { + continue; + } + // check which defenders the forced to attack creature can attack without paying a cost + Set defendersCostlessAttackable = new HashSet<>(defenders); + for (UUID defenderId : defenders) { + if (game.getContinuousEffects().checkIfThereArePayCostToAttackBlockEffects( + new DeclareAttackerEvent(defenderId, creature.getId(), creature.getControllerId()), game + )) { + defendersCostlessAttackable.remove(defenderId); + defendersForcedToAttack.remove(defenderId); + continue; + } + for (Map.Entry> entry : game.getContinuousEffects().getApplicableRestrictionEffects(creature, game).entrySet()) { + if (entry + .getValue() + .stream() + .anyMatch(ability -> entry.getKey().canAttack( + creature, defenderId, ability, game, false + ))) { + continue; + } + defendersCostlessAttackable.remove(defenderId); + defendersForcedToAttack.remove(defenderId); + break; + } + } + // if creature can attack someone other than a player that goaded them + // then they attack one of those players, otherwise they attack any player + if (!defendersForcedToAttack.stream().allMatch(creature.getGoadingPlayers()::contains)) { + defendersForcedToAttack.removeAll(creature.getGoadingPlayers()); + } + // force attack only if a defender can be attacked without paying a cost + if (defendersCostlessAttackable.isEmpty()) { + continue; + } + creaturesForcedToAttack.put(creature.getId(), defendersForcedToAttack); + // No need to attack a special defender + Set defendersToChooseFrom = defendersForcedToAttack.isEmpty() ? defendersCostlessAttackable : defendersForcedToAttack; + if (defendersToChooseFrom.size() == 1) { + player.declareAttacker(creature.getId(), defendersToChooseFrom.iterator().next(), game, false); + continue; + } + TargetDefender target = new TargetDefender(defendersToChooseFrom, creature.getId()); + target.setRequired(true); + target.setTargetName("planeswalker or player for " + creature.getLogName() + " to attack (must attack effect)"); + if (player.chooseTarget(Outcome.Damage, target, null, game)) { + player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false); } - } } @@ -529,28 +540,30 @@ public class Combat implements Serializable, Copyable { for (Map.Entry> entry : game.getContinuousEffects().getApplicableRestrictionEffects(attackingCreature, game).entrySet()) { RestrictionEffect effect = entry.getKey(); for (Ability ability : entry.getValue()) { - if (!effect.canAttackCheckAfter(numberAttackers, ability, game, true)) { - MageObject sourceObject = ability.getSourceObject(game); - if (attackingPlayer.isHuman()) { - attackingPlayer.resetPlayerPassedActions(); - game.informPlayer(attackingPlayer, attackingCreature.getIdName() + " can't attack this way (" + (sourceObject == null ? "null" : sourceObject.getIdName()) + ')'); - return false; - } else { - // remove attacking creatures for AI that are not allowed to attack - // can create possible not allowed attack scenarios, but not sure how to solve this - for (CombatGroup combatGroup : this.getGroups()) { - if (combatGroup.getAttackers().contains(attackingCreatureId)) { - attackerToRemove = attackingCreatureId; - } - } - check = true; // do the check again - if (numberOfChecks > 50) { - logger.error("Seems to be an AI declare attacker lock (reached 50 check iterations) " + (sourceObject == null ? "null" : sourceObject.getIdName())); - return true; // break the check - } - continue Check; - } + if (effect.canAttackCheckAfter(numberAttackers, ability, game, true)) { + continue; } + MageObject sourceObject = ability.getSourceObject(game); + if (attackingPlayer.isHuman()) { + attackingPlayer.resetPlayerPassedActions(); + game.informPlayer(attackingPlayer, attackingCreature.getIdName() + " can't attack this way (" + (sourceObject == null ? "null" : sourceObject.getIdName()) + ')'); + return false; + } + // remove attacking creatures for AI that are not allowed to attack + // can create possible not allowed attack scenarios, but not sure how to solve this + if (this.getGroups() + .stream() + .map(CombatGroup::getAttackers) + .flatMap(Collection::stream) + .anyMatch(attackingCreatureId::equals)) { + attackerToRemove = attackingCreatureId; + } + check = true; // do the check again + if (numberOfChecks > 50) { + logger.error("Seems to be an AI declare attacker lock (reached 50 check iterations) " + (sourceObject == null ? "null" : sourceObject.getIdName())); + return true; // break the check + } + continue Check; } } } @@ -1300,21 +1313,20 @@ public class Combat implements Serializable, Copyable { @SuppressWarnings("deprecation") public boolean declareAttacker(UUID creatureId, UUID defenderId, UUID playerId, Game game) { Permanent attacker = game.getPermanent(creatureId); - if (attacker != null) { - if (!game.replaceEvent(new DeclareAttackerEvent(defenderId, creatureId, playerId))) { - if (addAttackerToCombat(creatureId, defenderId, game)) { - if (!attacker.hasAbility(VigilanceAbility.getInstance(), game) - && !attacker.hasAbility(JohanVigilanceAbility.getInstance(), game)) { - if (!attacker.isTapped()) { - attacker.setTapped(true); - attackersTappedByAttack.add(attacker.getId()); - } - } - return true; - } - } + if (attacker == null + || game.replaceEvent(new DeclareAttackerEvent(defenderId, creatureId, playerId)) + || !addAttackerToCombat(creatureId, defenderId, game)) { + return false; } - return false; + if (attacker.hasAbility(VigilanceAbility.getInstance(), game) + || attacker.hasAbility(JohanVigilanceAbility.getInstance(), game)) { + return true; + } + if (!attacker.isTapped()) { + attacker.setTapped(true); + attackersTappedByAttack.add(attacker.getId()); + } + return true; } public boolean addAttackerToCombat(UUID attackerId, UUID defenderId, Game game) { diff --git a/Mage/src/main/java/mage/game/command/Commander.java b/Mage/src/main/java/mage/game/command/Commander.java index 08449a16bb8..47584bd9f1e 100644 --- a/Mage/src/main/java/mage/game/command/Commander.java +++ b/Mage/src/main/java/mage/game/command/Commander.java @@ -8,7 +8,6 @@ import mage.abilities.common.CastCommanderAbility; import mage.abilities.common.PlayLandAsCommanderAbility; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; -import mage.abilities.text.TextPart; import mage.cards.Card; import mage.cards.FrameStyle; import mage.constants.CardType; @@ -273,14 +272,6 @@ public class Commander implements CommandObject { public void setStartingLoyalty(int startingLoyalty) { } - @Override - public void adjustCosts(Ability ability, Game game) { - } - - @Override - public void adjustTargets(Ability ability, Game game) { - } - @Override public UUID getId() { return sourceObject.getId(); @@ -308,25 +299,17 @@ public class Commander implements CommandObject { @Override public boolean isAllCreatureTypes(Game game) { - return false; + return sourceObject.isAllCreatureTypes(game); } @Override public void setIsAllCreatureTypes(boolean value) { + sourceObject.setIsAllCreatureTypes(value); } @Override public void setIsAllCreatureTypes(Game game, boolean value) { - } - - @Override - public List getTextParts() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public TextPart addTextPart(TextPart textPart) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + sourceObject.setIsAllCreatureTypes(game, value); } @Override diff --git a/Mage/src/main/java/mage/game/command/Dungeon.java b/Mage/src/main/java/mage/game/command/Dungeon.java index 0170c47b762..5d8a470e1eb 100644 --- a/Mage/src/main/java/mage/game/command/Dungeon.java +++ b/Mage/src/main/java/mage/game/command/Dungeon.java @@ -12,7 +12,6 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; import mage.abilities.hint.HintUtils; -import mage.abilities.text.TextPart; import mage.cards.FrameStyle; import mage.choices.Choice; import mage.choices.ChoiceHintType; @@ -318,14 +317,6 @@ public class Dungeon implements CommandObject { public void setStartingLoyalty(int startingLoyalty) { } - @Override - public void adjustCosts(Ability ability, Game game) { - } - - @Override - public void adjustTargets(Ability ability, Game game) { - } - @Override public UUID getId() { return this.id; @@ -382,16 +373,6 @@ public class Dungeon implements CommandObject { } } - @Override - public List getTextParts() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public TextPart addTextPart(TextPart textPart) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - @Override public void removePTCDA() { } diff --git a/Mage/src/main/java/mage/game/command/Emblem.java b/Mage/src/main/java/mage/game/command/Emblem.java index 2e4fef05581..1372ababdd8 100644 --- a/Mage/src/main/java/mage/game/command/Emblem.java +++ b/Mage/src/main/java/mage/game/command/Emblem.java @@ -11,7 +11,6 @@ import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; -import mage.abilities.text.TextPart; import mage.cards.Card; import mage.cards.FrameStyle; import mage.constants.CardType; @@ -227,14 +226,6 @@ public class Emblem implements CommandObject { public void setStartingLoyalty(int startingLoyalty) { } - @Override - public void adjustCosts(Ability ability, Game game) { - } - - @Override - public void adjustTargets(Ability ability, Game game) { - } - @Override public UUID getId() { return this.id; @@ -291,16 +282,6 @@ public class Emblem implements CommandObject { } } - @Override - public List getTextParts() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public TextPart addTextPart(TextPart textPart) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - @Override public void removePTCDA() { } diff --git a/Mage/src/main/java/mage/game/command/Plane.java b/Mage/src/main/java/mage/game/command/Plane.java index ca483d84195..1d44b5e4e57 100644 --- a/Mage/src/main/java/mage/game/command/Plane.java +++ b/Mage/src/main/java/mage/game/command/Plane.java @@ -11,7 +11,6 @@ import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; -import mage.abilities.text.TextPart; import mage.cards.Card; import mage.cards.FrameStyle; import mage.constants.CardType; @@ -236,14 +235,6 @@ public class Plane implements CommandObject { public void setStartingLoyalty(int startingLoyalty) { } - @Override - public void adjustCosts(Ability ability, Game game) { - } - - @Override - public void adjustTargets(Ability ability, Game game) { - } - @Override public UUID getId() { return this.id; @@ -300,16 +291,6 @@ public class Plane implements CommandObject { } } - @Override - public List getTextParts() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public TextPart addTextPart(TextPart textPart) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - @Override public void removePTCDA() { } diff --git a/Mage/src/main/java/mage/game/command/dungeons/TombOfAnnihilationDungeon.java b/Mage/src/main/java/mage/game/command/dungeons/TombOfAnnihilationDungeon.java index 02a250a6ae0..5f56eaffdac 100644 --- a/Mage/src/main/java/mage/game/command/dungeons/TombOfAnnihilationDungeon.java +++ b/Mage/src/main/java/mage/game/command/dungeons/TombOfAnnihilationDungeon.java @@ -105,7 +105,7 @@ class VeilsOfFearEffect extends OneShotEffect { continue; } TargetDiscard target = new TargetDiscard(0, 1, StaticFilters.FILTER_CARD, playerId); - player.choose(Outcome.PreventDamage, target, source.getSourceId(), game); + player.choose(Outcome.PreventDamage, target, source, game); map.put(playerId, game.getCard(target.getFirstTarget())); } for (Map.Entry entry : map.entrySet()) { @@ -151,7 +151,7 @@ class OublietteEffect extends OneShotEffect { return true; } OublietteTarget target = new OublietteTarget(Math.min(saccable, 3)); - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); + player.choose(Outcome.Sacrifice, target, source, game); for (UUID targetId : target.getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent != null) { @@ -207,8 +207,8 @@ class OublietteTarget extends TargetControlledPermanent { @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set possibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); possibleTargets.removeIf(uuid -> !this.canTarget(sourceControllerId, uuid, null, game)); return possibleTargets; } @@ -216,7 +216,7 @@ class OublietteTarget extends TargetControlledPermanent { static int checkTargetCount(Ability source, Game game) { List permanents = game .getBattlefield() - .getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); + .getActivePermanents(filter, source.getControllerId(), source, game); return cardTypeAssigner.getRoleCount(new CardsImpl(permanents), game); } } @@ -246,7 +246,7 @@ class SandfallCellEffect extends OneShotEffect { continue; } TargetPermanent target = new TargetPermanent(0, 1, TombOfAnnihilationDungeon.filter, true); - player.choose(Outcome.PreventDamage, target, source.getSourceId(), game); + player.choose(Outcome.PreventDamage, target, source, game); map.put(playerId, game.getPermanent(target.getFirstTarget())); } for (Map.Entry entry : map.entrySet()) { diff --git a/Mage/src/main/java/mage/game/command/emblems/DarettiScrapSavantEmblem.java b/Mage/src/main/java/mage/game/command/emblems/DarettiScrapSavantEmblem.java index e9481b5ce9a..33ebf2dddc9 100644 --- a/Mage/src/main/java/mage/game/command/emblems/DarettiScrapSavantEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/DarettiScrapSavantEmblem.java @@ -93,7 +93,7 @@ class DarettiScrapSavantEffect extends OneShotEffect { Effect effect = new ReturnFromGraveyardToBattlefieldTargetEffect(); effect.setTargetPointer(new FixedTarget(card, game)); effect.setText("return that card to the battlefield at the beginning of the next end step"); - game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone.COMMAND, effect, TargetController.ANY), source); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect, TargetController.ANY), source); return true; } return false; diff --git a/Mage/src/main/java/mage/game/command/emblems/KayaTheInexorableEmblem.java b/Mage/src/main/java/mage/game/command/emblems/KayaTheInexorableEmblem.java index 96b753831dd..598351cb342 100644 --- a/Mage/src/main/java/mage/game/command/emblems/KayaTheInexorableEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/KayaTheInexorableEmblem.java @@ -1,48 +1,51 @@ package mage.game.command.emblems; -import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.choices.Choice; import mage.choices.ChoiceImpl; -import mage.constants.*; +import mage.constants.Outcome; +import mage.constants.SuperType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterCard; import mage.filter.common.FilterOwnedCard; -import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.command.Emblem; import mage.players.Player; -import mage.target.TargetCard; -import mage.target.common.TargetCardInExile; -import mage.target.common.TargetCardInHand; -import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; import java.util.LinkedHashSet; import java.util.Set; /** - * * @author weirddan455 */ -public class KayaTheInexorableEmblem extends Emblem { +public class KayaTheInexorableEmblem extends Emblem { // −7: You get an emblem with "At the beginning of your upkeep, you may cast a legendary spell from your hand, from your graveyard, or from among cards you own in exile without paying its mana cost." public KayaTheInexorableEmblem() { this.setName("Emblem Kaya"); this.setExpansionSetCodeForImage("KHM"); - this.getAbilities().add(new BeginningOfUpkeepTriggeredAbility(Zone.COMMAND, new KayaTheInexorableEmblemEffect(), TargetController.YOU, true, false)); + this.getAbilities().add(new BeginningOfUpkeepTriggeredAbility( + Zone.COMMAND, new KayaTheInexorableEmblemEffect(), + TargetController.YOU, true, false + )); } } class KayaTheInexorableEmblemEffect extends OneShotEffect { - private static final FilterOwnedCard filter = new FilterOwnedCard(); + private static final FilterCard filter = new FilterOwnedCard(); + private static final FilterCard filter2 = new FilterCard(); private static final Set choices = new LinkedHashSet<>(); + static { - filter.add(SuperType.LEGENDARY.getPredicate()); - filter.add(Predicates.not(CardType.LAND.getPredicate())); + filter2.add(SuperType.LEGENDARY.getPredicate()); choices.add("Hand"); choices.add("Graveyard"); choices.add("Exile"); @@ -50,7 +53,8 @@ class KayaTheInexorableEmblemEffect extends OneShotEffect { public KayaTheInexorableEmblemEffect() { super(Outcome.PlayForFree); - this.staticText = "cast a legendary spell from your hand, from your graveyard, or from among cards you own in exile without paying its mana cost"; + this.staticText = "cast a legendary spell from your hand, from your graveyard, " + + "or from among cards you own in exile without paying its mana cost"; } private KayaTheInexorableEmblemEffect(final KayaTheInexorableEmblemEffect effect) { @@ -65,40 +69,26 @@ class KayaTheInexorableEmblemEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - Choice zoneChoice = new ChoiceImpl(true); - zoneChoice.setMessage("Cast a legendary spell from hand, graveyard, or exile"); - zoneChoice.setChoices(choices); - zoneChoice.clearChoice(); - if (player.choose(Outcome.PlayForFree, zoneChoice, game)) { - TargetCard target = null; - switch (zoneChoice.getChoice()) { - case "Hand": - target = new TargetCardInHand(0, 1, filter); - target.setTargetName("legendary spell from your hand"); - break; - case "Graveyard": - target = new TargetCardInYourGraveyard(0, 1, filter, true); - target.setTargetName("legendary spell from your graveyard"); - break; - case "Exile": - target = new TargetCardInExile(0, 1, filter, null, true); - target.setNotTarget(true); - target.setTargetName("legendary spell you own in exile"); - break; - } - if (target != null && player.chooseTarget(Outcome.PlayForFree, target, source, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - boolean cardWasCast = player.cast(player.chooseAbilityForCast(card, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - return cardWasCast; - } - } - } + if (player == null) { + return false; } - return false; + Choice zoneChoice = new ChoiceImpl(true); + zoneChoice.setMessage("Cast a legendary spell from hand, graveyard, or exile"); + zoneChoice.setChoices(choices); + zoneChoice.clearChoice(); + player.choose(Outcome.PlayForFree, zoneChoice, game); + Cards cards = new CardsImpl(); + switch (zoneChoice.getChoice()) { + case "Hand": + cards.addAll(player.getHand()); + break; + case "Graveyard": + cards.addAll(player.getGraveyard()); + break; + case "Exile": + cards.addAll(game.getExile().getCards(filter, game)); + break; + } + return CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter2); } } diff --git a/Mage/src/main/java/mage/game/command/emblems/KothOfTheHammerEmblem.java b/Mage/src/main/java/mage/game/command/emblems/KothOfTheHammerEmblem.java index ad4ecfda6d6..f21f8dfc508 100644 --- a/Mage/src/main/java/mage/game/command/emblems/KothOfTheHammerEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/KothOfTheHammerEmblem.java @@ -51,7 +51,7 @@ class KothOfTheHammerThirdEffect extends ContinuousEffectImpl { switch (layer) { case AbilityAddingRemovingEffects_6: if (sublayer == SubLayer.NA) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(mountains, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(mountains, source.getControllerId(), source, game)) { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new TapSourceCost()); ability.addTarget(new TargetAnyTarget()); permanent.addAbility(ability, source.getSourceId(), game); diff --git a/Mage/src/main/java/mage/game/command/emblems/LilianaDefiantNecromancerEmblem.java b/Mage/src/main/java/mage/game/command/emblems/LilianaDefiantNecromancerEmblem.java index e9195046aee..fdc8029e6be 100644 --- a/Mage/src/main/java/mage/game/command/emblems/LilianaDefiantNecromancerEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/LilianaDefiantNecromancerEmblem.java @@ -53,7 +53,7 @@ class LilianaDefiantNecromancerEmblemEffect extends OneShotEffect { Effect effect = new ReturnFromGraveyardToBattlefieldTargetEffect(); effect.setTargetPointer(new FixedTarget(card, game)); effect.setText("return that card to the battlefield at the beginning of the next end step"); - game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(Zone.COMMAND, effect, TargetController.ANY), source); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect, TargetController.ANY), source); return true; } return false; diff --git a/Mage/src/main/java/mage/game/command/emblems/LolthSpiderQueenEmblem.java b/Mage/src/main/java/mage/game/command/emblems/LolthSpiderQueenEmblem.java index 9293b282ef9..a756c179563 100644 --- a/Mage/src/main/java/mage/game/command/emblems/LolthSpiderQueenEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/LolthSpiderQueenEmblem.java @@ -1,7 +1,7 @@ package mage.game.command.emblems; import mage.abilities.Ability; -import mage.abilities.common.ControlledCreaturesDealCombatDamagePlayerTriggeredAbility; +import mage.abilities.common.DealCombatDamageControlledTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.Effect; @@ -25,7 +25,7 @@ public final class LolthSpiderQueenEmblem extends Emblem { this.setName("Emblem Lolth"); this.setExpansionSetCodeForImage("AFR"); this.getAbilities().add(new ConditionalInterveningIfTriggeredAbility( - new ControlledCreaturesDealCombatDamagePlayerTriggeredAbility( + new DealCombatDamageControlledTriggeredAbility( Zone.COMMAND, new LolthSpiderQueenEmblemEffect(), true, true ), LolthSpiderQueenEmblemCondition.instance, "Whenever an opponent " + "is dealt combat damage by one or more creatures you control, " + diff --git a/Mage/src/main/java/mage/game/command/emblems/NarsetTranscendentEmblem.java b/Mage/src/main/java/mage/game/command/emblems/NarsetTranscendentEmblem.java index 80af9b6b1a8..6702ed52da7 100644 --- a/Mage/src/main/java/mage/game/command/emblems/NarsetTranscendentEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/NarsetTranscendentEmblem.java @@ -52,7 +52,7 @@ class NarsetTranscendentCantCastEffect extends ContinuousRuleModifyingEffectImpl @Override public String getInfoMessage(Ability source, GameEvent event, Game game) { - MageObject mageObject = game.getObject(source.getSourceId()); + MageObject mageObject = game.getObject(source); if (mageObject != null) { return "You can't cast can't cast noncreature spells (it is prevented by emblem of " + mageObject.getLogName() + ')'; } diff --git a/Mage/src/main/java/mage/game/command/emblems/SerraTheBenevolentEmblem.java b/Mage/src/main/java/mage/game/command/emblems/SerraTheBenevolentEmblem.java index 1d0ad23d58a..564e6dbb0c7 100644 --- a/Mage/src/main/java/mage/game/command/emblems/SerraTheBenevolentEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/SerraTheBenevolentEmblem.java @@ -53,7 +53,7 @@ class SerraTheBenevolentEmblemEffect extends ReplacementEffectImpl { && (controller.getLife() - event.getAmount()) < 1 && game.getBattlefield().count( StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getSourceId(), event.getPlayerId(), game) > 0 + event.getPlayerId(), source, game) > 0 ) { event.setAmount(controller.getLife() - 1); } diff --git a/Mage/src/main/java/mage/game/command/emblems/TamiyoTheMoonSageEmblem.java b/Mage/src/main/java/mage/game/command/emblems/TamiyoTheMoonSageEmblem.java index 6034f77158f..cb910858cb4 100644 --- a/Mage/src/main/java/mage/game/command/emblems/TamiyoTheMoonSageEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/TamiyoTheMoonSageEmblem.java @@ -1,10 +1,7 @@ - package mage.game.command.emblems; -import mage.abilities.Ability; import mage.abilities.common.PutCardIntoGraveFromAnywhereAllTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect.HandSizeModification; @@ -12,11 +9,10 @@ import mage.constants.Duration; import mage.constants.SetTargetPointer; import mage.constants.TargetController; import mage.constants.Zone; -import mage.filter.FilterCard; +import mage.filter.StaticFilters; import mage.game.command.Emblem; /** - * * @author spjspj */ public final class TamiyoTheMoonSageEmblem extends Emblem { @@ -28,11 +24,12 @@ public final class TamiyoTheMoonSageEmblem extends Emblem { public TamiyoTheMoonSageEmblem() { this.setName("Emblem Tamiyo"); - Ability ability = new SimpleStaticAbility(Zone.COMMAND, new MaximumHandSizeControllerEffect(Integer.MAX_VALUE, Duration.EndOfGame, HandSizeModification.SET)); - this.getAbilities().add(ability); - Effect effect = new ReturnToHandTargetEffect(); - effect.setText("return it to your hand"); + this.getAbilities().add(new SimpleStaticAbility(Zone.COMMAND, new MaximumHandSizeControllerEffect( + Integer.MAX_VALUE, Duration.Custom, HandSizeModification.SET + ))); this.getAbilities().add(new PutCardIntoGraveFromAnywhereAllTriggeredAbility( - Zone.COMMAND, effect, true, new FilterCard("a card"), TargetController.YOU, SetTargetPointer.CARD)); + Zone.COMMAND, new ReturnToHandTargetEffect().setText("return it to your hand"), + true, StaticFilters.FILTER_CARD_A, TargetController.YOU, SetTargetPointer.CARD + )); } } diff --git a/Mage/src/main/java/mage/game/command/emblems/TezzeretBetrayerOfFleshEmblem.java b/Mage/src/main/java/mage/game/command/emblems/TezzeretBetrayerOfFleshEmblem.java new file mode 100644 index 00000000000..48a63cb23c9 --- /dev/null +++ b/Mage/src/main/java/mage/game/command/emblems/TezzeretBetrayerOfFleshEmblem.java @@ -0,0 +1,23 @@ +package mage.game.command.emblems; + +import mage.abilities.common.BecomesTappedTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.command.Emblem; + +/** + * @author TheElk801 + */ +public final class TezzeretBetrayerOfFleshEmblem extends Emblem { + + // −6: You get an emblem with "Whenever an artifact you control becomes tapped, draw a card." + public TezzeretBetrayerOfFleshEmblem() { + this.setName("Emblem Tezzeret"); + this.setExpansionSetCodeForImage("NEO"); + this.getAbilities().add(new BecomesTappedTriggeredAbility( + Zone.COMMAND, new DrawCardSourceControllerEffect(1), false, + StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, false + )); + } +} diff --git a/Mage/src/main/java/mage/game/command/planes/HedronFieldsOfAgadeemPlane.java b/Mage/src/main/java/mage/game/command/planes/HedronFieldsOfAgadeemPlane.java index 4e498c5bfe3..87af270d4b7 100644 --- a/Mage/src/main/java/mage/game/command/planes/HedronFieldsOfAgadeemPlane.java +++ b/Mage/src/main/java/mage/game/command/planes/HedronFieldsOfAgadeemPlane.java @@ -95,6 +95,6 @@ class HedronFieldsOfAgadeemRestrictionEffect extends RestrictionEffect { if (!cPlane.getPlaneType().equals(Planes.PLANE_HEDRON_FIELDS_OF_AGADEEM)) { return false; } - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filter.match(permanent, source.getControllerId(), source, game); } } diff --git a/Mage/src/main/java/mage/game/command/planes/TazeemPlane.java b/Mage/src/main/java/mage/game/command/planes/TazeemPlane.java index 1671cd06640..6f9ba42e1ba 100644 --- a/Mage/src/main/java/mage/game/command/planes/TazeemPlane.java +++ b/Mage/src/main/java/mage/game/command/planes/TazeemPlane.java @@ -80,7 +80,7 @@ class TazeemCantBlockAllEffect extends RestrictionEffect { if (cPlane == null || !cPlane.getPlaneType().equals(Planes.PLANE_TAZEEM)) { return false; } - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filter.match(permanent, source.getControllerId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/game/permanent/Battlefield.java b/Mage/src/main/java/mage/game/permanent/Battlefield.java index b98857d6821..016c83c951a 100644 --- a/Mage/src/main/java/mage/game/permanent/Battlefield.java +++ b/Mage/src/main/java/mage/game/permanent/Battlefield.java @@ -70,17 +70,16 @@ public class Battlefield implements Serializable { * influence of the specified player id and that match the supplied filter. * * @param filter - * @param sourceId - sourceId of the MageObject the calling effect/ability - * belongs to * @param sourcePlayerId + * @param source * @param game * @return count */ - public int count(FilterPermanent filter, UUID sourceId, UUID sourcePlayerId, Game game) { + public int count(FilterPermanent filter, UUID sourcePlayerId, Ability source, Game game) { if (game.getRangeOfInfluence() == RangeOfInfluence.ALL) { return (int) field.values() .stream() - .filter(permanent -> filter.match(permanent, sourceId, sourcePlayerId, game) + .filter(permanent -> filter.match(permanent, sourcePlayerId, source, game) && permanent.isPhasedIn()) .count(); } else { @@ -88,13 +87,13 @@ public class Battlefield implements Serializable { return (int) field.values() .stream() .filter(permanent -> range.contains(permanent.getControllerId()) - && filter.match(permanent, sourceId, sourcePlayerId, game) + && filter.match(permanent, sourcePlayerId, source, game) && permanent.isPhasedIn()).count(); } } public boolean containsControlled(FilterPermanent filter, Ability source, Game game, int num) { - return containsControlled(filter, source.getSourceId(), source.getControllerId(), game, num); + return containsControlled(filter, source.getSourceId(), source.getControllerId(), source, game, num); } /** @@ -105,22 +104,23 @@ public class Battlefield implements Serializable { * @param filter * @param sourceId * @param controllerId controller and source can be different (from different players) - * @param num + * @param source * @param game + * @param num * @return boolean */ - public boolean containsControlled(FilterPermanent filter, UUID sourceId, UUID controllerId, Game game, int num) { + public boolean containsControlled(FilterPermanent filter, UUID sourceId, UUID controllerId, Ability source, Game game, int num) { return field.values() .stream() .filter(permanent -> permanent.isControlledBy(controllerId) - && filter.match(permanent, sourceId, controllerId, game) + && filter.match(permanent, controllerId, source, game) && permanent.isPhasedIn()) .count() >= num; } public boolean contains(FilterPermanent filter, Ability source, Game game, int num) { - return contains(filter, source.getSourceId(), source.getControllerId(), game, num); + return contains(filter, source.getSourceId(), source.getControllerId(), source, game, num); } /** @@ -131,21 +131,22 @@ public class Battlefield implements Serializable { * @param filter * @param sourceId can be null for default SBA checks like legendary rule * @param sourcePlayerId + * @param source * @param game * @param num * @return boolean */ - public boolean contains(FilterPermanent filter, UUID sourceId, UUID sourcePlayerId, Game game, int num) { + public boolean contains(FilterPermanent filter, UUID sourceId, UUID sourcePlayerId, Ability source, Game game, int num) { if (game.getRangeOfInfluence() == RangeOfInfluence.ALL) { return field.values().stream() - .filter(permanent -> filter.match(permanent, sourceId, sourcePlayerId, game) + .filter(permanent -> filter.match(permanent, sourcePlayerId, source, game) && permanent.isPhasedIn()).count() >= num; } else { List range = game.getState().getPlayersInRange(sourcePlayerId, game); return field.values().stream() .filter(permanent -> range.contains(permanent.getControllerId()) - && filter.match(permanent, sourceId, sourcePlayerId, game) + && filter.match(permanent, sourcePlayerId, source, game) && permanent.isPhasedIn()) .count() >= num; } @@ -236,8 +237,8 @@ public class Battlefield implements Serializable { /** * Returns all {@link Permanent} on the battlefield that match the supplied - * filter. This method ignores the range of influence. It ignores controller - * predicates + * filter. This method ignores the range of influence and ignores + * ObjectSourcePlayer predicates in the filter (e.g. controller predicates) * * @param filter * @param game @@ -253,7 +254,8 @@ public class Battlefield implements Serializable { /** * Returns all {@link Permanent} that match the filter and are controlled by - * controllerId. This method ignores the range of influence. + * controllerId. This method ignores the range of influence and ignores + * ObjectSourcePlayer predicates in the filter * * @param filter * @param controllerId @@ -288,23 +290,23 @@ public class Battlefield implements Serializable { * * @param filter * @param sourcePlayerId - * @param sourceId + * @param source * @param game * @return a list of {@link Permanent} * @see Permanent */ - public List getActivePermanents(FilterPermanent filter, UUID sourcePlayerId, UUID sourceId, Game game) { + public List getActivePermanents(FilterPermanent filter, UUID sourcePlayerId, Ability source, Game game) { if (game.getRangeOfInfluence() == RangeOfInfluence.ALL) { return field.values() .stream() - .filter(perm -> perm.isPhasedIn() && filter.match(perm, sourceId, sourcePlayerId, game)) + .filter(perm -> perm.isPhasedIn() && filter.match(perm, sourcePlayerId, source, game)) .collect(Collectors.toList()); } else { List range = game.getState().getPlayersInRange(sourcePlayerId, game); return field.values() .stream() .filter(perm -> perm.isPhasedIn() && range.contains(perm.getControllerId()) - && filter.match(perm, sourceId, sourcePlayerId, game)).collect(Collectors.toList()); + && filter.match(perm, sourcePlayerId, source, game)).collect(Collectors.toList()); } } diff --git a/Mage/src/main/java/mage/game/permanent/Permanent.java b/Mage/src/main/java/mage/game/permanent/Permanent.java index b91b9f740ae..32573f8c066 100644 --- a/Mage/src/main/java/mage/game/permanent/Permanent.java +++ b/Mage/src/main/java/mage/game/permanent/Permanent.java @@ -87,6 +87,10 @@ public interface Permanent extends Card, Controllable { */ boolean setClassLevel(int classLevel); + void addGoadingPlayer(UUID playerId); + + Set getGoadingPlayers(); + void setCardNumber(String cid); void setExpansionSetCode(String expansionSetCode); diff --git a/Mage/src/main/java/mage/game/permanent/PermanentCard.java b/Mage/src/main/java/mage/game/permanent/PermanentCard.java index 7289d13e36e..460edc15d17 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentCard.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentCard.java @@ -61,6 +61,7 @@ public class PermanentCard extends PermanentImpl { private void init(Card card, Game game) { power = card.getPower().copy(); toughness = card.getToughness().copy(); + startingLoyalty = card.getStartingLoyalty(); copyFromCard(card, game); // if temporary added abilities to the spell/card exist, you need to add it to the permanent derived from that card Abilities otherAbilities = game.getState().getAllOtherAbilities(card.getId()); diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index f27244bd087..e0f809d4f83 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -15,7 +15,6 @@ import mage.abilities.effects.common.RegenerateSourceEffect; import mage.abilities.hint.Hint; import mage.abilities.hint.HintUtils; import mage.abilities.keyword.*; -import mage.abilities.text.TextPart; import mage.cards.Card; import mage.cards.CardImpl; import mage.constants.*; @@ -73,6 +72,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { protected boolean manifested = false; protected boolean morphed = false; protected int classLevel = 1; + protected final Set goadingPlayers = new HashSet<>(); protected UUID originalControllerId; protected UUID controllerId; protected UUID beforeResetControllerId; @@ -166,6 +166,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { this.monstrous = permanent.monstrous; this.renowned = permanent.renowned; this.classLevel = permanent.classLevel; + this.goadingPlayers.addAll(permanent.goadingPlayers); this.pairedPermanent = permanent.pairedPermanent; this.bandedCards.addAll(permanent.bandedCards); this.timesLoyaltyUsed = permanent.timesLoyaltyUsed; @@ -210,9 +211,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { this.minBlockedBy = 1; this.maxBlockedBy = 0; this.copy = false; - for (TextPart textPart : textParts) { - textPart.reset(); - } + this.goadingPlayers.clear(); } @Override @@ -1127,19 +1126,35 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { MorphAbility.setPermanentToFaceDownCreature(this, game); } - EntersTheBattlefieldEvent event = new EntersTheBattlefieldEvent(this, source, getControllerId(), fromZone, EnterEventType.SELF); + if (game.replaceEvent(new EntersTheBattlefieldEvent(this, source, getControllerId(), fromZone, EnterEventType.SELF))) { + return false; + } + EntersTheBattlefieldEvent event = new EntersTheBattlefieldEvent(this, source, getControllerId(), fromZone); if (game.replaceEvent(event)) { return false; } - event = new EntersTheBattlefieldEvent(this, source, getControllerId(), fromZone); - if (!game.replaceEvent(event)) { - if (fireEvent) { - game.addSimultaneousEvent(event); - return true; + if (this.isPlaneswalker(game)) { + int loyalty; + if (this.getStartingLoyalty() == -2) { + loyalty = source.getManaCostsToPay().getX(); + } else { + loyalty = this.getStartingLoyalty(); + } + int countersToAdd; + if (this.hasAbility(CompleatedAbility.getInstance(), game)) { + countersToAdd = loyalty - 2 * source.getManaCostsToPay().getPhyrexianPaid(); + } else { + countersToAdd = loyalty; + } + if (countersToAdd > 0) { + this.addCounters(CounterType.LOYALTY.createInstance(countersToAdd), source, game); } - } - return false; + if (!fireEvent) { + return false; + } + game.addSimultaneousEvent(event); + return true; } @Override @@ -1189,14 +1204,11 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public boolean cantBeAttachedBy(MageObject attachment, Ability source, Game game, boolean silentMode) { for (ProtectionAbility ability : this.getAbilities(game).getProtectionAbilities()) { - if (!(attachment.hasSubtype(SubType.AURA, game) - && !ability.removesAuras()) - && !(attachment.hasSubtype(SubType.EQUIPMENT, game) - && !ability.removesEquipment())) { - if (!attachment.getId().equals(ability.getAuraIdNotToBeRemoved()) - && !ability.canTarget(attachment, game)) { - return !ability.getDoesntRemoveControlled() || isControlledBy(game.getControllerId(attachment.getId())); - } + if ((!attachment.hasSubtype(SubType.AURA, game) || ability.removesAuras()) + && (!attachment.hasSubtype(SubType.EQUIPMENT, game) || ability.removesEquipment()) + && !attachment.getId().equals(ability.getAuraIdNotToBeRemoved()) + && !ability.canTarget(attachment, game)) { + return !ability.getDoesntRemoveControlled() || isControlledBy(game.getControllerId(attachment.getId())); } } return game.getContinuousEffects().preventedByRuleModification(new StayAttachedEvent(this.getId(), attachment.getId(), source), null, game, silentMode); @@ -1333,14 +1345,10 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } //20101001 - 508.1c if (defenderId == null) { - boolean oneCanBeAttacked = false; - for (UUID defenderToCheckId : game.getCombat().getDefenders()) { - if (canAttackCheckRestrictionEffects(defenderToCheckId, game)) { - oneCanBeAttacked = true; - break; - } - } - if (!oneCanBeAttacked) { + if (game.getCombat() + .getDefenders() + .stream() + .noneMatch(defenderToCheckId -> canAttackCheckRestrictionEffects(defenderToCheckId, game))) { return false; } } else if (!canAttackCheckRestrictionEffects(defenderId, game)) { @@ -1570,6 +1578,16 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { return false; } + @Override + public void addGoadingPlayer(UUID playerId) { + this.goadingPlayers.add(playerId); + } + + @Override + public Set getGoadingPlayers() { + return goadingPlayers; + } + @Override public void setPairedCard(MageObjectReference pairedCard) { this.pairedPermanent = pairedCard; diff --git a/Mage/src/main/java/mage/game/permanent/PermanentToken.java b/Mage/src/main/java/mage/game/permanent/PermanentToken.java index b6407ac0b1b..ae37d07208e 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentToken.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentToken.java @@ -3,6 +3,7 @@ package mage.game.permanent; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCost; +import mage.abilities.keyword.ChangelingAbility; import mage.cards.Card; import mage.constants.EmptyNames; import mage.game.Game; @@ -86,6 +87,11 @@ public class PermanentToken extends PermanentImpl { this.supertype.addAll(token.getSuperType()); this.subtype.copyFrom(token.getSubtype(game)); this.tokenDescriptor = token.getTokenDescriptor(); + this.startingLoyalty = token.getStartingLoyalty(); + // workaround for entersTheBattlefield replacement effects + if (this.abilities.containsClass(ChangelingAbility.class)) { + this.subtype.setIsAllCreatureTypes(true); + } } @Override diff --git a/Mage/src/main/java/mage/game/permanent/token/ATATToken.java b/Mage/src/main/java/mage/game/permanent/token/ATATToken.java index e58cb29e90b..83de8f16a3f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ATATToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ATATToken.java @@ -14,7 +14,7 @@ import mage.abilities.effects.common.CreateTokenEffect; public final class ATATToken extends TokenImpl { public ATATToken() { - super("AT-AT", "5/5 white artifact AT-AT creature tokens with \"When this creature dies, create two 1/1 white Trooper creature tokens.\"", 5, 5); + super("AT-AT Token", "5/5 white artifact AT-AT creature tokens with \"When this creature dies, create two 1/1 white Trooper creature tokens.\"", 5, 5); this.setOriginalExpansionSetCode("SWS"); cardType.add(CardType.CREATURE); cardType.add(CardType.ARTIFACT); diff --git a/Mage/src/main/java/mage/game/permanent/token/AerieWorshippersBirdToken.java b/Mage/src/main/java/mage/game/permanent/token/AerieWorshippersBirdToken.java index a403149e9fe..37e55da7710 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AerieWorshippersBirdToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/AerieWorshippersBirdToken.java @@ -15,7 +15,7 @@ import mage.abilities.keyword.FlyingAbility; public final class AerieWorshippersBirdToken extends TokenImpl { public AerieWorshippersBirdToken() { - super("Bird", "2/2 blue Bird enchantment creature token with flying"); + super("Bird Token", "2/2 blue Bird enchantment creature token with flying"); cardType.add(CardType.ENCHANTMENT); cardType.add(CardType.CREATURE); color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/AkoumStonewakerElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/AkoumStonewakerElementalToken.java index b4137682d7a..2149e07488f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AkoumStonewakerElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/AkoumStonewakerElementalToken.java @@ -14,7 +14,7 @@ import java.util.Arrays; public final class AkoumStonewakerElementalToken extends TokenImpl { public AkoumStonewakerElementalToken() { - super("Elemental", "3/1 red Elemental creature token with trample and haste"); + super("Elemental Token", "3/1 red Elemental creature token with trample and haste"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.ELEMENTAL); diff --git a/Mage/src/main/java/mage/game/permanent/token/AkroanSoldierToken.java b/Mage/src/main/java/mage/game/permanent/token/AkroanSoldierToken.java index 49b481684e7..8aa189dfafc 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AkroanSoldierToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/AkroanSoldierToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class AkroanSoldierToken extends TokenImpl { public AkroanSoldierToken() { - super("Soldier", "1/1 red Soldier creature token with haste"); + super("Soldier Token", "1/1 red Soldier creature token with haste"); setTokenType(3); cardType.add(CardType.CREATURE); color.setRed(true); @@ -22,7 +22,7 @@ public final class AkroanSoldierToken extends TokenImpl { toughness = new MageInt(1); this.addAbility(HasteAbility.getInstance()); - availableImageSetCodes = Arrays.asList("THS"); + availableImageSetCodes = Arrays.asList("THS", "UMA"); } public AkroanSoldierToken(final AkroanSoldierToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/Angel33Token.java b/Mage/src/main/java/mage/game/permanent/token/Angel33Token.java index 29850afff17..36bad88919b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/Angel33Token.java +++ b/Mage/src/main/java/mage/game/permanent/token/Angel33Token.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class Angel33Token extends TokenImpl { public Angel33Token() { - super("Angel", "3/3 white Angel creature token with flying"); + super("Angel Token", "3/3 white Angel creature token with flying"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.ANGEL); diff --git a/Mage/src/main/java/mage/game/permanent/token/AngelToken.java b/Mage/src/main/java/mage/game/permanent/token/AngelToken.java index db5056b296c..7e54d265d04 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AngelToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/AngelToken.java @@ -10,7 +10,7 @@ import java.util.Arrays; public final class AngelToken extends TokenImpl { public AngelToken() { - super("Angel", "4/4 white Angel creature token with flying"); + super("Angel Token", "4/4 white Angel creature token with flying"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.ANGEL); @@ -20,7 +20,7 @@ public final class AngelToken extends TokenImpl { addAbility(FlyingAbility.getInstance()); availableImageSetCodes = Arrays.asList("APC", "AVR", "C14", "C15", "C18", "CON", "DDQ", "GTC", - "ISD", "M14", "MM3", "NEM", "OGW", "ORI", "PC2", "SCG", "SOI", "ZEN", "C20", "M21", "CMR", "AFC", "VOC"); + "ISD", "M14", "MM3", "NEM", "OGW", "ORI", "PC2", "SCG", "SOI", "ZEN", "C20", "M21", "CMR", "AFC", "VOC", "2XM"); } public AngelToken(final AngelToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/AngelVigilanceToken.java b/Mage/src/main/java/mage/game/permanent/token/AngelVigilanceToken.java index 0167c1a2bb2..f44cd62f23b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AngelVigilanceToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/AngelVigilanceToken.java @@ -6,10 +6,12 @@ import mage.abilities.keyword.VigilanceAbility; import mage.constants.CardType; import mage.constants.SubType; +import java.util.Arrays; + public final class AngelVigilanceToken extends TokenImpl { public AngelVigilanceToken() { - super("Angel", "4/4 white Angel creature token with flying and vigilance"); + super("Angel Token", "4/4 white Angel creature token with flying and vigilance"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.ANGEL); @@ -17,6 +19,8 @@ public final class AngelVigilanceToken extends TokenImpl { toughness = new MageInt(4); addAbility(FlyingAbility.getInstance()); addAbility(VigilanceAbility.getInstance()); + + availableImageSetCodes = Arrays.asList("NEC", "MH1", "WAR", "GRN", "M19"); } public AngelVigilanceToken(final AngelVigilanceToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/AngelWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/AngelWarriorToken.java index d0c86823648..fbd00510921 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AngelWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/AngelWarriorToken.java @@ -10,7 +10,7 @@ import java.util.Arrays; public final class AngelWarriorToken extends TokenImpl { public AngelWarriorToken() { - super("Angel Warrior", "4/4 white Angel Warrior creature token with flying"); + super("Angel Warrior Token", "4/4 white Angel Warrior creature token with flying"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.ANGEL); diff --git a/Mage/src/main/java/mage/game/permanent/token/AngelWarriorVigilanceToken.java b/Mage/src/main/java/mage/game/permanent/token/AngelWarriorVigilanceToken.java index 49984a4e93b..ef29130c8e5 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AngelWarriorVigilanceToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/AngelWarriorVigilanceToken.java @@ -11,7 +11,7 @@ import java.util.Arrays; public final class AngelWarriorVigilanceToken extends TokenImpl { public AngelWarriorVigilanceToken() { - super("Angel Warrior", "4/4 white Angel Warrior creature token with flying and vigilance"); + super("Angel Warrior Token", "4/4 white Angel Warrior creature token with flying and vigilance"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.ANGEL); diff --git a/Mage/src/main/java/mage/game/permanent/token/AnotherSpiritToken.java b/Mage/src/main/java/mage/game/permanent/token/AnotherSpiritToken.java index 9d31a09e05d..e01dfee0abe 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AnotherSpiritToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/AnotherSpiritToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class AnotherSpiritToken extends TokenImpl { public AnotherSpiritToken() { - super("Spirit", "3/3 white Spirit creature token with flying"); + super("Spirit Token", "3/3 white Spirit creature token with flying"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.SPIRIT); diff --git a/Mage/src/main/java/mage/game/permanent/token/AnthousaWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/AnthousaWarriorToken.java deleted file mode 100644 index 8dd5d9ee1df..00000000000 --- a/Mage/src/main/java/mage/game/permanent/token/AnthousaWarriorToken.java +++ /dev/null @@ -1,31 +0,0 @@ - - -package mage.game.permanent.token; - -import mage.constants.CardType; -import mage.constants.SubType; -import mage.MageInt; - -/** - * - * @author spjspj - */ -public final class AnthousaWarriorToken extends TokenImpl { - - public AnthousaWarriorToken() { - super("", "2/2 Warrior creatures"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.WARRIOR); - power = new MageInt(2); - toughness = new MageInt(2); - } - - public AnthousaWarriorToken(final AnthousaWarriorToken token) { - super(token); - } - - public AnthousaWarriorToken copy() { - return new AnthousaWarriorToken(this); - } -} - diff --git a/Mage/src/main/java/mage/game/permanent/token/ApeToken.java b/Mage/src/main/java/mage/game/permanent/token/ApeToken.java index b611c880653..f629e829f85 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ApeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ApeToken.java @@ -5,6 +5,8 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.MageInt; +import java.util.Arrays; + /** * * @author spjspj @@ -12,12 +14,14 @@ import mage.MageInt; public final class ApeToken extends TokenImpl { public ApeToken() { - super("Ape", "2/2 green Ape creature token"); + super("Ape Token", "2/2 green Ape creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.APE); power = new MageInt(2); toughness = new MageInt(2); + + availableImageSetCodes = Arrays.asList("2XM", "TSR", "C14"); } public ApeToken(final ApeToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/ArchitectOfTheUntamedBeastToken.java b/Mage/src/main/java/mage/game/permanent/token/ArchitectOfTheUntamedBeastToken.java index fdb347b0cd7..4da70553dcc 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ArchitectOfTheUntamedBeastToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ArchitectOfTheUntamedBeastToken.java @@ -13,7 +13,7 @@ import mage.MageInt; public final class ArchitectOfTheUntamedBeastToken extends TokenImpl { public ArchitectOfTheUntamedBeastToken() { - super("Beast", "6/6 colorless Beast artifact creature token"); + super("Beast Token", "6/6 colorless Beast artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.BEAST); diff --git a/Mage/src/main/java/mage/game/permanent/token/ArtifactWallToken.java b/Mage/src/main/java/mage/game/permanent/token/ArtifactWallToken.java index 4fcf0658c16..7987966e4d7 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ArtifactWallToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ArtifactWallToken.java @@ -8,7 +8,7 @@ import mage.constants.SubType; public final class ArtifactWallToken extends TokenImpl { public ArtifactWallToken() { - super("Wall", "0/4 colorless Wall artifact creature token with defender"); + super("Wall Token", "0/4 colorless Wall artifact creature token with defender"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.WALL); diff --git a/Mage/src/main/java/mage/game/permanent/token/AshiokNightmareMuseToken.java b/Mage/src/main/java/mage/game/permanent/token/AshiokNightmareMuseToken.java index 5678ce5f7f0..1be43c33bcc 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AshiokNightmareMuseToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/AshiokNightmareMuseToken.java @@ -23,7 +23,7 @@ import java.util.stream.Collectors; public final class AshiokNightmareMuseToken extends TokenImpl { public AshiokNightmareMuseToken() { - super("Nightmare", "2/3 blue and black Nightmare creature token with " + + super("Nightmare Token", "2/3 blue and black Nightmare creature token with " + "\"Whenever this creature attacks or blocks, each opponent exiles the top two cards of their library.\""); cardType.add(CardType.CREATURE); color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/AssassinToken.java b/Mage/src/main/java/mage/game/permanent/token/AssassinToken.java index 5775db91f28..7e33315dc8b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AssassinToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/AssassinToken.java @@ -15,7 +15,7 @@ import mage.abilities.effects.common.LoseGameTargetPlayerEffect; public final class AssassinToken extends TokenImpl { public AssassinToken() { - super("Assassin", "1/1 black Assassin creature tokens with \"Whenever this creature deals combat damage to a player, that player loses the game.\""); + super("Assassin Token", "1/1 black Assassin creature tokens with \"Whenever this creature deals combat damage to a player, that player loses the game.\""); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.ASSASSIN); diff --git a/Mage/src/main/java/mage/game/permanent/token/AssassinToken2.java b/Mage/src/main/java/mage/game/permanent/token/AssassinToken2.java index 2ddde6e5b40..ac7ddf60053 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AssassinToken2.java +++ b/Mage/src/main/java/mage/game/permanent/token/AssassinToken2.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class AssassinToken2 extends TokenImpl { public AssassinToken2() { - super("Assassin", "1/1 black Assassin creature token with deathtouch and \"Whenever this creature deals damage to a planeswalker, destroy that planeswalker.\""); + super("Assassin Token", "1/1 black Assassin creature token with deathtouch and \"Whenever this creature deals damage to a planeswalker, destroy that planeswalker.\""); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.ASSASSIN); diff --git a/Mage/src/main/java/mage/game/permanent/token/AssemblyWorkerToken.java b/Mage/src/main/java/mage/game/permanent/token/AssemblyWorkerToken.java index dfb513411a0..43719bfab3d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AssemblyWorkerToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/AssemblyWorkerToken.java @@ -14,7 +14,7 @@ import java.util.Arrays; public final class AssemblyWorkerToken extends TokenImpl { public AssemblyWorkerToken() { - super("Assembly-Worker", "2/2 colorless Assembly-Worker artifact creature token"); + super("Assembly-Worker Token", "2/2 colorless Assembly-Worker artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.ASSEMBLY_WORKER); diff --git a/Mage/src/main/java/mage/game/permanent/token/AtlaPalaniToken.java b/Mage/src/main/java/mage/game/permanent/token/AtlaPalaniToken.java index abcd1ffeeea..47f2a42e839 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AtlaPalaniToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/AtlaPalaniToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class AtlaPalaniToken extends TokenImpl { public AtlaPalaniToken() { - super("Egg", "0/1 green Egg creature token with defender"); + super("Egg Token", "0/1 green Egg creature token with defender"); cardType.add(CardType.CREATURE); subtype.add(SubType.EGG); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/AvatarToken.java b/Mage/src/main/java/mage/game/permanent/token/AvatarToken.java index cff99af782b..1af0d64eedb 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AvatarToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/AvatarToken.java @@ -1,33 +1,27 @@ - - package mage.game.permanent.token; -import mage.abilities.Ability; -import mage.constants.CardType; -import mage.constants.SubType; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.dynamicvalue.common.ControllerLifeCount; +import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; import mage.constants.SubLayer; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; +import mage.constants.SubType; /** - * * @author spjspj */ public final class AvatarToken extends TokenImpl { public AvatarToken() { - super("Avatar", "white Avatar creature token with \"This creature's power and toughness are each equal to your life total.\""); + super("Avatar Token", "white Avatar creature token. It has \"This creature's power and toughness are each equal to your life total.\""); cardType.add(CardType.CREATURE); subtype.add(SubType.AVATAR); color.setWhite(true); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AvatarTokenEffect())); + this.addAbility(new SimpleStaticAbility(new SetPowerToughnessSourceEffect( + ControllerLifeCount.instance, Duration.WhileOnBattlefield, + SubLayer.CharacteristicDefining_7a + ).setText("this creature's power and toughness are each equal to your life total"))); } public AvatarToken(final AvatarToken token) { @@ -38,34 +32,3 @@ public final class AvatarToken extends TokenImpl { return new AvatarToken(this); } } - -class AvatarTokenEffect extends ContinuousEffectImpl { - - public AvatarTokenEffect() { - super(Duration.WhileOnBattlefield, Layer.PTChangingEffects_7, SubLayer.SetPT_7b, Outcome.BoostCreature); - } - - public AvatarTokenEffect(final AvatarTokenEffect effect) { - super(effect); - } - - @Override - public AvatarTokenEffect copy() { - return new AvatarTokenEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent token = game.getPermanent(source.getSourceId()); - if (token != null) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - token.getPower().setValue(controller.getLife()); - token.getToughness().setValue(controller.getLife()); - return true; - } - } - return false; - } - -} diff --git a/Mage/src/main/java/mage/game/permanent/token/AvatarToken2.java b/Mage/src/main/java/mage/game/permanent/token/AvatarToken2.java index b63e3e14c5b..0f7993a1d8b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AvatarToken2.java +++ b/Mage/src/main/java/mage/game/permanent/token/AvatarToken2.java @@ -8,7 +8,7 @@ import mage.constants.SubType; public final class AvatarToken2 extends TokenImpl { public AvatarToken2() { - super("Avatar", "4/4 white Avatar creature token with flying"); + super("Avatar Token", "4/4 white Avatar creature token with flying"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.AVATAR); diff --git a/Mage/src/main/java/mage/game/permanent/token/BalduvianToken.java b/Mage/src/main/java/mage/game/permanent/token/BalduvianToken.java index 157e31ef2f6..4c5667e2cfe 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BalduvianToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BalduvianToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.HasteAbility; public final class BalduvianToken extends TokenImpl { public BalduvianToken() { - super("Graveborn", "3/1 black and red Graveborn creature token with haste"); + super("Graveborn Token", "3/1 black and red Graveborn creature token with haste"); cardType.add(CardType.CREATURE); color.setBlack(true); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/BaruFistOfKrosaToken.java b/Mage/src/main/java/mage/game/permanent/token/BaruFistOfKrosaToken.java index 4f78ccd9af4..1346b40d77b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BaruFistOfKrosaToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BaruFistOfKrosaToken.java @@ -17,7 +17,7 @@ public final class BaruFistOfKrosaToken extends TokenImpl { } public BaruFistOfKrosaToken(int xValue) { - super("Wurm", "X/X green Wurm creature token, where X is the number of lands you control"); + super("Wurm Token", "X/X green Wurm creature token, where X is the number of lands you control"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.WURM); diff --git a/Mage/src/main/java/mage/game/permanent/token/BatToken.java b/Mage/src/main/java/mage/game/permanent/token/BatToken.java index fab90e6b54e..db3e8d78e4b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BatToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BatToken.java @@ -10,7 +10,7 @@ import java.util.Arrays; public final class BatToken extends TokenImpl { public BatToken() { - super("Bat", "1/1 black Bat creature token with flying"); + super("Bat Token", "1/1 black Bat creature token with flying"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.BAT); diff --git a/Mage/src/main/java/mage/game/permanent/token/BearToken.java b/Mage/src/main/java/mage/game/permanent/token/BearToken.java index aaaf7313f9e..aac35eb9427 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BearToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BearToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class BearToken extends TokenImpl { public BearToken() { - super("Bear", "2/2 green Bear creature token"); + super("Bear Token", "2/2 green Bear creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.BEAR); diff --git a/Mage/src/main/java/mage/game/permanent/token/BearsCompanionBearToken.java b/Mage/src/main/java/mage/game/permanent/token/BearsCompanionBearToken.java index 7e7c7999dc8..71253db6209 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BearsCompanionBearToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BearsCompanionBearToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class BearsCompanionBearToken extends TokenImpl { public BearsCompanionBearToken() { - super("Bear", "4/4 green Bear creature token"); + super("Bear Token", "4/4 green Bear creature token"); setOriginalExpansionSetCode("KTK"); cardType.add(CardType.CREATURE); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/BeastToken.java b/Mage/src/main/java/mage/game/permanent/token/BeastToken.java index ae7bd504d88..80b799e088d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BeastToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BeastToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class BeastToken extends TokenImpl { public BeastToken() { - super("Beast", "3/3 green Beast creature token"); + super("Beast Token", "3/3 green Beast creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.BEAST); @@ -22,7 +22,7 @@ public final class BeastToken extends TokenImpl { availableImageSetCodes = Arrays.asList("5DN", "C14", "C16", "C19", "CMA", "CMD", "CN2", "GVL", "DD3C", "DD3GVL", "DDD", "DDL", "DST", "E01", "EVE", "LRW", "M10", "M11", "M12", - "M13", "M14", "M15", "MM3", "NPH", "PC2", "USG", "M19", "IKO", "M21", "CMR", "C21", "AFC", "MIC"); + "M13", "M14", "M15", "MM3", "NPH", "PC2", "USG", "M19", "IKO", "M21", "CMR", "C21", "AFC", "MIC", "NEC", "2XM"); } @Override diff --git a/Mage/src/main/java/mage/game/permanent/token/BeastToken2.java b/Mage/src/main/java/mage/game/permanent/token/BeastToken2.java index 2387f23798b..ff4154f25e4 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BeastToken2.java +++ b/Mage/src/main/java/mage/game/permanent/token/BeastToken2.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class BeastToken2 extends TokenImpl { public BeastToken2() { - super("Beast", "4/4 green Beast creature token"); + super("Beast Token", "4/4 green Beast creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.BEAST); diff --git a/Mage/src/main/java/mage/game/permanent/token/BeastToken3.java b/Mage/src/main/java/mage/game/permanent/token/BeastToken3.java index 0d6f52439f2..2f30bfcb59a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BeastToken3.java +++ b/Mage/src/main/java/mage/game/permanent/token/BeastToken3.java @@ -20,7 +20,7 @@ public final class BeastToken3 extends TokenImpl { } public BeastToken3(String setCode, int tokenType) { - super("Beast", "4/2 green Beast creature token"); + super("Beast Token", "4/2 green Beast creature token"); setOriginalExpansionSetCode("AKH"); cardType.add(CardType.CREATURE); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/BeastToken4.java b/Mage/src/main/java/mage/game/permanent/token/BeastToken4.java index 18a6c63d46b..e43290ac9a9 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BeastToken4.java +++ b/Mage/src/main/java/mage/game/permanent/token/BeastToken4.java @@ -21,7 +21,7 @@ public final class BeastToken4 extends TokenImpl { } public BeastToken4(String setCode, int tokenType) { - super("Beast", "2/2 green Beast creature token"); + super("Beast Token", "2/2 green Beast creature token"); setOriginalExpansionSetCode(setCode != null ? setCode : "EXO"); cardType.add(CardType.CREATURE); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/BelzenlokClericToken.java b/Mage/src/main/java/mage/game/permanent/token/BelzenlokClericToken.java index 10da78ae2da..810d61bbbd2 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BelzenlokClericToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BelzenlokClericToken.java @@ -20,7 +20,7 @@ public final class BelzenlokClericToken extends TokenImpl { } public BelzenlokClericToken() { - super("Cleric", "0/1 black Cleric creature token"); + super("Cleric Token", "0/1 black Cleric creature token"); availableImageSetCodes = tokenImageSets; cardType.add(CardType.CREATURE); subtype.add(SubType.CLERIC); diff --git a/Mage/src/main/java/mage/game/permanent/token/BelzenlokDemonToken.java b/Mage/src/main/java/mage/game/permanent/token/BelzenlokDemonToken.java index 795165bd029..800b85fc253 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BelzenlokDemonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BelzenlokDemonToken.java @@ -33,7 +33,7 @@ public final class BelzenlokDemonToken extends TokenImpl { } public BelzenlokDemonToken() { - super("Demon", "6/6 black Demon creature token with flying, trample, and " + super("Demon Token", "6/6 black Demon creature token with flying, trample, and " + "\"At the beginning of your upkeep, sacrifice another creature. If you can't, this creature deals 6 damage to you.\""); availableImageSetCodes = tokenImageSets; cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/BiogenicOozeToken.java b/Mage/src/main/java/mage/game/permanent/token/BiogenicOozeToken.java index 3f25f1635e7..7e85f4f6b54 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BiogenicOozeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BiogenicOozeToken.java @@ -7,7 +7,7 @@ import mage.constants.SubType; public final class BiogenicOozeToken extends TokenImpl { public BiogenicOozeToken() { - super("Ooze", "2/2 green Ooze creature token"); + super("Ooze Token", "2/2 green Ooze creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.OOZE); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/BirdIllusionToken.java b/Mage/src/main/java/mage/game/permanent/token/BirdIllusionToken.java index 6bb98201c18..fffd727d161 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BirdIllusionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BirdIllusionToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class BirdIllusionToken extends TokenImpl { public BirdIllusionToken() { - super("Bird Illusion", "1/1 blue Bird Illusion creature token with flying"); + super("Bird Illusion Token", "1/1 blue Bird Illusion creature token with flying"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.BIRD); diff --git a/Mage/src/main/java/mage/game/permanent/token/BirdSoldierToken.java b/Mage/src/main/java/mage/game/permanent/token/BirdSoldierToken.java index 3ea235fbb88..06ecbae0ad4 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BirdSoldierToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BirdSoldierToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class BirdSoldierToken extends TokenImpl { public BirdSoldierToken() { - super("Bird Soldier", "1/1 white Bird Soldier creature token with flying"); + super("Bird Soldier Token","1/1 white Bird Soldier creature token with flying"); cardType.add(CardType.CREATURE); subtype.add(SubType.BIRD); diff --git a/Mage/src/main/java/mage/game/permanent/token/BirdToken.java b/Mage/src/main/java/mage/game/permanent/token/BirdToken.java index c1b13a9e4c8..268fa489c23 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BirdToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BirdToken.java @@ -14,7 +14,7 @@ import java.util.Arrays; public final class BirdToken extends TokenImpl { public BirdToken() { - super("Bird", "1/1 white Bird creature token with flying"); + super("Bird Token", "1/1 white Bird creature token with flying"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.BIRD); diff --git a/Mage/src/main/java/mage/game/permanent/token/BloodAvatarToken.java b/Mage/src/main/java/mage/game/permanent/token/BloodAvatarToken.java index 5a1dac5d30d..c0df76bf865 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BloodAvatarToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BloodAvatarToken.java @@ -16,7 +16,7 @@ import java.util.Arrays; public final class BloodAvatarToken extends TokenImpl { public BloodAvatarToken() { - super("Avatar", "3/6 black and red Avatar creature token with haste and \"Whenever this creature attacks, it deals 3 damage to each opponent.\""); + super("Avatar Token", "3/6 black and red Avatar creature token with haste and \"Whenever this creature attacks, it deals 3 damage to each opponent.\""); cardType.add(CardType.CREATURE); color.setBlack(true); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/BloodToken.java b/Mage/src/main/java/mage/game/permanent/token/BloodToken.java index e7b92e36f79..4ed18fb5f89 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BloodToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BloodToken.java @@ -18,7 +18,7 @@ import java.util.Arrays; public final class BloodToken extends TokenImpl { public BloodToken() { - super("Blood", "Blood token"); + super("Blood Token", "Blood token"); cardType.add(CardType.ARTIFACT); subtype.add(SubType.BLOOD); diff --git a/Mage/src/main/java/mage/game/permanent/token/OwlToken.java b/Mage/src/main/java/mage/game/permanent/token/BlueBirdToken.java similarity index 66% rename from Mage/src/main/java/mage/game/permanent/token/OwlToken.java rename to Mage/src/main/java/mage/game/permanent/token/BlueBirdToken.java index bf3c342a92e..71702fe0a1a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/OwlToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BlueBirdToken.java @@ -10,10 +10,10 @@ import java.util.Arrays; /** * @author spjspj */ -public final class OwlToken extends TokenImpl { +public final class BlueBirdToken extends TokenImpl { - public OwlToken() { - super("Bird", "1/1 blue Bird creature token with flying"); + public BlueBirdToken() { + super("Bird Token", "1/1 blue Bird creature token with flying"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.BIRD); @@ -25,11 +25,11 @@ public final class OwlToken extends TokenImpl { availableImageSetCodes = Arrays.asList("EVE", "INV", "KHM"); } - public OwlToken(final OwlToken token) { + public BlueBirdToken(final BlueBirdToken token) { super(token); } - public OwlToken copy() { - return new OwlToken(this); + public BlueBirdToken copy() { + return new BlueBirdToken(this); } } diff --git a/Mage/src/main/java/mage/game/permanent/token/Boar2Token.java b/Mage/src/main/java/mage/game/permanent/token/Boar2Token.java index b151a3a41f0..c71b8a30e0b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/Boar2Token.java +++ b/Mage/src/main/java/mage/game/permanent/token/Boar2Token.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class Boar2Token extends TokenImpl { public Boar2Token() { - super("Boar", "2/2 green Boar creature token"); + super("Boar Token", "2/2 green Boar creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.BOAR); diff --git a/Mage/src/main/java/mage/game/permanent/token/Boar3Token.java b/Mage/src/main/java/mage/game/permanent/token/Boar3Token.java index 79f26040bcc..b2b1f8987b3 100644 --- a/Mage/src/main/java/mage/game/permanent/token/Boar3Token.java +++ b/Mage/src/main/java/mage/game/permanent/token/Boar3Token.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class Boar3Token extends TokenImpl { public Boar3Token() { - super("Boar", "3/1 green Boar creature token"); + super("Boar Token", "3/1 green Boar creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.BOAR); diff --git a/Mage/src/main/java/mage/game/permanent/token/BoarToken.java b/Mage/src/main/java/mage/game/permanent/token/BoarToken.java index ecf7bb3cfa0..00c44e2b14e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BoarToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BoarToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class BoarToken extends TokenImpl { public BoarToken() { - super("Boar", "3/3 green Boar creature token"); + super("Boar Token", "3/3 green Boar creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.BOAR); diff --git a/Mage/src/main/java/mage/game/permanent/token/BooToken.java b/Mage/src/main/java/mage/game/permanent/token/BooToken.java index 3f4db588240..ed595342ce6 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BooToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BooToken.java @@ -26,7 +26,7 @@ public final class BooToken extends TokenImpl { addAbility(TrampleAbility.getInstance()); addAbility(HasteAbility.getInstance()); - availableImageSetCodes = Arrays.asList("AFR"); + availableImageSetCodes = Arrays.asList("AFR", "CLB"); } private BooToken(final BooToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/BrainiacToken.java b/Mage/src/main/java/mage/game/permanent/token/BrainiacToken.java index 0467ccce646..d8db4ed79f6 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BrainiacToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BrainiacToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class BrainiacToken extends TokenImpl { public BrainiacToken() { - super("Brainiac", "1/1 red Brainiac creature token"); + super("Brainiac Token", "1/1 red Brainiac creature token"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.BRAINIAC); diff --git a/Mage/src/main/java/mage/game/permanent/token/BreedingPitThrullToken.java b/Mage/src/main/java/mage/game/permanent/token/BreedingPitThrullToken.java index 1f5aa8d7b4f..15a8f92166f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BreedingPitThrullToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BreedingPitThrullToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class BreedingPitThrullToken extends TokenImpl { public BreedingPitThrullToken() { - super("Thrull", "0/1 black Thrull creature token"); + super("Thrull Token", "0/1 black Thrull creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.THRULL); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/BrokenVisageSpiritToken.java b/Mage/src/main/java/mage/game/permanent/token/BrokenVisageSpiritToken.java index 688c6062382..cfd1d955db8 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BrokenVisageSpiritToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BrokenVisageSpiritToken.java @@ -16,7 +16,7 @@ public final class BrokenVisageSpiritToken extends TokenImpl { } public BrokenVisageSpiritToken(int tokenPower, int tokenToughness) { - super("Spirit", new StringBuilder(tokenPower).append('/').append(tokenToughness).append(" black Spirit creature token").toString()); + super("Spirit Token", new StringBuilder(tokenPower).append('/').append(tokenToughness).append(" black Spirit creature token").toString()); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.SPIRIT); diff --git a/Mage/src/main/java/mage/game/permanent/token/BroodKeeperDragonToken.java b/Mage/src/main/java/mage/game/permanent/token/BroodKeeperDragonToken.java index 191101098ad..07819ea32d4 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BroodKeeperDragonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BroodKeeperDragonToken.java @@ -18,7 +18,7 @@ import mage.constants.Zone; public final class BroodKeeperDragonToken extends TokenImpl { public BroodKeeperDragonToken() { - super("Dragon", "2/2 red Dragon creature token with flying. It has \"{R}: This creature gets +1/+0 until end of turn.\""); + super("Dragon Token", "2/2 red Dragon creature token with flying. It has \"{R}: This creature gets +1/+0 until end of turn.\""); this.setOriginalExpansionSetCode("M15"); cardType.add(CardType.CREATURE); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/BrudicladTelchorMyrToken.java b/Mage/src/main/java/mage/game/permanent/token/BrudicladTelchorMyrToken.java index 0a429195b3c..f2f67057cf0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BrudicladTelchorMyrToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BrudicladTelchorMyrToken.java @@ -13,11 +13,11 @@ public final class BrudicladTelchorMyrToken extends TokenImpl { static final private List tokenImageSets = new ArrayList<>(); static { - tokenImageSets.addAll(Arrays.asList("C18")); + tokenImageSets.addAll(Arrays.asList("C18", "2XM")); } public BrudicladTelchorMyrToken() { - super("Phyrexian Myr", "2/1 blue Phyrexian Myr artifact creature token"); + super("Phyrexian Myr Token", "2/1 blue Phyrexian Myr artifact creature token"); cardType.add(CardType.CREATURE); cardType.add(CardType.ARTIFACT); subtype.add(SubType.PHYREXIAN); diff --git a/Mage/src/main/java/mage/game/permanent/token/CallTheSkyBreakerElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/CallTheSkyBreakerElementalToken.java index 54cf2c60686..d2607f6acd3 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CallTheSkyBreakerElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CallTheSkyBreakerElementalToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class CallTheSkyBreakerElementalToken extends TokenImpl { public CallTheSkyBreakerElementalToken() { - super("Elemental", "5/5 blue and red Elemental creature token with flying"); + super("Elemental Token", "5/5 blue and red Elemental creature token with flying"); cardType.add(CardType.CREATURE); color.setBlue(true); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/CamaridToken.java b/Mage/src/main/java/mage/game/permanent/token/CamaridToken.java index 65e698ba919..e013c6e3cd3 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CamaridToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CamaridToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class CamaridToken extends TokenImpl { public CamaridToken() { - super("Camarid", "1/1 blue Camarid creature tokens"); + super("Camarid Token", "1/1 blue Camarid creature tokens"); this.setOriginalExpansionSetCode("FEM"); this.getPower().modifyBaseValue(1); this.getToughness().modifyBaseValue(1); diff --git a/Mage/src/main/java/mage/game/permanent/token/CaribouToken.java b/Mage/src/main/java/mage/game/permanent/token/CaribouToken.java index 5378a9fc143..e712f79f2b7 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CaribouToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CaribouToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class CaribouToken extends TokenImpl { public CaribouToken() { - super("Caribou", "0/1 white Caribou creature token"); + super("Caribou Token", "0/1 white Caribou creature token"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.CARIBOU); diff --git a/Mage/src/main/java/mage/game/permanent/token/CarnivoreToken.java b/Mage/src/main/java/mage/game/permanent/token/CarnivoreToken.java index 6c394717c73..71c247cae03 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CarnivoreToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CarnivoreToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class CarnivoreToken extends TokenImpl { public CarnivoreToken() { - super("Carnivore", "3/1 red Beast creature token"); + super("Carnivore Token", "3/1 red Beast creature token"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.BEAST); diff --git a/Mage/src/main/java/mage/game/permanent/token/CarrionBlackInsectToken.java b/Mage/src/main/java/mage/game/permanent/token/CarrionBlackInsectToken.java index 98e01857ffc..bac34750551 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CarrionBlackInsectToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CarrionBlackInsectToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class CarrionBlackInsectToken extends TokenImpl { public CarrionBlackInsectToken() { - super("Insect", "0/1 black Insect creature token"); + super("Insect Token", "0/1 black Insect creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.INSECT); diff --git a/Mage/src/main/java/mage/game/permanent/token/CatBeastToken.java b/Mage/src/main/java/mage/game/permanent/token/CatBeastToken.java index a6b4ffc1804..69a6cfc4cee 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CatBeastToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CatBeastToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class CatBeastToken extends TokenImpl { public CatBeastToken() { - super("Cat Beast", "2/2 white Cat Beast creature token"); + super("Cat Beast Token", "2/2 white Cat Beast creature token"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.CAT); diff --git a/Mage/src/main/java/mage/game/permanent/token/CatBirdToken.java b/Mage/src/main/java/mage/game/permanent/token/CatBirdToken.java index c4b276bcda0..53f893bbbed 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CatBirdToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CatBirdToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class CatBirdToken extends TokenImpl { public CatBirdToken() { - super("Cat Bird", "1/1 white Cat Bird creature token with flying"); + super("Cat Bird Token", "1/1 white Cat Bird creature token with flying"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.CAT); diff --git a/Mage/src/main/java/mage/game/permanent/token/CatHasteToken.java b/Mage/src/main/java/mage/game/permanent/token/CatHasteToken.java new file mode 100644 index 00000000000..b2f67dd8070 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/CatHasteToken.java @@ -0,0 +1,31 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.HasteAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class CatHasteToken extends TokenImpl { + + public CatHasteToken() { + super("Cat Token", "2/2 green Cat creature token with haste"); + cardType.add(CardType.CREATURE); + color.setGreen(true); + subtype.add(SubType.CAT); + power = new MageInt(2); + toughness = new MageInt(2); + + this.addAbility(HasteAbility.getInstance()); + } + + private CatHasteToken(final CatHasteToken token) { + super(token); + } + + public CatHasteToken copy() { + return new CatHasteToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/CatSoldierCreatureToken.java b/Mage/src/main/java/mage/game/permanent/token/CatSoldierCreatureToken.java index ab62f94e2fe..3eb45d336b1 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CatSoldierCreatureToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CatSoldierCreatureToken.java @@ -13,7 +13,7 @@ import mage.constants.SubType; public final class CatSoldierCreatureToken extends TokenImpl { public CatSoldierCreatureToken() { - super("Cat Soldier", "1/1 white Cat Soldier creature token with vigilance"); + super("Cat Soldier Token", "1/1 white Cat Soldier creature token with vigilance"); cardType.add(CardType.CREATURE); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/CatToken.java b/Mage/src/main/java/mage/game/permanent/token/CatToken.java index acf05a78f19..fb06f988a74 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CatToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CatToken.java @@ -12,14 +12,14 @@ import java.util.Arrays; public final class CatToken extends TokenImpl { public CatToken() { - super("Cat", "2/2 white Cat creature token"); + super("Cat Token", "2/2 white Cat creature token"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.CAT); power = new MageInt(2); toughness = new MageInt(2); - availableImageSetCodes = Arrays.asList("PMEI", "C14", "C15", "C17", "C18", "M13", "M14", "MBS", "SOM", "CMR"); + availableImageSetCodes = Arrays.asList("PMEI", "C14", "C15", "C17", "C18", "M13", "M14", "MBS", "SOM", "CMR", "2XM"); } public CatToken(final CatToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/CatToken2.java b/Mage/src/main/java/mage/game/permanent/token/CatToken2.java index 3e9ce3a75d5..253164b9a8d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CatToken2.java +++ b/Mage/src/main/java/mage/game/permanent/token/CatToken2.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class CatToken2 extends TokenImpl { public CatToken2() { - super("Cat", "1/1 white Cat creature token with lifelink"); + super("Cat Token", "1/1 white Cat creature token with lifelink"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.CAT); diff --git a/Mage/src/main/java/mage/game/permanent/token/CatToken3.java b/Mage/src/main/java/mage/game/permanent/token/CatToken3.java index af34cccab5b..07f26b40588 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CatToken3.java +++ b/Mage/src/main/java/mage/game/permanent/token/CatToken3.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class CatToken3 extends TokenImpl { public CatToken3() { - super("Cat", "1/1 white Cat creature token"); + super("Cat Token", "1/1 white Cat creature token"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.CAT); diff --git a/Mage/src/main/java/mage/game/permanent/token/CatWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/CatWarriorToken.java index 02b1bb9572a..325392f0bdd 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CatWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CatWarriorToken.java @@ -21,7 +21,7 @@ public final class CatWarriorToken extends TokenImpl { } public CatWarriorToken() { - super("Cat Warrior", "2/2 green Cat Warrior creature token with forestwalk"); + super("Cat Warrior Token", "2/2 green Cat Warrior creature token with forestwalk"); availableImageSetCodes = tokenImageSets; this.setOriginalExpansionSetCode("PLC"); this.getPower().modifyBaseValue(2); diff --git a/Mage/src/main/java/mage/game/permanent/token/CentaurEnchantmentCreatureToken.java b/Mage/src/main/java/mage/game/permanent/token/CentaurEnchantmentCreatureToken.java index e270f024b42..036f1cb52b1 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CentaurEnchantmentCreatureToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CentaurEnchantmentCreatureToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class CentaurEnchantmentCreatureToken extends TokenImpl { public CentaurEnchantmentCreatureToken() { - super("Centaur", "3/3 green Centaur enchantment creature token"); + super("Centaur Token", "3/3 green Centaur enchantment creature token"); cardType.add(CardType.ENCHANTMENT); cardType.add(CardType.CREATURE); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/CentaurToken.java b/Mage/src/main/java/mage/game/permanent/token/CentaurToken.java index 03a8c83ca71..a0ee1ec9bfc 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CentaurToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CentaurToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class CentaurToken extends TokenImpl { public CentaurToken() { - super("Centaur", "3/3 green Centaur creature token"); + super("Centaur Token", "3/3 green Centaur creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.CENTAUR); diff --git a/Mage/src/main/java/mage/game/permanent/token/ChainersTormentNightmareToken.java b/Mage/src/main/java/mage/game/permanent/token/ChainersTormentNightmareToken.java index ad357005716..0c30eee4f59 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ChainersTormentNightmareToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ChainersTormentNightmareToken.java @@ -22,7 +22,7 @@ public final class ChainersTormentNightmareToken extends TokenImpl { public ChainersTormentNightmareToken() { this(0); }; public ChainersTormentNightmareToken(int xValue) { - super("Nightmare Horror", "X/X black Nightmare Horror creature token"); + super("Nightmare Horror Token", "X/X black Nightmare Horror creature token"); availableImageSetCodes = tokenImageSets; setOriginalExpansionSetCode("DOM"); diff --git a/Mage/src/main/java/mage/game/permanent/token/ChasmSkulkerSquidToken.java b/Mage/src/main/java/mage/game/permanent/token/ChasmSkulkerSquidToken.java index f537c443bdd..80530a4e306 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ChasmSkulkerSquidToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ChasmSkulkerSquidToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.IslandwalkAbility; public final class ChasmSkulkerSquidToken extends TokenImpl { public ChasmSkulkerSquidToken() { - super("Squid", "1/1 blue Squid creature token with islandwalk"); + super("Squid Token", "1/1 blue Squid creature token with islandwalk"); this.setOriginalExpansionSetCode("M15"); cardType.add(CardType.CREATURE); color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/CitizenGreenWhiteToken.java b/Mage/src/main/java/mage/game/permanent/token/CitizenGreenWhiteToken.java new file mode 100644 index 00000000000..ada27037d0b --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/CitizenGreenWhiteToken.java @@ -0,0 +1,30 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class CitizenGreenWhiteToken extends TokenImpl { + + public CitizenGreenWhiteToken() { + super("Citizen Token", "1/1 green and white Citizen creature token"); + cardType.add(CardType.CREATURE); + color.setGreen(true); + color.setWhite(true); + + subtype.add(SubType.CITIZEN); + power = new MageInt(1); + toughness = new MageInt(1); + } + + private CitizenGreenWhiteToken(final CitizenGreenWhiteToken token) { + super(token); + } + + public CitizenGreenWhiteToken copy() { + return new CitizenGreenWhiteToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/CitizenToken.java b/Mage/src/main/java/mage/game/permanent/token/CitizenToken.java index f602d6ddb14..a46541ed98d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CitizenToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CitizenToken.java @@ -13,7 +13,7 @@ import mage.constants.SubType; public final class CitizenToken extends TokenImpl { public CitizenToken() { - super("Citizen", "1/1 white Citizen creature token"); + super("Citizen Token", "1/1 white Citizen creature token"); cardType.add(CardType.CREATURE); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/ClueArtifactToken.java b/Mage/src/main/java/mage/game/permanent/token/ClueArtifactToken.java index 78d5f3535b0..1bd0949ad7d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ClueArtifactToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ClueArtifactToken.java @@ -18,7 +18,7 @@ import java.util.Arrays; public final class ClueArtifactToken extends TokenImpl { public ClueArtifactToken() { - super("Clue", "colorless Clue artifact token with \"{2}, Sacrifice this artifact: Draw a card.\""); + super("Clue Token", "colorless Clue artifact token with \"{2}, Sacrifice this artifact: Draw a card.\""); cardType.add(CardType.ARTIFACT); subtype.add(SubType.CLUE); @@ -29,7 +29,7 @@ public final class ClueArtifactToken extends TokenImpl { ability.addCost(cost); this.addAbility(ability); - availableImageSetCodes = Arrays.asList("C18", "SOI", "MH2", "AFC", "MID", "VOC"); + availableImageSetCodes = Arrays.asList("C18", "SOI", "MH2", "AFC", "MID", "VOC", "SLD", "2XM"); } @Override diff --git a/Mage/src/main/java/mage/game/permanent/token/Construct4Token.java b/Mage/src/main/java/mage/game/permanent/token/Construct4Token.java index 13936b0261c..62c4634621d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/Construct4Token.java +++ b/Mage/src/main/java/mage/game/permanent/token/Construct4Token.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class Construct4Token extends TokenImpl { public Construct4Token() { - super("Construct", "4/4 colorless Construct artifact creature token"); + super("Construct Token", "4/4 colorless Construct artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.CONSTRUCT); diff --git a/Mage/src/main/java/mage/game/permanent/token/ConstructRedToken.java b/Mage/src/main/java/mage/game/permanent/token/ConstructRedToken.java index 84a3e7df896..697a75c1f64 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ConstructRedToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ConstructRedToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class ConstructRedToken extends TokenImpl { public ConstructRedToken() { - super("Construct token", "3/1 red Construct artifact creature token with haste"); + super("Construct Token", "3/1 red Construct artifact creature token with haste"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.CONSTRUCT); @@ -21,6 +21,15 @@ public final class ConstructRedToken extends TokenImpl { addAbility(HasteAbility.getInstance()); } + @Override + public void setExpansionSetCodeForImage(String code) { + super.setExpansionSetCodeForImage(code); + + if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("NEO")) { + setTokenType(2); + } + } + public ConstructRedToken(final ConstructRedToken token) { super(token); } diff --git a/Mage/src/main/java/mage/game/permanent/token/ConstructToken.java b/Mage/src/main/java/mage/game/permanent/token/ConstructToken.java index bfd43be2e15..106a1d78e6b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ConstructToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ConstructToken.java @@ -12,14 +12,23 @@ import java.util.Arrays; public final class ConstructToken extends TokenImpl { public ConstructToken() { - super("Construct", "1/1 colorless Construct artifact creature token"); + super("Construct Token", "1/1 colorless Construct artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.CONSTRUCT); power = new MageInt(1); toughness = new MageInt(1); - availableImageSetCodes = Arrays.asList("ZNR"); + availableImageSetCodes = Arrays.asList("ZNR", "NEO"); + } + + @Override + public void setExpansionSetCodeForImage(String code) { + super.setExpansionSetCodeForImage(code); + + if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("NEO")) { + setTokenType(1); + } } public ConstructToken(final ConstructToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/ConsumingBlobOozeToken.java b/Mage/src/main/java/mage/game/permanent/token/ConsumingBlobOozeToken.java index 3341105ea9e..c6683b7de14 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ConsumingBlobOozeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ConsumingBlobOozeToken.java @@ -18,7 +18,7 @@ import java.util.Arrays; public final class ConsumingBlobOozeToken extends TokenImpl { public ConsumingBlobOozeToken() { - super("Ooze", "green Ooze creature token with \"This creature's power is equal to the number of card types among cards in your graveyard and its toughness is equal to that number plus 1.\""); + super("Ooze Token", "green Ooze creature token with \"This creature's power is equal to the number of card types among cards in your graveyard and its toughness is equal to that number plus 1.\""); cardType.add(CardType.CREATURE); subtype.add(SubType.OOZE); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/CoralBarrierSquidToken.java b/Mage/src/main/java/mage/game/permanent/token/CoralBarrierSquidToken.java index 204d6717dd2..5715769da29 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CoralBarrierSquidToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CoralBarrierSquidToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.IslandwalkAbility; public final class CoralBarrierSquidToken extends TokenImpl { public CoralBarrierSquidToken() { - super("Squid", "1/1 blue Squid creature token with islandwalk"); + super("Squid Token", "1/1 blue Squid creature token with islandwalk"); this.setOriginalExpansionSetCode("M15"); cardType.add(CardType.CREATURE); color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/CorpseweftZombieToken.java b/Mage/src/main/java/mage/game/permanent/token/CorpseweftZombieToken.java index 9480897c735..ec89e38b48f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CorpseweftZombieToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CorpseweftZombieToken.java @@ -16,7 +16,7 @@ public final class CorpseweftZombieToken extends TokenImpl { } public CorpseweftZombieToken(int power, int toughness) { - super("Zombie Horror", "X/X black Zombie Horror creature token, where X is twice the number of cards exiled this way"); + super("Zombie Horror Token", "X/X black Zombie Horror creature token, where X is twice the number of cards exiled this way"); cardType.add(CardType.CREATURE); subtype.add(SubType.ZOMBIE); subtype.add(SubType.HORROR); diff --git a/Mage/src/main/java/mage/game/permanent/token/CorruptedZendikonOozeToken.java b/Mage/src/main/java/mage/game/permanent/token/CorruptedZendikonOozeToken.java index b28fbe39445..7df3545ec84 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CorruptedZendikonOozeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CorruptedZendikonOozeToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class CorruptedZendikonOozeToken extends TokenImpl { public CorruptedZendikonOozeToken() { - super("Ooze", "3/3 black Ooze creature"); + super("Ooze Token", "3/3 black Ooze creature"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.OOZE); diff --git a/Mage/src/main/java/mage/game/permanent/token/CrabToken.java b/Mage/src/main/java/mage/game/permanent/token/CrabToken.java index dba07185e1e..a420a68a50b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CrabToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CrabToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class CrabToken extends TokenImpl { public CrabToken() { - super("Crab", "0/3 blue Crab creature token"); + super("Crab Token", "0/3 blue Crab creature token"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.CRAB); diff --git a/Mage/src/main/java/mage/game/permanent/token/CreakwoodLiegeToken.java b/Mage/src/main/java/mage/game/permanent/token/CreakwoodLiegeToken.java index 084cfebc5cd..5d569c2b0fb 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CreakwoodLiegeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CreakwoodLiegeToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class CreakwoodLiegeToken extends TokenImpl { public CreakwoodLiegeToken() { - super("Worm", "1/1 black and green Worm creature token"); + super("Worm Token", "1/1 black and green Worm creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/CrestedSunmareToken.java b/Mage/src/main/java/mage/game/permanent/token/CrestedSunmareToken.java index 5b12d51c573..b7ffbd0180f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CrestedSunmareToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CrestedSunmareToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class CrestedSunmareToken extends TokenImpl { public CrestedSunmareToken() { - super("Horse", "5/5 white Horse creature token"); + super("Horse Token", "5/5 white Horse creature token"); power = new MageInt(5); toughness = new MageInt(5); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/CribSwapShapeshifterWhiteToken.java b/Mage/src/main/java/mage/game/permanent/token/CribSwapShapeshifterWhiteToken.java index 24212cb3330..6686003399f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CribSwapShapeshifterWhiteToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CribSwapShapeshifterWhiteToken.java @@ -5,19 +5,23 @@ import mage.abilities.keyword.ChangelingAbility; import mage.constants.CardType; import mage.constants.SubType; +import java.util.Arrays; + /** * @author spjspj */ public final class CribSwapShapeshifterWhiteToken extends TokenImpl { public CribSwapShapeshifterWhiteToken() { - super("Shapeshifter", "1/1 colorless Shapeshifter creature token with changeling"); + super("Shapeshifter Token", "1/1 colorless Shapeshifter creature token with changeling"); this.setOriginalExpansionSetCode("LRW"); cardType.add(CardType.CREATURE); subtype.add(SubType.SHAPESHIFTER); power = new MageInt(1); toughness = new MageInt(1); addAbility(new ChangelingAbility()); + + availableImageSetCodes = Arrays.asList("LRW", "C15", "CM2", "C18", "2XM"); } public CribSwapShapeshifterWhiteToken(final CribSwapShapeshifterWhiteToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/CrushOfTentaclesToken.java b/Mage/src/main/java/mage/game/permanent/token/CrushOfTentaclesToken.java index 7e0359e6745..77dea51a8b4 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CrushOfTentaclesToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CrushOfTentaclesToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class CrushOfTentaclesToken extends TokenImpl { public CrushOfTentaclesToken() { - super("Octopus", "8/8 blue Octopus creature"); + super("Octopus Token", "8/8 blue Octopus creature"); this.setExpansionSetCodeForImage("BFZ"); this.cardType.add(CardType.CREATURE); this.color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/CustomIllusionToken.java b/Mage/src/main/java/mage/game/permanent/token/CustomIllusionToken.java index 24d24f7f3f3..e3353d0a382 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CustomIllusionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CustomIllusionToken.java @@ -16,7 +16,7 @@ public final class CustomIllusionToken extends TokenImpl { } public CustomIllusionToken(int xValue) { - super("Illusion", "X/X blue Illusion creature token"); + super("Illusion Token", "X/X blue Illusion creature token"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.ILLUSION); diff --git a/Mage/src/main/java/mage/game/permanent/token/DarettiConstructToken.java b/Mage/src/main/java/mage/game/permanent/token/DarettiConstructToken.java index ca72b9bfa0a..a62fb9d7e9c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DarettiConstructToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DarettiConstructToken.java @@ -17,7 +17,7 @@ public final class DarettiConstructToken extends TokenImpl { } public DarettiConstructToken(String setCode) { - super("Construct", "1/1 colorless Construct artifact creature token with defender"); + super("Construct Token", "1/1 colorless Construct artifact creature token with defender"); this.setOriginalExpansionSetCode(setCode); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/DaxosSpiritToken.java b/Mage/src/main/java/mage/game/permanent/token/DaxosSpiritToken.java index b9ae698a311..97208196405 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DaxosSpiritToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DaxosSpiritToken.java @@ -25,7 +25,7 @@ import mage.players.Player; public final class DaxosSpiritToken extends TokenImpl { public DaxosSpiritToken() { - super("Spirit", "white and black Spirit enchantment creature token with \"This creature's power and toughness are each equal to the number of experience counters you have.\""); + super("Spirit Token", "white and black Spirit enchantment creature token with \"This creature's power and toughness are each equal to the number of experience counters you have.\""); this.setOriginalExpansionSetCode("C15"); setTokenType(2); cardType.add(CardType.ENCHANTMENT); diff --git a/Mage/src/main/java/mage/game/permanent/token/DeadlyGrubInsectToken.java b/Mage/src/main/java/mage/game/permanent/token/DeadlyGrubInsectToken.java index 479718031b9..697530d2bef 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DeadlyGrubInsectToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DeadlyGrubInsectToken.java @@ -15,7 +15,7 @@ import java.util.Arrays; public final class DeadlyGrubInsectToken extends TokenImpl { public DeadlyGrubInsectToken() { - super("Insect", "6/1 green Insect creature token with shroud"); + super("Insect Token", "6/1 green Insect creature token with shroud"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.INSECT); diff --git a/Mage/src/main/java/mage/game/permanent/token/DeathpactAngelToken.java b/Mage/src/main/java/mage/game/permanent/token/DeathpactAngelToken.java index ffd6cb67596..4c97e0ba83c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DeathpactAngelToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DeathpactAngelToken.java @@ -28,7 +28,7 @@ public final class DeathpactAngelToken extends TokenImpl { } public DeathpactAngelToken() { - super("Cleric", "1/1 white and black Cleric creature token. It has \"{3}{W}{B}{B}, {T}, Sacrifice this creature: Return a card named Deathpact Angel from your graveyard to the battlefield.\""); + super("Cleric Token", "1/1 white and black Cleric creature token. It has \"{3}{W}{B}{B}, {T}, Sacrifice this creature: Return a card named Deathpact Angel from your graveyard to the battlefield.\""); cardType.add(CardType.CREATURE); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/DeathtouchRatToken.java b/Mage/src/main/java/mage/game/permanent/token/DeathtouchRatToken.java index edbd8a30761..7a57ebab779 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DeathtouchRatToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DeathtouchRatToken.java @@ -21,7 +21,7 @@ public final class DeathtouchRatToken extends TokenImpl { } public DeathtouchRatToken() { - super("Rat", "1/1 black Rat creature token with deathtouch"); + super("Rat Token", "1/1 black Rat creature token with deathtouch"); this.setExpansionSetCodeForImage("C17"); availableImageSetCodes = tokenImageSets; this.cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/DeathtouchSnakeToken.java b/Mage/src/main/java/mage/game/permanent/token/DeathtouchSnakeToken.java index 8d3c7883fef..1434e2cbc7c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DeathtouchSnakeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DeathtouchSnakeToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.DeathtouchAbility; public final class DeathtouchSnakeToken extends TokenImpl { public DeathtouchSnakeToken() { - super("Snake", "1/1 green Snake creature token with deathtouch"); + super("Snake Token", "1/1 green Snake creature token with deathtouch"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.SNAKE); diff --git a/Mage/src/main/java/mage/game/permanent/token/DefenderPlantToken.java b/Mage/src/main/java/mage/game/permanent/token/DefenderPlantToken.java index 53b819bee85..e52f3fc1a58 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DefenderPlantToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DefenderPlantToken.java @@ -21,7 +21,7 @@ public final class DefenderPlantToken extends TokenImpl { } public DefenderPlantToken(String setCode, int tokenType) { - super("Plant", "0/2 green Plant creature token with defender"); + super("Plant Token", "0/2 green Plant creature token with defender"); color.setGreen(true); cardType.add(CardType.CREATURE); subtype.add(SubType.PLANT); diff --git a/Mage/src/main/java/mage/game/permanent/token/DemonBerserkerToken.java b/Mage/src/main/java/mage/game/permanent/token/DemonBerserkerToken.java index e83764d49c9..b1d4716880d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DemonBerserkerToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DemonBerserkerToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class DemonBerserkerToken extends TokenImpl { public DemonBerserkerToken() { - super("Demon Berserker", "2/3 red Demon Berserker creature token with menace"); + super("Demon Berserker Token", "2/3 red Demon Berserker creature token with menace"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.DEMON); diff --git a/Mage/src/main/java/mage/game/permanent/token/DemonFlyingToken.java b/Mage/src/main/java/mage/game/permanent/token/DemonFlyingToken.java index 94a77e583df..4fb17832da6 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DemonFlyingToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DemonFlyingToken.java @@ -17,7 +17,7 @@ public final class DemonFlyingToken extends TokenImpl { } public DemonFlyingToken(int xValue) { - super("Demon", "X/X black Demon creature token with flying"); + super("Demon Token", "X/X black Demon creature token with flying"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.DEMON); diff --git a/Mage/src/main/java/mage/game/permanent/token/DemonToken.java b/Mage/src/main/java/mage/game/permanent/token/DemonToken.java index e39d299c507..137cdb1ded8 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DemonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DemonToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class DemonToken extends TokenImpl { public DemonToken() { - super("Demon", "5/5 black Demon creature token with flying"); + super("Demon Token", "5/5 black Demon creature token with flying"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.DEMON); @@ -21,7 +21,7 @@ public final class DemonToken extends TokenImpl { toughness = new MageInt(5); addAbility(FlyingAbility.getInstance()); - availableImageSetCodes.addAll(Arrays.asList("AVR", "C14", "DD3A", "ISD", "ORI", "M20", "M21")); + availableImageSetCodes.addAll(Arrays.asList("AVR", "C14", "DD3A", "ISD", "ORI", "M20", "M21", "2XM")); } public DemonToken(final DemonToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/DeserterToken.java b/Mage/src/main/java/mage/game/permanent/token/DeserterToken.java index c285dd8e8ce..8efa1e3e374 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DeserterToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DeserterToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class DeserterToken extends TokenImpl { public DeserterToken() { - super("Deserter", "0/1 white Deserter creature token"); + super("Deserter Token", "0/1 white Deserter creature token"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.DESERTER); diff --git a/Mage/src/main/java/mage/game/permanent/token/DevastatingSummonsElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/DevastatingSummonsElementalToken.java index c8c576c5e3f..eacc378f4d2 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DevastatingSummonsElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DevastatingSummonsElementalToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class DevastatingSummonsElementalToken extends TokenImpl { public DevastatingSummonsElementalToken() { - super("Elemental", "X/X red Elemental creature"); + super("Elemental Token", "X/X red Elemental creature"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.ELEMENTAL); diff --git a/Mage/src/main/java/mage/game/permanent/token/DevilToken.java b/Mage/src/main/java/mage/game/permanent/token/DevilToken.java index 729af8219a0..4e1a13d2037 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DevilToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DevilToken.java @@ -20,7 +20,7 @@ import mage.target.common.TargetAnyTarget; public final class DevilToken extends TokenImpl { public DevilToken() { - super("Devil", "1/1 red Devil creature token with \"When this creature dies, it deals 1 damage to any target.\""); + super("Devil Token", "1/1 red Devil creature token with \"When this creature dies, it deals 1 damage to any target.\""); cardType.add(CardType.CREATURE); subtype.add(SubType.DEVIL); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/DinOfTheFireherdToken.java b/Mage/src/main/java/mage/game/permanent/token/DinOfTheFireherdToken.java index 775459ce188..deb74b52628 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DinOfTheFireherdToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DinOfTheFireherdToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class DinOfTheFireherdToken extends TokenImpl { public DinOfTheFireherdToken() { - super("Elemental", "5/5 black and red Elemental creature"); + super("Elemental Token", "5/5 black and red Elemental creature"); cardType.add(CardType.CREATURE); subtype.add(SubType.ELEMENTAL); color.setBlack(true); @@ -21,6 +21,15 @@ public final class DinOfTheFireherdToken extends TokenImpl { toughness = new MageInt(5); } + @Override + public void setExpansionSetCodeForImage(String code) { + super.setExpansionSetCodeForImage(code); + + if (getOriginalExpansionSetCode().equals("SHM")) { + this.setTokenType(1); + } + } + public DinOfTheFireherdToken(final DinOfTheFireherdToken token) { super(token); } diff --git a/Mage/src/main/java/mage/game/permanent/token/DinosaurBeastToken.java b/Mage/src/main/java/mage/game/permanent/token/DinosaurBeastToken.java index 17f93178ef6..f2948c89f60 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DinosaurBeastToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DinosaurBeastToken.java @@ -14,7 +14,7 @@ public final class DinosaurBeastToken extends TokenImpl { this(0); } public DinosaurBeastToken(int xValue) { - super("Dinosaur Beast", "X/X green Dinosaur Beast creature token with trample"); + super("Dinosaur Beast Token", "X/X green Dinosaur Beast creature token with trample"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.DINOSAUR); diff --git a/Mage/src/main/java/mage/game/permanent/token/DinosaurCatToken.java b/Mage/src/main/java/mage/game/permanent/token/DinosaurCatToken.java index c5a2db7fd2e..5d511b392f0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DinosaurCatToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DinosaurCatToken.java @@ -6,7 +6,7 @@ import mage.constants.SubType; public final class DinosaurCatToken extends TokenImpl { public DinosaurCatToken() { - super("Dinosaur Cat", "2/2 red and white Dinosaur Cat creature token"); + super("Dinosaur Cat Token", "2/2 red and white Dinosaur Cat creature token"); cardType.add(CardType.CREATURE); color.setRed(true); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/DinosaurHasteToken.java b/Mage/src/main/java/mage/game/permanent/token/DinosaurHasteToken.java index 49a560d930b..5929502e4b5 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DinosaurHasteToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DinosaurHasteToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class DinosaurHasteToken extends TokenImpl { public DinosaurHasteToken() { - super("Dinosaur", "1/1 red Dinosaur creature token with haste"); + super("Dinosaur Token", "1/1 red Dinosaur creature token with haste"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.DINOSAUR); diff --git a/Mage/src/main/java/mage/game/permanent/token/DinosaurToken.java b/Mage/src/main/java/mage/game/permanent/token/DinosaurToken.java index 44bfc7e8aa1..bc8e3b2be5d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DinosaurToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DinosaurToken.java @@ -13,7 +13,7 @@ import mage.constants.SubType; public final class DinosaurToken extends TokenImpl { public DinosaurToken() { - super("Dinosaur", "3/3 green Dinosaur creature token with trample"); + super("Dinosaur Token", "3/3 green Dinosaur creature token with trample"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.DINOSAUR); diff --git a/Mage/src/main/java/mage/game/permanent/token/DjinnMonkToken.java b/Mage/src/main/java/mage/game/permanent/token/DjinnMonkToken.java index 5b4e48babb2..12b50751925 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DjinnMonkToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DjinnMonkToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class DjinnMonkToken extends TokenImpl { public DjinnMonkToken() { - super("Djinn Monk", "2/2 blue Djinn Monk creature token with flying"); + super("Djinn Monk Token", "2/2 blue Djinn Monk creature token with flying"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.DJINN); diff --git a/Mage/src/main/java/mage/game/permanent/token/DjinnToken.java b/Mage/src/main/java/mage/game/permanent/token/DjinnToken.java index 34776c6ec07..5e6acc97e55 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DjinnToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DjinnToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class DjinnToken extends TokenImpl { public DjinnToken() { - super("Djinn", "5/5 colorless Djinn artifact creature token with flying"); + super("Djinn Token", "5/5 colorless Djinn artifact creature token with flying"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.DJINN); diff --git a/Mage/src/main/java/mage/game/permanent/token/DogIllusionToken.java b/Mage/src/main/java/mage/game/permanent/token/DogIllusionToken.java index 253761eb5b6..4ad66147f1e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DogIllusionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DogIllusionToken.java @@ -22,7 +22,7 @@ import java.util.Arrays; public final class DogIllusionToken extends TokenImpl { public DogIllusionToken() { - super("Dog Illusion", "blue Dog Illusion creature token with \"This creature's power and toughness are each equal to twice the number of cards in your hand.\""); + super("Dog Illusion Token", "blue Dog Illusion creature token with \"This creature's power and toughness are each equal to twice the number of cards in your hand.\""); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.DOG); diff --git a/Mage/src/main/java/mage/game/permanent/token/DogVigilanceToken.java b/Mage/src/main/java/mage/game/permanent/token/DogVigilanceToken.java new file mode 100644 index 00000000000..17b3a0806c3 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/DogVigilanceToken.java @@ -0,0 +1,32 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.VigilanceAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class DogVigilanceToken extends TokenImpl { + + public DogVigilanceToken() { + super("Dog Token", "3/1 green Dog creature token with vigilance"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.DOG); + + color.setGreen(true); + power = new MageInt(3); + toughness = new MageInt(1); + + this.addAbility(VigilanceAbility.getInstance()); + } + + private DogVigilanceToken(final DogVigilanceToken token) { + super(token); + } + + public DogVigilanceToken copy() { + return new DogVigilanceToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/DokaiWeaverofLifeToken.java b/Mage/src/main/java/mage/game/permanent/token/DokaiWeaverofLifeToken.java index 1fdaffe7b72..474949f21a0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DokaiWeaverofLifeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DokaiWeaverofLifeToken.java @@ -22,7 +22,7 @@ public final class DokaiWeaverofLifeToken extends TokenImpl { static final FilterControlledPermanent filterLands = new FilterControlledLandPermanent("lands you control"); public DokaiWeaverofLifeToken() { - super("Elemental", "X/X green Elemental creature token, where X is the number of lands you control"); + super("Elemental Token", "X/X green Elemental creature token, where X is the number of lands you control"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.ELEMENTAL); diff --git a/Mage/src/main/java/mage/game/permanent/token/DoomedArtisanToken.java b/Mage/src/main/java/mage/game/permanent/token/DoomedArtisanToken.java index 105212f4d89..0691f8281f7 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DoomedArtisanToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DoomedArtisanToken.java @@ -26,7 +26,7 @@ public final class DoomedArtisanToken extends TokenImpl { private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); public DoomedArtisanToken() { - super("Sculpture", "colorless Sculpture artifact creature token with \"This creature's power and toughness are each equal to the number of Sculptures you control.\""); + super("Sculpture Token", "colorless Sculpture artifact creature token with \"This creature's power and toughness are each equal to the number of Sculptures you control.\""); setOriginalExpansionSetCode("C19"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/DorotheasRetributionSpiritToken.java b/Mage/src/main/java/mage/game/permanent/token/DorotheasRetributionSpiritToken.java index de468ca1d17..fe7cf5add86 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DorotheasRetributionSpiritToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DorotheasRetributionSpiritToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class DorotheasRetributionSpiritToken extends TokenImpl { public DorotheasRetributionSpiritToken() { - super("Spirit", "4/4 white Spirit creature token with flying"); + super("Spirit Token", "4/4 white Spirit creature token with flying"); cardType.add(CardType.CREATURE); subtype.add(SubType.SPIRIT); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/DragonBroodmotherDragonToken.java b/Mage/src/main/java/mage/game/permanent/token/DragonBroodmotherDragonToken.java index 9f163eb36dc..f1e703849d7 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DragonBroodmotherDragonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DragonBroodmotherDragonToken.java @@ -15,7 +15,7 @@ import mage.constants.SubType; public final class DragonBroodmotherDragonToken extends TokenImpl { public DragonBroodmotherDragonToken() { - super("Dragon", "1/1 red and green Dragon creature token with flying and devour 2"); + super("Dragon Token", "1/1 red and green Dragon creature token with flying and devour 2"); cardType.add(CardType.CREATURE); color.setGreen(true); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/DragonEggDragonToken.java b/Mage/src/main/java/mage/game/permanent/token/DragonEggDragonToken.java index 04a1155edae..cd3d12b56ad 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DragonEggDragonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DragonEggDragonToken.java @@ -18,7 +18,7 @@ import java.util.Arrays; public final class DragonEggDragonToken extends TokenImpl { public DragonEggDragonToken() { - super("Dragon", "2/2 red Dragon creature token with flying and \"{R}: This creature gets +1/+0 until end of turn.\""); + super("Dragon Token", "2/2 red Dragon creature token with flying and \"{R}: This creature gets +1/+0 until end of turn.\""); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.DRAGON); diff --git a/Mage/src/main/java/mage/game/permanent/token/DragonIllusionToken.java b/Mage/src/main/java/mage/game/permanent/token/DragonIllusionToken.java index 0a1386500cf..68cec03e74c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DragonIllusionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DragonIllusionToken.java @@ -19,7 +19,7 @@ public class DragonIllusionToken extends TokenImpl { } public DragonIllusionToken(int xValue) { - super("Dragon Illusion", "X/X red Dragon Illusion creature token with flying and haste"); + super("Dragon Illusion Token", "X/X red Dragon Illusion creature token with flying and haste"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.DRAGON); diff --git a/Mage/src/main/java/mage/game/permanent/token/DragonSpiritToken.java b/Mage/src/main/java/mage/game/permanent/token/DragonSpiritToken.java index e8dac34bae5..b183ca19a2b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DragonSpiritToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DragonSpiritToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class DragonSpiritToken extends TokenImpl { public DragonSpiritToken() { - super("Dragon Spirit token", "5/5 red Dragon Spirit creature token with flying"); + super("Dragon Spirit Token", "5/5 red Dragon Spirit creature token with flying"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.DRAGON); diff --git a/Mage/src/main/java/mage/game/permanent/token/DragonToken.java b/Mage/src/main/java/mage/game/permanent/token/DragonToken.java index babf74f8df8..8fe6c311a9f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DragonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DragonToken.java @@ -29,7 +29,7 @@ public final class DragonToken extends TokenImpl { } public DragonToken(String setCode, int tokenType) { - super("Dragon", "4/4 red Dragon creature token with flying"); + super("Dragon Token", "4/4 red Dragon creature token with flying"); availableImageSetCodes = tokenImageSets; setOriginalExpansionSetCode(setCode); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/DragonToken2.java b/Mage/src/main/java/mage/game/permanent/token/DragonToken2.java index 9dd33ac0b8d..631846deb83 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DragonToken2.java +++ b/Mage/src/main/java/mage/game/permanent/token/DragonToken2.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class DragonToken2 extends TokenImpl { public DragonToken2() { - super("Dragon", "5/5 red Dragon creature token with flying"); + super("Dragon Token", "5/5 red Dragon creature token with flying"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.DRAGON); diff --git a/Mage/src/main/java/mage/game/permanent/token/DragonTokenGold.java b/Mage/src/main/java/mage/game/permanent/token/DragonTokenGold.java index 13d468195d3..09c35e83010 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DragonTokenGold.java +++ b/Mage/src/main/java/mage/game/permanent/token/DragonTokenGold.java @@ -31,7 +31,7 @@ public final class DragonTokenGold extends TokenImpl { } public DragonTokenGold(String setCode, int tokenType) { - super("Dragon", "4/4 gold Dragon creature token with flying"); + super("Dragon Token", "4/4 gold Dragon creature token with flying"); availableImageSetCodes = tokenImageSets; setOriginalExpansionSetCode(setCode); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/DrakeToken.java b/Mage/src/main/java/mage/game/permanent/token/DrakeToken.java index 9fbd97fa032..55ad6dfdc8a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DrakeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DrakeToken.java @@ -14,7 +14,7 @@ import java.util.Arrays; public final class DrakeToken extends TokenImpl { public DrakeToken() { - super("Drake", "2/2 blue Drake creature token with flying"); + super("Drake Token", "2/2 blue Drake creature token with flying"); this.cardType.add(CardType.CREATURE); this.subtype.add(SubType.DRAKE); @@ -24,7 +24,7 @@ public final class DrakeToken extends TokenImpl { this.addAbility(FlyingAbility.getInstance()); - availableImageSetCodes = Arrays.asList("AKH", "C15", "C19", "M13", "C20", "ZNR", "C21"); + availableImageSetCodes = Arrays.asList("AKH", "C15", "C19", "M13", "C20", "ZNR", "C21", "UMA"); } public DrakeToken(final DrakeToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/DroidToken.java b/Mage/src/main/java/mage/game/permanent/token/DroidToken.java index a3a3cd1d2f0..6fb64eaae1f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DroidToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DroidToken.java @@ -14,7 +14,7 @@ import mage.constants.SubType; public final class DroidToken extends TokenImpl { public DroidToken() { - super("Droid", "1/1 colorless Droid creature token"); + super("Droid Token", "1/1 colorless Droid creature token"); availableImageSetCodes.addAll(Collections.singletonList("SWS")); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/DuneBroodNephilimToken.java b/Mage/src/main/java/mage/game/permanent/token/DuneBroodNephilimToken.java index 51799e349ab..3b74f75f588 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DuneBroodNephilimToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DuneBroodNephilimToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class DuneBroodNephilimToken extends TokenImpl { public DuneBroodNephilimToken() { - super("Sand", "1/1 colorless Sand creature token"); + super("Sand Token", "1/1 colorless Sand creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.SAND); power = new MageInt(1); diff --git a/Mage/src/main/java/mage/game/permanent/token/DwarfBerserkerToken.java b/Mage/src/main/java/mage/game/permanent/token/DwarfBerserkerToken.java index 2803ffe89e2..a0bc31c7669 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DwarfBerserkerToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DwarfBerserkerToken.java @@ -9,7 +9,7 @@ import java.util.Arrays; public final class DwarfBerserkerToken extends TokenImpl { public DwarfBerserkerToken() { - super("Dwarf Berserker", "2/1 red Dwarf Berserker creature token"); + super("Dwarf Berserker Token", "2/1 red Dwarf Berserker creature token"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.DWARF); diff --git a/Mage/src/main/java/mage/game/permanent/token/DwarfToken.java b/Mage/src/main/java/mage/game/permanent/token/DwarfToken.java index 861d0bad56e..dd6c349178f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DwarfToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DwarfToken.java @@ -10,7 +10,7 @@ import mage.constants.SubType; public final class DwarfToken extends TokenImpl { public DwarfToken() { - super("Dwarf", "1/1 red Dwarf creature token"); + super("Dwarf Token", "1/1 red Dwarf creature token"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.DWARF); diff --git a/Mage/src/main/java/mage/game/permanent/token/EdgarMarkovToken.java b/Mage/src/main/java/mage/game/permanent/token/EdgarMarkovToken.java index 467f16a0b35..e250a9099bb 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EdgarMarkovToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EdgarMarkovToken.java @@ -20,7 +20,7 @@ public final class EdgarMarkovToken extends TokenImpl { } public EdgarMarkovToken() { - super("Vampire", "1/1 black Vampire creature token"); + super("Vampire Token", "1/1 black Vampire creature token"); availableImageSetCodes = tokenImageSets; setExpansionSetCodeForImage("C17"); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/EdgarMarkovsCoffinVampireToken.java b/Mage/src/main/java/mage/game/permanent/token/EdgarMarkovsCoffinVampireToken.java index d625f5c6732..180dbba1e6a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EdgarMarkovsCoffinVampireToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EdgarMarkovsCoffinVampireToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class EdgarMarkovsCoffinVampireToken extends TokenImpl { public EdgarMarkovsCoffinVampireToken() { - super("Vampire", "1/1 white and black Vampire creature token with lifelink"); + super("Vampire Token", "1/1 white and black Vampire creature token with lifelink"); cardType.add(CardType.CREATURE); color.setWhite(true); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/EldraziAnnihilatorToken.java b/Mage/src/main/java/mage/game/permanent/token/EldraziAnnihilatorToken.java index da9a93e57f9..e527673f857 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EldraziAnnihilatorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EldraziAnnihilatorToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.AnnihilatorAbility; public final class EldraziAnnihilatorToken extends TokenImpl { public EldraziAnnihilatorToken() { - super("Eldrazi", "7/7 colorless Eldrazi creature token"); + super("Eldrazi Token", "7/7 colorless Eldrazi creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.ELDRAZI); setExpansionSetCodeForImage("PCA"); diff --git a/Mage/src/main/java/mage/game/permanent/token/EldraziHorrorToken.java b/Mage/src/main/java/mage/game/permanent/token/EldraziHorrorToken.java index 4c541c96b36..6672d2ba127 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EldraziHorrorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EldraziHorrorToken.java @@ -21,7 +21,7 @@ public final class EldraziHorrorToken extends TokenImpl { } public EldraziHorrorToken() { - super("Eldrazi Horror", "3/2 colorless Eldrazi Horror creature token"); + super("Eldrazi Horror Token", "3/2 colorless Eldrazi Horror creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.ELDRAZI); subtype.add(SubType.HORROR); diff --git a/Mage/src/main/java/mage/game/permanent/token/EldraziScionToken.java b/Mage/src/main/java/mage/game/permanent/token/EldraziScionToken.java index 7b5c526790f..c0d9ed64002 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EldraziScionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EldraziScionToken.java @@ -27,7 +27,7 @@ public final class EldraziScionToken extends TokenImpl { } public EldraziScionToken() { - super("Eldrazi Scion", "1/1 colorless Eldrazi Scion creature token with \"Sacrifice this creature: Add {C}.\""); + super("Eldrazi Scion Token", "1/1 colorless Eldrazi Scion creature token with \"Sacrifice this creature: Add {C}.\""); cardType.add(CardType.CREATURE); subtype.add(SubType.ELDRAZI); subtype.add(SubType.SCION); diff --git a/Mage/src/main/java/mage/game/permanent/token/EldraziSpawnToken.java b/Mage/src/main/java/mage/game/permanent/token/EldraziSpawnToken.java index 01f5e695fdd..66c351a7e7a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EldraziSpawnToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EldraziSpawnToken.java @@ -18,7 +18,7 @@ import java.util.Arrays; public final class EldraziSpawnToken extends TokenImpl { public EldraziSpawnToken() { - super("Eldrazi Spawn", "0/1 colorless Eldrazi Spawn creature with \"Sacrifice this creature: Add {C}.\""); + super("Eldrazi Spawn Token", "0/1 colorless Eldrazi Spawn creature token. It has \"Sacrifice this creature: Add {C}.\""); cardType.add(CardType.CREATURE); subtype.add(SubType.ELDRAZI); subtype.add(SubType.SPAWN); @@ -26,7 +26,7 @@ public final class EldraziSpawnToken extends TokenImpl { toughness = new MageInt(1); addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.ColorlessMana(1), new SacrificeSourceCost())); - availableImageSetCodes = Arrays.asList("CMD", "DDP", "MM2", "PC2", "ROE", "MIC"); + availableImageSetCodes = Arrays.asList("CMD", "DDP", "MM2", "PC2", "ROE", "MIC", "2XM"); } @Override diff --git a/Mage/src/main/java/mage/game/permanent/token/EldraziToken.java b/Mage/src/main/java/mage/game/permanent/token/EldraziToken.java index ff8a1eb999b..47d618151af 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EldraziToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EldraziToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class EldraziToken extends TokenImpl { public EldraziToken() { - super("Eldrazi", "10/10 colorless Eldrazi creature token"); + super("Eldrazi Token", "10/10 colorless Eldrazi creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.ELDRAZI); power = new MageInt(10); diff --git a/Mage/src/main/java/mage/game/permanent/token/Elemental44Token.java b/Mage/src/main/java/mage/game/permanent/token/Elemental44Token.java index a03e1137dfc..9ec0d1c6ace 100644 --- a/Mage/src/main/java/mage/game/permanent/token/Elemental44Token.java +++ b/Mage/src/main/java/mage/game/permanent/token/Elemental44Token.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class Elemental44Token extends TokenImpl { public Elemental44Token() { - super("Elemental", "4/4 blue and red Elemental creature token"); + super("Elemental Token", "4/4 blue and red Elemental creature token"); cardType.add(CardType.CREATURE); color.setBlue(true); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/ElementalCatToken.java b/Mage/src/main/java/mage/game/permanent/token/ElementalCatToken.java index 13a993952c1..654664db451 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ElementalCatToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ElementalCatToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.HasteAbility; public final class ElementalCatToken extends TokenImpl { public ElementalCatToken() { - super("Elemental Cat", "1/1 red Elemental Cat creature token"); + super("Elemental Cat Token", "1/1 red Elemental Cat creature token"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.ELEMENTAL); diff --git a/Mage/src/main/java/mage/game/permanent/token/ElementalMasteryElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/ElementalMasteryElementalToken.java index cbbf16b4bbb..67a186493d1 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ElementalMasteryElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ElementalMasteryElementalToken.java @@ -13,7 +13,7 @@ import mage.constants.SubType; public final class ElementalMasteryElementalToken extends TokenImpl { public ElementalMasteryElementalToken() { - super("Elemental", "1/1 red Elemental creature token with haste"); + super("Elemental Token", "1/1 red Elemental creature token with haste"); cardType.add(CardType.CREATURE); subtype.add(SubType.ELEMENTAL); color.setRed(true); @@ -21,6 +21,16 @@ public final class ElementalMasteryElementalToken extends TokenImpl { toughness = new MageInt(1); addAbility(HasteAbility.getInstance()); } + + @Override + public void setExpansionSetCodeForImage(String code) { + super.setExpansionSetCodeForImage(code); + + if (getOriginalExpansionSetCode().equals("SHM")) { + this.setTokenType(2); + } + } + public ElementalMasteryElementalToken(final ElementalMasteryElementalToken token) { super(token); } diff --git a/Mage/src/main/java/mage/game/permanent/token/ElementalShamanToken.java b/Mage/src/main/java/mage/game/permanent/token/ElementalShamanToken.java index 0ebe90174f1..e9122f5d645 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ElementalShamanToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ElementalShamanToken.java @@ -34,7 +34,7 @@ public final class ElementalShamanToken extends TokenImpl { } public ElementalShamanToken(String setCode) { - super("Elemental Shaman", "3/1 red Elemental Shaman creature token"); + super("Elemental Shaman Token", "3/1 red Elemental Shaman creature token"); availableImageSetCodes = tokenImageSets; setOriginalExpansionSetCode(setCode); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/ElementalTokenWithHaste.java b/Mage/src/main/java/mage/game/permanent/token/ElementalTokenWithHaste.java index a37a3ce7734..be28990827a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ElementalTokenWithHaste.java +++ b/Mage/src/main/java/mage/game/permanent/token/ElementalTokenWithHaste.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class ElementalTokenWithHaste extends TokenImpl { public ElementalTokenWithHaste() { - super("Elemental", "3/1 red Elemental creature token with haste"); + super("Elemental Token", "3/1 red Elemental creature token with haste"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.ELEMENTAL); @@ -21,7 +21,7 @@ public final class ElementalTokenWithHaste extends TokenImpl { toughness = new MageInt(1); this.addAbility(HasteAbility.getInstance()); - availableImageSetCodes = Arrays.asList("C20", "PMEI", "OGW", "SOK", "MRD"); + availableImageSetCodes = Arrays.asList("C20", "PMEI", "OGW", "SOK", "MRD", "CON"); } public ElementalTokenWithHaste(final ElementalTokenWithHaste token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/ElephantResurgenceToken.java b/Mage/src/main/java/mage/game/permanent/token/ElephantResurgenceToken.java index 686a443bcc1..6de7fd8f31e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ElephantResurgenceToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ElephantResurgenceToken.java @@ -18,7 +18,7 @@ import mage.filter.common.FilterCreatureCard; public final class ElephantResurgenceToken extends TokenImpl { public ElephantResurgenceToken() { - super("Elephant", "green Elephant creature token. Those creatures have \"This creature's power and toughness are each equal to the number of creature cards in its controller's graveyard.\""); + super("Elephant Token", "green Elephant creature token. Those creatures have \"This creature's power and toughness are each equal to the number of creature cards in its controller's graveyard.\""); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.ELEPHANT); diff --git a/Mage/src/main/java/mage/game/permanent/token/ElephantToken.java b/Mage/src/main/java/mage/game/permanent/token/ElephantToken.java index b7884146289..d621cc6179f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ElephantToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ElephantToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class ElephantToken extends TokenImpl { public ElephantToken() { - super("Elephant", "3/3 green Elephant creature token"); + super("Elephant Token", "3/3 green Elephant creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.ELEPHANT); @@ -20,7 +20,7 @@ public final class ElephantToken extends TokenImpl { toughness = new MageInt(3); availableImageSetCodes = Arrays.asList("C13", "C14", "C15", "CMA", "CMD", "CNS", "GVL", "DDD", - "EMA", "INV", "JUD", "MM2", "ODY", "ROE", "TSP", "VMA", "WWK", "MH1", "CMR", "C21", "MIC"); + "EMA", "INV", "JUD", "MM2", "ODY", "ROE", "TSP", "VMA", "WWK", "MH1", "CMR", "C21", "MIC", "NEC", "2XM"); } public ElephantToken(final ElephantToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/ElfDruidToken.java b/Mage/src/main/java/mage/game/permanent/token/ElfDruidToken.java index 04adef5c71a..9e14c28ebbe 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ElfDruidToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ElfDruidToken.java @@ -24,7 +24,7 @@ public final class ElfDruidToken extends TokenImpl { } public ElfDruidToken(String setCode, int tokenType) { - super("Elf Druid", "1/1 green Elf Druid creature token with \"{T}: Add {G}.\""); + super("Elf Druid Token", "1/1 green Elf Druid creature token with \"{T}: Add {G}.\""); this.cardType.add(CardType.CREATURE); this.color.setGreen(true); this.subtype.add(SubType.ELF); diff --git a/Mage/src/main/java/mage/game/permanent/token/ElfKnightToken.java b/Mage/src/main/java/mage/game/permanent/token/ElfKnightToken.java index b2483d23fb5..eb2da5939c9 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ElfKnightToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ElfKnightToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class ElfKnightToken extends TokenImpl { public ElfKnightToken() { - super("Elf Knight", "2/2 green and white Elf Knight creature token with vigilance"); + super("Elf Knight Token", "2/2 green and white Elf Knight creature token with vigilance"); this.setExpansionSetCodeForImage("GRN"); cardType.add(CardType.CREATURE); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/ElfWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/ElfWarriorToken.java index c94493e7752..5bb78727bbf 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ElfWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ElfWarriorToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class ElfWarriorToken extends TokenImpl { public ElfWarriorToken() { - super("Elf Warrior", "1/1 green Elf Warrior creature token"); + super("Elf Warrior Token", "1/1 green Elf Warrior creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.ELF); @@ -35,5 +35,9 @@ public final class ElfWarriorToken extends TokenImpl { @Override public void setExpansionSetCodeForImage(String code) { super.setExpansionSetCodeForImage(code); + + if (getOriginalExpansionSetCode().equals("SHM")) { + this.setTokenType(1); + } } } diff --git a/Mage/src/main/java/mage/game/permanent/token/EmptyToken.java b/Mage/src/main/java/mage/game/permanent/token/EmptyToken.java index 566c417b4d2..6a7152665ad 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EmptyToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EmptyToken.java @@ -7,7 +7,7 @@ package mage.game.permanent.token; public final class EmptyToken extends TokenImpl { public EmptyToken() { - super("", ""); + super(" Token", ""); } public EmptyToken(final EmptyToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/ErrandOfDutyKnightToken.java b/Mage/src/main/java/mage/game/permanent/token/ErrandOfDutyKnightToken.java index ed151193cbd..14e852cfe1d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ErrandOfDutyKnightToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ErrandOfDutyKnightToken.java @@ -13,7 +13,7 @@ import mage.constants.SubType; public final class ErrandOfDutyKnightToken extends TokenImpl { public ErrandOfDutyKnightToken() { - super("Knight", "1/1 white Knight creature token with banding"); + super("Knight Token", "1/1 white Knight creature token with banding"); cardType.add(CardType.CREATURE); subtype.add(SubType.KNIGHT); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/EtheriumCellToken.java b/Mage/src/main/java/mage/game/permanent/token/EtheriumCellToken.java index ff472627b30..a1bc68568af 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EtheriumCellToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EtheriumCellToken.java @@ -16,7 +16,7 @@ import mage.constants.Zone; public final class EtheriumCellToken extends TokenImpl { public EtheriumCellToken() { - super("Etherium Cell", "colorless artifact token named Etherium Cell which has \"{T}, Sacrifice this artifact: Add one mana of any color.\""); + super("Etherium Cell", "colorless artifact token named Etherium Cell with \"{T}, Sacrifice this artifact: Add one mana of any color.\""); this.setOriginalExpansionSetCode("AER"); cardType.add(CardType.ARTIFACT); diff --git a/Mage/src/main/java/mage/game/permanent/token/EwokToken.java b/Mage/src/main/java/mage/game/permanent/token/EwokToken.java index 1d295b536e8..a71d688e02b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EwokToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EwokToken.java @@ -13,7 +13,7 @@ import mage.constants.SubType; public final class EwokToken extends TokenImpl { public EwokToken() { - super("Ewok", "1/1 green Ewok creature tokens", 1, 1); + super("Ewok Token", "1/1 green Ewok creature tokens", 1, 1); availableImageSetCodes.addAll(Collections.singletonList("SWS")); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/ExpansionSymbolToken.java b/Mage/src/main/java/mage/game/permanent/token/ExpansionSymbolToken.java index 1f608901ce2..eb4547484f6 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ExpansionSymbolToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ExpansionSymbolToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class ExpansionSymbolToken extends TokenImpl { public ExpansionSymbolToken() { - super("Expansion-Symbol", "1/1 colorless Expansion-Symbol creature token"); + super("Expansion-Symbol Token", "1/1 colorless Expansion-Symbol creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.EXPANSION_SYMBOL); power = new MageInt(1); diff --git a/Mage/src/main/java/mage/game/permanent/token/EyesOfTheWisentElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/EyesOfTheWisentElementalToken.java index 76ea60a0094..3e9edc30606 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EyesOfTheWisentElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EyesOfTheWisentElementalToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class EyesOfTheWisentElementalToken extends TokenImpl { public EyesOfTheWisentElementalToken() { - super("Elemental", "4/4 green Elemental creature token"); + super("Elemental Token", "4/4 green Elemental creature token"); this.setOriginalExpansionSetCode("MMA"); cardType.add(CardType.CREATURE); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/FableOfTheMirrorBreakerToken.java b/Mage/src/main/java/mage/game/permanent/token/FableOfTheMirrorBreakerToken.java new file mode 100644 index 00000000000..bb211bcd3b6 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/FableOfTheMirrorBreakerToken.java @@ -0,0 +1,33 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public class FableOfTheMirrorBreakerToken extends TokenImpl { + + public FableOfTheMirrorBreakerToken() { + super("Goblin Shaman Token", "2/2 red Goblin Shaman creature token with \"Whenever this creature attacks, create a Treasure token.\""); + cardType.add(CardType.CREATURE); + color.setRed(true); + subtype.add(SubType.GOBLIN); + subtype.add(SubType.SHAMAN); + power = new MageInt(2); + toughness = new MageInt(2); + addAbility(new AttacksTriggeredAbility(new CreateTokenEffect(new TreasureToken())).setTriggerPhrase("Whenever this creature attacks, ")); + } + + private FableOfTheMirrorBreakerToken(final FableOfTheMirrorBreakerToken token) { + super(token); + } + + @Override + public FableOfTheMirrorBreakerToken copy() { + return new FableOfTheMirrorBreakerToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/FaerieDragonToken.java b/Mage/src/main/java/mage/game/permanent/token/FaerieDragonToken.java index 379164ea695..9cd0b70087b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FaerieDragonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FaerieDragonToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public class FaerieDragonToken extends TokenImpl { public FaerieDragonToken() { - super("Faerie Dragon", "1/1 blue Faerie Dragon creature token with flying"); + super("Faerie Dragon Token", "1/1 blue Faerie Dragon creature token with flying"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.FAERIE); diff --git a/Mage/src/main/java/mage/game/permanent/token/FaerieRogueToken.java b/Mage/src/main/java/mage/game/permanent/token/FaerieRogueToken.java index 06eeda19d7e..0b4e64bdb11 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FaerieRogueToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FaerieRogueToken.java @@ -4,6 +4,7 @@ import mage.MageInt; import mage.abilities.keyword.FlyingAbility; import mage.constants.CardType; import mage.constants.SubType; +import mage.util.RandomUtil; import java.util.Arrays; @@ -13,7 +14,7 @@ import java.util.Arrays; public final class FaerieRogueToken extends TokenImpl { public FaerieRogueToken() { - super("Faerie Rogue", "1/1 black Faerie Rogue creature token with flying"); + super("Faerie Rogue Token", "1/1 black Faerie Rogue creature token with flying"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.FAERIE); @@ -22,7 +23,16 @@ public final class FaerieRogueToken extends TokenImpl { toughness = new MageInt(1); addAbility(FlyingAbility.getInstance()); - availableImageSetCodes = Arrays.asList("SHM", "MOR", "MMA", "MM2", "ZNC"); + availableImageSetCodes = Arrays.asList("MOR", "MM2", "ZNC", "UMA", "SLD"); + } + + @Override + public void setExpansionSetCodeForImage(String code) { + super.setExpansionSetCodeForImage(code); + + if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("SLD")) { + setTokenType(RandomUtil.nextInt(4) + 1); + } } public FaerieRogueToken(final FaerieRogueToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/FaerieToken.java b/Mage/src/main/java/mage/game/permanent/token/FaerieToken.java index bc53e43870a..53f59c44120 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FaerieToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FaerieToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class FaerieToken extends TokenImpl { public FaerieToken() { - super("Faerie", "1/1 blue Faerie creature token with flying"); + super("Faerie Token", "1/1 blue Faerie creature token with flying"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.FAERIE); diff --git a/Mage/src/main/java/mage/game/permanent/token/FesteringGoblinToken.java b/Mage/src/main/java/mage/game/permanent/token/FesteringGoblinToken.java index 6f85ef6a2c9..ccfd3e1e5ce 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FesteringGoblinToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FesteringGoblinToken.java @@ -17,7 +17,7 @@ import mage.target.common.TargetCreaturePermanent; public final class FesteringGoblinToken extends TokenImpl { public FesteringGoblinToken() { - super("Festering Goblin", "1/1 black Zombie Goblin creature token named Festering Goblin with \"When Festering Goblin dies, target creature gets -1/-1 until end of turn.\""); + super("Festering Goblin", "1/1 black Zombie Goblin creature token named Festering Goblin. It has \"When Festering Goblin dies, target creature gets -1/-1 until end of turn.\""); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.ZOMBIE); diff --git a/Mage/src/main/java/mage/game/permanent/token/FishToken.java b/Mage/src/main/java/mage/game/permanent/token/FishToken.java new file mode 100644 index 00000000000..7688aec0972 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/FishToken.java @@ -0,0 +1,31 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.CantBeBlockedSourceAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class FishToken extends TokenImpl { + + public FishToken() { + super("Fish Token", "1/1 blue Fish creature token with \"This creature can't be blocked.\""); + cardType.add(CardType.CREATURE); + subtype.add(SubType.FISH); + color.setBlue(true); + power = new MageInt(1); + toughness = new MageInt(1); + + addAbility(new CantBeBlockedSourceAbility("this creature can't be blocked")); + } + + public FishToken(final FishToken token) { + super(token); + } + + public FishToken copy() { + return new FishToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/FleshCarverHorrorToken.java b/Mage/src/main/java/mage/game/permanent/token/FleshCarverHorrorToken.java index b826239e56f..4b1c7ab4935 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FleshCarverHorrorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FleshCarverHorrorToken.java @@ -16,7 +16,7 @@ public final class FleshCarverHorrorToken extends TokenImpl { } public FleshCarverHorrorToken(int xValue) { - super("Horror", "X/X black Horror creature token"); + super("Horror Token", "X/X black Horror creature token"); setOriginalExpansionSetCode("C14"); cardType.add(CardType.CREATURE); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/FlurryOfHornsMinotaurToken.java b/Mage/src/main/java/mage/game/permanent/token/FlurryOfHornsMinotaurToken.java index a4d6f1da0a8..2f4b10bbdc9 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FlurryOfHornsMinotaurToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FlurryOfHornsMinotaurToken.java @@ -14,7 +14,7 @@ import mage.abilities.keyword.HasteAbility; public final class FlurryOfHornsMinotaurToken extends TokenImpl { public FlurryOfHornsMinotaurToken() { - super("Minotaur", "2/3 red Minotaur creature tokens with haste"); + super("Minotaur Token", "2/3 red Minotaur creature tokens with haste"); this.setOriginalExpansionSetCode("JOU"); cardType.add(CardType.CREATURE); color.setColor(ObjectColor.RED); diff --git a/Mage/src/main/java/mage/game/permanent/token/FoodToken.java b/Mage/src/main/java/mage/game/permanent/token/FoodToken.java index d825ed8d1d1..42f54556592 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FoodToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FoodToken.java @@ -24,7 +24,7 @@ public final class FoodToken extends TokenImpl { static final private List tokenImageSets = new ArrayList<>(); public FoodToken() { - super("Food", "Food token"); + super("Food Token", "Food token"); cardType.add(CardType.ARTIFACT); subtype.add(SubType.FOOD); diff --git a/Mage/src/main/java/mage/game/permanent/token/ForlornPseudammaZombieToken.java b/Mage/src/main/java/mage/game/permanent/token/ForlornPseudammaZombieToken.java index a49e7343db8..732df162524 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ForlornPseudammaZombieToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ForlornPseudammaZombieToken.java @@ -13,7 +13,7 @@ import mage.MageInt; public final class ForlornPseudammaZombieToken extends TokenImpl { public ForlornPseudammaZombieToken() { - super("Zombie", "2/2 black Zombie enchantment creature token"); + super("Zombie Token", "2/2 black Zombie enchantment creature token"); cardType.add(CardType.ENCHANTMENT); cardType.add(CardType.CREATURE); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/FractalToken.java b/Mage/src/main/java/mage/game/permanent/token/FractalToken.java index a427e9b1b0d..91b3737adb9 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FractalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FractalToken.java @@ -20,7 +20,7 @@ import java.util.UUID; public final class FractalToken extends TokenImpl { public FractalToken() { - super("Fractal", "0/0 green and blue Fractal creature token"); + super("Fractal Token", "0/0 green and blue Fractal creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.FRACTAL); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/FrogLizardToken.java b/Mage/src/main/java/mage/game/permanent/token/FrogLizardToken.java index e2c725fed3d..e6d01b46c2d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FrogLizardToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FrogLizardToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class FrogLizardToken extends TokenImpl { public FrogLizardToken() { - super("Frog Lizard", "3/3 green Frog Lizard creature token"); + super("Frog Lizard Token", "3/3 green Frog Lizard creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.FROG); diff --git a/Mage/src/main/java/mage/game/permanent/token/FrogToken.java b/Mage/src/main/java/mage/game/permanent/token/FrogToken.java index 1dd66a20ae2..ee956324dfb 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FrogToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FrogToken.java @@ -13,7 +13,7 @@ import mage.MageInt; public final class FrogToken extends TokenImpl { public FrogToken() { - super("Frog", "1/1 blue Frog creature token"); + super("Frog Token", "1/1 blue Frog creature token"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.FROG); diff --git a/Mage/src/main/java/mage/game/permanent/token/FungusBeastToken.java b/Mage/src/main/java/mage/game/permanent/token/FungusBeastToken.java index 6430fdf296e..8c24296c618 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FungusBeastToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FungusBeastToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class FungusBeastToken extends TokenImpl { public FungusBeastToken() { - super("Fungus Beast", "4/4 green Fungus Beast creature token with trample"); + super("Fungus Beast Token", "4/4 green Fungus Beast creature token with trample"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.FUNGUS); diff --git a/Mage/src/main/java/mage/game/permanent/token/GargoyleToken.java b/Mage/src/main/java/mage/game/permanent/token/GargoyleToken.java index 29e4b21c93d..ae726a221a0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GargoyleToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GargoyleToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class GargoyleToken extends TokenImpl { public GargoyleToken() { - super("Gargoyle", "3/4 colorless Gargoyle artifact creature token with flying"); + super("Gargoyle Token", "3/4 colorless Gargoyle artifact creature token with flying"); cardType.add(CardType.CREATURE); cardType.add(CardType.ARTIFACT); subtype.add(SubType.GARGOYLE); diff --git a/Mage/src/main/java/mage/game/permanent/token/GarrukApexPredatorBeastToken.java b/Mage/src/main/java/mage/game/permanent/token/GarrukApexPredatorBeastToken.java index 5d1f182654a..3264ae5dffb 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GarrukApexPredatorBeastToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GarrukApexPredatorBeastToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.DeathtouchAbility; public final class GarrukApexPredatorBeastToken extends TokenImpl { public GarrukApexPredatorBeastToken() { - super("Beast", "3/3 black Beast creature token with deathtouch"); + super("Beast Token", "3/3 black Beast creature token with deathtouch"); setOriginalExpansionSetCode("M15"); setTokenType(1); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/GarrukCursedHuntsmanToken.java b/Mage/src/main/java/mage/game/permanent/token/GarrukCursedHuntsmanToken.java index 2fb450d53e5..ecccb692c2c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GarrukCursedHuntsmanToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GarrukCursedHuntsmanToken.java @@ -18,7 +18,7 @@ public final class GarrukCursedHuntsmanToken extends TokenImpl { = new FilterControlledPermanent(SubType.GARRUK, "Garruk you control"); public GarrukCursedHuntsmanToken() { - super("Wolf", "2/2 black and green Wolf creature token with \"When this creature dies, put a loyalty counter on each Garruk you control.\""); + super("Wolf Token", "2/2 black and green Wolf creature token with \"When this creature dies, put a loyalty counter on each Garruk you control.\""); cardType.add(CardType.CREATURE); color.setBlack(true); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/GiantBaitingGiantWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/GiantBaitingGiantWarriorToken.java index 395e126aaaa..6f12de84739 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GiantBaitingGiantWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GiantBaitingGiantWarriorToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.HasteAbility; public final class GiantBaitingGiantWarriorToken extends TokenImpl { public GiantBaitingGiantWarriorToken() { - super("Giant Warrior", "4/4 red and green Giant Warrior creature token with haste"); + super("Giant Warrior Token", "4/4 red and green Giant Warrior creature token with haste"); cardType.add(CardType.CREATURE); color.setRed(true); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/GiantBirdToken.java b/Mage/src/main/java/mage/game/permanent/token/GiantBirdToken.java index e1287a49a96..3364fe7f852 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GiantBirdToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GiantBirdToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class GiantBirdToken extends TokenImpl { public GiantBirdToken() { - super("Giant Bird", "4/4 red Giant Bird creature token"); + super("Giant Bird Token", "4/4 red Giant Bird creature token"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.GIANT); diff --git a/Mage/src/main/java/mage/game/permanent/token/GiantOpportunityToken.java b/Mage/src/main/java/mage/game/permanent/token/GiantOpportunityToken.java index d8bee08b4eb..d0ba47a14d4 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GiantOpportunityToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GiantOpportunityToken.java @@ -10,7 +10,7 @@ import mage.constants.SubType; public final class GiantOpportunityToken extends TokenImpl { public GiantOpportunityToken() { - super("Giant", "7/7 green Giant creature token"); + super("Giant Token", "7/7 green Giant creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.GIANT); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/GiantToken.java b/Mage/src/main/java/mage/game/permanent/token/GiantToken.java index 1101b1d6a93..e74e3c72772 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GiantToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GiantToken.java @@ -14,7 +14,7 @@ import java.util.Arrays; public final class GiantToken extends TokenImpl { public GiantToken() { - super("Giant", "4/4 red Giant creature token"); + super("Giant Token", "4/4 red Giant creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.GIANT); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/GiantWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/GiantWarriorToken.java index 03da6d74867..4efe2970fb5 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GiantWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GiantWarriorToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class GiantWarriorToken extends TokenImpl { public GiantWarriorToken() { - super("Giant Warrior", "5/5 white Giant Warrior creature token"); + super("Giant Warrior Token", "5/5 white Giant Warrior creature token"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.GIANT); diff --git a/Mage/src/main/java/mage/game/permanent/token/GiantWizardToken.java b/Mage/src/main/java/mage/game/permanent/token/GiantWizardToken.java index 45398742824..262a40c37a5 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GiantWizardToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GiantWizardToken.java @@ -9,7 +9,7 @@ import java.util.Arrays; public final class GiantWizardToken extends TokenImpl { public GiantWizardToken() { - super("Giant Wizard", "4/4 blue Giant Wizard creature token"); + super("Giant Wizard Token", "4/4 blue Giant Wizard creature token"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.GIANT); diff --git a/Mage/src/main/java/mage/game/permanent/token/GnomeToken.java b/Mage/src/main/java/mage/game/permanent/token/GnomeToken.java index b3461e2edf8..d6bb6e8572b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GnomeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GnomeToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class GnomeToken extends TokenImpl { public GnomeToken() { - super("Gnome", "1/1 colorless Gnome artifact creature token"); + super("Gnome Token", "1/1 colorless Gnome artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.GNOME); diff --git a/Mage/src/main/java/mage/game/permanent/token/GoatToken.java b/Mage/src/main/java/mage/game/permanent/token/GoatToken.java index 5f286483afd..6cb4d5af8fc 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GoatToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GoatToken.java @@ -28,7 +28,7 @@ public final class GoatToken extends TokenImpl { } public GoatToken(String setCode, int tokenType) { - super("Goat", "0/1 white Goat creature token"); + super("Goat Token", "0/1 white Goat creature token"); availableImageSetCodes = tokenImageSets; setOriginalExpansionSetCode(setCode); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/GoblinRogueToken.java b/Mage/src/main/java/mage/game/permanent/token/GoblinRogueToken.java index a59881c2faf..cff570f388e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GoblinRogueToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GoblinRogueToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class GoblinRogueToken extends TokenImpl { public GoblinRogueToken() { - super("Goblin Rogue", "1/1 black Goblin Rogue creature token"); + super("Goblin Rogue Token", "1/1 black Goblin Rogue creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.GOBLIN); diff --git a/Mage/src/main/java/mage/game/permanent/token/GoblinScoutsToken.java b/Mage/src/main/java/mage/game/permanent/token/GoblinScoutsToken.java index 5ac834a92e1..c0b959d36fc 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GoblinScoutsToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GoblinScoutsToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.MountainwalkAbility; public final class GoblinScoutsToken extends TokenImpl { public GoblinScoutsToken() { - super("Goblin Scout", "1/1 red Goblin Scout creature tokens with mountainwalk"); + super("Goblin Scout Token", "1/1 red Goblin Scout creature tokens with mountainwalk"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.GOBLIN); diff --git a/Mage/src/main/java/mage/game/permanent/token/GoblinSoldierToken.java b/Mage/src/main/java/mage/game/permanent/token/GoblinSoldierToken.java index 8682237b611..c47025526f1 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GoblinSoldierToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GoblinSoldierToken.java @@ -1,5 +1,3 @@ - - package mage.game.permanent.token; import mage.constants.CardType; import mage.constants.SubType; @@ -12,7 +10,7 @@ import mage.MageInt; public final class GoblinSoldierToken extends TokenImpl { public GoblinSoldierToken() { - super("Goblin Soldier", "1/1 red and white Goblin Soldier creature tokens"); + super("Goblin Soldier Token", "1/1 red and white Goblin Soldier creature token"); cardType.add(CardType.CREATURE); color.setRed(true); color.setWhite(true); @@ -21,6 +19,7 @@ public final class GoblinSoldierToken extends TokenImpl { power = new MageInt(1); toughness = new MageInt(1); } + public GoblinSoldierToken(final GoblinSoldierToken token) { super(token); } @@ -28,5 +27,4 @@ public final class GoblinSoldierToken extends TokenImpl { public GoblinSoldierToken copy() { return new GoblinSoldierToken(this); } - } diff --git a/Mage/src/main/java/mage/game/permanent/token/GoblinToken.java b/Mage/src/main/java/mage/game/permanent/token/GoblinToken.java index d75f24acff8..70e125f2d6b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GoblinToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GoblinToken.java @@ -23,7 +23,7 @@ public final class GoblinToken extends TokenImpl { } public GoblinToken() { - super("Goblin", "1/1 red Goblin creature token"); + super("Goblin Token", "1/1 red Goblin creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.GOBLIN); color.setRed(true); @@ -32,7 +32,7 @@ public final class GoblinToken extends TokenImpl { availableImageSetCodes = Arrays.asList("10E", "ALA", "SOM", "M10", "NPH", "M13", "RTR", "MMA", "M15", "C14", "KTK", "EVG", "DTK", "ORI", "DDG", "DDN", "EVG", "MM2", - "MM3", "EMA", "C16", "DOM", "ANA", "RNA", "WAR", "MH1", "TSR", "MH2", "AFR"); + "MM3", "EMA", "C16", "DOM", "ANA", "RNA", "WAR", "MH1", "TSR", "MH2", "AFR", "NEC"); } public GoblinToken(final GoblinToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/GoblinTrenchesToken.java b/Mage/src/main/java/mage/game/permanent/token/GoblinTrenchesToken.java deleted file mode 100644 index 94b1e50c952..00000000000 --- a/Mage/src/main/java/mage/game/permanent/token/GoblinTrenchesToken.java +++ /dev/null @@ -1,32 +0,0 @@ - - -package mage.game.permanent.token; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.MageInt; - -/** - * - * @author spjspj - */ -public final class GoblinTrenchesToken extends TokenImpl { - - public GoblinTrenchesToken() { - super("Goblin Soldier", "1/1 red and white Goblin Soldier creature tokens"); - cardType.add(CardType.CREATURE); - color.setRed(true); - color.setWhite(true); - subtype.add(SubType.GOBLIN); - subtype.add(SubType.SOLDIER); - power = new MageInt(1); - toughness = new MageInt(1); - } - - public GoblinTrenchesToken(final GoblinTrenchesToken token) { - super(token); - } - - public GoblinTrenchesToken copy() { - return new GoblinTrenchesToken(this); - } -} diff --git a/Mage/src/main/java/mage/game/permanent/token/GoblinWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/GoblinWarriorToken.java index ec79599e77f..28c17966bc4 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GoblinWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GoblinWarriorToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class GoblinWarriorToken extends TokenImpl { public GoblinWarriorToken() { - super("Goblin Warrior", "1/1 red and green Goblin Warrior creature token"); + super("Goblin Warrior Token", "1/1 red and green Goblin Warrior creature token"); cardType.add(CardType.CREATURE); color.setRed(true); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/GoblinWizardToken.java b/Mage/src/main/java/mage/game/permanent/token/GoblinWizardToken.java index 1ab3106fb8f..ef8e87db515 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GoblinWizardToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GoblinWizardToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class GoblinWizardToken extends TokenImpl { public GoblinWizardToken() { - super("Goblin Wizard", "1/1 red Goblin Wizard creature token with prowess"); + super("Goblin Wizard Token", "1/1 red Goblin Wizard creature token with prowess"); cardType.add(CardType.CREATURE); subtype.add(SubType.GOBLIN); subtype.add(SubType.WIZARD); diff --git a/Mage/src/main/java/mage/game/permanent/token/GodEternalOketraToken.java b/Mage/src/main/java/mage/game/permanent/token/GodEternalOketraToken.java index 37e965bdbbb..87607b85da3 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GodEternalOketraToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GodEternalOketraToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class GodEternalOketraToken extends TokenImpl { public GodEternalOketraToken() { - super("Zombie Warrior", "4/4 black Zombie Warrior creature token with vigilance"); + super("Zombie Warrior Token", "4/4 black Zombie Warrior creature token with vigilance"); setOriginalExpansionSetCode("WAR"); // default cardType.add(CardType.CREATURE); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/GodFavoredGeneralSoldierToken.java b/Mage/src/main/java/mage/game/permanent/token/GodFavoredGeneralSoldierToken.java index 2a1a0007f27..d01d4b66000 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GodFavoredGeneralSoldierToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GodFavoredGeneralSoldierToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class GodFavoredGeneralSoldierToken extends TokenImpl { public GodFavoredGeneralSoldierToken() { - super("Soldier", "1/1 white Soldier enchantment creature token"); + super("Soldier Token", "1/1 white Soldier enchantment creature token"); cardType.add(CardType.ENCHANTMENT); cardType.add(CardType.CREATURE); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/GodSireBeastToken.java b/Mage/src/main/java/mage/game/permanent/token/GodSireBeastToken.java index 04764f2c584..cbd0ba45067 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GodSireBeastToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GodSireBeastToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class GodSireBeastToken extends TokenImpl { public GodSireBeastToken() { - super("Beast", "8/8 Beast creature token that's red, green, and white"); + super("Beast Token", "8/8 Beast creature token that's red, green, and white"); cardType.add(CardType.CREATURE); color.setGreen(true); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/GoldForgeGarrisonGolemToken.java b/Mage/src/main/java/mage/game/permanent/token/GoldForgeGarrisonGolemToken.java index fcdc4d081da..6145ae87b12 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GoldForgeGarrisonGolemToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GoldForgeGarrisonGolemToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class GoldForgeGarrisonGolemToken extends TokenImpl { public GoldForgeGarrisonGolemToken() { - super("Golem", "4/4 colorless Golem artifact creature token"); + super("Golem Token", "4/4 colorless Golem artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/GoldToken.java b/Mage/src/main/java/mage/game/permanent/token/GoldToken.java index 9f82f171dca..19efc143904 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GoldToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GoldToken.java @@ -22,7 +22,7 @@ public final class GoldToken extends TokenImpl { } public GoldToken() { - super("Gold", "Gold token"); + super("Gold Token", "Gold token"); availableImageSetCodes = tokenImageSets; cardType.add(CardType.ARTIFACT); subtype.add(SubType.GOLD); diff --git a/Mage/src/main/java/mage/game/permanent/token/GoldmeadowHarrierToken.java b/Mage/src/main/java/mage/game/permanent/token/GoldmeadowHarrierToken.java index 835566acf1d..457d5d4f57a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GoldmeadowHarrierToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GoldmeadowHarrierToken.java @@ -19,7 +19,7 @@ import mage.target.common.TargetCreaturePermanent; public final class GoldmeadowHarrierToken extends TokenImpl { public GoldmeadowHarrierToken() { - super("Goldmeadow Harrier", "1/1 white Kithkin Soldier creature token named Goldmeadow Harrier with \"{W}, {T}: Tap target creature.\""); + super("Goldmeadow Harrier", "1/1 white Kithkin Soldier creature token named Goldmeadow Harrier. It has \"{W}, {T}: Tap target creature.\""); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.KITHKIN); diff --git a/Mage/src/main/java/mage/game/permanent/token/GolemFlyingToken.java b/Mage/src/main/java/mage/game/permanent/token/GolemFlyingToken.java index 12006c51c84..25a057caafa 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GolemFlyingToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GolemFlyingToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class GolemFlyingToken extends TokenImpl { public GolemFlyingToken() { - super("Golem", "3/3 colorless Golem artifact creature token with flying"); + super("Golem Token", "3/3 colorless Golem artifact creature token with flying"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.GOLEM); diff --git a/Mage/src/main/java/mage/game/permanent/token/GolemToken.java b/Mage/src/main/java/mage/game/permanent/token/GolemToken.java index 4463f181005..c34d881b31c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GolemToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GolemToken.java @@ -12,14 +12,14 @@ import java.util.Arrays; public final class GolemToken extends TokenImpl { public GolemToken() { - super("Golem", "3/3 colorless Golem artifact creature token"); + super("Golem Token", "3/3 colorless Golem artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.GOLEM); power = new MageInt(3); toughness = new MageInt(3); - availableImageSetCodes = Arrays.asList("MM2", "NPH", "SOM", "MH1", "M20", "CMR"); + availableImageSetCodes = Arrays.asList("MM2", "NPH", "SOM", "MH1", "M20", "CMR", "2XM"); } public GolemToken(final GolemToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/GolemTrampleToken.java b/Mage/src/main/java/mage/game/permanent/token/GolemTrampleToken.java index 05cd763cb7e..949e3136cd6 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GolemTrampleToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GolemTrampleToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class GolemTrampleToken extends TokenImpl { public GolemTrampleToken() { - super("Golem", "3/3 colorless Golem artifact creature token with trample"); + super("Golem Token", "3/3 colorless Golem artifact creature token with trample"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.GOLEM); diff --git a/Mage/src/main/java/mage/game/permanent/token/GolemVigilanceToken.java b/Mage/src/main/java/mage/game/permanent/token/GolemVigilanceToken.java index 17e9ce7749f..15847391c96 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GolemVigilanceToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GolemVigilanceToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class GolemVigilanceToken extends TokenImpl { public GolemVigilanceToken() { - super("Golem", "3/3 colorless Golem artifact creature token with vigilance"); + super("Golem Token", "3/3 colorless Golem artifact creature token with vigilance"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.GOLEM); diff --git a/Mage/src/main/java/mage/game/permanent/token/GrakmawSkyclaveRavagerHydraToken.java b/Mage/src/main/java/mage/game/permanent/token/GrakmawSkyclaveRavagerHydraToken.java index e7b90016008..a34b2d01832 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GrakmawSkyclaveRavagerHydraToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GrakmawSkyclaveRavagerHydraToken.java @@ -16,7 +16,7 @@ public final class GrakmawSkyclaveRavagerHydraToken extends TokenImpl { } public GrakmawSkyclaveRavagerHydraToken(int xValue) { - super("Hydra", "X/X black and green Hydra creature token"); + super("Hydra Token", "X/X black and green Hydra creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/GreenAndWhiteElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/GreenAndWhiteElementalToken.java index 25d37498d9e..1c475f092de 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GreenAndWhiteElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GreenAndWhiteElementalToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class GreenAndWhiteElementalToken extends TokenImpl { public GreenAndWhiteElementalToken() { - super("Elemental", "8/8 green and white Elemental creature token with vigilance"); + super("Elemental Token", "8/8 green and white Elemental creature token with vigilance"); cardType.add(CardType.CREATURE); color.setGreen(true); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/GreenCat2Token.java b/Mage/src/main/java/mage/game/permanent/token/GreenCat2Token.java index 7db5cdccbfc..1b9feda07e3 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GreenCat2Token.java +++ b/Mage/src/main/java/mage/game/permanent/token/GreenCat2Token.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class GreenCat2Token extends TokenImpl { public GreenCat2Token() { - super("Cat", "2/2 green Cat creature token"); + super("Cat Token", "2/2 green Cat creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.CAT); diff --git a/Mage/src/main/java/mage/game/permanent/token/GreenCatToken.java b/Mage/src/main/java/mage/game/permanent/token/GreenCatToken.java index d90855b0e44..930dd620d84 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GreenCatToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GreenCatToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class GreenCatToken extends TokenImpl { public GreenCatToken() { - super("Cat", "1/1 green Cat creature token"); + super("Cat Token", "1/1 green Cat creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.CAT); diff --git a/Mage/src/main/java/mage/game/permanent/token/GreenDogToken.java b/Mage/src/main/java/mage/game/permanent/token/GreenDogToken.java index dddd7317332..956165d8dee 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GreenDogToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GreenDogToken.java @@ -10,7 +10,7 @@ import mage.constants.SubType; public final class GreenDogToken extends TokenImpl { public GreenDogToken() { - super("Dog", "1/1 green Dog creature token"); + super("Dog Token", "1/1 green Dog creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.DOG); diff --git a/Mage/src/main/java/mage/game/permanent/token/RhysTheRedeemedToken.java b/Mage/src/main/java/mage/game/permanent/token/GreenWhiteElfWarriorToken.java similarity index 63% rename from Mage/src/main/java/mage/game/permanent/token/RhysTheRedeemedToken.java rename to Mage/src/main/java/mage/game/permanent/token/GreenWhiteElfWarriorToken.java index 3874bea8718..28cd41d8921 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RhysTheRedeemedToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GreenWhiteElfWarriorToken.java @@ -9,10 +9,10 @@ import java.util.Arrays; /** * @author spjspj */ -public final class RhysTheRedeemedToken extends TokenImpl { +public final class GreenWhiteElfWarriorToken extends TokenImpl { - public RhysTheRedeemedToken() { - super("Elf Warrior", "1/1 green and white Elf Warrior creature token"); + public GreenWhiteElfWarriorToken() { + super("Elf Warrior Token", "1/1 green and white Elf Warrior creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); color.setWhite(true); @@ -21,15 +21,15 @@ public final class RhysTheRedeemedToken extends TokenImpl { power = new MageInt(1); toughness = new MageInt(1); - availableImageSetCodes = Arrays.asList("SHM"); + availableImageSetCodes = Arrays.asList("SHM", "2XM"); } - public RhysTheRedeemedToken(final RhysTheRedeemedToken token) { + public GreenWhiteElfWarriorToken(final GreenWhiteElfWarriorToken token) { super(token); } - public RhysTheRedeemedToken copy() { - return new RhysTheRedeemedToken(this); + public GreenWhiteElfWarriorToken copy() { + return new GreenWhiteElfWarriorToken(this); } @Override diff --git a/Mage/src/main/java/mage/game/permanent/token/GremlinToken.java b/Mage/src/main/java/mage/game/permanent/token/GremlinToken.java index 8b799a9034d..cf86dff6698 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GremlinToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GremlinToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class GremlinToken extends TokenImpl { public GremlinToken() { - super("Gremlin", "2/2 red Gremlin creature token"); + super("Gremlin Token", "2/2 red Gremlin creature token"); cardType.add(CardType.CREATURE); this.setOriginalExpansionSetCode("AER"); subtype.add(SubType.GREMLIN); diff --git a/Mage/src/main/java/mage/game/permanent/token/GriffinToken.java b/Mage/src/main/java/mage/game/permanent/token/GriffinToken.java index 0fae4a81022..6b2fe9c0c3a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GriffinToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GriffinToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class GriffinToken extends TokenImpl { public GriffinToken() { - super("Griffin", "2/2 white Griffin creature token with flying"); + super("Griffin Token", "2/2 white Griffin creature token with flying"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.GRIFFIN); diff --git a/Mage/src/main/java/mage/game/permanent/token/GrismoldPlantToken.java b/Mage/src/main/java/mage/game/permanent/token/GrismoldPlantToken.java index 51ffa57bbd9..56f1eb7629f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GrismoldPlantToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GrismoldPlantToken.java @@ -17,7 +17,7 @@ public final class GrismoldPlantToken extends TokenImpl { } public GrismoldPlantToken() { - super("Plant", "1/1 green Plant creature"); + super("Plant Token", "1/1 green Plant creature"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.PLANT); diff --git a/Mage/src/main/java/mage/game/permanent/token/GrovetenderDruidsPlantToken.java b/Mage/src/main/java/mage/game/permanent/token/GrovetenderDruidsPlantToken.java index 22094914661..6c11b69fe5b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GrovetenderDruidsPlantToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GrovetenderDruidsPlantToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class GrovetenderDruidsPlantToken extends TokenImpl { public GrovetenderDruidsPlantToken() { - super("Plant", "1/1 green Plant creature token"); + super("Plant Token", "1/1 green Plant creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.PLANT); diff --git a/Mage/src/main/java/mage/game/permanent/token/GuardianIdolGolemToken.java b/Mage/src/main/java/mage/game/permanent/token/GuardianIdolGolemToken.java index 626f4a26741..ee4e098b003 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GuardianIdolGolemToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GuardianIdolGolemToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class GuardianIdolGolemToken extends TokenImpl { public GuardianIdolGolemToken() { - super("Golem", "2/2 Golem artifact creature token"); + super("Golem Token", "2/2 Golem artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.GOLEM); diff --git a/Mage/src/main/java/mage/game/permanent/token/GutterGrimeToken.java b/Mage/src/main/java/mage/game/permanent/token/GutterGrimeToken.java index a6997c2f4b4..21e300c3169 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GutterGrimeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GutterGrimeToken.java @@ -29,7 +29,7 @@ public final class GutterGrimeToken extends TokenImpl { } public GutterGrimeToken(UUID sourceId) { - super("Ooze", "green Ooze creature token with \"This creature's power and toughness are each equal to the number of slime counters on Gutter Grime.\""); + super("Ooze Token", "green Ooze creature token with \"This creature's power and toughness are each equal to the number of slime counters on Gutter Grime.\""); cardType.add(CardType.CREATURE); subtype.add(SubType.OOZE); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/HammerOfPurphorosGolemToken.java b/Mage/src/main/java/mage/game/permanent/token/HammerOfPurphorosGolemToken.java index 3420af70a82..f910e371949 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HammerOfPurphorosGolemToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HammerOfPurphorosGolemToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class HammerOfPurphorosGolemToken extends TokenImpl { public HammerOfPurphorosGolemToken() { - super("Golem", "3/3 colorless Golem enchantment artifact creature token"); + super("Golem Token", "3/3 colorless Golem enchantment artifact creature token"); setOriginalExpansionSetCode("THS"); cardType.add(CardType.ENCHANTMENT); cardType.add(CardType.ARTIFACT); diff --git a/Mage/src/main/java/mage/game/permanent/token/AbhorrentOverlordHarpyToken.java b/Mage/src/main/java/mage/game/permanent/token/HarpyToken.java similarity index 56% rename from Mage/src/main/java/mage/game/permanent/token/AbhorrentOverlordHarpyToken.java rename to Mage/src/main/java/mage/game/permanent/token/HarpyToken.java index d8273083ec2..7d9c05fbb07 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AbhorrentOverlordHarpyToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HarpyToken.java @@ -1,5 +1,3 @@ - - package mage.game.permanent.token; import mage.constants.CardType; @@ -11,10 +9,10 @@ import mage.abilities.keyword.FlyingAbility; * * @author spjspj */ -public final class AbhorrentOverlordHarpyToken extends TokenImpl { +public final class HarpyToken extends TokenImpl { - public AbhorrentOverlordHarpyToken() { - super("Harpy", "1/1 black Harpy creature tokens with flying"); + public HarpyToken() { + super("Harpy Token", "1/1 black Harpy creature token with flying"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.HARPY); @@ -24,11 +22,11 @@ public final class AbhorrentOverlordHarpyToken extends TokenImpl { this.addAbility(FlyingAbility.getInstance()); } - public AbhorrentOverlordHarpyToken(final AbhorrentOverlordHarpyToken token) { + public HarpyToken(final HarpyToken token) { super(token); } - public AbhorrentOverlordHarpyToken copy() { - return new AbhorrentOverlordHarpyToken(this); + public HarpyToken copy() { + return new HarpyToken(this); } } diff --git a/Mage/src/main/java/mage/game/permanent/token/HauntedAngelToken.java b/Mage/src/main/java/mage/game/permanent/token/HauntedAngelToken.java index b03ced80b06..163ad68289e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HauntedAngelToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HauntedAngelToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class HauntedAngelToken extends TokenImpl { public HauntedAngelToken() { - super("Angel", "3/3 black Angel creature token with flying"); + super("Angel Token", "3/3 black Angel creature token with flying"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.ANGEL); diff --git a/Mage/src/main/java/mage/game/permanent/token/HazezonTamarSandWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/HazezonTamarSandWarriorToken.java index 0d0461951f9..e4beae8f30b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HazezonTamarSandWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HazezonTamarSandWarriorToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class HazezonTamarSandWarriorToken extends TokenImpl { public HazezonTamarSandWarriorToken() { - super("Sand Warrior", "1/1 Sand Warrior creature tokens that are red, green, and white"); + super("Sand Warrior Token", "1/1 Sand Warrior creature tokens that are red, green, and white"); cardType.add(CardType.CREATURE); color.setRed(true); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/HeliodGodOfTheSunToken.java b/Mage/src/main/java/mage/game/permanent/token/HeliodGodOfTheSunToken.java index f22622473f9..370cf461909 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HeliodGodOfTheSunToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HeliodGodOfTheSunToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class HeliodGodOfTheSunToken extends TokenImpl { public HeliodGodOfTheSunToken() { - super("Cleric", "2/1 white Cleric enchantment creature token"); + super("Cleric Token", "2/1 white Cleric enchantment creature token"); this.cardType.add(CardType.CREATURE); this.cardType.add(CardType.ENCHANTMENT); diff --git a/Mage/src/main/java/mage/game/permanent/token/HellionHasteToken.java b/Mage/src/main/java/mage/game/permanent/token/HellionHasteToken.java index eb8053c36fe..7bb525bb43c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HellionHasteToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HellionHasteToken.java @@ -13,7 +13,7 @@ import mage.constants.SubType; public final class HellionHasteToken extends TokenImpl { public HellionHasteToken() { - super("Hellion", "4/4 red Hellion creature token with haste"); + super("Hellion Token", "4/4 red Hellion creature token with haste"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.HELLION); diff --git a/Mage/src/main/java/mage/game/permanent/token/HellionToken.java b/Mage/src/main/java/mage/game/permanent/token/HellionToken.java index e1dce3e2a72..23e2a2c8142 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HellionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HellionToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class HellionToken extends TokenImpl { public HellionToken() { - super("Hellion", "4/4 red Hellion creature token"); + super("Hellion Token", "4/4 red Hellion creature token"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.HELLION); diff --git a/Mage/src/main/java/mage/game/permanent/token/HippoToken.java b/Mage/src/main/java/mage/game/permanent/token/HippoToken.java index e54c51257c3..ea472c4dad3 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HippoToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HippoToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class HippoToken extends TokenImpl { public HippoToken() { - super("Hippo", "1/1 green Hippo creature token"); + super("Hippo Token", "1/1 green Hippo creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/HippoToken2.java b/Mage/src/main/java/mage/game/permanent/token/HippoToken2.java index 68f7ba8801a..0947b817ee9 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HippoToken2.java +++ b/Mage/src/main/java/mage/game/permanent/token/HippoToken2.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class HippoToken2 extends TokenImpl { public HippoToken2() { - super("Hippo", "3/3 green Hippo creature token"); + super("Hippo Token", "3/3 green Hippo creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.HIPPO); diff --git a/Mage/src/main/java/mage/game/permanent/token/HomunculusToken.java b/Mage/src/main/java/mage/game/permanent/token/HomunculusToken.java index 83aff50e61d..00d921ea89a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HomunculusToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HomunculusToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class HomunculusToken extends TokenImpl { public HomunculusToken() { - super("Homunculus", "0/1 blue Homunculus artifact creature token"); + super("Homunculus Token", "0/1 blue Homunculus artifact creature token"); cardType.add(CardType.CREATURE); cardType.add(CardType.ARTIFACT); color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/HornetToken.java b/Mage/src/main/java/mage/game/permanent/token/HornetToken.java index 46d789cf83d..e25a0052726 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HornetToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HornetToken.java @@ -19,7 +19,7 @@ public final class HornetToken extends TokenImpl { } public HornetToken(String setCode) { - super("Hornet", "1/1 colorless Insect artifact creature token with flying and haste"); + super("Hornet Token", "1/1 colorless Insect artifact creature token with flying and haste"); this.setOriginalExpansionSetCode(setCode); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/HorrorToken.java b/Mage/src/main/java/mage/game/permanent/token/HorrorToken.java index 6de9685a13b..301bfa92ed9 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HorrorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HorrorToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class HorrorToken extends TokenImpl { public HorrorToken() { - super("Horror", "4/4 black Horror creature token"); + super("Horror Token", "4/4 black Horror creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.HORROR); diff --git a/Mage/src/main/java/mage/game/permanent/token/HourOfNeedSphinxToken.java b/Mage/src/main/java/mage/game/permanent/token/HourOfNeedSphinxToken.java index c4b68063859..69839e16969 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HourOfNeedSphinxToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HourOfNeedSphinxToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class HourOfNeedSphinxToken extends TokenImpl { public HourOfNeedSphinxToken() { - super("Sphinx", "4/4 blue Sphinx creature token with flying"); + super("Sphinx Token", "4/4 blue Sphinx creature token with flying"); this.setOriginalExpansionSetCode("JOU"); cardType.add(CardType.CREATURE); color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/HumanClericToken.java b/Mage/src/main/java/mage/game/permanent/token/HumanClericToken.java index e57bcd4fc1f..d8ba920dd99 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HumanClericToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HumanClericToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class HumanClericToken extends TokenImpl { public HumanClericToken() { - super("Human Cleric", "1/1 white and black Human Cleric creature token"); + super("Human Cleric Token", "1/1 white and black Human Cleric creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.HUMAN); subtype.add(SubType.CLERIC); diff --git a/Mage/src/main/java/mage/game/permanent/token/HumanMonkToken.java b/Mage/src/main/java/mage/game/permanent/token/HumanMonkToken.java index d01233da9f0..c8dc6597c58 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HumanMonkToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HumanMonkToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class HumanMonkToken extends TokenImpl { public HumanMonkToken() { - super("Human Monk token", "1/1 green Monk creature token with \"{T}: Add {G}.\""); + super("Human Monk Token", "1/1 green Human Monk creature token with \"{T}: Add {G}.\""); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.HUMAN); diff --git a/Mage/src/main/java/mage/game/permanent/token/HumanSoldierToken.java b/Mage/src/main/java/mage/game/permanent/token/HumanSoldierToken.java index 8d6dbe2daaa..6b9dbfe571f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HumanSoldierToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HumanSoldierToken.java @@ -10,7 +10,7 @@ import java.util.Arrays; public final class HumanSoldierToken extends TokenImpl { public HumanSoldierToken() { - super("Human Soldier", "1/1 white Human Soldier creature token"); + super("Human Soldier Token", "1/1 white Human Soldier creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.HUMAN); subtype.add(SubType.SOLDIER); @@ -18,7 +18,7 @@ public final class HumanSoldierToken extends TokenImpl { power = new MageInt(1); toughness = new MageInt(1); - availableImageSetCodes = Arrays.asList("SOI", "THB", "IKO", "MIC"); + availableImageSetCodes = Arrays.asList("SOI", "THB", "IKO", "MIC", "2XM"); } @Override diff --git a/Mage/src/main/java/mage/game/permanent/token/HumanSoldierTrainingToken.java b/Mage/src/main/java/mage/game/permanent/token/HumanSoldierTrainingToken.java index 6f87411e6d9..e1f345f844b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HumanSoldierTrainingToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HumanSoldierTrainingToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public class HumanSoldierTrainingToken extends TokenImpl { public HumanSoldierTrainingToken() { - super("Human Soldier", "1/1 green and white Human Soldier creature token with training"); + super("Human Soldier Token", "1/1 green and white Human Soldier creature token with training"); cardType.add(CardType.CREATURE); color.setGreen(true); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/HumanToken.java b/Mage/src/main/java/mage/game/permanent/token/HumanToken.java index 873aa867551..efc8ceba89d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HumanToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HumanToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class HumanToken extends TokenImpl { public HumanToken() { - super("Human", "1/1 white Human creature token"); + super("Human Token", "1/1 white Human creature token"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.HUMAN); diff --git a/Mage/src/main/java/mage/game/permanent/token/HumanWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/HumanWarriorToken.java index 6bd1cf9aaac..58b464fb87e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HumanWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HumanWarriorToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class HumanWarriorToken extends TokenImpl { public HumanWarriorToken() { - super("Human Warrior", "1/1 white Human Warrior creature token"); + super("Human Warrior Token", "1/1 white Human Warrior creature token"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.HUMAN); diff --git a/Mage/src/main/java/mage/game/permanent/token/HumanWizardToken.java b/Mage/src/main/java/mage/game/permanent/token/HumanWizardToken.java index 647cd1d0d1e..419666e1965 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HumanWizardToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HumanWizardToken.java @@ -7,7 +7,7 @@ import mage.constants.SubType; public final class HumanWizardToken extends TokenImpl { public HumanWizardToken() { - super("Human Wizard", "1/1 blue Human Wizard creature token"); + super("Human Wizard Token", "1/1 blue Human Wizard creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.HUMAN); subtype.add(SubType.WIZARD); diff --git a/Mage/src/main/java/mage/game/permanent/token/HungryForMoreVampireToken.java b/Mage/src/main/java/mage/game/permanent/token/HungryForMoreVampireToken.java index 30f7d80e98a..139f6c6a58e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HungryForMoreVampireToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HungryForMoreVampireToken.java @@ -15,7 +15,7 @@ import java.util.Arrays; public final class HungryForMoreVampireToken extends TokenImpl { public HungryForMoreVampireToken() { - super("Vampire", "3/1 black and red Vampire creature token with trample, lifelink, and haste"); + super("Vampire Token", "3/1 black and red Vampire creature token with trample, lifelink, and haste"); cardType.add(CardType.CREATURE); color.setRed(true); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/HuntedCentaurToken.java b/Mage/src/main/java/mage/game/permanent/token/HuntedCentaurToken.java index 63fbd6c7930..e82bd1819c7 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HuntedCentaurToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HuntedCentaurToken.java @@ -23,7 +23,7 @@ public final class HuntedCentaurToken extends TokenImpl { } public HuntedCentaurToken() { - super("Centaur", "3/3 green Centaur creature tokens with protection from black"); + super("Centaur Token", "3/3 green Centaur creature tokens with protection from black"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.CENTAUR); diff --git a/Mage/src/main/java/mage/game/permanent/token/HuntedDragonKnightToken.java b/Mage/src/main/java/mage/game/permanent/token/HuntedDragonKnightToken.java index 856a763e911..8f4e424fe28 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HuntedDragonKnightToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HuntedDragonKnightToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class HuntedDragonKnightToken extends TokenImpl { public HuntedDragonKnightToken() { - super("Knight", "2/2 white Knight creature tokens with first strike"); + super("Knight Token", "2/2 white Knight creature tokens with first strike"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.KNIGHT); diff --git a/Mage/src/main/java/mage/game/permanent/token/HunterToken.java b/Mage/src/main/java/mage/game/permanent/token/HunterToken.java index ee71154f722..ccdbaf1dc19 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HunterToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HunterToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class HunterToken extends TokenImpl { public HunterToken() { - super("Hunter", "4/4 red Hunter creature token", 4, 4); + super("Hunter Token", "4/4 red Hunter creature token", 4, 4); this.setOriginalExpansionSetCode("SWS"); cardType.add(CardType.CREATURE); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/HydraBroodmasterToken.java b/Mage/src/main/java/mage/game/permanent/token/HydraBroodmasterToken.java index c5528dd68b8..5604b846770 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HydraBroodmasterToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HydraBroodmasterToken.java @@ -16,7 +16,7 @@ public final class HydraBroodmasterToken extends TokenImpl { } public HydraBroodmasterToken(int power, int toughness) { - super("Hydra", "green Hydra creature token"); + super("Hydra Token", "green Hydra creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.HYDRA); diff --git a/Mage/src/main/java/mage/game/permanent/token/IllusionToken.java b/Mage/src/main/java/mage/game/permanent/token/IllusionToken.java index 0a1aa382d26..da30f56feb8 100644 --- a/Mage/src/main/java/mage/game/permanent/token/IllusionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/IllusionToken.java @@ -11,7 +11,7 @@ import mage.MageInt; public final class IllusionToken extends TokenImpl { public IllusionToken() { - super("Illusion", "2/2 blue Illusion creature token"); + super("Illusion Token", "2/2 blue Illusion creature token"); cardType.add(CardType.CREATURE); color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/InexorableBlobOozeToken.java b/Mage/src/main/java/mage/game/permanent/token/InexorableBlobOozeToken.java index e69fa6de419..be7d7463cc3 100644 --- a/Mage/src/main/java/mage/game/permanent/token/InexorableBlobOozeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/InexorableBlobOozeToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class InexorableBlobOozeToken extends TokenImpl { public InexorableBlobOozeToken() { - super("Ooze", "3/3 green Ooze creature token"); + super("Ooze Token", "3/3 green Ooze creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.OOZE); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/InklingToken.java b/Mage/src/main/java/mage/game/permanent/token/InklingToken.java index 9a86376eed7..f53e4662591 100644 --- a/Mage/src/main/java/mage/game/permanent/token/InklingToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/InklingToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class InklingToken extends TokenImpl { public InklingToken() { - super("Inkling", "2/1 white and black Inkling creature token with flying"); + super("Inkling Token", "2/1 white and black Inkling creature token with flying"); cardType.add(CardType.CREATURE); color.setWhite(true); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/InsectDeathToken.java b/Mage/src/main/java/mage/game/permanent/token/InsectDeathToken.java index 97e5e6c4725..884c0812925 100644 --- a/Mage/src/main/java/mage/game/permanent/token/InsectDeathToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/InsectDeathToken.java @@ -14,7 +14,7 @@ import java.util.Arrays; public final class InsectDeathToken extends TokenImpl { public InsectDeathToken() { - super("Insect", "1/1 green Insect creature token with flying and deathtouch"); + super("Insect Token", "1/1 green Insect creature token with flying and deathtouch"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.INSECT); diff --git a/Mage/src/main/java/mage/game/permanent/token/InsectInfectToken.java b/Mage/src/main/java/mage/game/permanent/token/InsectInfectToken.java index 36b6ad9263a..fda10067cf3 100644 --- a/Mage/src/main/java/mage/game/permanent/token/InsectInfectToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/InsectInfectToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class InsectInfectToken extends TokenImpl { public InsectInfectToken() { - super("Phyrexian Insect", "1/1 green Phyrexian Insect creature token with infect"); + super("Phyrexian Insect Token", "1/1 green Phyrexian Insect creature token with infect"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.PHYREXIAN); diff --git a/Mage/src/main/java/mage/game/permanent/token/InsectToken.java b/Mage/src/main/java/mage/game/permanent/token/InsectToken.java index 272c30fd96a..87fa2498fe3 100644 --- a/Mage/src/main/java/mage/game/permanent/token/InsectToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/InsectToken.java @@ -16,7 +16,7 @@ public final class InsectToken extends TokenImpl { } public InsectToken(String setCode) { - super("Insect", "1/1 green Insect creature token"); + super("Insect Token", "1/1 green Insect creature token"); setOriginalExpansionSetCode(setCode); cardType.add(CardType.CREATURE); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/IxalanVampireToken.java b/Mage/src/main/java/mage/game/permanent/token/IxalanVampireToken.java index 2395dc2ebc5..65a194af0a5 100644 --- a/Mage/src/main/java/mage/game/permanent/token/IxalanVampireToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/IxalanVampireToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.LifelinkAbility; public final class IxalanVampireToken extends TokenImpl { public IxalanVampireToken() { - super("Vampire", "1/1 white Vampire creature token with lifelink"); + super("Vampire Token", "1/1 white Vampire creature token with lifelink"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.VAMPIRE); diff --git a/Mage/src/main/java/mage/game/permanent/token/IzoniInsectToken.java b/Mage/src/main/java/mage/game/permanent/token/IzoniInsectToken.java index 86d4386c28b..e62b2f97416 100644 --- a/Mage/src/main/java/mage/game/permanent/token/IzoniInsectToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/IzoniInsectToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class IzoniInsectToken extends TokenImpl { public IzoniInsectToken() { - super("Insect", "1/1 black and green Insect creature token"); + super("Insect Token", "1/1 black and green Insect creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/JaceCunningCastawayIllusionToken.java b/Mage/src/main/java/mage/game/permanent/token/JaceCunningCastawayIllusionToken.java index e1b6839f289..e3b63c2f93c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/JaceCunningCastawayIllusionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/JaceCunningCastawayIllusionToken.java @@ -19,7 +19,7 @@ import mage.game.stack.Spell; public final class JaceCunningCastawayIllusionToken extends TokenImpl { public JaceCunningCastawayIllusionToken() { - super("Illusion", "2/2 blue Illusion creature token with \"When this creature becomes the target of a spell, sacrifice it.\""); + super("Illusion Token", "2/2 blue Illusion creature token with \"When this creature becomes the target of a spell, sacrifice it.\""); cardType.add(CardType.CREATURE); color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/JoinTheRanksSoldierToken.java b/Mage/src/main/java/mage/game/permanent/token/JoinTheRanksSoldierToken.java index 36321493efa..b7d6be41b55 100644 --- a/Mage/src/main/java/mage/game/permanent/token/JoinTheRanksSoldierToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/JoinTheRanksSoldierToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class JoinTheRanksSoldierToken extends TokenImpl { public JoinTheRanksSoldierToken() { - super("Soldier Ally", "1/1 white Soldier Ally creature token"); + super("Soldier Ally Token", "1/1 white Soldier Ally creature token"); this.setOriginalExpansionSetCode("WWK"); cardType.add(CardType.CREATURE); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/KalitasVampireToken.java b/Mage/src/main/java/mage/game/permanent/token/KalitasVampireToken.java index 1f7c8b98573..53975b09b93 100644 --- a/Mage/src/main/java/mage/game/permanent/token/KalitasVampireToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/KalitasVampireToken.java @@ -16,7 +16,7 @@ public final class KalitasVampireToken extends TokenImpl { } public KalitasVampireToken(int tokenPower, int tokenToughness) { - super("Vampire", new StringBuilder(tokenPower).append('/').append(tokenToughness).append(" black Vampire creature token").toString()); + super("Vampire Token", new StringBuilder(tokenPower).append('/').append(tokenToughness).append(" black Vampire creature token").toString()); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.VAMPIRE); diff --git a/Mage/src/main/java/mage/game/permanent/token/KalonianTwingroveTreefolkWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/KalonianTwingroveTreefolkWarriorToken.java index de4d9be1e25..eef22ad7f03 100644 --- a/Mage/src/main/java/mage/game/permanent/token/KalonianTwingroveTreefolkWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/KalonianTwingroveTreefolkWarriorToken.java @@ -24,7 +24,7 @@ public final class KalonianTwingroveTreefolkWarriorToken extends TokenImpl { } public KalonianTwingroveTreefolkWarriorToken() { - super("Treefolk Warrior", "green Treefolk Warrior creature token with \"This creature's power and toughness are each equal to the number of Forests you control.\""); + super("Treefolk Warrior Token", "green Treefolk Warrior creature token with \"This creature's power and toughness are each equal to the number of Forests you control.\""); this.setOriginalExpansionSetCode("M15"); cardType.add(CardType.CREATURE); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/KarnConstructToken.java b/Mage/src/main/java/mage/game/permanent/token/KarnConstructToken.java index ad692964513..e761180f28e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/KarnConstructToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/KarnConstructToken.java @@ -18,7 +18,7 @@ import java.util.Arrays; public final class KarnConstructToken extends TokenImpl { public KarnConstructToken() { - super("Construct", "0/0 colorless Construct artifact creature token with \"This creature gets +1/+1 for each artifact you control.\""); + super("Construct Token", "0/0 colorless Construct artifact creature token with \"This creature gets +1/+1 for each artifact you control.\""); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.CONSTRUCT); diff --git a/Mage/src/main/java/mage/game/permanent/token/KaroxBladewingDragonToken.java b/Mage/src/main/java/mage/game/permanent/token/KaroxBladewingDragonToken.java index cb6a9896847..6c25cc69a38 100644 --- a/Mage/src/main/java/mage/game/permanent/token/KaroxBladewingDragonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/KaroxBladewingDragonToken.java @@ -21,7 +21,7 @@ public final class KaroxBladewingDragonToken extends TokenImpl { } public KaroxBladewingDragonToken() { - super("Karox Bladewing", "legendary 4/4 red Dragon creature token with flying", 4, 4); + super("Karox Bladewing Token", "legendary 4/4 red Dragon creature token with flying", 4, 4); availableImageSetCodes = tokenImageSets; this.setOriginalExpansionSetCode("DOM"); diff --git a/Mage/src/main/java/mage/game/permanent/token/KeimiToken.java b/Mage/src/main/java/mage/game/permanent/token/KeimiToken.java new file mode 100644 index 00000000000..fb154e2d992 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/KeimiToken.java @@ -0,0 +1,47 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; + +import java.util.Arrays; + +/** + * @author TheElk801 + */ +public final class KeimiToken extends TokenImpl { + + public KeimiToken() { + super("Keimi", "Keimi, a legendary 3/3 black and green Frog creature token with \"Whenever you cast an enchantment spell, each opponent loses 1 life and you gain 1 life.\""); + supertype.add(SuperType.LEGENDARY); + cardType.add(CardType.CREATURE); + color.setBlack(true); + color.setGreen(true); + subtype.add(SubType.FROG); + power = new MageInt(3); + toughness = new MageInt(3); + + Ability ability = new SpellCastControllerTriggeredAbility( + new LoseLifeOpponentsEffect(1), + StaticFilters.FILTER_SPELL_AN_ENCHANTMENT, false + ); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + this.addAbility(ability); + + availableImageSetCodes = Arrays.asList("NEO"); + } + + private KeimiToken(final KeimiToken token) { + super(token); + } + + public KeimiToken copy() { + return new KeimiToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/KithkinSoldierToken.java b/Mage/src/main/java/mage/game/permanent/token/KithkinSoldierToken.java index 4c199dc9e66..7bb85e89ccc 100644 --- a/Mage/src/main/java/mage/game/permanent/token/KithkinSoldierToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/KithkinSoldierToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class KithkinSoldierToken extends TokenImpl { public KithkinSoldierToken() { - super("Kithkin Soldier", "1/1 white Kithkin Soldier creature token"); + super("Kithkin Soldier Token", "1/1 white Kithkin Soldier creature token"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.KITHKIN); diff --git a/Mage/src/main/java/mage/game/permanent/token/KnightAllyToken.java b/Mage/src/main/java/mage/game/permanent/token/KnightAllyToken.java index 70e6ae380fd..1a457412dca 100644 --- a/Mage/src/main/java/mage/game/permanent/token/KnightAllyToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/KnightAllyToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class KnightAllyToken extends TokenImpl { public KnightAllyToken() { - super("Knight Ally", "2/2 white Knight Ally creature token"); + super("Knight Ally Token", "2/2 white Knight Ally creature token"); this.setExpansionSetCodeForImage("BFZ"); cardType.add(CardType.CREATURE); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/KnightToken.java b/Mage/src/main/java/mage/game/permanent/token/KnightToken.java index 7c3adb84c41..195cbe133c7 100644 --- a/Mage/src/main/java/mage/game/permanent/token/KnightToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/KnightToken.java @@ -14,7 +14,7 @@ import java.util.Arrays; public final class KnightToken extends TokenImpl { public KnightToken() { - super("Knight", "2/2 white Knight creature token with vigilance"); + super("Knight Token", "2/2 white Knight creature token with vigilance"); cardType.add(CardType.CREATURE); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/KorAllyToken.java b/Mage/src/main/java/mage/game/permanent/token/KorAllyToken.java index 7118fbc8d88..6875b531639 100644 --- a/Mage/src/main/java/mage/game/permanent/token/KorAllyToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/KorAllyToken.java @@ -9,7 +9,7 @@ import java.util.Arrays; public final class KorAllyToken extends TokenImpl { public KorAllyToken() { - super("Kor Ally", "1/1 white Kor Ally creature token"); + super("Kor Ally Token", "1/1 white Kor Ally creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.KOR); subtype.add(SubType.ALLY); diff --git a/Mage/src/main/java/mage/game/permanent/token/KorSoldierToken.java b/Mage/src/main/java/mage/game/permanent/token/KorSoldierToken.java index b3378c99495..82a5a31c281 100644 --- a/Mage/src/main/java/mage/game/permanent/token/KorSoldierToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/KorSoldierToken.java @@ -14,7 +14,7 @@ import mage.MageInt; public final class KorSoldierToken extends TokenImpl { public KorSoldierToken() { - super("Kor Soldier", "1/1 white Kor Soldier creature token"); + super("Kor Soldier Token", "1/1 white Kor Soldier creature token"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.KOR); diff --git a/Mage/src/main/java/mage/game/permanent/token/KorWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/KorWarriorToken.java index 9f75f1e1108..4e75f1cef67 100644 --- a/Mage/src/main/java/mage/game/permanent/token/KorWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/KorWarriorToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class KorWarriorToken extends TokenImpl { public KorWarriorToken() { - super("Kor Warrior", "1/1 white Kor Warrior creature token"); + super("Kor Warrior Token", "1/1 white Kor Warrior creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.KOR); subtype.add(SubType.WARRIOR); diff --git a/Mage/src/main/java/mage/game/permanent/token/Kraken99Token.java b/Mage/src/main/java/mage/game/permanent/token/Kraken99Token.java index 3a47a233434..5a1feb18078 100644 --- a/Mage/src/main/java/mage/game/permanent/token/Kraken99Token.java +++ b/Mage/src/main/java/mage/game/permanent/token/Kraken99Token.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class Kraken99Token extends TokenImpl { public Kraken99Token() { - super("Kraken", "9/9 blue Kraken creature token"); + super("Kraken Token", "9/9 blue Kraken creature token"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.KRAKEN); diff --git a/Mage/src/main/java/mage/game/permanent/token/KrakenHexproofToken.java b/Mage/src/main/java/mage/game/permanent/token/KrakenHexproofToken.java index 64c9b08ed2b..5a49756a87d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/KrakenHexproofToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/KrakenHexproofToken.java @@ -13,7 +13,7 @@ import mage.constants.SubType; public final class KrakenHexproofToken extends TokenImpl { public KrakenHexproofToken() { - super("Kraken", "8/8 blue Kraken creature token with hexproof"); + super("Kraken Token", "8/8 blue Kraken creature token with hexproof"); this.cardType.add(CardType.CREATURE); this.subtype.add(SubType.KRAKEN); this.color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/KrakenToken.java b/Mage/src/main/java/mage/game/permanent/token/KrakenToken.java index 7a28867ffbb..886fc92ee61 100644 --- a/Mage/src/main/java/mage/game/permanent/token/KrakenToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/KrakenToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class KrakenToken extends TokenImpl { public KrakenToken() { - super("Kraken", "8/8 blue Kraken creature token"); + super("Kraken Token", "8/8 blue Kraken creature token"); this.cardType.add(CardType.CREATURE); this.subtype.add(SubType.KRAKEN); this.color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/LeafdrakeRoostDrakeToken.java b/Mage/src/main/java/mage/game/permanent/token/LeafdrakeRoostDrakeToken.java index 69cc8040abc..6d6b5efd776 100644 --- a/Mage/src/main/java/mage/game/permanent/token/LeafdrakeRoostDrakeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/LeafdrakeRoostDrakeToken.java @@ -30,7 +30,7 @@ public final class LeafdrakeRoostDrakeToken extends TokenImpl { } public LeafdrakeRoostDrakeToken(String setCode, int tokenType) { - super("Drake", "2/2 green and blue Drake creature token with flying"); + super("Drake Token", "2/2 green and blue Drake creature token with flying"); availableImageSetCodes = tokenImageSets; setOriginalExpansionSetCode(setCode); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/LinvalaAngelToken.java b/Mage/src/main/java/mage/game/permanent/token/LinvalaAngelToken.java index d9397da5981..f3f96cfa774 100644 --- a/Mage/src/main/java/mage/game/permanent/token/LinvalaAngelToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/LinvalaAngelToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class LinvalaAngelToken extends TokenImpl { public LinvalaAngelToken() { - super("Angel", "3/3 white Angel creature token with flying"); + super("Angel Token", "3/3 white Angel creature token with flying"); setOriginalExpansionSetCode("OGW"); cardType.add(CardType.CREATURE); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/LizardToken.java b/Mage/src/main/java/mage/game/permanent/token/LizardToken.java index 47773e5e40b..16a21f73bf0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/LizardToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/LizardToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class LizardToken extends TokenImpl { public LizardToken() { - super("Lizard", "2/2 green Lizard creature token"); + super("Lizard Token", "2/2 green Lizard creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.LIZARD); diff --git a/Mage/src/main/java/mage/game/permanent/token/LolthSpiderToken.java b/Mage/src/main/java/mage/game/permanent/token/LolthSpiderToken.java index 039cda1c577..3a7819a67cc 100644 --- a/Mage/src/main/java/mage/game/permanent/token/LolthSpiderToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/LolthSpiderToken.java @@ -14,7 +14,7 @@ import java.util.Arrays; public final class LolthSpiderToken extends TokenImpl { public LolthSpiderToken() { - super("Spider", "2/1 black Spider creature token with menace and reach"); + super("Spider Token", "2/1 black Spider creature token with menace and reach"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.SPIDER); diff --git a/Mage/src/main/java/mage/game/permanent/token/MagesAttendantToken.java b/Mage/src/main/java/mage/game/permanent/token/MagesAttendantToken.java new file mode 100644 index 00000000000..1e1640a8751 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/MagesAttendantToken.java @@ -0,0 +1,42 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CounterUnlessPaysEffect; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.TargetSpell; + +/** + * @author TheElk801 + */ +public final class MagesAttendantToken extends TokenImpl { + + public MagesAttendantToken() { + super("Wizard Token", "1/1 blue Wizard creature token with \"{1}, Sacrifice this creature: Counter target noncreature spell unless its controller pays {1}.\""); + cardType.add(CardType.CREATURE); + subtype.add(SubType.WIZARD); + color.setBlue(true); + power = new MageInt(1); + toughness = new MageInt(1); + + Ability ability = new SimpleActivatedAbility( + new CounterUnlessPaysEffect(new GenericManaCost(1)), new GenericManaCost(1) + ); + ability.addCost(new SacrificeSourceCost().setText("sacrifice this creature")); + ability.addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_NON_CREATURE)); + this.addAbility(ability); + } + + private MagesAttendantToken(final MagesAttendantToken token) { + super(token); + } + + public MagesAttendantToken copy() { + return new MagesAttendantToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/MarathWillOfTheWildElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/MarathWillOfTheWildElementalToken.java index 200f68b756b..6fec479ea44 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MarathWillOfTheWildElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MarathWillOfTheWildElementalToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class MarathWillOfTheWildElementalToken extends TokenImpl { public MarathWillOfTheWildElementalToken() { - super("Elemental", "X/X green Elemental creature token"); + super("Elemental Token", "X/X green Elemental creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.ELEMENTAL); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/MarduStrikeLeaderWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/MarduStrikeLeaderWarriorToken.java index 7a4dc7adaff..925b80f1e6c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MarduStrikeLeaderWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MarduStrikeLeaderWarriorToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class MarduStrikeLeaderWarriorToken extends TokenImpl { public MarduStrikeLeaderWarriorToken() { - super("Warrior", "2/1 black Warrior creature token"); + super("Warrior Token", "2/1 black Warrior creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.WARRIOR); diff --git a/Mage/src/main/java/mage/game/permanent/token/MaritLageToken.java b/Mage/src/main/java/mage/game/permanent/token/MaritLageToken.java index 67cbafef84f..7dee1085f8e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MaritLageToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MaritLageToken.java @@ -27,7 +27,7 @@ public final class MaritLageToken extends TokenImpl { this.addAbility(FlyingAbility.getInstance()); this.addAbility(IndestructibleAbility.getInstance()); - availableImageSetCodes.addAll(Arrays.asList("CSP", "MH1")); + availableImageSetCodes.addAll(Arrays.asList("CSP", "MH1", "UMA", "2XM")); } public MaritLageToken(final MaritLageToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/MasterOfWavesElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/MasterOfWavesElementalToken.java index 533b8000568..7a05eb10de8 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MasterOfWavesElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MasterOfWavesElementalToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class MasterOfWavesElementalToken extends TokenImpl { public MasterOfWavesElementalToken() { - super("Elemental", "1/0 blue Elemental creature"); + super("Elemental Token", "1/0 blue Elemental creature"); this.cardType.add(CardType.CREATURE); this.subtype.add(SubType.ELEMENTAL); diff --git a/Mage/src/main/java/mage/game/permanent/token/MechtitanToken.java b/Mage/src/main/java/mage/game/permanent/token/MechtitanToken.java new file mode 100644 index 00000000000..7d9851edcb7 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/MechtitanToken.java @@ -0,0 +1,41 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; + +/** + * @author TheElk801 + */ +public final class MechtitanToken extends TokenImpl { + + public MechtitanToken() { + super("Mechtitan", "Mechtitan, a legendary 10/10 Construct artifact creature token with flying, vigilance, trample, lifelink, and haste that's all colors"); + addSuperType(SuperType.LEGENDARY); + cardType.add(CardType.ARTIFACT); + cardType.add(CardType.CREATURE); + subtype.add(SubType.CONSTRUCT); + color.setWhite(true); + color.setBlue(true); + color.setBlack(true); + color.setRed(true); + color.setGreen(true); + power = new MageInt(10); + toughness = new MageInt(10); + addAbility(FlyingAbility.getInstance()); + addAbility(VigilanceAbility.getInstance()); + addAbility(TrampleAbility.getInstance()); + addAbility(LifelinkAbility.getInstance()); + addAbility(HasteAbility.getInstance()); + } + + public MechtitanToken(final MechtitanToken token) { + super(token); + } + + public MechtitanToken copy() { + return new MechtitanToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/MelokuTheCloudedMirrorToken.java b/Mage/src/main/java/mage/game/permanent/token/MelokuTheCloudedMirrorToken.java index e30640b377d..fa7d177ede9 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MelokuTheCloudedMirrorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MelokuTheCloudedMirrorToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class MelokuTheCloudedMirrorToken extends TokenImpl { public MelokuTheCloudedMirrorToken() { - super("Illusion", "1/1 blue Illusion creature token with flying"); + super("Illusion Token", "1/1 blue Illusion creature token with flying"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.ILLUSION); diff --git a/Mage/src/main/java/mage/game/permanent/token/MercyKillingToken.java b/Mage/src/main/java/mage/game/permanent/token/MercyKillingToken.java deleted file mode 100644 index f066130b9be..00000000000 --- a/Mage/src/main/java/mage/game/permanent/token/MercyKillingToken.java +++ /dev/null @@ -1,32 +0,0 @@ - - -package mage.game.permanent.token; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.MageInt; - -/** - * - * @author spjspj - */ -public final class MercyKillingToken extends TokenImpl { - - public MercyKillingToken() { - super("Elf Warrior", "1/1 green and white Elf Warrior creature token"); - cardType.add(CardType.CREATURE); - color.setGreen(true); - color.setWhite(true); - subtype.add(SubType.ELF); - subtype.add(SubType.WARRIOR); - power = new MageInt(1); - toughness = new MageInt(1); - } - - public MercyKillingToken(final MercyKillingToken token) { - super(token); - } - - public MercyKillingToken copy() { - return new MercyKillingToken(this); - } -} diff --git a/Mage/src/main/java/mage/game/permanent/token/MerfolkHexproofToken.java b/Mage/src/main/java/mage/game/permanent/token/MerfolkHexproofToken.java index 500cfc2345b..687e3136703 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MerfolkHexproofToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MerfolkHexproofToken.java @@ -14,7 +14,7 @@ import mage.constants.SubType; public final class MerfolkHexproofToken extends TokenImpl { public MerfolkHexproofToken() { - super("Merfolk", "1/1 blue Merfolk creature token with hexproof"); + super("Merfolk Token", "1/1 blue Merfolk creature token with hexproof"); this.cardType.add(CardType.CREATURE); this.subtype.add(SubType.MERFOLK); this.color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/MerfolkToken.java b/Mage/src/main/java/mage/game/permanent/token/MerfolkToken.java index 37a366a5e70..18f0acb9e76 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MerfolkToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MerfolkToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class MerfolkToken extends TokenImpl { public MerfolkToken() { - super("Merfolk", "1/1 blue Merfolk creature token"); + super("Merfolk Token", "1/1 blue Merfolk creature token"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.MERFOLK); diff --git a/Mage/src/main/java/mage/game/permanent/token/MerfolkWizardToken.java b/Mage/src/main/java/mage/game/permanent/token/MerfolkWizardToken.java index bfc9eeeaee4..63682a51210 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MerfolkWizardToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MerfolkWizardToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class MerfolkWizardToken extends TokenImpl { public MerfolkWizardToken() { - super("Merfolk Wizard", "1/1 blue Merfolk Wizard creature token"); + super("Merfolk Wizard Token", "1/1 blue Merfolk Wizard creature token"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.MERFOLK); diff --git a/Mage/src/main/java/mage/game/permanent/token/MesmerizingBenthidToken.java b/Mage/src/main/java/mage/game/permanent/token/MesmerizingBenthidToken.java index 2e52c6e8cb2..685f5dc84d5 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MesmerizingBenthidToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MesmerizingBenthidToken.java @@ -1,7 +1,7 @@ package mage.game.permanent.token; import mage.MageInt; -import mage.abilities.common.BlocksSourceTriggeredAbility; +import mage.abilities.common.BlocksCreatureTriggeredAbility; import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; import mage.constants.CardType; import mage.constants.SubType; @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class MesmerizingBenthidToken extends TokenImpl { public MesmerizingBenthidToken() { - super("Illusion", "0/2 blue Illusion creature token with \"Whenever this creature blocks a creature, that creature doesn't untap during its controller's next untap step.\""); + super("Illusion Token", "0/2 blue Illusion creature token with \"Whenever this creature blocks a creature, that creature doesn't untap during its controller's next untap step.\""); cardType.add(CardType.CREATURE); color.setBlue(true); setOriginalExpansionSetCode("RNA"); @@ -20,9 +20,8 @@ public final class MesmerizingBenthidToken extends TokenImpl { subtype.add(SubType.ILLUSION); power = new MageInt(0); toughness = new MageInt(2); - this.addAbility(new BlocksSourceTriggeredAbility( - new DontUntapInControllersNextUntapStepTargetEffect("that creature"), - false, true + this.addAbility(new BlocksCreatureTriggeredAbility( + new DontUntapInControllersNextUntapStepTargetEffect("that creature") )); } diff --git a/Mage/src/main/java/mage/game/permanent/token/MetallurgicSummoningsConstructToken.java b/Mage/src/main/java/mage/game/permanent/token/MetallurgicSummoningsConstructToken.java index 427f98c3766..54d0ca4f68e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MetallurgicSummoningsConstructToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MetallurgicSummoningsConstructToken.java @@ -17,7 +17,7 @@ public final class MetallurgicSummoningsConstructToken extends TokenImpl { } public MetallurgicSummoningsConstructToken(int xValue) { - super("Construct", "X/X colorless Construct artifact creature token"); + super("Construct Token", "X/X colorless Construct artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.CONSTRUCT); diff --git a/Mage/src/main/java/mage/game/permanent/token/MinionToken.java b/Mage/src/main/java/mage/game/permanent/token/MinionToken.java index 4a532e2cfa1..da91cbc7fd0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MinionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MinionToken.java @@ -17,7 +17,7 @@ public final class MinionToken extends TokenImpl { } public MinionToken(String setCode) { - super("Phyrexian Minion", "X/X black Phyrexian Minion creature token"); + super("Phyrexian Minion Token", "X/X black Phyrexian Minion creature token"); this.setOriginalExpansionSetCode(setCode); cardType.add(CardType.CREATURE); subtype.add(SubType.PHYREXIAN); diff --git a/Mage/src/main/java/mage/game/permanent/token/MinionToken2.java b/Mage/src/main/java/mage/game/permanent/token/MinionToken2.java index d5d750deb0f..91ec948d84f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MinionToken2.java +++ b/Mage/src/main/java/mage/game/permanent/token/MinionToken2.java @@ -17,7 +17,7 @@ public final class MinionToken2 extends TokenImpl { } public MinionToken2(String setCode) { - super("Minion", "1/1 black Minion creature token"); + super("Minion Token", "1/1 black Minion creature token"); this.setOriginalExpansionSetCode(setCode); cardType.add(CardType.CREATURE); subtype.add(SubType.MINION); diff --git a/Mage/src/main/java/mage/game/permanent/token/MinnWilyIllusionistToken.java b/Mage/src/main/java/mage/game/permanent/token/MinnWilyIllusionistToken.java index 26bf97900fd..26af3f0fecf 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MinnWilyIllusionistToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MinnWilyIllusionistToken.java @@ -29,7 +29,7 @@ public final class MinnWilyIllusionistToken extends TokenImpl { private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); public MinnWilyIllusionistToken() { - super("Illusion", "1/1 blue Illusion creature token with \"This creature gets +1/+0 for each other Illusion you control.\""); + super("Illusion Token", "1/1 blue Illusion creature token with \"This creature gets +1/+0 for each other Illusion you control.\""); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.ILLUSION); diff --git a/Mage/src/main/java/mage/game/permanent/token/MinotaurToken.java b/Mage/src/main/java/mage/game/permanent/token/MinotaurToken.java index 2e9d4e7d905..698338e175e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MinotaurToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MinotaurToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class MinotaurToken extends TokenImpl { public MinotaurToken() { - super("Minotaur", "2/3 red Minotaur creature token"); + super("Minotaur Token", "2/3 red Minotaur creature token"); cardType.add(CardType.CREATURE); color.setColor(ObjectColor.RED); subtype.add(SubType.MINOTAUR); diff --git a/Mage/src/main/java/mage/game/permanent/token/MonasteryMentorToken.java b/Mage/src/main/java/mage/game/permanent/token/MonasteryMentorToken.java index 9a35537d5e5..b1e1a2e6c19 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MonasteryMentorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MonasteryMentorToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.ProwessAbility; public final class MonasteryMentorToken extends TokenImpl { public MonasteryMentorToken() { - super("Monk", "1/1 white Monk creature token with prowess"); + super("Monk Token", "1/1 white Monk creature token with prowess"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.MONK); diff --git a/Mage/src/main/java/mage/game/permanent/token/MouseToken.java b/Mage/src/main/java/mage/game/permanent/token/MouseToken.java index 5f7428f9b94..3e06b4aa402 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MouseToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MouseToken.java @@ -10,7 +10,7 @@ import mage.constants.SubType; public final class MouseToken extends TokenImpl { public MouseToken() { - super("Mouse", "1/1 white Mouse creature token"); + super("Mouse Token", "1/1 white Mouse creature token"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.MOUSE); diff --git a/Mage/src/main/java/mage/game/permanent/token/MuYanlingSkyDancerToken.java b/Mage/src/main/java/mage/game/permanent/token/MuYanlingSkyDancerToken.java index 13e4b367b4b..d8ab0a21f14 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MuYanlingSkyDancerToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MuYanlingSkyDancerToken.java @@ -8,7 +8,7 @@ import mage.constants.SubType; public final class MuYanlingSkyDancerToken extends TokenImpl { public MuYanlingSkyDancerToken() { - super("Elemental Bird", "4/4 blue Elemental Bird creature token with flying"); + super("Elemental Bird Token", "4/4 blue Elemental Bird creature token with flying"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.ELEMENTAL); diff --git a/Mage/src/main/java/mage/game/permanent/token/MyrToken.java b/Mage/src/main/java/mage/game/permanent/token/MyrToken.java index 1ba863df311..212b6937aa4 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MyrToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MyrToken.java @@ -9,14 +9,14 @@ import java.util.Arrays; public final class MyrToken extends TokenImpl { public MyrToken() { - super("Myr", "1/1 colorless Myr artifact creature token"); + super("Myr Token", "1/1 colorless Myr artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.MYR); power = new MageInt(1); toughness = new MageInt(1); - availableImageSetCodes = Arrays.asList("C13", "C14", "DST", "MBS", "MM2", "MRD", "NPH", "SOM", "MH1", "C21"); + availableImageSetCodes = Arrays.asList("C13", "C14", "DST", "MBS", "MM2", "MRD", "NPH", "SOM", "MH1", "C21", "NEC", "2XM"); } public MyrToken(final MyrToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/MysticGenesisOozeToken.java b/Mage/src/main/java/mage/game/permanent/token/MysticGenesisOozeToken.java index 20523f5204b..254083d33f0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MysticGenesisOozeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MysticGenesisOozeToken.java @@ -15,7 +15,7 @@ public final class MysticGenesisOozeToken extends TokenImpl { this(0); } public MysticGenesisOozeToken(int xValue) { - super("Ooze", "X/X green Ooze creature token"); + super("Ooze Token", "X/X green Ooze creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.OOZE); diff --git a/Mage/src/main/java/mage/game/permanent/token/NestOfScarabsBlackInsectToken.java b/Mage/src/main/java/mage/game/permanent/token/NestOfScarabsBlackInsectToken.java index 02c764c2eda..9233f73fb39 100644 --- a/Mage/src/main/java/mage/game/permanent/token/NestOfScarabsBlackInsectToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/NestOfScarabsBlackInsectToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class NestOfScarabsBlackInsectToken extends TokenImpl { public NestOfScarabsBlackInsectToken() { - super("Insect", "1/1 black Insect creature token"); + super("Insect Token", "1/1 black Insect creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.INSECT); diff --git a/Mage/src/main/java/mage/game/permanent/token/NighteyesTheDesecratorToken.java b/Mage/src/main/java/mage/game/permanent/token/NighteyesTheDesecratorToken.java index 800fc02f5d5..3490ecd0f00 100644 --- a/Mage/src/main/java/mage/game/permanent/token/NighteyesTheDesecratorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/NighteyesTheDesecratorToken.java @@ -20,7 +20,7 @@ import mage.target.common.TargetCardInGraveyard; public final class NighteyesTheDesecratorToken extends TokenImpl { public NighteyesTheDesecratorToken() { - super("Nighteyes the Desecrator", ""); + super("Nighteyes the Desecrator Token", ""); addSuperType(SuperType.LEGENDARY); cardType.add(CardType.CREATURE); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/NightwingHorrorToken.java b/Mage/src/main/java/mage/game/permanent/token/NightwingHorrorToken.java index bd0082403b9..01096f3fb8a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/NightwingHorrorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/NightwingHorrorToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class NightwingHorrorToken extends TokenImpl { public NightwingHorrorToken() { - super("Horror", "1/1 blue and black Horror creature token with flying"); + super("Horror Token", "1/1 blue and black Horror creature token with flying"); cardType.add(CardType.CREATURE); this.color.setBlue(true); this.color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/OctopusToken.java b/Mage/src/main/java/mage/game/permanent/token/OctopusToken.java index 0b7ea29d4e7..16f3bfeaae5 100644 --- a/Mage/src/main/java/mage/game/permanent/token/OctopusToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/OctopusToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class OctopusToken extends TokenImpl { public OctopusToken() { - super("Octopus", "8/8 blue Octopus creature token"); + super("Octopus Token", "8/8 blue Octopus creature token"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.OCTOPUS); diff --git a/Mage/src/main/java/mage/game/permanent/token/OgreToken.java b/Mage/src/main/java/mage/game/permanent/token/OgreToken.java index 87767529a59..79045d07ba1 100644 --- a/Mage/src/main/java/mage/game/permanent/token/OgreToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/OgreToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class OgreToken extends TokenImpl { public OgreToken() { - super("Ogre", "3/3 red Ogre creature"); + super("Ogre Token", "3/3 red Ogre creature"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.OGRE); diff --git a/Mage/src/main/java/mage/game/permanent/token/OgreWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/OgreWarriorToken.java new file mode 100644 index 00000000000..b8f45c9c7ba --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/OgreWarriorToken.java @@ -0,0 +1,29 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class OgreWarriorToken extends TokenImpl { + + public OgreWarriorToken() { + super("Ogre Warrior Token", "4/3 black Ogre Warrior creature token"); + color.setBlack(true); + cardType.add(CardType.CREATURE); + subtype.add(SubType.OGRE); + subtype.add(SubType.WARRIOR); + power = new MageInt(4); + toughness = new MageInt(3); + } + + public OgreWarriorToken(final OgreWarriorToken token) { + super(token); + } + + public OgreWarriorToken copy() { + return new OgreWarriorToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/OminousRoostBirdToken.java b/Mage/src/main/java/mage/game/permanent/token/OminousRoostBirdToken.java index 9a4579b7caa..23b169db6c7 100644 --- a/Mage/src/main/java/mage/game/permanent/token/OminousRoostBirdToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/OminousRoostBirdToken.java @@ -11,7 +11,7 @@ import java.util.Arrays; public class OminousRoostBirdToken extends TokenImpl { public OminousRoostBirdToken() { - super("Bird", "1/1 blue Bird creature token with flying and \"This creature can block only creatures with flying\""); + super("Bird Token", "1/1 blue Bird creature token with flying and \"This creature can block only creatures with flying\""); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.BIRD); diff --git a/Mage/src/main/java/mage/game/permanent/token/OmnathElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/OmnathElementalToken.java index b0183904b78..16e03105858 100644 --- a/Mage/src/main/java/mage/game/permanent/token/OmnathElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/OmnathElementalToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class OmnathElementalToken extends TokenImpl { public OmnathElementalToken() { - super("Elemental", "5/5 red and green Elemental creature token"); + super("Elemental Token", "5/5 red and green Elemental creature token"); setTokenType(1); setOriginalExpansionSetCode("BFZ"); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/OneDozenEyesBeastToken.java b/Mage/src/main/java/mage/game/permanent/token/OneDozenEyesBeastToken.java index e19b0e192c5..8effbf8882c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/OneDozenEyesBeastToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/OneDozenEyesBeastToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class OneDozenEyesBeastToken extends TokenImpl { public OneDozenEyesBeastToken() { - super("Beast", "5/5 green Beast creature token"); + super("Beast Token", "5/5 green Beast creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.BEAST); diff --git a/Mage/src/main/java/mage/game/permanent/token/OonaQueenFaerieRogueToken.java b/Mage/src/main/java/mage/game/permanent/token/OonaQueenFaerieRogueToken.java index db71895af10..48a2eef4acd 100644 --- a/Mage/src/main/java/mage/game/permanent/token/OonaQueenFaerieRogueToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/OonaQueenFaerieRogueToken.java @@ -6,6 +6,8 @@ import mage.constants.SubType; import mage.MageInt; import mage.abilities.keyword.FlyingAbility; +import java.util.Arrays; + /** * * @author spjspj @@ -13,7 +15,7 @@ import mage.abilities.keyword.FlyingAbility; public final class OonaQueenFaerieRogueToken extends TokenImpl { public OonaQueenFaerieRogueToken() { - super("Faerie Rogue", "1/1 blue and black Faerie Rogue creature token with flying"); + super("Faerie Rogue Token", "1/1 blue and black Faerie Rogue creature token with flying"); cardType.add(CardType.CREATURE); color.setBlue(true); color.setBlack(true); @@ -22,6 +24,8 @@ public final class OonaQueenFaerieRogueToken extends TokenImpl { power = new MageInt(1); toughness = new MageInt(1); this.addAbility(FlyingAbility.getInstance()); + + availableImageSetCodes = Arrays.asList("MMA", "SHM"); } public OonaQueenFaerieRogueToken(final OonaQueenFaerieRogueToken token) { super(token); diff --git a/Mage/src/main/java/mage/game/permanent/token/Ooze2Token.java b/Mage/src/main/java/mage/game/permanent/token/Ooze2Token.java index 513573d97fb..a7a04ac0640 100644 --- a/Mage/src/main/java/mage/game/permanent/token/Ooze2Token.java +++ b/Mage/src/main/java/mage/game/permanent/token/Ooze2Token.java @@ -14,7 +14,7 @@ import mage.abilities.effects.common.CreateTokenEffect; public final class Ooze2Token extends TokenImpl { public Ooze2Token() { - super("Ooze", "2/2 green Ooze creature tokens with \"When this creature is put into a graveyard, create two 1/1 green Ooze creature tokens.\""); + super("Ooze Token", "2/2 green Ooze creature token. It has \"When this creature dies, create two 1/1 green Ooze creature tokens.\""); cardType.add(CardType.CREATURE); subtype.add(SubType.OOZE); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/OozeToken.java b/Mage/src/main/java/mage/game/permanent/token/OozeToken.java index d4593f73efe..4398e1c5f27 100644 --- a/Mage/src/main/java/mage/game/permanent/token/OozeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/OozeToken.java @@ -4,10 +4,12 @@ import mage.MageInt; import mage.constants.CardType; import mage.constants.SubType; +import java.util.Arrays; + public final class OozeToken extends TokenImpl { public OozeToken(int power, int toughness) { - super("Ooze", power + "/" + toughness + " green ooze creature token"); + super("Ooze Token", power + "/" + toughness + " green ooze creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.OOZE); @@ -16,12 +18,14 @@ public final class OozeToken extends TokenImpl { } public OozeToken() { - super("Ooze", "X/X green ooze creature token"); + super("Ooze Token", "X/X green ooze creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.OOZE); power = new MageInt(0); toughness = new MageInt(0); + + availableImageSetCodes = Arrays.asList("ALA", "ROE", "RTR", "MM3", "UMA", "GK2", "2XM"); } public OozeToken(final OozeToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/OphiomancerSnakeToken.java b/Mage/src/main/java/mage/game/permanent/token/OphiomancerSnakeToken.java index a3b3f578363..7a4a0ab65f0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/OphiomancerSnakeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/OphiomancerSnakeToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.DeathtouchAbility; public final class OphiomancerSnakeToken extends TokenImpl { public OphiomancerSnakeToken() { - super("Snake", "1/1 black Snake creature token with deathtouch"); + super("Snake Token", "1/1 black Snake creature token with deathtouch"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.SNAKE); diff --git a/Mage/src/main/java/mage/game/permanent/token/OrderedMigrationBirdToken.java b/Mage/src/main/java/mage/game/permanent/token/OrderedMigrationBirdToken.java deleted file mode 100644 index b0872ea465b..00000000000 --- a/Mage/src/main/java/mage/game/permanent/token/OrderedMigrationBirdToken.java +++ /dev/null @@ -1,32 +0,0 @@ - -package mage.game.permanent.token; - -import mage.MageInt; -import mage.abilities.keyword.FlyingAbility; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author LoneFox - */ -public final class OrderedMigrationBirdToken extends TokenImpl { - - public OrderedMigrationBirdToken() { - super("Bird", "1/1 blue Bird creature token with flying"); - cardType.add(CardType.CREATURE); - color.setBlue(true); - subtype.add(SubType.BIRD); - power = new MageInt(1); - toughness = new MageInt(1); - addAbility(FlyingAbility.getInstance()); - } - - public OrderedMigrationBirdToken(final OrderedMigrationBirdToken token) { - super(token); - } - - public OrderedMigrationBirdToken copy() { - return new OrderedMigrationBirdToken(this); - } -} diff --git a/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentClericToken.java b/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentClericToken.java index e6553091f6a..64b6dc529fb 100644 --- a/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentClericToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentClericToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class OutlawsMerrimentClericToken extends TokenImpl { public OutlawsMerrimentClericToken() { - super("Human Cleric", "2/1 Human Cleric with lifelink and haste"); + super("Human Cleric Token", "2/1 Human Cleric with lifelink and haste"); cardType.add(CardType.CREATURE); subtype.add(SubType.HUMAN); subtype.add(SubType.CLERIC); diff --git a/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentRogueToken.java b/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentRogueToken.java index 11d4f52d8fd..4e6ff6fefaa 100644 --- a/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentRogueToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentRogueToken.java @@ -15,7 +15,7 @@ import mage.target.common.TargetAnyTarget; public final class OutlawsMerrimentRogueToken extends TokenImpl { public OutlawsMerrimentRogueToken() { - super("Human Rogue", "1/2 Human Rogue with haste and \"When this creature enters the battlefield, it deals 1 damage to any target.\""); + super("Human Rogue Token", "1/2 Human Rogue with haste and \"When this creature enters the battlefield, it deals 1 damage to any target.\""); cardType.add(CardType.CREATURE); subtype.add(SubType.HUMAN); subtype.add(SubType.ROGUE); diff --git a/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentWarriorToken.java index fdf816a51d8..3142391ba17 100644 --- a/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/OutlawsMerrimentWarriorToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class OutlawsMerrimentWarriorToken extends TokenImpl { public OutlawsMerrimentWarriorToken() { - super("Human Warrior", "3/1 Human Warrior with trample and haste"); + super("Human Warrior Token", "3/1 Human Warrior with trample and haste"); cardType.add(CardType.CREATURE); subtype.add(SubType.HUMAN); subtype.add(SubType.WARRIOR); diff --git a/Mage/src/main/java/mage/game/permanent/token/OviyaPashiriSageLifecrafterToken.java b/Mage/src/main/java/mage/game/permanent/token/OviyaPashiriSageLifecrafterToken.java index 282cf8d8e0e..892f38036df 100644 --- a/Mage/src/main/java/mage/game/permanent/token/OviyaPashiriSageLifecrafterToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/OviyaPashiriSageLifecrafterToken.java @@ -16,7 +16,7 @@ public final class OviyaPashiriSageLifecrafterToken extends TokenImpl { } public OviyaPashiriSageLifecrafterToken(int number) { - super("Construct", "an X/X colorless Construct artifact creature token, where X is the number of creatures you control"); + super("Construct Token", "an X/X colorless Construct artifact creature token, where X is the number of creatures you control"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.CONSTRUCT); diff --git a/Mage/src/main/java/mage/game/permanent/token/OxToken.java b/Mage/src/main/java/mage/game/permanent/token/OxToken.java index 082fe757927..77ae9530d7b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/OxToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/OxToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class OxToken extends TokenImpl { public OxToken() { - super("Ox", "2/4 white Ox creature token"); + super("Ox Token", "2/4 white Ox creature token"); cardType.add(CardType.CREATURE); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/PatagiaViperSnakeToken.java b/Mage/src/main/java/mage/game/permanent/token/PatagiaViperSnakeToken.java index f554901c28d..4f910019d2a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PatagiaViperSnakeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PatagiaViperSnakeToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class PatagiaViperSnakeToken extends TokenImpl { public PatagiaViperSnakeToken() { - super("Snake", "1/1 green and blue Snake creature token"); + super("Snake Token", "1/1 green and blue Snake creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/PegasusToken.java b/Mage/src/main/java/mage/game/permanent/token/PegasusToken.java index 119fee8afe2..26554dfb363 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PegasusToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PegasusToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class PegasusToken extends TokenImpl { public PegasusToken() { - super("Pegasus", "1/1 white Pegasus creature token with flying"); + super("Pegasus Token", "1/1 white Pegasus creature token with flying"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.PEGASUS); diff --git a/Mage/src/main/java/mage/game/permanent/token/PegasusToken2.java b/Mage/src/main/java/mage/game/permanent/token/PegasusToken2.java index 5994c79f743..620d5512fa0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PegasusToken2.java +++ b/Mage/src/main/java/mage/game/permanent/token/PegasusToken2.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class PegasusToken2 extends TokenImpl { public PegasusToken2() { - super("Pegasus", "2/2 white Pegasus creature token with flying"); + super("Pegasus Token", "2/2 white Pegasus creature token with flying"); this.cardType.add(CardType.CREATURE); this.color.setWhite(true); this.subtype.add(SubType.PEGASUS); diff --git a/Mage/src/main/java/mage/game/permanent/token/PentaviteToken.java b/Mage/src/main/java/mage/game/permanent/token/PentaviteToken.java index 2d24d3e34b4..efed3decd08 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PentaviteToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PentaviteToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class PentaviteToken extends TokenImpl { public PentaviteToken() { - super("Pentavite", "1/1 colorless Pentavite artifact creature token with flying"); + super("Pentavite Token", "1/1 colorless Pentavite artifact creature token with flying"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.PENTAVITE); diff --git a/Mage/src/main/java/mage/game/permanent/token/PenumbraBobcatToken.java b/Mage/src/main/java/mage/game/permanent/token/PenumbraBobcatToken.java index 7a73e237654..316f45153a0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PenumbraBobcatToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PenumbraBobcatToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class PenumbraBobcatToken extends TokenImpl { public PenumbraBobcatToken() { - super("Cat", "2/1 black Cat creature token"); + super("Cat Token", "2/1 black Cat creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.CAT); diff --git a/Mage/src/main/java/mage/game/permanent/token/PenumbraKavuToken.java b/Mage/src/main/java/mage/game/permanent/token/PenumbraKavuToken.java index b6efaf716a8..44245c263bd 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PenumbraKavuToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PenumbraKavuToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class PenumbraKavuToken extends TokenImpl { public PenumbraKavuToken() { - super("Kavu", "3/3 black Kavu creature token"); + super("Kavu Token", "3/3 black Kavu creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.KAVU); diff --git a/Mage/src/main/java/mage/game/permanent/token/PenumbraSpiderToken.java b/Mage/src/main/java/mage/game/permanent/token/PenumbraSpiderToken.java index 60fd2885593..684062092c1 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PenumbraSpiderToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PenumbraSpiderToken.java @@ -15,7 +15,7 @@ public final class PenumbraSpiderToken extends TokenImpl { public PenumbraSpiderToken() { - super("Spider", "2/4 black Spider creature token with reach"); + super("Spider Token", "2/4 black Spider creature token with reach"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.SPIDER); diff --git a/Mage/src/main/java/mage/game/permanent/token/PenumbraWurmToken.java b/Mage/src/main/java/mage/game/permanent/token/PenumbraWurmToken.java index e42e1834df7..6501f23b799 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PenumbraWurmToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PenumbraWurmToken.java @@ -6,6 +6,8 @@ import mage.constants.SubType; import mage.MageInt; import mage.abilities.keyword.TrampleAbility; +import java.util.Arrays; + /** * * @author spjspj @@ -13,7 +15,7 @@ import mage.abilities.keyword.TrampleAbility; public final class PenumbraWurmToken extends TokenImpl { public PenumbraWurmToken() { - super("Wurm", "6/6 black Wurm creature token with trample"); + super("Wurm Token", "6/6 black Wurm creature token with trample"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.WURM); @@ -21,6 +23,8 @@ public final class PenumbraWurmToken extends TokenImpl { toughness = new MageInt(6); this.addAbility(TrampleAbility.getInstance()); + + availableImageSetCodes.addAll(Arrays.asList("UMA")); } public PenumbraWurmToken(final PenumbraWurmToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/Pest11GainLifeToken.java b/Mage/src/main/java/mage/game/permanent/token/Pest11GainLifeToken.java index 5724949cff9..6f6be5f4478 100644 --- a/Mage/src/main/java/mage/game/permanent/token/Pest11GainLifeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/Pest11GainLifeToken.java @@ -14,7 +14,7 @@ import java.util.Arrays; public final class Pest11GainLifeToken extends TokenImpl { public Pest11GainLifeToken() { - super("Pest", "1/1 black and green Pest creature token with \"When this creature dies, you gain 1 life.\""); + super("Pest Token", "1/1 black and green Pest creature token with \"When this creature dies, you gain 1 life.\""); cardType.add(CardType.CREATURE); color.setBlack(true); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/PestToken.java b/Mage/src/main/java/mage/game/permanent/token/PestToken.java index 75be33db38e..ecc96a850e0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PestToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PestToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class PestToken extends TokenImpl { public PestToken() { - super("Pest", "0/1 colorless Pest artifact creature token"); + super("Pest Token", "0/1 colorless Pest artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.PEST); diff --git a/Mage/src/main/java/mage/game/permanent/token/PharikaSnakeToken.java b/Mage/src/main/java/mage/game/permanent/token/PharikaSnakeToken.java index 4b775da2148..d70d27e1a7a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PharikaSnakeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PharikaSnakeToken.java @@ -12,7 +12,7 @@ import mage.abilities.keyword.DeathtouchAbility; public final class PharikaSnakeToken extends TokenImpl { public PharikaSnakeToken() { - super("Snake", "1/1 black and green Snake enchantment creature token with deathtouch", 1, 1); + super("Snake Token", "1/1 black and green Snake enchantment creature token with deathtouch", 1, 1); this.setOriginalExpansionSetCode("JOU"); cardType.add(CardType.ENCHANTMENT); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/PhyrexianBeastToken.java b/Mage/src/main/java/mage/game/permanent/token/PhyrexianBeastToken.java index ea23331ddca..b859ba35db7 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PhyrexianBeastToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PhyrexianBeastToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class PhyrexianBeastToken extends TokenImpl { public PhyrexianBeastToken() { - super("Phyrexian Beast", "4/4 green Phyrexian Beast creature token"); + super("Phyrexian Beast Token", "4/4 green Phyrexian Beast creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.PHYREXIAN); diff --git a/Mage/src/main/java/mage/game/permanent/token/PhyrexianGermToken.java b/Mage/src/main/java/mage/game/permanent/token/PhyrexianGermToken.java index c8c9b04df04..457570875c5 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PhyrexianGermToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PhyrexianGermToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class PhyrexianGermToken extends TokenImpl { public PhyrexianGermToken() { - super("Phyrexian Germ", "0/0 black Phyrexian Germ creature token"); + super("Phyrexian Germ Token", "0/0 black Phyrexian Germ creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.PHYREXIAN); @@ -20,7 +20,7 @@ public final class PhyrexianGermToken extends TokenImpl { power = new MageInt(0); toughness = new MageInt(0); - availableImageSetCodes = Arrays.asList("C14", "C15", "MBS", "MM2", "NPH", "PC2", "MH2"); + availableImageSetCodes = Arrays.asList("C14", "C15", "MBS", "MM2", "NPH", "PC2", "MH2", "NEC", "2XM"); } @Override diff --git a/Mage/src/main/java/mage/game/permanent/token/PhyrexianGoblinToken.java b/Mage/src/main/java/mage/game/permanent/token/PhyrexianGoblinToken.java index 3bb54a71dff..fce194cf0d4 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PhyrexianGoblinToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PhyrexianGoblinToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class PhyrexianGoblinToken extends TokenImpl { public PhyrexianGoblinToken() { - super("Phyrexian Goblin", "1/1 red Phyrexian Goblin creature token with haste"); + super("Phyrexian Goblin Token", "1/1 red Phyrexian Goblin creature token with haste"); cardType.add(CardType.CREATURE); subtype.add(SubType.PHYREXIAN); subtype.add(SubType.GOBLIN); diff --git a/Mage/src/main/java/mage/game/permanent/token/PhyrexianGolemToken.java b/Mage/src/main/java/mage/game/permanent/token/PhyrexianGolemToken.java index bded6b25ff3..00acbcd7a67 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PhyrexianGolemToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PhyrexianGolemToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class PhyrexianGolemToken extends TokenImpl { public PhyrexianGolemToken() { - super("Phyrexian Golem", "3/3 colorless Phyrexian Golem artifact creature token"); + super("Phyrexian Golem Token", "3/3 colorless Phyrexian Golem artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.PHYREXIAN); diff --git a/Mage/src/main/java/mage/game/permanent/token/PhyrexianMyrToken.java b/Mage/src/main/java/mage/game/permanent/token/PhyrexianMyrToken.java index 852325af146..f79360365ed 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PhyrexianMyrToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PhyrexianMyrToken.java @@ -7,7 +7,7 @@ import mage.constants.SubType; public final class PhyrexianMyrToken extends TokenImpl { public PhyrexianMyrToken() { - super("Phyrexian Myr", "1/1 colorless Phyrexian Myr artifact creature token"); + super("Phyrexian Myr Token", "1/1 colorless Phyrexian Myr artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.PHYREXIAN); diff --git a/Mage/src/main/java/mage/game/permanent/token/PhyrexianRebirthHorrorToken.java b/Mage/src/main/java/mage/game/permanent/token/PhyrexianRebirthHorrorToken.java index fe8c9bb6d17..0f99af9b2c9 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PhyrexianRebirthHorrorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PhyrexianRebirthHorrorToken.java @@ -16,7 +16,7 @@ public final class PhyrexianRebirthHorrorToken extends TokenImpl { } public PhyrexianRebirthHorrorToken(int power, int toughness) { - super("Phyrexian Horror", "X/X colorless Phyrexian Horror artifact creature token"); + super("Phyrexian Horror Token", "X/X colorless Phyrexian Horror artifact creature token"); this.cardType.add(CardType.ARTIFACT); this.cardType.add(CardType.CREATURE); this.subtype.add(SubType.PHYREXIAN); diff --git a/Mage/src/main/java/mage/game/permanent/token/PhyrexianZombieToken.java b/Mage/src/main/java/mage/game/permanent/token/PhyrexianZombieToken.java index dd34ca13a25..067367321b6 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PhyrexianZombieToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PhyrexianZombieToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class PhyrexianZombieToken extends TokenImpl { public PhyrexianZombieToken() { - super("Phyrexian Zombie", "2/2 black Phyrexian Zombie creature token"); + super("Phyrexian Zombie Token", "2/2 black Phyrexian Zombie creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.PHYREXIAN); diff --git a/Mage/src/main/java/mage/game/permanent/token/PilotToken.java b/Mage/src/main/java/mage/game/permanent/token/PilotToken.java index 2f921839c8b..020cd39b577 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PilotToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PilotToken.java @@ -5,18 +5,22 @@ import mage.abilities.common.CrewIncreasedPowerAbility; import mage.constants.CardType; import mage.constants.SubType; +import java.util.Arrays; + /** * @author TheElk801 */ public final class PilotToken extends TokenImpl { public PilotToken() { - super("Pilot token", "1/1 colorless Pilot creature token with \"This creature crews Vehicles as though its power were 2 greater.\""); + super("Pilot Token", "1/1 colorless Pilot creature token with \"This creature crews Vehicles as though its power were 2 greater.\""); cardType.add(CardType.CREATURE); subtype.add(SubType.PILOT); power = new MageInt(1); toughness = new MageInt(1); addAbility(new CrewIncreasedPowerAbility("this creature")); + + availableImageSetCodes = Arrays.asList("NEO"); } public PilotToken(final PilotToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/PincherToken.java b/Mage/src/main/java/mage/game/permanent/token/PincherToken.java index 8fe8ebf6a2c..e996e55ea0e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PincherToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PincherToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class PincherToken extends TokenImpl { public PincherToken() { - super("Pincher", "2/2 colorless Pincher creature token"); + super("Pincher Token", "2/2 colorless Pincher creature token"); setOriginalExpansionSetCode("5ND"); cardType.add(CardType.CREATURE); subtype.add(SubType.PINCHER); diff --git a/Mage/src/main/java/mage/game/permanent/token/PirateToken.java b/Mage/src/main/java/mage/game/permanent/token/PirateToken.java index 545bc43402c..092aa5761c9 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PirateToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PirateToken.java @@ -13,7 +13,7 @@ import mage.constants.SubType; public final class PirateToken extends TokenImpl { public PirateToken() { - super("Pirate", "2/2 black Pirate creature token with menace"); + super("Pirate Token", "2/2 black Pirate creature token with menace"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.PIRATE); diff --git a/Mage/src/main/java/mage/game/permanent/token/PlanewideCelebrationToken.java b/Mage/src/main/java/mage/game/permanent/token/PlanewideCelebrationToken.java index 5405ab52358..5193ff31f53 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PlanewideCelebrationToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PlanewideCelebrationToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class PlanewideCelebrationToken extends TokenImpl { public PlanewideCelebrationToken() { - super("Citizen", "2/2 Citizen creature token that's all colors"); + super("Citizen Token", "2/2 Citizen creature token that's all colors"); cardType.add(CardType.CREATURE); color.setWhite(true); color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/PlantToken.java b/Mage/src/main/java/mage/game/permanent/token/PlantToken.java index b4e5db12667..93ff1c57dac 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PlantToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PlantToken.java @@ -9,14 +9,14 @@ import java.util.Arrays; public final class PlantToken extends TokenImpl { public PlantToken() { - super("Plant", "0/1 green Plant creature token"); + super("Plant Token", "0/1 green Plant creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.PLANT); power = new MageInt(0); toughness = new MageInt(1); - availableImageSetCodes = Arrays.asList("ARC", "C13", "C18", "DDP", "OGW", "PC2", "WWK", "XLN", "ZEN", "ZNR", "CMR"); + availableImageSetCodes = Arrays.asList("ARC", "C13", "C18", "DDP", "OGW", "PC2", "WWK", "XLN", "ZEN", "ZNR", "CMR", "NEC", "2XM"); } public PlantToken(final PlantToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/PongifyApeToken.java b/Mage/src/main/java/mage/game/permanent/token/PongifyApeToken.java index 16a31ed60a8..bdbe3fece0e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PongifyApeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PongifyApeToken.java @@ -14,7 +14,7 @@ import java.util.Arrays; public final class PongifyApeToken extends TokenImpl { public PongifyApeToken() { - super("Ape", "3/3 green Ape creature token"); + super("Ape Token", "3/3 green Ape creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.APE); diff --git a/Mage/src/main/java/mage/game/permanent/token/PrismToken.java b/Mage/src/main/java/mage/game/permanent/token/PrismToken.java index 8f0336ee67f..8fe9417a576 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PrismToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PrismToken.java @@ -21,7 +21,7 @@ public final class PrismToken extends TokenImpl { } public PrismToken() { - super("Prism", "0/1 colorless Prism artifact creature token"); + super("Prism Token", "0/1 colorless Prism artifact creature token"); availableImageSetCodes = tokenImageSets; cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/PurphorossInterventionToken.java b/Mage/src/main/java/mage/game/permanent/token/PurphorossInterventionToken.java index 2517b79aa0a..f28731dc478 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PurphorossInterventionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PurphorossInterventionToken.java @@ -15,7 +15,7 @@ public final class PurphorossInterventionToken extends TokenImpl { this(0); } public PurphorossInterventionToken(int power) { - super("Elemental", "X/1 red Elemental creature token with trample and haste"); + super("Elemental Token", "X/1 red Elemental creature token with trample and haste"); this.cardType.add(CardType.CREATURE); this.subtype.add(SubType.ELEMENTAL); this.color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/PursuedWhaleToken.java b/Mage/src/main/java/mage/game/permanent/token/PursuedWhaleToken.java index a0831031503..21b95780a38 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PursuedWhaleToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PursuedWhaleToken.java @@ -7,8 +7,7 @@ import mage.abilities.effects.common.combat.CantBlockSourceEffect; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; import java.util.Arrays; @@ -17,14 +16,8 @@ import java.util.Arrays; */ public final class PursuedWhaleToken extends TokenImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control"); - - static { - filter.add(TargetController.YOU.getControllerPredicate()); - } - public PursuedWhaleToken() { - super("Pirate", "1/1 red Pirate creature token with \"This creature can't block\" and \"Creatures you control attack each combat if able.\""); + super("Pirate Token", "1/1 red Pirate creature token with \"This creature can't block\" and \"Creatures you control attack each combat if able.\""); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.PIRATE); @@ -33,9 +26,7 @@ public final class PursuedWhaleToken extends TokenImpl { this.addAbility(new SimpleStaticAbility(new CantBlockSourceEffect(Duration.WhileOnBattlefield) .setText("this creature can't block"))); - this.addAbility(new SimpleStaticAbility(new AttacksIfAbleAllEffect( - filter, Duration.WhileOnBattlefield, true - ))); + this.addAbility(new SimpleStaticAbility(new AttacksIfAbleAllEffect(StaticFilters.FILTER_CONTROLLED_CREATURES))); availableImageSetCodes = Arrays.asList("M21"); } diff --git a/Mage/src/main/java/mage/game/permanent/token/QueenMarchesaAssassinToken.java b/Mage/src/main/java/mage/game/permanent/token/QueenMarchesaAssassinToken.java index 1afa17bd771..fe6b5b6bc63 100644 --- a/Mage/src/main/java/mage/game/permanent/token/QueenMarchesaAssassinToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/QueenMarchesaAssassinToken.java @@ -14,7 +14,7 @@ import mage.abilities.keyword.HasteAbility; public final class QueenMarchesaAssassinToken extends TokenImpl { public QueenMarchesaAssassinToken() { - super("Assassin", "1/1 black Assassin creature tokens with deathtouch and haste"); + super("Assassin Token", "1/1 black Assassin creature tokens with deathtouch and haste"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.ASSASSIN); diff --git a/Mage/src/main/java/mage/game/permanent/token/QuestForTheGravelordZombieToken.java b/Mage/src/main/java/mage/game/permanent/token/QuestForTheGravelordZombieToken.java index 2855ee46ce8..3bc9cb3ee67 100644 --- a/Mage/src/main/java/mage/game/permanent/token/QuestForTheGravelordZombieToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/QuestForTheGravelordZombieToken.java @@ -13,7 +13,7 @@ import mage.constants.SubType; public final class QuestForTheGravelordZombieToken extends TokenImpl { public QuestForTheGravelordZombieToken() { - super("Zombie Giant", "5/5 black Zombie Giant creature token"); + super("Zombie Giant Token", "5/5 black Zombie Giant creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.ZOMBIE); subtype.add(SubType.GIANT); diff --git a/Mage/src/main/java/mage/game/permanent/token/RakdosGuildmageGoblinToken.java b/Mage/src/main/java/mage/game/permanent/token/RakdosGuildmageGoblinToken.java index 51ebd774da6..acd488a355f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RakdosGuildmageGoblinToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RakdosGuildmageGoblinToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.HasteAbility; public final class RakdosGuildmageGoblinToken extends TokenImpl { public RakdosGuildmageGoblinToken() { - super("Goblin", "2/1 red Goblin creature token with haste"); + super("Goblin Token", "2/1 red Goblin creature token with haste"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.GOBLIN); diff --git a/Mage/src/main/java/mage/game/permanent/token/RakkaMarElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/RakkaMarElementalToken.java deleted file mode 100644 index 3c25d9646b3..00000000000 --- a/Mage/src/main/java/mage/game/permanent/token/RakkaMarElementalToken.java +++ /dev/null @@ -1,32 +0,0 @@ - -package mage.game.permanent.token; - -import mage.MageInt; -import mage.abilities.keyword.HasteAbility; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * - * @author spjspj - */ -public final class RakkaMarElementalToken extends TokenImpl { - - public RakkaMarElementalToken () { - super("Elemental", "3/1 red Elemental creature with Haste"); - cardType.add(CardType.CREATURE); - color.setRed(true); - subtype.add(SubType.ELEMENTAL); - power = new MageInt(3); - toughness = new MageInt(1); - addAbility(HasteAbility.getInstance()); - } - - public RakkaMarElementalToken(final RakkaMarElementalToken token) { - super(token); - } - - public RakkaMarElementalToken copy() { - return new RakkaMarElementalToken(this); - } -} diff --git a/Mage/src/main/java/mage/game/permanent/token/RallyTheHordeWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/RallyTheHordeWarriorToken.java index bbc2c3efb63..dd978b48aae 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RallyTheHordeWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RallyTheHordeWarriorToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class RallyTheHordeWarriorToken extends TokenImpl { public RallyTheHordeWarriorToken() { - super("Warrior", "1/1 red Warrior creature token"); + super("Warrior Token", "1/1 red Warrior creature token"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.WARRIOR); diff --git a/Mage/src/main/java/mage/game/permanent/token/RatToken.java b/Mage/src/main/java/mage/game/permanent/token/RatToken.java index 2a2c9dd1f77..d18aaa0981d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RatToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RatToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class RatToken extends TokenImpl { public RatToken() { - super("Rat", "1/1 black Rat creature token"); + super("Rat Token", "1/1 black Rat creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.RAT); diff --git a/Mage/src/main/java/mage/game/permanent/token/RebelStarshipToken.java b/Mage/src/main/java/mage/game/permanent/token/RebelStarshipToken.java index b1385767645..ccd0ccb0858 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RebelStarshipToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RebelStarshipToken.java @@ -12,7 +12,7 @@ import mage.abilities.keyword.SpaceflightAbility; public final class RebelStarshipToken extends TokenImpl { public RebelStarshipToken() { - super("B-Wing", "2/3 blue Rebel Starship artifact creature tokens with spaceflight name B-Wing", 2, 3); + super("B-Wing Token", "2/3 blue Rebel Starship artifact creature tokens with spaceflight name B-Wing", 2, 3); this.setOriginalExpansionSetCode("SWS"); cardType.add(CardType.CREATURE); cardType.add(CardType.ARTIFACT); diff --git a/Mage/src/main/java/mage/game/permanent/token/RebelToken.java b/Mage/src/main/java/mage/game/permanent/token/RebelToken.java index c8bca8a53ac..9507b6d80c4 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RebelToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RebelToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class RebelToken extends TokenImpl { public RebelToken() { - super("Rebel", "1/1 white Rebel creature token", 1, 1); + super("Rebel Token", "1/1 white Rebel creature token", 1, 1); this.setOriginalExpansionSetCode("SWS"); cardType.add(CardType.CREATURE); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/RedElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/RedElementalToken.java index 9b8fc4ce8ca..99035ae26bd 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RedElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RedElementalToken.java @@ -13,14 +13,14 @@ import java.util.Arrays; public final class RedElementalToken extends TokenImpl { public RedElementalToken() { - super("Elemental", "1/1 red Elemental creature token"); + super("Elemental Token", "1/1 red Elemental creature token"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.ELEMENTAL); power = new MageInt(1); toughness = new MageInt(1); - availableImageSetCodes = Arrays.asList("C13", "EMA", "M14", "SHM", "MH1", "M20"); + availableImageSetCodes = Arrays.asList("C13", "EMA", "M14", "SHM", "MH1", "M20", "RIX", "UMA", "NEC"); } @Override @@ -35,9 +35,17 @@ public final class RedElementalToken extends TokenImpl { setTokenType(RandomUtil.nextInt(2) + 1); } + if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("RIX")) { + setTokenType(2); + } + if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("SHM")) { setTokenType(2); } + + if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("UMA")) { + setTokenType(RandomUtil.nextInt(2) + 2); // 2..3 + } } public RedElementalToken(final RedElementalToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/RedElementalWithTrampleAndHaste.java b/Mage/src/main/java/mage/game/permanent/token/RedElementalWithTrampleAndHaste.java index 30c9a7b197c..08512f80491 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RedElementalWithTrampleAndHaste.java +++ b/Mage/src/main/java/mage/game/permanent/token/RedElementalWithTrampleAndHaste.java @@ -13,7 +13,7 @@ import mage.util.RandomUtil; public final class RedElementalWithTrampleAndHaste extends TokenImpl { public RedElementalWithTrampleAndHaste() { - super("Elemental", "7/1 red Elemental creature token with trample and haste"); + super("Elemental Token", "7/1 red Elemental creature token with trample and haste"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.ELEMENTAL); diff --git a/Mage/src/main/java/mage/game/permanent/token/RedGreenBeastToken.java b/Mage/src/main/java/mage/game/permanent/token/RedGreenBeastToken.java index 55a29a38b31..8618650af10 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RedGreenBeastToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RedGreenBeastToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class RedGreenBeastToken extends TokenImpl { public RedGreenBeastToken() { - super("Beast", "4/4 red and green Beast creature token with trample"); + super("Beast Token", "4/4 red and green Beast creature token with trample"); cardType.add(CardType.CREATURE); color.setRed(true); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/RedHumanToken.java b/Mage/src/main/java/mage/game/permanent/token/RedHumanToken.java index ef7f4c58daf..264b43d91c7 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RedHumanToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RedHumanToken.java @@ -15,7 +15,7 @@ import java.util.Arrays; public final class RedHumanToken extends TokenImpl { public RedHumanToken() { - super("Human", "1/1 red Human creature token"); + super("Human Token", "1/1 red Human creature token"); this.cardType.add(CardType.CREATURE); this.subtype.add(SubType.HUMAN); diff --git a/Mage/src/main/java/mage/game/permanent/token/RedWhiteGolemToken.java b/Mage/src/main/java/mage/game/permanent/token/RedWhiteGolemToken.java index a215ef4abfe..e344af37b7d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RedWhiteGolemToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RedWhiteGolemToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public class RedWhiteGolemToken extends TokenImpl { public RedWhiteGolemToken() { - super("Golem", "4/4 red and white Golem artifact creature token"); + super("Golem Token", "4/4 red and white Golem artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.GOLEM); diff --git a/Mage/src/main/java/mage/game/permanent/token/RedWolfToken.java b/Mage/src/main/java/mage/game/permanent/token/RedWolfToken.java index fe49cf801c0..46aeb2c56f3 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RedWolfToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RedWolfToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class RedWolfToken extends TokenImpl { public RedWolfToken() { - super("Wolf", "3/2 red Wolf creature token"); + super("Wolf Token", "3/2 red Wolf creature token"); cardType.add(CardType.CREATURE); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/ReefWormFishToken.java b/Mage/src/main/java/mage/game/permanent/token/ReefWormFishToken.java index e0af3a533f0..707763f9b47 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ReefWormFishToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ReefWormFishToken.java @@ -14,7 +14,7 @@ import java.util.Arrays; public final class ReefWormFishToken extends TokenImpl { public ReefWormFishToken() { - super("Fish", "3/3 blue Fish creature token with \"When this creature dies, create a 6/6 blue Whale creature token with \"When this creature dies, create a 9/9 blue Kraken creature token.\"\""); + super("Fish Token", "3/3 blue Fish creature token with \"When this creature dies, create a 6/6 blue Whale creature token with \"When this creature dies, create a 9/9 blue Kraken creature token.\"\""); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.FISH); diff --git a/Mage/src/main/java/mage/game/permanent/token/ReefWormWhaleToken.java b/Mage/src/main/java/mage/game/permanent/token/ReefWormWhaleToken.java index 2a8bfa70955..537e48db9db 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ReefWormWhaleToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ReefWormWhaleToken.java @@ -14,7 +14,7 @@ import java.util.Arrays; public final class ReefWormWhaleToken extends TokenImpl { public ReefWormWhaleToken() { - super("Whale", "6/6 blue Whale creature token with \"When this creature dies, create a 9/9 blue Kraken creature token.\""); + super("Whale Token", "6/6 blue Whale creature token with \"When this creature dies, create a 9/9 blue Kraken creature token.\""); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.WHALE); diff --git a/Mage/src/main/java/mage/game/permanent/token/ReflectionBlueToken.java b/Mage/src/main/java/mage/game/permanent/token/ReflectionBlueToken.java index f970ecb8efa..d326697f850 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ReflectionBlueToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ReflectionBlueToken.java @@ -10,7 +10,7 @@ import mage.constants.SubType; public final class ReflectionBlueToken extends TokenImpl { public ReflectionBlueToken() { - super("Reflection", "3/2 blue Reflection creature token"); + super("Reflection Token", "3/2 blue Reflection creature token"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.REFLECTION); diff --git a/Mage/src/main/java/mage/game/permanent/token/ReflectionPureToken.java b/Mage/src/main/java/mage/game/permanent/token/ReflectionPureToken.java index 15ed5bebd33..6ab0041e74b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ReflectionPureToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ReflectionPureToken.java @@ -16,7 +16,7 @@ public final class ReflectionPureToken extends TokenImpl { } public ReflectionPureToken(int xValue) { - super("Reflection", "X/X white Reflection creature token, where X is the mana value of that spell"); + super("Reflection Token", "X/X white Reflection creature token, where X is the mana value of that spell"); this.setOriginalExpansionSetCode("INV"); cardType.add(CardType.CREATURE); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/ReflectionToken.java b/Mage/src/main/java/mage/game/permanent/token/ReflectionToken.java index 3b268d15ca1..2e53f13b01f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ReflectionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ReflectionToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class ReflectionToken extends TokenImpl { public ReflectionToken() { - super("Reflection", "2/2 white Reflection creature token"); + super("Reflection Token", "2/2 white Reflection creature token"); this.setOriginalExpansionSetCode("TMP"); cardType.add(CardType.CREATURE); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/RekindlingPhoenixToken.java b/Mage/src/main/java/mage/game/permanent/token/RekindlingPhoenixToken.java index ddbf336d51f..affd29c9310 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RekindlingPhoenixToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RekindlingPhoenixToken.java @@ -24,7 +24,7 @@ import mage.target.common.TargetCardInYourGraveyard; public final class RekindlingPhoenixToken extends TokenImpl { public RekindlingPhoenixToken() { - super("Elemental", "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.\""); + super("Elemental Token", "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.\""); setTokenType(1); cardType.add(CardType.CREATURE); subtype.add(SubType.ELEMENTAL); diff --git a/Mage/src/main/java/mage/game/permanent/token/RelicRobberToken.java b/Mage/src/main/java/mage/game/permanent/token/RelicRobberToken.java index b49c5d97919..abebd803438 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RelicRobberToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RelicRobberToken.java @@ -15,7 +15,7 @@ import java.util.Arrays; public final class RelicRobberToken extends TokenImpl { public RelicRobberToken() { - super("Goblin Construct", "0/1 colorless Goblin Construct artifact creature token with \"This creature can't block\" and \"At the beginning of your upkeep, this creature deals 1 damage to you.\""); + super("Goblin Construct Token", "0/1 colorless Goblin Construct artifact creature token with \"This creature can't block\" and \"At the beginning of your upkeep, this creature deals 1 damage to you.\""); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.GOBLIN); diff --git a/Mage/src/main/java/mage/game/permanent/token/RenownedWeaverSpiderToken.java b/Mage/src/main/java/mage/game/permanent/token/RenownedWeaverSpiderToken.java index cc91c55382d..14d9e7a01c0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RenownedWeaverSpiderToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RenownedWeaverSpiderToken.java @@ -16,7 +16,7 @@ import java.util.Arrays; public final class RenownedWeaverSpiderToken extends TokenImpl { public RenownedWeaverSpiderToken() { - super("Spider", "1/3 green Spider enchantment creature token with reach"); + super("Spider Token", "1/3 green Spider enchantment creature token with reach"); cardType.add(CardType.ENCHANTMENT); cardType.add(CardType.CREATURE); color.setColor(ObjectColor.GREEN); diff --git a/Mage/src/main/java/mage/game/permanent/token/ResearchDevelopmentToken.java b/Mage/src/main/java/mage/game/permanent/token/ResearchDevelopmentToken.java index 29938baeb3a..2932743c4cd 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ResearchDevelopmentToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ResearchDevelopmentToken.java @@ -20,7 +20,7 @@ public final class ResearchDevelopmentToken extends TokenImpl { } public ResearchDevelopmentToken() { - super("Elemental", "3/1 red Elemental creature token"); + super("Elemental Token", "3/1 red Elemental creature token"); availableImageSetCodes = tokenImageSets; cardType.add(CardType.CREATURE); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/RhinoToken.java b/Mage/src/main/java/mage/game/permanent/token/RhinoToken.java index 259f3e846f8..f8b8e06e8a8 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RhinoToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RhinoToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class RhinoToken extends TokenImpl { public RhinoToken() { - super("Rhino", "4/4 green Rhino creature token with trample"); + super("Rhino Token", "4/4 green Rhino creature token with trample"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.RHINO); diff --git a/Mage/src/main/java/mage/game/permanent/token/RhinoWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/RhinoWarriorToken.java new file mode 100644 index 00000000000..a051e1dcfe1 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/RhinoWarriorToken.java @@ -0,0 +1,33 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.Arrays; + +/** + * @author TheElk801 + */ +public final class RhinoWarriorToken extends TokenImpl { + + public RhinoWarriorToken() { + super("Rhino Warrior Token", "4/4 green Rhino Warrior creature token"); + cardType.add(CardType.CREATURE); + color.setGreen(true); + subtype.add(SubType.RHINO); + subtype.add(SubType.WARRIOR); + power = new MageInt(4); + toughness = new MageInt(4); + + availableImageSetCodes = Arrays.asList("SNC"); + } + + public RhinoWarriorToken(final RhinoWarriorToken token) { + super(token); + } + + public RhinoWarriorToken copy() { + return new RhinoWarriorToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/RhonassLastStandToken.java b/Mage/src/main/java/mage/game/permanent/token/RhonassLastStandToken.java index 85a13db68a8..49ee9f3fab0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RhonassLastStandToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RhonassLastStandToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class RhonassLastStandToken extends TokenImpl { public RhonassLastStandToken() { - super("Snake", "5/4 green Snake creature token"); + super("Snake Token", "5/4 green Snake creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.SNAKE); diff --git a/Mage/src/main/java/mage/game/permanent/token/RiftmarkedKnightToken.java b/Mage/src/main/java/mage/game/permanent/token/RiftmarkedKnightToken.java index 28114c00288..1d013958b03 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RiftmarkedKnightToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RiftmarkedKnightToken.java @@ -18,7 +18,7 @@ import java.util.Arrays; public final class RiftmarkedKnightToken extends TokenImpl { public RiftmarkedKnightToken() { - super("Knight", "2/2 black Knight creature token with flanking, protection from white, and haste"); + super("Knight Token", "2/2 black Knight creature token with flanking, protection from white, and haste"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.KNIGHT); diff --git a/Mage/src/main/java/mage/game/permanent/token/RiptideReplicatorToken.java b/Mage/src/main/java/mage/game/permanent/token/RiptideReplicatorToken.java index ab70e8e24a3..1ba2668f062 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RiptideReplicatorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RiptideReplicatorToken.java @@ -1,29 +1,20 @@ - - package mage.game.permanent.token; -import mage.constants.CardType; + import mage.MageInt; import mage.ObjectColor; +import mage.constants.CardType; import mage.constants.SubType; /** - * * @author spjspj */ public final class RiptideReplicatorToken extends TokenImpl { - public RiptideReplicatorToken() { - this(null, null, 1); - } public RiptideReplicatorToken(ObjectColor color, SubType type, int x) { - super(type != null ? type.getDescription() : "", "X/X creature token of the chosen color and type"); + super(type.getDescription() + " Token", "X/X creature token of the chosen color and type"); cardType.add(CardType.CREATURE); - if (color != null) { - this.color.setColor(color); - } - if (type != null) { - subtype.add(type); - } + this.color.setColor(color); + subtype.add(type); power = new MageInt(x); toughness = new MageInt(x); } diff --git a/Mage/src/main/java/mage/game/permanent/token/RiseOfEaglesBirdToken.java b/Mage/src/main/java/mage/game/permanent/token/RiseOfEaglesBirdToken.java index c2e699b2f67..b23fe2769a1 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RiseOfEaglesBirdToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RiseOfEaglesBirdToken.java @@ -14,7 +14,7 @@ import mage.abilities.keyword.FlyingAbility; public final class RiseOfEaglesBirdToken extends TokenImpl { public RiseOfEaglesBirdToken() { - super("Bird", "2/2 blue Bird enchantment creature tokens with flying"); + super("Bird Token", "2/2 blue Bird enchantment creature tokens with flying"); this.setOriginalExpansionSetCode("BNG"); this.setTokenType(2); cardType.add(CardType.ENCHANTMENT); diff --git a/Mage/src/main/java/mage/game/permanent/token/RiseOfTheAntsInsectToken.java b/Mage/src/main/java/mage/game/permanent/token/RiseOfTheAntsInsectToken.java index 2a20ab1ee5e..0447d65cec5 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RiseOfTheAntsInsectToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RiseOfTheAntsInsectToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class RiseOfTheAntsInsectToken extends TokenImpl { public RiseOfTheAntsInsectToken() { - super("Insect", "3/3 green Insect creature token"); + super("Insect Token", "3/3 green Insect creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.INSECT); diff --git a/Mage/src/main/java/mage/game/permanent/token/RitualOfTheReturnedZombieToken.java b/Mage/src/main/java/mage/game/permanent/token/RitualOfTheReturnedZombieToken.java index dfe2f6c89c8..8cbf6e4ad74 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RitualOfTheReturnedZombieToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RitualOfTheReturnedZombieToken.java @@ -15,7 +15,7 @@ public final class RitualOfTheReturnedZombieToken extends TokenImpl { this(1,1); } public RitualOfTheReturnedZombieToken(int power, int toughness) { - super("Zombie", "black Zombie creature token with power equal to the exiled card's power and toughness equal to the exiled card's toughness"); + super("Zombie Token", "black Zombie creature token with power equal to the exiled card's power and toughness equal to the exiled card's toughness"); this.setOriginalExpansionSetCode("JOU"); cardType.add(CardType.CREATURE); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/RocEggToken.java b/Mage/src/main/java/mage/game/permanent/token/RocEggToken.java index 4bd15467301..c6fb4dbdf31 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RocEggToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RocEggToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class RocEggToken extends TokenImpl { public RocEggToken() { - super("Bird", "3/3 white Bird creature token with flying"); + super("Bird Token", "3/3 white Bird creature token with flying"); cardType.add(CardType.CREATURE); subtype.add(SubType.BIRD); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/RogueToken.java b/Mage/src/main/java/mage/game/permanent/token/RogueToken.java new file mode 100644 index 00000000000..bf80cd1d32e --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/RogueToken.java @@ -0,0 +1,28 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class RogueToken extends TokenImpl { + + public RogueToken() { + super("Rogue Token", "2/2 black Rogue creature token"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.ROGUE); + color.setBlack(true); + power = new MageInt(2); + toughness = new MageInt(2); + } + + public RogueToken(final RogueToken token) { + super(token); + } + + public RogueToken copy() { + return new RogueToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/RukhEggBirdToken.java b/Mage/src/main/java/mage/game/permanent/token/RukhEggBirdToken.java index d64895ee8c7..055955de724 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RukhEggBirdToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/RukhEggBirdToken.java @@ -17,7 +17,7 @@ public final class RukhEggBirdToken extends TokenImpl { } public RukhEggBirdToken(String setCode) { - super("Bird", "4/4 red Bird creature token with flying"); + super("Bird Token", "4/4 red Bird creature token with flying"); this.setOriginalExpansionSetCode(setCode); cardType.add(CardType.CREATURE); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/SalamnderWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/SalamnderWarriorToken.java index 57054c4a723..1d9cba5e3d8 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SalamnderWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SalamnderWarriorToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class SalamnderWarriorToken extends TokenImpl { public SalamnderWarriorToken() { - super("Salamander Warrior", "4/3 blue Salamander Warrior creature token"); + super("Salamander Warrior Token", "4/3 blue Salamander Warrior creature token"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.SALAMANDER); diff --git a/Mage/src/main/java/mage/game/permanent/token/SamuraiToken.java b/Mage/src/main/java/mage/game/permanent/token/SamuraiToken.java index 729c2e432c5..051c31b49b6 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SamuraiToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SamuraiToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public class SamuraiToken extends TokenImpl { public SamuraiToken() { - super("Samurai token", "2/2 white Samurai creature token with vigilance."); + super("Samurai Token", "2/2 white Samurai creature token with vigilance."); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.SAMURAI); diff --git a/Mage/src/main/java/mage/game/permanent/token/SaprolingBurstToken.java b/Mage/src/main/java/mage/game/permanent/token/SaprolingBurstToken.java index e0416e121cd..c6484e1eb86 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SaprolingBurstToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SaprolingBurstToken.java @@ -29,7 +29,7 @@ public final class SaprolingBurstToken extends TokenImpl { } public SaprolingBurstToken(MageObjectReference saprolingBurstMOR) { - super("Saproling", "green Saproling creature token with \"This creature's power and toughness are each equal to the number of fade counters on Saproling Burst.\""); + super("Saproling Token", "green Saproling creature token with \"This creature's power and toughness are each equal to the number of fade counters on Saproling Burst.\""); this.color.setGreen(true); this.subtype.add(SubType.SAPROLING); this.cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/SaprolingToken.java b/Mage/src/main/java/mage/game/permanent/token/SaprolingToken.java index 80c2054d68e..38286520c25 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SaprolingToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SaprolingToken.java @@ -47,12 +47,14 @@ public final class SaprolingToken extends TokenImpl { "CMR", "TSR", "C21", - "AFC" + "AFC", + "NEC", + "2XM" )); } public SaprolingToken() { - super("Saproling", "1/1 green Saproling creature token"); + super("Saproling Token", "1/1 green Saproling creature token"); availableImageSetCodes = tokenImageSets; cardType.add(CardType.CREATURE); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/SatyrCantBlockToken.java b/Mage/src/main/java/mage/game/permanent/token/SatyrCantBlockToken.java index 89998d219a2..2f2d19714c1 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SatyrCantBlockToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SatyrCantBlockToken.java @@ -13,7 +13,7 @@ import mage.constants.SubType; public final class SatyrCantBlockToken extends TokenImpl { public SatyrCantBlockToken() { - super("Satyr", "1/1 red Satyr creature token with \"This creature can't block.\""); + super("Satyr Token", "1/1 red Satyr creature token with \"This creature can't block.\""); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.SATYR); diff --git a/Mage/src/main/java/mage/game/permanent/token/SatyrNyxSmithElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/SatyrNyxSmithElementalToken.java index 201ea26aeec..643c400a6ed 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SatyrNyxSmithElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SatyrNyxSmithElementalToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.HasteAbility; public final class SatyrNyxSmithElementalToken extends TokenImpl { public SatyrNyxSmithElementalToken() { - super("Elemental", "3/1 red Elemental enchantment creature token with haste"); + super("Elemental Token", "3/1 red Elemental enchantment creature token with haste"); cardType.add(CardType.ENCHANTMENT); cardType.add(CardType.CREATURE); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/SeedGuardianToken.java b/Mage/src/main/java/mage/game/permanent/token/SeedGuardianToken.java index 1be69e9ca0a..6b53ecaaecd 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SeedGuardianToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SeedGuardianToken.java @@ -16,7 +16,7 @@ public final class SeedGuardianToken extends TokenImpl { } public SeedGuardianToken(int xValue) { - super("Elemental", "X/X green Elemental creature token"); + super("Elemental Token", "X/X green Elemental creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.ELEMENTAL); diff --git a/Mage/src/main/java/mage/game/permanent/token/SeizeTheStormElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/SeizeTheStormElementalToken.java index fa33fe5146a..41106539856 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SeizeTheStormElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SeizeTheStormElementalToken.java @@ -24,7 +24,7 @@ public final class SeizeTheStormElementalToken extends TokenImpl { } public SeizeTheStormElementalToken(DynamicValue xValue, Hint hint) { - super("Elemental", "red Elemental creature token with trample and " + + super("Elemental Token", "red Elemental creature token with trample and " + "\"This creature's power and toughness are each equal to the number of instant " + "and sorcery cards in your graveyard plus the number of cards with flashback you own in exile.\""); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/SekKuarDeathkeeperGravebornToken.java b/Mage/src/main/java/mage/game/permanent/token/SekKuarDeathkeeperGravebornToken.java index fd049a066ac..1351021fd8b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SekKuarDeathkeeperGravebornToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SekKuarDeathkeeperGravebornToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.HasteAbility; public final class SekKuarDeathkeeperGravebornToken extends TokenImpl { public SekKuarDeathkeeperGravebornToken() { - super("Graveborn", "3/1 black and red Graveborn creature token with haste"); + super("Graveborn Token", "3/1 black and red Graveborn creature token with haste"); cardType.add(CardType.CREATURE); color.setBlack(true); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/SengirNosferatuBatToken.java b/Mage/src/main/java/mage/game/permanent/token/SengirNosferatuBatToken.java index 409067f34bc..23662c07a3a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SengirNosferatuBatToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SengirNosferatuBatToken.java @@ -27,7 +27,7 @@ import java.util.Arrays; public final class SengirNosferatuBatToken extends TokenImpl { public SengirNosferatuBatToken() { - super("Bat", "1/2 black Bat creature token with flying"); + super("Bat Token", "1/2 black Bat creature token with flying"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.BAT); @@ -85,7 +85,7 @@ class ReturnSengirNosferatuEffect extends OneShotEffect { } Target target = new TargetCardInExile(filter); target.setNotTarget(true); - if (!target.canChoose(source.getSourceId(), source.getControllerId(), game)) { + if (!target.canChoose(source.getControllerId(), source, game)) { return false; } player.chooseTarget(Outcome.PutCreatureInPlay, target, source, game); diff --git a/Mage/src/main/java/mage/game/permanent/token/SerfToken.java b/Mage/src/main/java/mage/game/permanent/token/SerfToken.java index a4f9e5967d7..f09c4693835 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SerfToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SerfToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class SerfToken extends TokenImpl { public SerfToken() { - super("Serf", "0/1 black Serf creature token"); + super("Serf Token", "0/1 black Serf creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.SERF); diff --git a/Mage/src/main/java/mage/game/permanent/token/SerpentGeneratorSnakeToken.java b/Mage/src/main/java/mage/game/permanent/token/SerpentGeneratorSnakeToken.java index 5d28f3acc6c..8b17581037d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SerpentGeneratorSnakeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SerpentGeneratorSnakeToken.java @@ -15,7 +15,7 @@ import mage.constants.SubType; public final class SerpentGeneratorSnakeToken extends TokenImpl { public SerpentGeneratorSnakeToken() { - super("Snake", "1/1 colorless Snake artifact creature token with \"Whenever this creature deals damage to a player, that player gets a poison counter.\""); + super("Snake Token", "1/1 colorless Snake artifact creature token with \"Whenever this creature deals damage to a player, that player gets a poison counter.\""); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.SNAKE); diff --git a/Mage/src/main/java/mage/game/permanent/token/ServoToken.java b/Mage/src/main/java/mage/game/permanent/token/ServoToken.java index 6720a24f2c3..d4777a1be10 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ServoToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ServoToken.java @@ -13,14 +13,14 @@ import java.util.Arrays; public final class ServoToken extends TokenImpl { public ServoToken() { - super("Servo", "1/1 colorless Servo artifact creature token"); + super("Servo Token", "1/1 colorless Servo artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.SERVO); power = new MageInt(1); toughness = new MageInt(1); - availableImageSetCodes = Arrays.asList("C18", "KLD", "WAR", "KHC", "AFC"); + availableImageSetCodes = Arrays.asList("C18", "KLD", "WAR", "KHC", "AFC", "2XM"); } @Override diff --git a/Mage/src/main/java/mage/game/permanent/token/ShapeshifterBlueToken.java b/Mage/src/main/java/mage/game/permanent/token/ShapeshifterBlueToken.java index 853ec5a8d46..4cdf2240060 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ShapeshifterBlueToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ShapeshifterBlueToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class ShapeshifterBlueToken extends TokenImpl { public ShapeshifterBlueToken() { - super("Shapeshifter", "2/2 blue Shapeshifter creature token with changeling"); + super("Shapeshifter Token", "2/2 blue Shapeshifter creature token with changeling"); cardType.add(CardType.CREATURE); subtype.add(SubType.SHAPESHIFTER); color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/ShapeshifterToken.java b/Mage/src/main/java/mage/game/permanent/token/ShapeshifterToken.java index 26f1734143e..940cdb17dba 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ShapeshifterToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ShapeshifterToken.java @@ -21,7 +21,7 @@ public final class ShapeshifterToken extends TokenImpl { } public ShapeshifterToken() { - super("Shapeshifter", "2/2 colorless Shapeshifter creature token with changeling"); + super("Shapeshifter Token", "2/2 colorless Shapeshifter creature token with changeling"); availableImageSetCodes = tokenImageSets; cardType.add(CardType.CREATURE); subtype.add(SubType.SHAPESHIFTER); diff --git a/Mage/src/main/java/mage/game/permanent/token/ShardToken.java b/Mage/src/main/java/mage/game/permanent/token/ShardToken.java index 2f338be839f..82d09efa19d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ShardToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ShardToken.java @@ -18,7 +18,7 @@ import java.util.Arrays; public final class ShardToken extends TokenImpl { public ShardToken() { - super("Shard", "Shard token"); + super("Shard Token", "Shard token"); cardType.add(CardType.ENCHANTMENT); subtype.add(SubType.SHARD); diff --git a/Mage/src/main/java/mage/game/permanent/token/SharkToken.java b/Mage/src/main/java/mage/game/permanent/token/SharkToken.java index 0cbe1538b75..ae816c5dcc2 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SharkToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SharkToken.java @@ -14,7 +14,7 @@ public final class SharkToken extends TokenImpl { this(0); } public SharkToken(int xValue) { - super("Shark", "X/X blue Shark creature token with flying"); + super("Shark Token", "X/X blue Shark creature token with flying"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.SHARK); diff --git a/Mage/src/main/java/mage/game/permanent/token/SheepToken.java b/Mage/src/main/java/mage/game/permanent/token/SheepToken.java index a4233845935..ab2f53d1b02 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SheepToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SheepToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class SheepToken extends TokenImpl { public SheepToken() { - super("Sheep", "0/1 green Sheep creature token"); + super("Sheep Token", "0/1 green Sheep creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.SHEEP); diff --git a/Mage/src/main/java/mage/game/permanent/token/ShrineToken.java b/Mage/src/main/java/mage/game/permanent/token/ShrineToken.java new file mode 100644 index 00000000000..3df8ba38ea0 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/ShrineToken.java @@ -0,0 +1,33 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.Arrays; + +/** + * @author TheElk801 + */ +public final class ShrineToken extends TokenImpl { + + public ShrineToken() { + super("Shrine Token", "1/1 colorless Shrine enchantment creature token"); + cardType.add(CardType.ENCHANTMENT); + cardType.add(CardType.CREATURE); + subtype.add(SubType.SHRINE); + power = new MageInt(1); + toughness = new MageInt(1); + + availableImageSetCodes = Arrays.asList("NEC"); + } + + public ShrineToken(final ShrineToken token) { + super(token); + } + + @Override + public ShrineToken copy() { + return new ShrineToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/SkeletonRegenerateToken.java b/Mage/src/main/java/mage/game/permanent/token/SkeletonRegenerateToken.java index 997691918d7..7f63f3382cc 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SkeletonRegenerateToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SkeletonRegenerateToken.java @@ -12,7 +12,7 @@ import mage.constants.Zone; public final class SkeletonRegenerateToken extends TokenImpl { public SkeletonRegenerateToken() { - super("Skeleton", "1/1 black Skeleton creature token with \"{B}: Regenerate this creature\""); + super("Skeleton Token", "1/1 black Skeleton creature token with \"{B}: Regenerate this creature\""); cardType.add(CardType.CREATURE); this.subtype.add(SubType.SKELETON); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/SkeletonToken.java b/Mage/src/main/java/mage/game/permanent/token/SkeletonToken.java index 237215f4ab6..1124a7c878c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SkeletonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SkeletonToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class SkeletonToken extends TokenImpl { public SkeletonToken() { - super("Skeleton", "1/1 black Skeleton creature token"); + super("Skeleton Token", "1/1 black Skeleton creature token"); cardType.add(CardType.CREATURE); this.subtype.add(SubType.SKELETON); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/SkywiseTeachingsToken.java b/Mage/src/main/java/mage/game/permanent/token/SkywiseTeachingsToken.java index 743fe20171e..25fd6e41d53 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SkywiseTeachingsToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SkywiseTeachingsToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class SkywiseTeachingsToken extends TokenImpl { public SkywiseTeachingsToken() { - super("Djinn Monk", "2/2 blue Djinn Monk creature token with flying"); + super("Djinn Monk Token", "2/2 blue Djinn Monk creature token with flying"); cardType.add(CardType.CREATURE); color.setBlue(true); this.subtype.add(SubType.DJINN); diff --git a/Mage/src/main/java/mage/game/permanent/token/SliverToken.java b/Mage/src/main/java/mage/game/permanent/token/SliverToken.java index a35648a22c7..bcd48365ece 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SliverToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SliverToken.java @@ -14,7 +14,7 @@ import mage.MageInt; public final class SliverToken extends TokenImpl { public SliverToken() { - super("Sliver", "1/1 colorless Sliver creature token"); + super("Sliver Token", "1/1 colorless Sliver creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.SLIVER); power = new MageInt(1); diff --git a/Mage/src/main/java/mage/game/permanent/token/SlugToken.java b/Mage/src/main/java/mage/game/permanent/token/SlugToken.java index 941509cc13d..8fc56ac9329 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SlugToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SlugToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class SlugToken extends TokenImpl { public SlugToken() { - super("Slug", "1/1 black Slug creature token"); + super("Slug Token", "1/1 black Slug creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.SLUG); diff --git a/Mage/src/main/java/mage/game/permanent/token/SmokeBlessingToken.java b/Mage/src/main/java/mage/game/permanent/token/SmokeBlessingToken.java new file mode 100644 index 00000000000..147e3600544 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/SmokeBlessingToken.java @@ -0,0 +1,81 @@ +package mage.game.permanent.token; + +import mage.abilities.Ability; +import mage.abilities.common.DiesAttachedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; + +import java.util.Arrays; + +/** + * @author TheElk801 + */ +public final class SmokeBlessingToken extends TokenImpl { + + public SmokeBlessingToken() { + super( + "Smoke Blessing", "red Aura enchantment token named Smoke Blessing " + + "attached to that creature. Those tokens have enchant creature and " + + "\"When enchanted creature dies, it deals 1 damage to its controller and you create a Treasure token.\"" + ); + cardType.add(CardType.ENCHANTMENT); + color.setRed(true); + subtype.add(SubType.AURA); + + TargetPermanent auraTarget = new TargetPermanent(); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + ability.addTarget(auraTarget); + ability.addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(ability); + + this.addAbility(new DiesAttachedTriggeredAbility(new SmokeBlessingTokenEffect(), "enchanted creature")); + + availableImageSetCodes = Arrays.asList("NEC"); + } + + public SmokeBlessingToken(final SmokeBlessingToken token) { + super(token); + } + + public SmokeBlessingToken copy() { + return new SmokeBlessingToken(this); + } +} + +class SmokeBlessingTokenEffect extends OneShotEffect { + + SmokeBlessingTokenEffect() { + super(Outcome.Benefit); + staticText = "it deals 1 damage to its controller and you create a Treasure token"; + } + + private SmokeBlessingTokenEffect(final SmokeBlessingTokenEffect effect) { + super(effect); + } + + @Override + public SmokeBlessingTokenEffect copy() { + return new SmokeBlessingTokenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = (Permanent) getValue("attachedTo"); + if (permanent != null) { + Player player = game.getPlayer(permanent.getControllerId()); + if (player != null) { + player.damage(1, permanent.getId(), source, game); + } + } + new TreasureToken().putOntoBattlefield(1, game, source); + return true; + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/SnakeToken.java b/Mage/src/main/java/mage/game/permanent/token/SnakeToken.java index 20b5308cf11..716bdfaefd2 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SnakeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SnakeToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class SnakeToken extends TokenImpl { public SnakeToken() { - super("Snake", "1/1 green Snake creature token"); + super("Snake Token", "1/1 green Snake creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.SNAKE); diff --git a/Mage/src/main/java/mage/game/permanent/token/SoldierLifelinkToken.java b/Mage/src/main/java/mage/game/permanent/token/SoldierLifelinkToken.java index 4b8ca53fb20..1a8c6bdb9c6 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SoldierLifelinkToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SoldierLifelinkToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class SoldierLifelinkToken extends TokenImpl { public SoldierLifelinkToken() { - super("Soldier", "1/1 white Soldier creature token with lifelink"); + super("Soldier Token", "1/1 white Soldier creature token with lifelink"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.SOLDIER); diff --git a/Mage/src/main/java/mage/game/permanent/token/SoldierToken.java b/Mage/src/main/java/mage/game/permanent/token/SoldierToken.java index 3c80ef10b36..80ac240481e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SoldierToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SoldierToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class SoldierToken extends TokenImpl { public SoldierToken() { - super("Soldier", "1/1 white Soldier creature token"); + super("Soldier Token", "1/1 white Soldier creature token"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.SOLDIER); @@ -22,7 +22,7 @@ public final class SoldierToken extends TokenImpl { availableImageSetCodes = Arrays.asList("10E", "M15", "C14", "ORI", "ALA", "DDF", "THS", "M12", "M13", "MM2", "MMA", "RTR", "SOM", "DDO", "M10", "ORI", "EMN", "EMA", "CN2", "C16", "MM3", "E01", - "DOM", "MH1", "M20", "C20", "M21", "CMR", "KHC", "TSR"); + "DOM", "MH1", "M20", "C20", "M21", "CMR", "KHC", "TSR", "2XM"); } public SoldierToken(final SoldierToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/SoldierTokenWithHaste.java b/Mage/src/main/java/mage/game/permanent/token/SoldierTokenWithHaste.java index 14c3cc05998..31e5880338b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SoldierTokenWithHaste.java +++ b/Mage/src/main/java/mage/game/permanent/token/SoldierTokenWithHaste.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class SoldierTokenWithHaste extends TokenImpl { public SoldierTokenWithHaste() { - super("Soldier", "1/1 red and white Soldier creature token with haste"); + super("Soldier Token", "1/1 red and white Soldier creature token with haste"); cardType.add(CardType.CREATURE); color.setWhite(true); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/SoldierVigilanceToken.java b/Mage/src/main/java/mage/game/permanent/token/SoldierVigilanceToken.java index 34a79a9df8c..beac376b0bf 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SoldierVigilanceToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SoldierVigilanceToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class SoldierVigilanceToken extends TokenImpl { public SoldierVigilanceToken() { - super("Soldier", "2/2 white Soldier creature token with vigilance"); + super("Soldier Token", "2/2 white Soldier creature token with vigilance"); cardType.add(CardType.CREATURE); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/SorinLordOfInnistradVampireToken.java b/Mage/src/main/java/mage/game/permanent/token/SorinLordOfInnistradVampireToken.java index 9e81cc4e87b..c9fd2d762a6 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SorinLordOfInnistradVampireToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SorinLordOfInnistradVampireToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.LifelinkAbility; public final class SorinLordOfInnistradVampireToken extends TokenImpl { public SorinLordOfInnistradVampireToken() { - super("Vampire", "1/1 black Vampire creature token with lifelink"); + super("Vampire Token", "1/1 black Vampire creature token with lifelink"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.VAMPIRE); diff --git a/Mage/src/main/java/mage/game/permanent/token/SorinSolemnVisitorVampireToken.java b/Mage/src/main/java/mage/game/permanent/token/SorinSolemnVisitorVampireToken.java index bde1506ce58..4b9a4a859f3 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SorinSolemnVisitorVampireToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SorinSolemnVisitorVampireToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class SorinSolemnVisitorVampireToken extends TokenImpl { public SorinSolemnVisitorVampireToken() { - super("Vampire", "2/2 black Vampire creature token with flying"); + super("Vampire Token", "2/2 black Vampire creature token with flying"); setOriginalExpansionSetCode("KTK"); cardType.add(CardType.CREATURE); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/SoundTheCallToken.java b/Mage/src/main/java/mage/game/permanent/token/SoundTheCallToken.java index 77c4b6aa63e..b889d6ced45 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SoundTheCallToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SoundTheCallToken.java @@ -26,7 +26,7 @@ public final class SoundTheCallToken extends TokenImpl { } public SoundTheCallToken() { - super("Wolf", "1/1 green Wolf creature token. It has \"This creature gets +1/+1 for each card named Sound the Call in each graveyard.\""); + super("Wolf Token", "1/1 green Wolf creature token. It has \"This creature gets +1/+1 for each card named Sound the Call in each graveyard.\""); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.WOLF); diff --git a/Mage/src/main/java/mage/game/permanent/token/SparkElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/SparkElementalToken.java index 1cc0a518906..50e2453f631 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SparkElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SparkElementalToken.java @@ -8,6 +8,8 @@ import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.TrampleAbility; import mage.constants.TargetController; +import java.util.Arrays; + /** * * @author spjspj @@ -15,7 +17,7 @@ import mage.constants.TargetController; public final class SparkElementalToken extends TokenImpl { public SparkElementalToken() { - super("Spark Elemental", "3/1 red Elemental creature token named Spark Elemental with trample, haste, and \"At the beginning of the end step, sacrifice Spark Elemental.\""); + super("Spark Elemental", "3/1 red Elemental creature token named Spark Elemental. It has trample, haste, and \"At the beginning of the end step, sacrifice Spark Elemental.\""); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.ELEMENTAL); @@ -25,6 +27,8 @@ public final class SparkElementalToken extends TokenImpl { this.addAbility(TrampleAbility.getInstance()); this.addAbility(HasteAbility.getInstance()); this.addAbility(new BeginningOfEndStepTriggeredAbility(new SacrificeSourceEffect(), TargetController.ANY, false)); + + availableImageSetCodes = Arrays.asList("UMA"); } public SparkElementalToken(final SparkElementalToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/SpawningGroundsBeastToken.java b/Mage/src/main/java/mage/game/permanent/token/SpawningGroundsBeastToken.java index bf19754bdd6..92c26afcb2e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SpawningGroundsBeastToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SpawningGroundsBeastToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class SpawningGroundsBeastToken extends TokenImpl { public SpawningGroundsBeastToken() { - super("Beast", "5/5 green Beast creature token with trample"); + super("Beast Token", "5/5 green Beast creature token with trample"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.BEAST); diff --git a/Mage/src/main/java/mage/game/permanent/token/SpawningPitToken.java b/Mage/src/main/java/mage/game/permanent/token/SpawningPitToken.java index f81e52f44b9..daf1e9e07f5 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SpawningPitToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SpawningPitToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class SpawningPitToken extends TokenImpl { public SpawningPitToken() { - super("Spawn", "2/2 colorless Spawn artifact creature token"); + super("Spawn Token", "2/2 colorless Spawn artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); this.subtype.add(SubType.SPAWN); diff --git a/Mage/src/main/java/mage/game/permanent/token/SpiderToken.java b/Mage/src/main/java/mage/game/permanent/token/SpiderToken.java index eab04a5ea3f..78a86d83fdd 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SpiderToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SpiderToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class SpiderToken extends TokenImpl { public SpiderToken() { - super("Spider", "1/2 green Spider creature token with reach"); + super("Spider Token", "1/2 green Spider creature token with reach"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.SPIDER); @@ -22,7 +22,7 @@ public final class SpiderToken extends TokenImpl { this.addAbility(ReachAbility.getInstance()); - availableImageSetCodes.addAll(Arrays.asList("C15", "EMN", "ISD", "SHM", "MH1", "THB", "MID")); + availableImageSetCodes.addAll(Arrays.asList("C15", "EMN", "ISD", "SHM", "MH1", "THB", "MID", "UMA")); } public SpiderToken(final SpiderToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/SpikeToken.java b/Mage/src/main/java/mage/game/permanent/token/SpikeToken.java index 3c9a24cefc6..841427990a8 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SpikeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SpikeToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class SpikeToken extends TokenImpl { public SpikeToken() { - super("Spike", "1/1 green Spike creature token"); + super("Spike Token", "1/1 green Spike creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.SPIKE); diff --git a/Mage/src/main/java/mage/game/permanent/token/Spirit22Token.java b/Mage/src/main/java/mage/game/permanent/token/Spirit22Token.java new file mode 100644 index 00000000000..8ab0b9c707f --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/Spirit22Token.java @@ -0,0 +1,32 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.FlyingAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * + * @author weirddan455 + */ +public class Spirit22Token extends TokenImpl { + + public Spirit22Token() { + super("Spirit Token", "2/2 white Spirit creature token with flying"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.SPIRIT); + color.setWhite(true); + power = new MageInt(2); + toughness = new MageInt(2); + addAbility(FlyingAbility.getInstance()); + } + + private Spirit22Token(final Spirit22Token token) { + super(token); + } + + @Override + public Spirit22Token copy() { + return new Spirit22Token(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/Spirit32Token.java b/Mage/src/main/java/mage/game/permanent/token/Spirit32Token.java index 22716ab5f74..b7d4d8e7e29 100644 --- a/Mage/src/main/java/mage/game/permanent/token/Spirit32Token.java +++ b/Mage/src/main/java/mage/game/permanent/token/Spirit32Token.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class Spirit32Token extends TokenImpl { public Spirit32Token() { - super("Spirit", "3/2 red and white Spirit creature token"); + super("Spirit Token", "3/2 red and white Spirit creature token"); cardType.add(CardType.CREATURE); color.setRed(true); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/SpiritBlueToken.java b/Mage/src/main/java/mage/game/permanent/token/SpiritBlueToken.java index 6cd7374debe..836d21d1efe 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SpiritBlueToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SpiritBlueToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class SpiritBlueToken extends TokenImpl { public SpiritBlueToken() { - super("Spirit", "1/1 blue Spirit creature token with flying"); + super("Spirit Token", "1/1 blue Spirit creature token with flying"); cardType.add(CardType.CREATURE); subtype.add(SubType.SPIRIT); color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/SpiritClericToken.java b/Mage/src/main/java/mage/game/permanent/token/SpiritClericToken.java index 0f69fd243c9..f514b78e3eb 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SpiritClericToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SpiritClericToken.java @@ -21,7 +21,7 @@ import java.util.Arrays; public class SpiritClericToken extends TokenImpl { public SpiritClericToken() { - super("Spirit Cleric", "white Spirit Cleric creature token with \"This creature's power and toughness are each equal to the number of Spirits you control.\""); + super("Spirit Cleric Token", "white Spirit Cleric creature token with \"This creature's power and toughness are each equal to the number of Spirits you control.\""); cardType.add(CardType.CREATURE); subtype.add(SubType.SPIRIT); subtype.add(SubType.CLERIC); diff --git a/Mage/src/main/java/mage/game/permanent/token/SpiritGreenToken.java b/Mage/src/main/java/mage/game/permanent/token/SpiritGreenToken.java index 25caf91f278..a9490ec0f9a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SpiritGreenToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SpiritGreenToken.java @@ -10,7 +10,7 @@ import mage.constants.SubType; public final class SpiritGreenToken extends TokenImpl { public SpiritGreenToken() { - super("Spirit token", "4/5 green Spirit creature token"); + super("Spirit Token", "4/5 green Spirit creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.SPIRIT); color.setGreen(true); @@ -18,6 +18,15 @@ public final class SpiritGreenToken extends TokenImpl { toughness = new MageInt(5); } + @Override + public void setExpansionSetCodeForImage(String code) { + super.setExpansionSetCodeForImage(code); + + if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("NEO")) { + setTokenType(3); + } + } + public SpiritGreenToken(final SpiritGreenToken token) { super(token); } diff --git a/Mage/src/main/java/mage/game/permanent/token/SpiritGreenXToken.java b/Mage/src/main/java/mage/game/permanent/token/SpiritGreenXToken.java index e329aa24ee0..e78a58f19f9 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SpiritGreenXToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SpiritGreenXToken.java @@ -4,18 +4,31 @@ import mage.MageInt; import mage.constants.CardType; import mage.constants.SubType; +import java.util.Arrays; + /** * @author TheElk801 */ public final class SpiritGreenXToken extends TokenImpl { public SpiritGreenXToken(int xValue) { - super("Spirit token", "X/X green Spirit creature token"); + super("Spirit Token", "X/X green Spirit creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.SPIRIT); color.setGreen(true); power = new MageInt(xValue); toughness = new MageInt(xValue); + + availableImageSetCodes = Arrays.asList("NEO"); + } + + @Override + public void setExpansionSetCodeForImage(String code) { + super.setExpansionSetCodeForImage(code); + + if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("NEO")) { + setTokenType(2); + } } public SpiritGreenXToken(final SpiritGreenXToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/SpiritRedToken.java b/Mage/src/main/java/mage/game/permanent/token/SpiritRedToken.java index 004ced270ca..9ad263f913c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SpiritRedToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SpiritRedToken.java @@ -5,19 +5,32 @@ import mage.abilities.keyword.MenaceAbility; import mage.constants.CardType; import mage.constants.SubType; +import java.util.Arrays; + /** * @author TheElk801 */ public final class SpiritRedToken extends TokenImpl { public SpiritRedToken() { - super("Spirit token", "2/2 red Spirit creature token with menace"); + super("Spirit Token", "2/2 red Spirit creature token with menace"); cardType.add(CardType.CREATURE); subtype.add(SubType.SPIRIT); color.setRed(true); power = new MageInt(2); toughness = new MageInt(2); addAbility(new MenaceAbility()); + + availableImageSetCodes = Arrays.asList("NEO"); + } + + @Override + public void setExpansionSetCodeForImage(String code) { + super.setExpansionSetCodeForImage(code); + + if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("NEO")) { + setTokenType(4); + } } public SpiritRedToken(final SpiritRedToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/SpiritToken.java b/Mage/src/main/java/mage/game/permanent/token/SpiritToken.java index fe315474b55..7878427dd4b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SpiritToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SpiritToken.java @@ -12,13 +12,13 @@ import java.util.Arrays; public final class SpiritToken extends TokenImpl { public SpiritToken() { - super("Spirit", "1/1 colorless Spirit creature token"); + super("Spirit Token", "1/1 colorless Spirit creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.SPIRIT); power = new MageInt(1); toughness = new MageInt(1); - availableImageSetCodes = Arrays.asList("C19", "CHK", "EMA", "EXP", "SOK", "V12", "VOC"); + availableImageSetCodes = Arrays.asList("C19", "CHK", "EMA", "EXP", "NEO", "SOK", "V12", "VOC"); } @Override @@ -32,6 +32,10 @@ public final class SpiritToken extends TokenImpl { if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("EMA")) { setTokenType(2); } + + if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("NEO")) { + setTokenType(1); + } } public SpiritToken(final SpiritToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/SpiritWhiteToken.java b/Mage/src/main/java/mage/game/permanent/token/SpiritWhiteToken.java index c2d05a2f959..271419f23f1 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SpiritWhiteToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SpiritWhiteToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class SpiritWhiteToken extends TokenImpl { public SpiritWhiteToken() { - super("Spirit", "1/1 white Spirit creature token with flying"); + super("Spirit Token", "1/1 white Spirit creature token with flying"); cardType.add(CardType.CREATURE); subtype.add(SubType.SPIRIT); color.setWhite(true); @@ -24,7 +24,7 @@ public final class SpiritWhiteToken extends TokenImpl { availableImageSetCodes = Arrays.asList("AVR", "C14", "CNS", "DDC", "DDK", "FRF", "ISD", "KTK", "M15", "MM2", "SHM", "SOI", "EMA", "C16", "MM3", "CMA", "E01", "ANA", "GPT", "RAV", "EMN", "RNA", "M20", "C20", "CMR", "KHM", - "MID", "VOW"); + "MID", "VOW", "UMA"); } @Override @@ -39,6 +39,9 @@ public final class SpiritWhiteToken extends TokenImpl { if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("EMA")) { setTokenType(2); } + if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("UMA")) { + setTokenType(1); + } } public SpiritWhiteToken(final SpiritWhiteToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/SplinterToken.java b/Mage/src/main/java/mage/game/permanent/token/SplinterToken.java index bc5bfdcbca8..2597d256c65 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SplinterToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SplinterToken.java @@ -15,7 +15,7 @@ import mage.abilities.keyword.FlyingAbility; public final class SplinterToken extends TokenImpl { public SplinterToken() { - super("Splinter", "1/1 green Splinter creature token"); + super("Splinter Token", "1/1 green Splinter creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.SPLINTER); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/SpoilsOfBloodHorrorToken.java b/Mage/src/main/java/mage/game/permanent/token/SpoilsOfBloodHorrorToken.java index e49b5949ad9..920b1b0421e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SpoilsOfBloodHorrorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SpoilsOfBloodHorrorToken.java @@ -15,7 +15,7 @@ public final class SpoilsOfBloodHorrorToken extends TokenImpl { this(1); } public SpoilsOfBloodHorrorToken(int xValue) { - super("Horror", "X/X black Horror creature token"); + super("Horror Token", "X/X black Horror creature token"); setOriginalExpansionSetCode("C14"); cardType.add(CardType.CREATURE); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/SpyMasterGoblinToken.java b/Mage/src/main/java/mage/game/permanent/token/SpyMasterGoblinToken.java index da3cb49d28b..6dbf66a3124 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SpyMasterGoblinToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SpyMasterGoblinToken.java @@ -1,16 +1,13 @@ - - package mage.game.permanent.token; -import mage.constants.CardType; -import mage.constants.SubType; + import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.combat.AttacksIfAbleAllEffect; +import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; +import mage.constants.SubType; +import mage.filter.StaticFilters; /** * @@ -18,22 +15,15 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class SpyMasterGoblinToken extends TokenImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures you control"); - - static { - filter.add(TargetController.YOU.getControllerPredicate()); - } - public SpyMasterGoblinToken() { - super("Goblin", "1/1 red Goblin creature token with \"Creatures you control attack each combat if able.\""); + super("Goblin Token", "1/1 red Goblin creature token with \"Creatures you control attack each combat if able.\""); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.GOBLIN); power = new MageInt(1); toughness = new MageInt(1); - Effect effect = new AttacksIfAbleAllEffect(filter, Duration.WhileOnBattlefield, true); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + this.addAbility(new SimpleStaticAbility(new AttacksIfAbleAllEffect(StaticFilters.FILTER_CONTROLLED_CREATURES))); } public SpyMasterGoblinToken(final SpyMasterGoblinToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/SquirrelToken.java b/Mage/src/main/java/mage/game/permanent/token/SquirrelToken.java index c346cd8eb9d..f33268a59f6 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SquirrelToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SquirrelToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class SquirrelToken extends TokenImpl { public SquirrelToken() { - super("Squirrel", "1/1 green Squirrel creature token"); + super("Squirrel Token", "1/1 green Squirrel creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.SQUIRREL); color.setGreen(true); @@ -20,7 +20,7 @@ public final class SquirrelToken extends TokenImpl { toughness = new MageInt(1); availableImageSetCodes = Arrays.asList("CMD", "CNS", "ODY", "PCY", "TOR", "ULG", "UNH", "WMA", - "WTH", "MH1", "MH2"); + "WTH", "MH1", "MH2", "2XM"); } public SquirrelToken(final SquirrelToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/StarfishToken.java b/Mage/src/main/java/mage/game/permanent/token/StarfishToken.java index 7d355ceff39..77329e78276 100644 --- a/Mage/src/main/java/mage/game/permanent/token/StarfishToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/StarfishToken.java @@ -15,7 +15,7 @@ public final class StarfishToken extends TokenImpl { } public StarfishToken(String setCode, int tokenType) { - super("Starfish", "0/1 blue Starfish creature token"); + super("Starfish Token", "0/1 blue Starfish creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.STARFISH); color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/StitcherGeralfZombieToken.java b/Mage/src/main/java/mage/game/permanent/token/StitcherGeralfZombieToken.java index 5b36fa03997..fc63461b683 100644 --- a/Mage/src/main/java/mage/game/permanent/token/StitcherGeralfZombieToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/StitcherGeralfZombieToken.java @@ -16,7 +16,7 @@ public final class StitcherGeralfZombieToken extends TokenImpl { } public StitcherGeralfZombieToken(int xValue) { - super("Zombie", "X/X blue Zombie creature token"); + super("Zombie Token", "X/X blue Zombie creature token"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.ZOMBIE); diff --git a/Mage/src/main/java/mage/game/permanent/token/StitchersApprenticeHomunculusToken.java b/Mage/src/main/java/mage/game/permanent/token/StitchersApprenticeHomunculusToken.java index fa83cda6dfc..387e3d0f287 100644 --- a/Mage/src/main/java/mage/game/permanent/token/StitchersApprenticeHomunculusToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/StitchersApprenticeHomunculusToken.java @@ -5,6 +5,8 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.MageInt; +import java.util.Arrays; + /** * * @author spjspj @@ -12,12 +14,14 @@ import mage.MageInt; public final class StitchersApprenticeHomunculusToken extends TokenImpl { public StitchersApprenticeHomunculusToken() { - super("Homunculus", "2/2 blue Homunculus creature"); + super("Homunculus Token", "2/2 blue Homunculus creature"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.HOMUNCULUS); power = new MageInt(2); toughness = new MageInt(2); + + availableImageSetCodes = Arrays.asList("UMA"); } public StitchersApprenticeHomunculusToken(final StitchersApprenticeHomunculusToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/StoneTrapIdolToken.java b/Mage/src/main/java/mage/game/permanent/token/StoneTrapIdolToken.java index bad943aa929..328bae3f3ee 100644 --- a/Mage/src/main/java/mage/game/permanent/token/StoneTrapIdolToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/StoneTrapIdolToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.TrampleAbility; public final class StoneTrapIdolToken extends TokenImpl { public StoneTrapIdolToken() { - super("Construct", "6/12 colorless Construct artifact creature token with trample"); + super("Construct Token", "6/12 colorless Construct artifact creature token with trample"); cardType.add(CardType.CREATURE); cardType.add(CardType.ARTIFACT); subtype.add(SubType.CONSTRUCT); diff --git a/Mage/src/main/java/mage/game/permanent/token/SubterraneanTremorsLizardToken.java b/Mage/src/main/java/mage/game/permanent/token/SubterraneanTremorsLizardToken.java index e5624079b53..7f97a66eee9 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SubterraneanTremorsLizardToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SubterraneanTremorsLizardToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class SubterraneanTremorsLizardToken extends TokenImpl { public SubterraneanTremorsLizardToken() { - super("Lizard", "an 8/8 red Lizard creature token"); + super("Lizard Token", "an 8/8 red Lizard creature token"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.LIZARD); diff --git a/Mage/src/main/java/mage/game/permanent/token/SurvivorToken.java b/Mage/src/main/java/mage/game/permanent/token/SurvivorToken.java index 71797e9ff24..11961a865e1 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SurvivorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SurvivorToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class SurvivorToken extends TokenImpl { public SurvivorToken() { - super("Survivor", "1/1 red Survivor creature token"); + super("Survivor Token", "1/1 red Survivor creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.SURVIVOR); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/SwanSongBirdToken.java b/Mage/src/main/java/mage/game/permanent/token/SwanSongBirdToken.java index a2c8fe91a49..4292f212bc6 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SwanSongBirdToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SwanSongBirdToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class SwanSongBirdToken extends TokenImpl { public SwanSongBirdToken() { - super("Bird", "2/2 blue Bird creature token with flying"); + super("Bird Token", "2/2 blue Bird creature token with flying"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.BIRD); diff --git a/Mage/src/main/java/mage/game/permanent/token/SylvanOfferingTreefolkToken.java b/Mage/src/main/java/mage/game/permanent/token/SylvanOfferingTreefolkToken.java index 73077e75888..2d384188a59 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SylvanOfferingTreefolkToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SylvanOfferingTreefolkToken.java @@ -15,7 +15,7 @@ public final class SylvanOfferingTreefolkToken extends TokenImpl { this(1); } public SylvanOfferingTreefolkToken(int xValue) { - super("Treefolk", "X/X green Treefolk creature token"); + super("Treefolk Token", "X/X green Treefolk creature token"); setOriginalExpansionSetCode("C14"); cardType.add(CardType.CREATURE); subtype.add(SubType.TREEFOLK); diff --git a/Mage/src/main/java/mage/game/permanent/token/TamiyosNotebookToken.java b/Mage/src/main/java/mage/game/permanent/token/TamiyosNotebookToken.java new file mode 100644 index 00000000000..62320faa451 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/TamiyosNotebookToken.java @@ -0,0 +1,34 @@ +package mage.game.permanent.token; + +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.constants.CardType; +import mage.constants.SuperType; +import mage.filter.FilterCard; + +/** + * @author TheElk801 + */ +public final class TamiyosNotebookToken extends TokenImpl { + + private static final FilterCard filter = new FilterCard("spells"); + + public TamiyosNotebookToken() { + super("Tamiyo's Notebook", "Tamiyo's Notebook, a legendary colorless artifact token with \"Spells you cast cost {2} less to cast\" and \"{T}: Draw a card.\""); + addSuperType(SuperType.LEGENDARY); + this.cardType.add(CardType.ARTIFACT); + this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 2))); + this.addAbility(new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new TapSourceCost())); + } + + public TamiyosNotebookToken(final TamiyosNotebookToken token) { + super(token); + } + + public TamiyosNotebookToken copy() { + return new TamiyosNotebookToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/TatsumaDragonToken.java b/Mage/src/main/java/mage/game/permanent/token/TatsumaDragonToken.java index 35221bece39..16d194523a4 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TatsumaDragonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TatsumaDragonToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class TatsumaDragonToken extends TokenImpl { public TatsumaDragonToken() { - super("Dragon Spirit", "5/5 blue Dragon Spirit creature token with flying"); + super("Dragon Spirit Token", "5/5 blue Dragon Spirit creature token with flying"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.DRAGON); diff --git a/Mage/src/main/java/mage/game/permanent/token/TemptWithVengeanceElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/TemptWithVengeanceElementalToken.java index 8fb2edb7950..a039d095e70 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TemptWithVengeanceElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TemptWithVengeanceElementalToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.HasteAbility; public final class TemptWithVengeanceElementalToken extends TokenImpl { public TemptWithVengeanceElementalToken() { - super("Elemental", "1/1 red Elemental creature tokens with haste"); + super("Elemental Token", "1/1 red Elemental creature tokens with haste"); cardType.add(CardType.CREATURE); subtype.add(SubType.ELEMENTAL); diff --git a/Mage/src/main/java/mage/game/permanent/token/TentacleToken.java b/Mage/src/main/java/mage/game/permanent/token/TentacleToken.java index 946da812ab5..122f49bae25 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TentacleToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TentacleToken.java @@ -10,7 +10,7 @@ import mage.constants.SubType; public final class TentacleToken extends TokenImpl { public TentacleToken() { - super("Tentacle", "1/1 blue Tentacle creature token"); + super("Tentacle Token", "1/1 blue Tentacle creature token"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.TENTACLE); diff --git a/Mage/src/main/java/mage/game/permanent/token/TetraviteToken.java b/Mage/src/main/java/mage/game/permanent/token/TetraviteToken.java index 596d9d86953..4d93b4dd303 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TetraviteToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TetraviteToken.java @@ -15,7 +15,7 @@ import mage.game.events.GameEvent; public final class TetraviteToken extends TokenImpl { public TetraviteToken() { - super("Tetravite", "1/1 colorless Tetravite artifact creature token with flying and \"This creature can't be enchanted.\""); + super("Tetravite Token", "1/1 colorless Tetravite artifact creature token with flying and \"This creature can't be enchanted.\""); cardType.add(CardType.CREATURE); cardType.add(CardType.ARTIFACT); subtype.add(SubType.TETRAVITE); diff --git a/Mage/src/main/java/mage/game/permanent/token/TeyoToken.java b/Mage/src/main/java/mage/game/permanent/token/TeyoToken.java index 251ec6ca7dc..016bd9db07e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TeyoToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TeyoToken.java @@ -8,7 +8,7 @@ import mage.constants.SubType; public final class TeyoToken extends TokenImpl { public TeyoToken() { - super("Wall", "0/3 white Wall creature token with defender"); + super("Wall Token", "0/3 white Wall creature token with defender"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.WALL); diff --git a/Mage/src/main/java/mage/game/permanent/token/ThatcherHumanToken.java b/Mage/src/main/java/mage/game/permanent/token/ThatcherHumanToken.java index dfa8d843bff..355f242a783 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ThatcherHumanToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ThatcherHumanToken.java @@ -14,7 +14,7 @@ import mage.constants.SubType; public final class ThatcherHumanToken extends TokenImpl { public ThatcherHumanToken() { - super("Human", "1/1 red Human creature token with haste"); + super("Human Token", "1/1 red Human creature token with haste"); this.cardType.add(CardType.CREATURE); this.subtype.add(SubType.HUMAN); addAbility(HasteAbility.getInstance()); diff --git a/Mage/src/main/java/mage/game/permanent/token/TheLocustGodInsectToken.java b/Mage/src/main/java/mage/game/permanent/token/TheLocustGodInsectToken.java index c22ec75b438..a9edb85c299 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TheLocustGodInsectToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TheLocustGodInsectToken.java @@ -14,7 +14,7 @@ import java.util.Arrays; public final class TheLocustGodInsectToken extends TokenImpl { public TheLocustGodInsectToken() { - super("Insect", "1/1 blue and red Insect creature token with flying and haste"); + super("Insect Token", "1/1 blue and red Insect creature token with flying and haste"); cardType.add(CardType.CREATURE); color.setBlue(true); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/ThopterColorlessToken.java b/Mage/src/main/java/mage/game/permanent/token/ThopterColorlessToken.java index db8a0b754a3..2fbc4251513 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ThopterColorlessToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ThopterColorlessToken.java @@ -14,7 +14,7 @@ import java.util.Arrays; public final class ThopterColorlessToken extends TokenImpl { public ThopterColorlessToken() { - super("Thopter", "1/1 colorless Thopter artifact creature token with flying"); + super("Thopter Token", "1/1 colorless Thopter artifact creature token with flying"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.THOPTER); @@ -24,7 +24,7 @@ public final class ThopterColorlessToken extends TokenImpl { addAbility(FlyingAbility.getInstance()); availableImageSetCodes = Arrays.asList("C18", "EXO", "KLD", "MBS", "ORI", "VMA", "M19", "ZNC", - "KHC", "C21", "MH2", "AFC", "VOC"); + "KHC", "C21", "MH2", "AFC", "VOC", "NEC", "2XM"); } @Override @@ -40,6 +40,9 @@ public final class ThopterColorlessToken extends TokenImpl { if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("ORI")) { this.setTokenType(RandomUtil.nextInt(2) + 1); } + if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("2XM")) { + this.setTokenType(1); + } } diff --git a/Mage/src/main/java/mage/game/permanent/token/ThopterToken.java b/Mage/src/main/java/mage/game/permanent/token/ThopterToken.java index f422785dc96..11b0a328478 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ThopterToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ThopterToken.java @@ -6,6 +6,8 @@ import mage.constants.SubType; import mage.MageInt; import mage.abilities.keyword.FlyingAbility; +import java.util.Arrays; + /** * * @author spjspj @@ -13,7 +15,7 @@ import mage.abilities.keyword.FlyingAbility; public final class ThopterToken extends TokenImpl { public ThopterToken() { - super("Thopter", "1/1 blue Thopter artifact creature tokens with flying"); + super("Thopter Token", "1/1 blue Thopter artifact creature token with flying"); cardType.add(CardType.CREATURE); cardType.add(CardType.ARTIFACT); color.setBlue(true); @@ -21,6 +23,17 @@ public final class ThopterToken extends TokenImpl { power = new MageInt(1); toughness = new MageInt(1); this.addAbility(FlyingAbility.getInstance()); + + availableImageSetCodes = Arrays.asList("ALA", "C16", "C18", "2XM"); + } + + @Override + public void setExpansionSetCodeForImage(String code) { + super.setExpansionSetCodeForImage(code); + + if (getOriginalExpansionSetCode().equals("2XM")) { + this.setTokenType(2); + } } public ThopterToken(final ThopterToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/ThrullToken.java b/Mage/src/main/java/mage/game/permanent/token/ThrullToken.java index a417cea7211..6f204e6e32a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ThrullToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ThrullToken.java @@ -22,7 +22,7 @@ public final class ThrullToken extends TokenImpl { } public ThrullToken() { - super("Thrull", "1/1 black Thrull creature token"); + super("Thrull Token", "1/1 black Thrull creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.THRULL); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/TidalWaveWallToken.java b/Mage/src/main/java/mage/game/permanent/token/TidalWaveWallToken.java index 39d242a8ce5..ee2ffdffa83 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TidalWaveWallToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TidalWaveWallToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.DefenderAbility; public final class TidalWaveWallToken extends TokenImpl { public TidalWaveWallToken() { - super("Wall", "5/5 blue Wall creature token with defender"); + super("Wall Token", "5/5 blue Wall creature token with defender"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.WALL); diff --git a/Mage/src/main/java/mage/game/permanent/token/TilonallisSummonerElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/TilonallisSummonerElementalToken.java deleted file mode 100644 index 57ec5377890..00000000000 --- a/Mage/src/main/java/mage/game/permanent/token/TilonallisSummonerElementalToken.java +++ /dev/null @@ -1,31 +0,0 @@ -package mage.game.permanent.token; - -import mage.MageInt; -import mage.constants.CardType; -import mage.constants.SubType; - -/** - * @author LevelX2 - */ -public final class TilonallisSummonerElementalToken extends TokenImpl { - - public TilonallisSummonerElementalToken() { - super("Elemental", "1/1 red Elemental creature tokens"); - cardType.add(CardType.CREATURE); - subtype.add(SubType.ELEMENTAL); - color.setRed(true); - power = new MageInt(1); - toughness = new MageInt(1); - - setTokenType(2); - } - - public TilonallisSummonerElementalToken(final TilonallisSummonerElementalToken token) { - super(token); - } - - @Override - public TilonallisSummonerElementalToken copy() { - return new TilonallisSummonerElementalToken(this); - } -} diff --git a/Mage/src/main/java/mage/game/permanent/token/TitanForgeGolemToken.java b/Mage/src/main/java/mage/game/permanent/token/TitanForgeGolemToken.java index 70bfd582cb2..29ab5f49c2e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TitanForgeGolemToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TitanForgeGolemToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class TitanForgeGolemToken extends TokenImpl { public TitanForgeGolemToken() { - super("Golem", "9/9 colorless Golem artifact creature token"); + super("Golem Token", "9/9 colorless Golem artifact creature token"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.GOLEM); diff --git a/Mage/src/main/java/mage/game/permanent/token/TitaniaProtectorOfArgothElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/TitaniaProtectorOfArgothElementalToken.java index 39b7c418008..7aa39f49d18 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TitaniaProtectorOfArgothElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TitaniaProtectorOfArgothElementalToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class TitaniaProtectorOfArgothElementalToken extends TokenImpl { public TitaniaProtectorOfArgothElementalToken() { - super("Elemental", "5/3 green Elemental creature token"); + super("Elemental Token", "5/3 green Elemental creature token"); this.cardType.add(CardType.CREATURE); this.color.setGreen(true); this.subtype.add(SubType.ELEMENTAL); diff --git a/Mage/src/main/java/mage/game/permanent/token/Token.java b/Mage/src/main/java/mage/game/permanent/token/Token.java index 02c5b36bc51..d13b52d8879 100644 --- a/Mage/src/main/java/mage/game/permanent/token/Token.java +++ b/Mage/src/main/java/mage/game/permanent/token/Token.java @@ -21,8 +21,6 @@ public interface Token extends MageObject { String getDescription(); - UUID getLastAddedToken(); - List getLastAddedTokenIds(); void addAbility(Ability ability); diff --git a/Mage/src/main/java/mage/game/permanent/token/TokenImpl.java b/Mage/src/main/java/mage/game/permanent/token/TokenImpl.java index a323b1af453..ca2655b9cc9 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TokenImpl.java +++ b/Mage/src/main/java/mage/game/permanent/token/TokenImpl.java @@ -30,7 +30,6 @@ public abstract class TokenImpl extends MageObjectImpl implements Token { protected String description; private final ArrayList lastAddedTokenIds = new ArrayList<>(); - private UUID lastAddedTokenId; private int tokenType; private String originalCardNumber; private String originalExpansionSetCode; @@ -76,7 +75,6 @@ public abstract class TokenImpl extends MageObjectImpl implements Token { super(token); this.description = token.description; this.tokenType = token.tokenType; - this.lastAddedTokenId = token.lastAddedTokenId; this.lastAddedTokenIds.addAll(token.lastAddedTokenIds); this.originalCardNumber = token.originalCardNumber; this.originalExpansionSetCode = token.originalExpansionSetCode; @@ -113,11 +111,6 @@ public abstract class TokenImpl extends MageObjectImpl implements Token { return description; } - @Override - public UUID getLastAddedToken() { - return lastAddedTokenId; - } - @Override public List getLastAddedTokenIds() { return new ArrayList<>(lastAddedTokenIds); @@ -238,6 +231,14 @@ public abstract class TokenImpl extends MageObjectImpl implements Token { } } putOntoBattlefieldHelper(event, game, source, tapped, attacking, attackedPlayer, created); + event.getTokens() + .keySet() + .stream() + .map(Token::getLastAddedTokenIds) + .flatMap(Collection::stream) + .distinct() + .filter(uuid -> !this.lastAddedTokenIds.contains(uuid)) + .forEach(this.lastAddedTokenIds::add); return true; } return false; @@ -293,7 +294,6 @@ public abstract class TokenImpl extends MageObjectImpl implements Token { // keep tokens ids if (token instanceof TokenImpl) { ((TokenImpl) token).lastAddedTokenIds.add(permanent.getId()); - ((TokenImpl) token).lastAddedTokenId = permanent.getId(); } // created token events @@ -349,7 +349,7 @@ public abstract class TokenImpl extends MageObjectImpl implements Token { // select new target auraTarget.setNotTarget(true); - if (!controller.choose(auraOutcome, auraTarget, source.getSourceId(), game)) { + if (!controller.choose(auraOutcome, auraTarget, source, game)) { break; } UUID targetId = auraTarget.getFirstTarget(); diff --git a/Mage/src/main/java/mage/game/permanent/token/TreasureToken.java b/Mage/src/main/java/mage/game/permanent/token/TreasureToken.java index d436e3005ab..c6606892609 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TreasureToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TreasureToken.java @@ -18,7 +18,7 @@ import java.util.Arrays; public final class TreasureToken extends TokenImpl { public TreasureToken() { - super("Treasure", "Treasure token"); + super("Treasure Token", "Treasure token"); cardType.add(CardType.ARTIFACT); subtype.add(SubType.TREASURE); @@ -27,7 +27,7 @@ public final class TreasureToken extends TokenImpl { ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); - availableImageSetCodes = Arrays.asList("XLN", "RNA", "M20", "C19", "C20", "M21", "CMR", "KHM", "STX", "MH2", "AFR", "VOW"); + availableImageSetCodes = Arrays.asList("XLN", "RNA", "M20", "C19", "C20", "M21", "CMR", "KHM", "STX", "MH2", "AFR", "VOW", "NEO", "SLD", "2XM"); } public TreasureToken(final TreasureToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/TreefolkShamanToken.java b/Mage/src/main/java/mage/game/permanent/token/TreefolkShamanToken.java index 33a14db3c5a..fe2cc6cc0f4 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TreefolkShamanToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TreefolkShamanToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class TreefolkShamanToken extends TokenImpl { public TreefolkShamanToken() { - super("Treefolk Shaman", "2/5 green Treefolk Shaman creature token"); + super("Treefolk Shaman Token", "2/5 green Treefolk Shaman creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.TREEFOLK); diff --git a/Mage/src/main/java/mage/game/permanent/token/TriskelaviteToken.java b/Mage/src/main/java/mage/game/permanent/token/TriskelaviteToken.java index d8f28e061b9..5fe19519082 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TriskelaviteToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TriskelaviteToken.java @@ -19,7 +19,7 @@ import mage.target.common.TargetAnyTarget; public final class TriskelaviteToken extends TokenImpl { public TriskelaviteToken() { - super("Triskelavite", "1/1 colorless Triskelavite artifact creature token with flying. It has \"Sacrifice this creature: This creature deals 1 damage to any target.\""); + super("Triskelavite Token", "1/1 colorless Triskelavite artifact creature token with flying. It has \"Sacrifice this creature: This creature deals 1 damage to any target.\""); this.setOriginalExpansionSetCode("TSP"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/TrollWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/TrollWarriorToken.java index 171c0bc88ed..40f63593ebe 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TrollWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TrollWarriorToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class TrollWarriorToken extends TokenImpl { public TrollWarriorToken() { - super("Troll Warrior", "4/4 green Troll Warrior creature token with trample"); + super("Troll Warrior Token", "4/4 green Troll Warrior creature token with trample"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.TROLL); diff --git a/Mage/src/main/java/mage/game/permanent/token/TrooperToken.java b/Mage/src/main/java/mage/game/permanent/token/TrooperToken.java index 6d26000a756..3cb8adbe6f0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TrooperToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TrooperToken.java @@ -14,7 +14,7 @@ import mage.constants.SubType; public final class TrooperToken extends TokenImpl { public TrooperToken() { - super("Trooper", "1/1 white Trooper creature token"); + super("Trooper Token", "1/1 white Trooper creature token"); availableImageSetCodes.addAll(Collections.singletonList("SWS")); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/TrooperToken2.java b/Mage/src/main/java/mage/game/permanent/token/TrooperToken2.java index 6a35e1f3651..3e9b0c31d68 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TrooperToken2.java +++ b/Mage/src/main/java/mage/game/permanent/token/TrooperToken2.java @@ -14,7 +14,7 @@ import mage.constants.SubType; public final class TrooperToken2 extends TokenImpl { public TrooperToken2() { - super("Trooper", "1/1 black Trooper creature token"); + super("Trooper Token", "1/1 black Trooper creature token"); availableImageSetCodes.addAll(Collections.singletonList("SWS")); this.setTokenType(2); diff --git a/Mage/src/main/java/mage/game/permanent/token/TuktukTheReturnedToken.java b/Mage/src/main/java/mage/game/permanent/token/TuktukTheReturnedToken.java index 8c20f9ae918..e5684c22068 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TuktukTheReturnedToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TuktukTheReturnedToken.java @@ -5,18 +5,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; +import java.util.Arrays; + /** * @author spjspj */ public final class TuktukTheReturnedToken extends TokenImpl { public TuktukTheReturnedToken() { - this("ROE"); - } - - public TuktukTheReturnedToken(String setCode) { super("Tuktuk the Returned", "Tuktuk the Returned, a legendary 5/5 colorless Goblin Golem artifact creature token"); - setOriginalExpansionSetCode(setCode); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); addSuperType(SuperType.LEGENDARY); @@ -24,6 +21,8 @@ public final class TuktukTheReturnedToken extends TokenImpl { subtype.add(SubType.GOLEM); power = new MageInt(5); toughness = new MageInt(5); + + availableImageSetCodes = Arrays.asList("ROE", "C14", "CM2", "2XM"); } public TuktukTheReturnedToken(final TuktukTheReturnedToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/TuskenRaiderToken.java b/Mage/src/main/java/mage/game/permanent/token/TuskenRaiderToken.java index 6ecff848eb8..2fe476f053a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TuskenRaiderToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TuskenRaiderToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class TuskenRaiderToken extends TokenImpl { public TuskenRaiderToken() { - super("Tusken Raider", "white Tusken Raider creature token", 1, 1); + super("Tusken Raider Token", "white Tusken Raider creature token", 1, 1); this.setOriginalExpansionSetCode("SWS"); cardType.add(CardType.CREATURE); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/UginTheIneffableToken.java b/Mage/src/main/java/mage/game/permanent/token/UginTheIneffableToken.java index 8bbb0002e22..a4fc8b57e00 100644 --- a/Mage/src/main/java/mage/game/permanent/token/UginTheIneffableToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/UginTheIneffableToken.java @@ -10,7 +10,7 @@ import mage.constants.SubType; public final class UginTheIneffableToken extends TokenImpl { public UginTheIneffableToken() { - super("Spirit", "2/2 colorless Spirit creature token"); + super("Spirit Token", "2/2 colorless Spirit creature token"); setExpansionSetCodeForImage("WAR"); // default cardType.add(CardType.CREATURE); subtype.add(SubType.SPIRIT); diff --git a/Mage/src/main/java/mage/game/permanent/token/UktabiKongApeToken.java b/Mage/src/main/java/mage/game/permanent/token/UktabiKongApeToken.java index 8fb6538aaf0..4aa1b270f94 100644 --- a/Mage/src/main/java/mage/game/permanent/token/UktabiKongApeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/UktabiKongApeToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class UktabiKongApeToken extends TokenImpl { public UktabiKongApeToken() { - super("Ape", "1/1 green Ape creature token"); + super("Ape Token", "1/1 green Ape creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.APE); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/UnicornToken.java b/Mage/src/main/java/mage/game/permanent/token/UnicornToken.java index 4d118d3df82..899a6fe2198 100644 --- a/Mage/src/main/java/mage/game/permanent/token/UnicornToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/UnicornToken.java @@ -7,7 +7,7 @@ import mage.constants.SubType; public final class UnicornToken extends TokenImpl { public UnicornToken() { - super("Unicorn", "2/2 white Unicorn creature token"); + super("Unicorn Token", "2/2 white Unicorn creature token"); setExpansionSetCodeForImage("JMP"); cardType.add(CardType.CREATURE); subtype.add(SubType.UNICORN); diff --git a/Mage/src/main/java/mage/game/permanent/token/UtvaraHellkiteDragonToken.java b/Mage/src/main/java/mage/game/permanent/token/UtvaraHellkiteDragonToken.java index 98bedc8bf69..323e40c4e2b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/UtvaraHellkiteDragonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/UtvaraHellkiteDragonToken.java @@ -21,7 +21,7 @@ public final class UtvaraHellkiteDragonToken extends TokenImpl { } public UtvaraHellkiteDragonToken() { - super("Dragon", "6/6 red Dragon creature token with flying"); + super("Dragon Token", "6/6 red Dragon creature token with flying"); availableImageSetCodes = tokenImageSets; setExpansionSetCodeForImage("C17"); cardType.add(CardType.CREATURE); diff --git a/Mage/src/main/java/mage/game/permanent/token/ValdukElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/ValdukElementalToken.java index 9b10f6d21dc..65a9eeed65c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ValdukElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ValdukElementalToken.java @@ -26,7 +26,7 @@ public final class ValdukElementalToken extends TokenImpl { } public ValdukElementalToken(String setCode) { - super("Elemental", "3/1 red Elemental creature token with trample and haste"); + super("Elemental Token", "3/1 red Elemental creature token with trample and haste"); availableImageSetCodes = tokenImageSets; cardType.add(CardType.CREATURE); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/VampireKnightToken.java b/Mage/src/main/java/mage/game/permanent/token/VampireKnightToken.java index 34fefb1679f..3c1a99c1845 100644 --- a/Mage/src/main/java/mage/game/permanent/token/VampireKnightToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/VampireKnightToken.java @@ -8,7 +8,7 @@ import mage.constants.SubType; public final class VampireKnightToken extends TokenImpl { public VampireKnightToken() { - super("Vampire Knight", "1/1 black Vampire Knight creature token with lifelink"); + super("Vampire Knight Token", "1/1 black Vampire Knight creature token with lifelink"); cardType.add(CardType.CREATURE); subtype.add(SubType.VAMPIRE); subtype.add(SubType.KNIGHT); diff --git a/Mage/src/main/java/mage/game/permanent/token/VampireLifelinkToken.java b/Mage/src/main/java/mage/game/permanent/token/VampireLifelinkToken.java index c8d7686b335..fe5afdbb3a6 100644 --- a/Mage/src/main/java/mage/game/permanent/token/VampireLifelinkToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/VampireLifelinkToken.java @@ -15,7 +15,7 @@ import java.util.Arrays; public class VampireLifelinkToken extends TokenImpl { public VampireLifelinkToken() { - super("Vampire", "2/3 black Vampire creature token with flying and lifelink"); + super("Vampire Token", "2/3 black Vampire creature token with flying and lifelink"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.VAMPIRE); diff --git a/Mage/src/main/java/mage/game/permanent/token/VampireToken.java b/Mage/src/main/java/mage/game/permanent/token/VampireToken.java index c0acb79c8f4..936357d1756 100644 --- a/Mage/src/main/java/mage/game/permanent/token/VampireToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/VampireToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class VampireToken extends TokenImpl { public VampireToken() { - super("Vampire", "2/2 black Vampire creature token with flying"); + super("Vampire Token", "2/2 black Vampire creature token with flying"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.VAMPIRE); diff --git a/Mage/src/main/java/mage/game/permanent/token/VoiceOfResurgenceToken.java b/Mage/src/main/java/mage/game/permanent/token/VoiceOfResurgenceToken.java index cf5134219eb..68cef9b2c8d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/VoiceOfResurgenceToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/VoiceOfResurgenceToken.java @@ -9,13 +9,15 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; +import java.util.Arrays; + /** * @author spjspj */ public final class VoiceOfResurgenceToken extends TokenImpl { public VoiceOfResurgenceToken() { - super("Elemental", "X/X green and white Elemental creature with with \"This creature's power and toughness are each equal to the number of creatures you control."); + super("Elemental Token", "X/X green and white Elemental creature with with \"This creature's power and toughness are each equal to the number of creatures you control."); setOriginalExpansionSetCode("DGM"); cardType.add(CardType.CREATURE); color.setGreen(true); @@ -28,6 +30,8 @@ public final class VoiceOfResurgenceToken extends TokenImpl { // This creature's power and toughness are each equal to the number of creatures you control. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SetPowerToughnessSourceEffect( CreaturesYouControlCount.instance, Duration.EndOfGame))); + + availableImageSetCodes = Arrays.asList("DGM", "MM3", "2XM"); } public VoiceOfResurgenceToken(final VoiceOfResurgenceToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/VoiceOfTheWoodsElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/VoiceOfTheWoodsElementalToken.java index 8e87a5dd238..4057c269132 100644 --- a/Mage/src/main/java/mage/game/permanent/token/VoiceOfTheWoodsElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/VoiceOfTheWoodsElementalToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class VoiceOfTheWoodsElementalToken extends TokenImpl { public VoiceOfTheWoodsElementalToken() { - super("Elemental", "7/7 green Elemental creature token with trample"); + super("Elemental Token", "7/7 green Elemental creature token with trample"); cardType.add(CardType.CREATURE); subtype.add(SubType.ELEMENTAL); diff --git a/Mage/src/main/java/mage/game/permanent/token/VolrathsLaboratoryToken.java b/Mage/src/main/java/mage/game/permanent/token/VolrathsLaboratoryToken.java index 77dffa3e24a..254f6505d5b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/VolrathsLaboratoryToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/VolrathsLaboratoryToken.java @@ -1,29 +1,20 @@ - - package mage.game.permanent.token; -import mage.constants.CardType; + import mage.MageInt; import mage.ObjectColor; +import mage.constants.CardType; import mage.constants.SubType; /** - * * @author spjspj */ public final class VolrathsLaboratoryToken extends TokenImpl { - public VolrathsLaboratoryToken() { - this(null, null); - } public VolrathsLaboratoryToken(ObjectColor color, SubType type) { - super(type != null ? type.getDescription() : "", "2/2 creature token of the chosen color and type"); + super(type.getDescription() + " Token", "2/2 creature token of the chosen color and type"); cardType.add(CardType.CREATURE); - if (color != null) { - this.color.setColor(color); - } - if (type != null) { - subtype.add(type); - } + this.color.setColor(color); + subtype.add(type); power = new MageInt(2); toughness = new MageInt(2); } diff --git a/Mage/src/main/java/mage/game/permanent/token/VrondissRageOfAncientsToken.java b/Mage/src/main/java/mage/game/permanent/token/VrondissRageOfAncientsToken.java index c1648e89bde..3ba0900c4ce 100644 --- a/Mage/src/main/java/mage/game/permanent/token/VrondissRageOfAncientsToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/VrondissRageOfAncientsToken.java @@ -14,7 +14,7 @@ import java.util.Arrays; public final class VrondissRageOfAncientsToken extends TokenImpl { public VrondissRageOfAncientsToken() { - super("Dragon Spirit", "5/4 red and green Dragon Spirit creature token with \"When this creature deals damage, sacrifice it.\""); + super("Dragon Spirit Token", "5/4 red and green Dragon Spirit creature token with \"When this creature deals damage, sacrifice it.\""); cardType.add(CardType.CREATURE); color.setRed(true); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/WalkerOfTheGroveToken.java b/Mage/src/main/java/mage/game/permanent/token/WalkerOfTheGroveToken.java index 0a31fce5795..7938131ef6b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WalkerOfTheGroveToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WalkerOfTheGroveToken.java @@ -9,25 +9,26 @@ import java.util.Arrays; /** * @author spjspj */ + public final class WalkerOfTheGroveToken extends TokenImpl { public WalkerOfTheGroveToken() { - super("Elemental", "4/4 green Elemental creature token"); + super("Elemental Token", "4/4 green Elemental creature token"); cardType.add(CardType.CREATURE); this.subtype.add(SubType.ELEMENTAL); this.color.setGreen(true); power = new MageInt(4); toughness = new MageInt(4); - availableImageSetCodes = Arrays.asList("C13", "LRW", "MMA", "MOR"); + availableImageSetCodes = Arrays.asList("LRW", "MMA", "DDR", "UMA"); } @Override public void setExpansionSetCodeForImage(String code) { super.setExpansionSetCodeForImage(code); - if (getOriginalExpansionSetCode().equals("C13")) { - this.setTokenType(2); + if (getOriginalExpansionSetCode().equals("UMA")) { + this.setTokenType(1); } } diff --git a/Mage/src/main/java/mage/game/permanent/token/WalkerToken.java b/Mage/src/main/java/mage/game/permanent/token/WalkerToken.java index 69ed0501183..e3c330b9ecc 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WalkerToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WalkerToken.java @@ -3,6 +3,9 @@ package mage.game.permanent.token; import mage.MageInt; import mage.constants.CardType; import mage.constants.SubType; +import mage.util.RandomUtil; + +import java.util.Arrays; /** * @author TheElk801 @@ -10,12 +13,23 @@ import mage.constants.SubType; public final class WalkerToken extends TokenImpl { public WalkerToken() { - super("Walker", "Walker token"); + super("Walker Token", "Walker token"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.ZOMBIE); power = new MageInt(2); toughness = new MageInt(2); + + availableImageSetCodes = Arrays.asList("SLD"); + } + + @Override + public void setExpansionSetCodeForImage(String code) { + super.setExpansionSetCodeForImage(code); + + if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("SLD")) { + setTokenType(RandomUtil.nextInt(5) + 1); + } } public WalkerToken(final WalkerToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/WallOfResurgenceToken.java b/Mage/src/main/java/mage/game/permanent/token/WallOfResurgenceToken.java index 18d6cdb7b77..138e06cee3b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WallOfResurgenceToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WallOfResurgenceToken.java @@ -8,7 +8,7 @@ import mage.constants.SubType; public final class WallOfResurgenceToken extends TokenImpl { public WallOfResurgenceToken() { - super("", "0/0 Elemental creature with haste"); + super(" Token", "0/0 Elemental creature with haste"); this.cardType.add(CardType.CREATURE); this.subtype.add(SubType.ELEMENTAL); diff --git a/Mage/src/main/java/mage/game/permanent/token/WallToken.java b/Mage/src/main/java/mage/game/permanent/token/WallToken.java deleted file mode 100644 index d1fdcf21fe8..00000000000 --- a/Mage/src/main/java/mage/game/permanent/token/WallToken.java +++ /dev/null @@ -1,32 +0,0 @@ - - -package mage.game.permanent.token; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.MageInt; -import mage.abilities.keyword.DefenderAbility; - -/** - * - * @author spjspj - */ -public final class WallToken extends TokenImpl { - - public WallToken() { - super("", "2/6 white wall creature with defender"); - cardType.add(CardType.CREATURE); - color.setWhite(true); - subtype.add(SubType.WALL); - power = new MageInt(2); - toughness = new MageInt(6); - this.addAbility(DefenderAbility.getInstance()); - } - - public WallToken(final WallToken token) { - super(token); - } - - public WallToken copy() { - return new WallToken(this); - } -} diff --git a/Mage/src/main/java/mage/game/permanent/token/WandOfTheElementsFirstToken.java b/Mage/src/main/java/mage/game/permanent/token/WandOfTheElementsFirstToken.java index 13fc1c12e97..728879a69a8 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WandOfTheElementsFirstToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WandOfTheElementsFirstToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class WandOfTheElementsFirstToken extends TokenImpl { public WandOfTheElementsFirstToken() { - super("Elemental", "2/2 blue Elemental creature token with flying"); + super("Elemental Token", "2/2 blue Elemental creature token with flying"); cardType.add(CardType.CREATURE); this.subtype.add(SubType.ELEMENTAL); this.color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/WandOfTheElementsSecondToken.java b/Mage/src/main/java/mage/game/permanent/token/WandOfTheElementsSecondToken.java index 43baf70390b..7f3bda800ef 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WandOfTheElementsSecondToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WandOfTheElementsSecondToken.java @@ -10,7 +10,7 @@ import mage.constants.SubType; public final class WandOfTheElementsSecondToken extends TokenImpl { public WandOfTheElementsSecondToken() { - super("Elemental", "3/3 red Elemental creature token"); + super("Elemental Token", "3/3 red Elemental creature token"); cardType.add(CardType.CREATURE); this.subtype.add(SubType.ELEMENTAL); this.color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/WardenSphinxToken.java b/Mage/src/main/java/mage/game/permanent/token/WardenSphinxToken.java index 45542d6ae06..d8b08db40f1 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WardenSphinxToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WardenSphinxToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class WardenSphinxToken extends TokenImpl { public WardenSphinxToken() { - super("Sphinx", "4/4 white and blue Sphinx creature token with flying and vigilance"); + super("Sphinx Token", "4/4 white and blue Sphinx creature token with flying and vigilance"); this.setOriginalExpansionSetCode("RNA"); color.setWhite(true); color.setBlue(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/WarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/WarriorToken.java index 12adf2aca76..bc4f4bedbb8 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WarriorToken.java @@ -16,7 +16,7 @@ import mage.util.RandomUtil; public final class WarriorToken extends TokenImpl { public WarriorToken() { - super("Warrior", "1/1 white Warrior creature token"); + super("Warrior Token", "1/1 white Warrior creature token"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.WARRIOR); diff --git a/Mage/src/main/java/mage/game/permanent/token/WarriorVigilantToken.java b/Mage/src/main/java/mage/game/permanent/token/WarriorVigilantToken.java index f92dab4987e..18ca24d4b2a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WarriorVigilantToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WarriorVigilantToken.java @@ -16,7 +16,7 @@ import mage.constants.SubType; public final class WarriorVigilantToken extends TokenImpl { public WarriorVigilantToken() { - super("Warrior", "1/1 white Warrior creature token with vigilance"); + super("Warrior Token", "1/1 white Warrior creature token with vigilance"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.WARRIOR); diff --git a/Mage/src/main/java/mage/game/permanent/token/WasitoraCatDragonToken.java b/Mage/src/main/java/mage/game/permanent/token/WasitoraCatDragonToken.java index 77dc8c07af9..64b3e2aaf66 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WasitoraCatDragonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WasitoraCatDragonToken.java @@ -22,7 +22,7 @@ public final class WasitoraCatDragonToken extends TokenImpl { } public WasitoraCatDragonToken() { - super("Cat Dragon", "3/3 black, red, and green Cat Dragon creature token with flying"); + super("Cat Dragon Token", "3/3 black, red, and green Cat Dragon creature token with flying"); availableImageSetCodes = tokenImageSets; setOriginalExpansionSetCode("C17"); diff --git a/Mage/src/main/java/mage/game/permanent/token/WaylayToken.java b/Mage/src/main/java/mage/game/permanent/token/WaylayToken.java index 67c49089b88..ff87ed2f459 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WaylayToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WaylayToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class WaylayToken extends TokenImpl { public WaylayToken() { - super("Knight", "2/2 white Knight creature token"); + super("Knight Token", "2/2 white Knight creature token"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.KNIGHT); diff --git a/Mage/src/main/java/mage/game/permanent/token/WeirdToken.java b/Mage/src/main/java/mage/game/permanent/token/WeirdToken.java index fcec46692ad..60c22c217f9 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WeirdToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WeirdToken.java @@ -14,7 +14,7 @@ import mage.abilities.keyword.FlyingAbility; public final class WeirdToken extends TokenImpl { public WeirdToken() { - super("Weird", "3/3 blue Weird create token with defender and flying"); + super("Weird Token", "3/3 blue Weird create token with defender and flying"); cardType.add(CardType.CREATURE); color.setBlue(true); subtype.add(SubType.WEIRD); diff --git a/Mage/src/main/java/mage/game/permanent/token/WeirdToken2.java b/Mage/src/main/java/mage/game/permanent/token/WeirdToken2.java index aeb5d0a367d..22be2351a42 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WeirdToken2.java +++ b/Mage/src/main/java/mage/game/permanent/token/WeirdToken2.java @@ -16,7 +16,7 @@ public final class WeirdToken2 extends TokenImpl { } public WeirdToken2(int xValue) { - super("Weird", "X/X blue and red Weird creature token"); + super("Weird Token", "X/X blue and red Weird creature token"); cardType.add(CardType.CREATURE); color.setBlue(true); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/WhiteBlackSpiritToken.java b/Mage/src/main/java/mage/game/permanent/token/WhiteBlackSpiritToken.java index 77ec0133542..f646e03d45f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WhiteBlackSpiritToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WhiteBlackSpiritToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class WhiteBlackSpiritToken extends TokenImpl { public WhiteBlackSpiritToken() { - super("Spirit", "1/1 white and black Spirit creature token with flying"); + super("Spirit Token", "1/1 white and black Spirit creature token with flying"); cardType.add(CardType.CREATURE); color.setWhite(true); color.setBlack(true); @@ -22,7 +22,16 @@ public final class WhiteBlackSpiritToken extends TokenImpl { toughness = new MageInt(1); this.addAbility(FlyingAbility.getInstance()); - availableImageSetCodes.addAll(Arrays.asList("MH1", "C21")); + availableImageSetCodes.addAll(Arrays.asList("MH1", "C21", "UMA")); + } + + @Override + public void setExpansionSetCodeForImage(String code) { + super.setExpansionSetCodeForImage(code); + + if (getOriginalExpansionSetCode().equals("UMA")) { + this.setTokenType(2); + } } public WhiteBlackSpiritToken(final WhiteBlackSpiritToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/DovescapeToken.java b/Mage/src/main/java/mage/game/permanent/token/WhiteBlueBirdToken.java similarity index 60% rename from Mage/src/main/java/mage/game/permanent/token/DovescapeToken.java rename to Mage/src/main/java/mage/game/permanent/token/WhiteBlueBirdToken.java index 73534848d8d..1cdfdabfde4 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DovescapeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WhiteBlueBirdToken.java @@ -1,5 +1,3 @@ - - package mage.game.permanent.token; import mage.constants.CardType; import mage.constants.SubType; @@ -10,10 +8,10 @@ import mage.abilities.keyword.FlyingAbility; * * @author spjspj */ -public final class DovescapeToken extends TokenImpl { +public final class WhiteBlueBirdToken extends TokenImpl { - public DovescapeToken() { - super("Bird", "1/1 white and blue Bird creature token with flying"); + public WhiteBlueBirdToken() { + super("Bird Token", "1/1 white and blue Bird creature token with flying"); cardType.add(CardType.CREATURE); color.setWhite(true); color.setBlue(true); @@ -22,11 +20,11 @@ public final class DovescapeToken extends TokenImpl { toughness = new MageInt(1); this.addAbility(FlyingAbility.getInstance()); } - public DovescapeToken(final DovescapeToken token) { + public WhiteBlueBirdToken(final WhiteBlueBirdToken token) { super(token); } - public DovescapeToken copy() { - return new DovescapeToken(this); + public WhiteBlueBirdToken copy() { + return new WhiteBlueBirdToken(this); } } diff --git a/Mage/src/main/java/mage/game/permanent/token/WhiteDogToken.java b/Mage/src/main/java/mage/game/permanent/token/WhiteDogToken.java index 2e182866dd7..5caff0492c4 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WhiteDogToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WhiteDogToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class WhiteDogToken extends TokenImpl { public WhiteDogToken() { - super("Dog", "1/1 white Dog creature token"); + super("Dog Token", "1/1 white Dog creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.DOG); diff --git a/Mage/src/main/java/mage/game/permanent/token/WhiteElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/WhiteElementalToken.java index 59ea1d700e8..e4d9738bda9 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WhiteElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WhiteElementalToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class WhiteElementalToken extends TokenImpl { public WhiteElementalToken() { - super("Elemental", "4/4 white Elemental creature token with flying"); + super("Elemental Token", "4/4 white Elemental creature token with flying"); cardType.add(CardType.CREATURE); color.setWhite(true); subtype.add(SubType.ELEMENTAL); diff --git a/Mage/src/main/java/mage/game/permanent/token/WingmateRocToken.java b/Mage/src/main/java/mage/game/permanent/token/WingmateRocToken.java index 0bc2872f8b9..2a6de56a91a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WingmateRocToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WingmateRocToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.FlyingAbility; public final class WingmateRocToken extends TokenImpl { public WingmateRocToken() { - super("Bird", "3/4 white Bird creature token with flying"); + super("Bird Token", "3/4 white Bird creature token with flying"); cardType.add(CardType.CREATURE); subtype.add(SubType.BIRD); color.setWhite(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/WizardToken.java b/Mage/src/main/java/mage/game/permanent/token/WizardToken.java index ecc864261f5..67a04fb3a07 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WizardToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WizardToken.java @@ -4,21 +4,20 @@ import mage.MageInt; import mage.constants.CardType; import mage.constants.SubType; +/** + * @author TheElk801 + */ public final class WizardToken extends TokenImpl { public WizardToken() { - this("WAR"); - } - - public WizardToken(String setCode) { - super("Wizard", "2/2 blue Wizard creature token"); + super("Wizard Token", "2/2 blue Wizard creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.WIZARD); color.setBlue(true); power = new MageInt(2); toughness = new MageInt(2); - setOriginalExpansionSetCode(setCode); + setOriginalExpansionSetCode("WAR"); } private WizardToken(final WizardToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/WolfToken.java b/Mage/src/main/java/mage/game/permanent/token/WolfToken.java index 30870f4a7be..ab117f81331 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WolfToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WolfToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class WolfToken extends TokenImpl { public WolfToken() { - super("Wolf", "2/2 green Wolf creature token"); + super("Wolf Token", "2/2 green Wolf creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); @@ -23,7 +23,7 @@ public final class WolfToken extends TokenImpl { availableImageSetCodes = Arrays.asList("BNG", "C14", "C15", "CMA", "CMD", "CNS", "DKA", "EVE", "ISD", "LRW", "M10", "M14", "MM2", "MOR", "SHM", "SOI", "SOM", "V10", "WWK", "ZEN", "WAR", "M20", - "THB", "AFR", "MID", "VOW"); + "THB", "AFR", "MID", "VOW", "2XM"); } @Override diff --git a/Mage/src/main/java/mage/game/permanent/token/WolfTokenWithDeathtouch.java b/Mage/src/main/java/mage/game/permanent/token/WolfTokenWithDeathtouch.java index 25858e1b725..a9202f14f28 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WolfTokenWithDeathtouch.java +++ b/Mage/src/main/java/mage/game/permanent/token/WolfTokenWithDeathtouch.java @@ -14,7 +14,7 @@ import mage.abilities.keyword.DeathtouchAbility; public final class WolfTokenWithDeathtouch extends TokenImpl { public WolfTokenWithDeathtouch() { - super("Wolf", "1/1 black Wolf creature token with deathtouch"); + super("Wolf Token", "1/1 black Wolf creature token with deathtouch"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.WOLF); diff --git a/Mage/src/main/java/mage/game/permanent/token/WolfsQuarryToken.java b/Mage/src/main/java/mage/game/permanent/token/WolfsQuarryToken.java index 889e46a3d7d..ec50441c2d6 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WolfsQuarryToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WolfsQuarryToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class WolfsQuarryToken extends TokenImpl { public WolfsQuarryToken() { - super("Boar", "1/1 green Boar creature token with \"When this creature dies, create a Food token.\""); + super("Boar Token", "1/1 green Boar creature token with \"When this creature dies, create a Food token.\""); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.BOAR); diff --git a/Mage/src/main/java/mage/game/permanent/token/WormHarvestToken.java b/Mage/src/main/java/mage/game/permanent/token/WormHarvestToken.java index f1d333c7614..44c2d902d8b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WormHarvestToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WormHarvestToken.java @@ -12,7 +12,7 @@ import mage.MageInt; public final class WormHarvestToken extends TokenImpl { public WormHarvestToken() { - super("Worm", "1/1 black and green Worm creature token"); + super("Worm Token", "1/1 black and green Worm creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/WrennAndSevenTreefolkToken.java b/Mage/src/main/java/mage/game/permanent/token/WrennAndSevenTreefolkToken.java index e8ac755adef..46b6e300ab9 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WrennAndSevenTreefolkToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WrennAndSevenTreefolkToken.java @@ -18,7 +18,7 @@ import java.util.Arrays; public final class WrennAndSevenTreefolkToken extends TokenImpl { public WrennAndSevenTreefolkToken() { - super("Treefolk", "green Treefolk creature token with reach and \"This creature's power and toughness are each equal to the number of lands you control.\""); + super("Treefolk Token", "green Treefolk creature token with reach and \"This creature's power and toughness are each equal to the number of lands you control.\""); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.TREEFOLK); diff --git a/Mage/src/main/java/mage/game/permanent/token/Wurm55Token.java b/Mage/src/main/java/mage/game/permanent/token/Wurm55Token.java index b327c022636..a4d015c39d0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/Wurm55Token.java +++ b/Mage/src/main/java/mage/game/permanent/token/Wurm55Token.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class Wurm55Token extends TokenImpl { public Wurm55Token() { - super("Wurm", "5/5 green Wurm creature token"); + super("Wurm Token", "5/5 green Wurm creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.WURM); diff --git a/Mage/src/main/java/mage/game/permanent/token/WurmCallingWurmToken.java b/Mage/src/main/java/mage/game/permanent/token/WurmCallingWurmToken.java index c8c07d2c85b..f9bb8b99d45 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WurmCallingWurmToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WurmCallingWurmToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class WurmCallingWurmToken extends TokenImpl { public WurmCallingWurmToken() { - super("Wurm", "X/X green Wurm creature token"); + super("Wurm Token", "X/X green Wurm creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.WURM); diff --git a/Mage/src/main/java/mage/game/permanent/token/WurmToken.java b/Mage/src/main/java/mage/game/permanent/token/WurmToken.java index 9bc31559b09..7362612740b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WurmToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WurmToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class WurmToken extends TokenImpl { public WurmToken() { - super("Wurm", "6/6 green Wurm creature token"); + super("Wurm Token", "6/6 green Wurm creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.WURM); diff --git a/Mage/src/main/java/mage/game/permanent/token/WurmWithDeathtouchToken.java b/Mage/src/main/java/mage/game/permanent/token/WurmWithDeathtouchToken.java index 6908ef89ef0..44fa430f5a4 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WurmWithDeathtouchToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WurmWithDeathtouchToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class WurmWithDeathtouchToken extends TokenImpl { public WurmWithDeathtouchToken() { - super("Phyrexian Wurm", "3/3 colorless Phyrexian Wurm artifact creature token with deathtouch"); + super("Phyrexian Wurm Token", "3/3 colorless Phyrexian Wurm artifact creature token with deathtouch"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.PHYREXIAN); @@ -22,12 +22,25 @@ public final class WurmWithDeathtouchToken extends TokenImpl { toughness = new MageInt(3); this.addAbility(DeathtouchAbility.getInstance()); - availableImageSetCodes = Arrays.asList("C14", "SOM"); + availableImageSetCodes = Arrays.asList("C14", "SOM", "2XM"); } @Override public void setExpansionSetCodeForImage(String code) { super.setExpansionSetCodeForImage(code); + + if (getOriginalExpansionSetCode().equals("C14")) { + this.setTokenType(1); + } + if (getOriginalExpansionSetCode().equals("SOM")) { + this.setTokenType(1); + } + if (getOriginalExpansionSetCode().equals("CM2")) { + this.setTokenType(1); + } + if (getOriginalExpansionSetCode().equals("2XM")) { + this.setTokenType(1); + } } public WurmWithDeathtouchToken(final WurmWithDeathtouchToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/WurmWithLifelinkToken.java b/Mage/src/main/java/mage/game/permanent/token/WurmWithLifelinkToken.java index 8db4b8b82fa..2cbba52636f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WurmWithLifelinkToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WurmWithLifelinkToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class WurmWithLifelinkToken extends TokenImpl { public WurmWithLifelinkToken() { - super("Phyrexian Wurm", "3/3 colorless Phyrexian Wurm artifact creature token with lifelink"); + super("Phyrexian Wurm Token", "3/3 colorless Phyrexian Wurm artifact creature token with lifelink"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); subtype.add(SubType.PHYREXIAN); @@ -22,7 +22,7 @@ public final class WurmWithLifelinkToken extends TokenImpl { toughness = new MageInt(3); this.addAbility(LifelinkAbility.getInstance()); - availableImageSetCodes = Arrays.asList("C14", "SOM"); + availableImageSetCodes = Arrays.asList("C14", "SOM", "2XM"); } @Override @@ -32,10 +32,15 @@ public final class WurmWithLifelinkToken extends TokenImpl { if (getOriginalExpansionSetCode().equals("C14")) { this.setTokenType(2); } - if (getOriginalExpansionSetCode().equals("SOM")) { this.setTokenType(2); } + if (getOriginalExpansionSetCode().equals("CM2")) { + this.setTokenType(2); + } + if (getOriginalExpansionSetCode().equals("2XM")) { + this.setTokenType(2); + } } public WurmWithLifelinkToken(final WurmWithLifelinkToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/WurmWithTrampleToken.java b/Mage/src/main/java/mage/game/permanent/token/WurmWithTrampleToken.java index dad1649b036..2fc00530781 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WurmWithTrampleToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WurmWithTrampleToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class WurmWithTrampleToken extends TokenImpl { public WurmWithTrampleToken() { - super("Wurm", "5/5 green Wurm creature token with trample"); + super("Wurm Token", "5/5 green Wurm creature token with trample"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.WURM); diff --git a/Mage/src/main/java/mage/game/permanent/token/XenagosSatyrToken.java b/Mage/src/main/java/mage/game/permanent/token/XenagosSatyrToken.java index a988c885da5..af90ba5d06b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/XenagosSatyrToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/XenagosSatyrToken.java @@ -13,7 +13,7 @@ import mage.abilities.keyword.HasteAbility; public final class XenagosSatyrToken extends TokenImpl { public XenagosSatyrToken() { - super("Satyr", "2/2 red and green Satyr creature token with haste"); + super("Satyr Token", "2/2 red and green Satyr creature token with haste"); cardType.add(CardType.CREATURE); color.setRed(true); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/ZaxaraTheExemplaryHydraToken.java b/Mage/src/main/java/mage/game/permanent/token/ZaxaraTheExemplaryHydraToken.java index ce9eaee6dd1..7ad03bc037b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ZaxaraTheExemplaryHydraToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ZaxaraTheExemplaryHydraToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public class ZaxaraTheExemplaryHydraToken extends TokenImpl { public ZaxaraTheExemplaryHydraToken() { - super("Hydra", "0/0 green Hydra creature token"); + super("Hydra Token", "0/0 green Hydra creature token"); cardType.add(CardType.CREATURE); color.setGreen(true); subtype.add(SubType.HYDRA); diff --git a/Mage/src/main/java/mage/game/permanent/token/ZendikarsRoilElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/ZendikarsRoilElementalToken.java index 3654f4a568b..b8753dfd66a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ZendikarsRoilElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ZendikarsRoilElementalToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class ZendikarsRoilElementalToken extends TokenImpl { public ZendikarsRoilElementalToken() { - super("Elemental", "2/2 green Elemental creature token"); + super("Elemental Token", "2/2 green Elemental creature token"); cardType.add(CardType.CREATURE); subtype.add(SubType.ELEMENTAL); color.setGreen(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/ZombieArmyToken.java b/Mage/src/main/java/mage/game/permanent/token/ZombieArmyToken.java index 723d84dd17f..e32d893adaa 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ZombieArmyToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ZombieArmyToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class ZombieArmyToken extends TokenImpl { public ZombieArmyToken() { - super("Zombie Army", "0/0 black Zombie Army creature token"); + super("Zombie Army Token", "0/0 black Zombie Army creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/ZombieBerserkerToken.java b/Mage/src/main/java/mage/game/permanent/token/ZombieBerserkerToken.java index ae2d8440ede..b43c276ee82 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ZombieBerserkerToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ZombieBerserkerToken.java @@ -12,7 +12,7 @@ import java.util.Arrays; public final class ZombieBerserkerToken extends TokenImpl { public ZombieBerserkerToken() { - super("Zombie Berserker", "2/2 black Zombie Berserker creature token"); + super("Zombie Berserker Token", "2/2 black Zombie Berserker creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.ZOMBIE); diff --git a/Mage/src/main/java/mage/game/permanent/token/ZombieDecayedToken.java b/Mage/src/main/java/mage/game/permanent/token/ZombieDecayedToken.java index f36d562da62..dead837da0c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ZombieDecayedToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ZombieDecayedToken.java @@ -14,7 +14,7 @@ import java.util.Arrays; public final class ZombieDecayedToken extends TokenImpl { public ZombieDecayedToken() { - super("Zombie", "2/2 black Zombie creature token with decayed"); + super("Zombie Token", "2/2 black Zombie creature token with decayed"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.ZOMBIE); diff --git a/Mage/src/main/java/mage/game/permanent/token/ZombieKnightToken.java b/Mage/src/main/java/mage/game/permanent/token/ZombieKnightToken.java index 54f8f33a71f..57902cb2983 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ZombieKnightToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ZombieKnightToken.java @@ -17,7 +17,7 @@ public final class ZombieKnightToken extends TokenImpl { } public ZombieKnightToken(){ - super("Zombie Knight", "a 2/2 black Zombie Knight creature token with menace"); + super("Zombie Knight Token", "a 2/2 black Zombie Knight creature token with menace"); availableImageSetCodes = tokenImageSets; setOriginalExpansionSetCode("DOM"); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/ZombieMenaceToken.java b/Mage/src/main/java/mage/game/permanent/token/ZombieMenaceToken.java index ad4cc7a671a..ae0e0201600 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ZombieMenaceToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ZombieMenaceToken.java @@ -14,7 +14,7 @@ public class ZombieMenaceToken extends TokenImpl { } public ZombieMenaceToken(int xValue) { - super("Zombie", "X/X blue and black Zombie creature token with menace"); + super("Zombie Token", "X/X blue and black Zombie creature token with menace"); cardType.add(CardType.CREATURE); color.setBlue(true); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/ZombieToken.java b/Mage/src/main/java/mage/game/permanent/token/ZombieToken.java index 3589b3747ad..dc8be137427 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ZombieToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ZombieToken.java @@ -13,7 +13,7 @@ import java.util.Arrays; public final class ZombieToken extends TokenImpl { public ZombieToken() { - super("Zombie", "2/2 black Zombie creature token"); + super("Zombie Token", "2/2 black Zombie creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.ZOMBIE); @@ -25,7 +25,7 @@ public final class ZombieToken extends TokenImpl { "CNS", "MMA", "BNG", "KTK", "DTK", "ORI", "OGW", "SOI", "EMN", "EMA", "MM3", "AKH", "CMA", "E01", "RNA", "WAR", "MH1", "M20", "C19", "THB", "M21", - "CMR", "C21", "MH2", "AFR", "MIC", "VOW"); + "CMR", "C21", "MH2", "AFR", "MIC", "VOW", "UMA"); } @Override diff --git a/Mage/src/main/java/mage/game/permanent/token/ZombieToken2.java b/Mage/src/main/java/mage/game/permanent/token/ZombieToken2.java index 5e3e3ead5ce..a9cad050516 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ZombieToken2.java +++ b/Mage/src/main/java/mage/game/permanent/token/ZombieToken2.java @@ -16,7 +16,7 @@ public final class ZombieToken2 extends TokenImpl { } public ZombieToken2(int zPower, int zToughness) { - super("Zombie", String.valueOf(zPower) + '/' + String.valueOf(zToughness) + " black Zombie creature token"); + super("Zombie Token", String.valueOf(zPower) + '/' + String.valueOf(zToughness) + " black Zombie creature token"); cardType.add(CardType.CREATURE); color.setBlack(true); subtype.add(SubType.ZOMBIE); diff --git a/Mage/src/main/java/mage/game/permanent/token/ZombieWizardToken.java b/Mage/src/main/java/mage/game/permanent/token/ZombieWizardToken.java index d4d701f5d72..749bb34564a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ZombieWizardToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ZombieWizardToken.java @@ -13,7 +13,7 @@ import mage.MageInt; public final class ZombieWizardToken extends TokenImpl { public ZombieWizardToken() { - super("Zombie Wizard", "1/1 blue and black Zombie Wizard creature token"); + super("Zombie Wizard Token", "1/1 blue and black Zombie Wizard creature token"); cardType.add(CardType.CREATURE); color.setBlue(true); color.setBlack(true); diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index db5d6697c21..56c90ba6bdf 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -12,7 +12,6 @@ import mage.abilities.costs.mana.ManaCosts; import mage.abilities.keyword.BestowAbility; import mage.abilities.keyword.MorphAbility; import mage.abilities.keyword.TransformAbility; -import mage.abilities.text.TextPart; import mage.cards.*; import mage.constants.*; import mage.counters.Counter; @@ -63,6 +62,7 @@ public class Spell extends StackObjectImpl implements Card { private boolean countered; private boolean resolving = false; private UUID commandedBy = null; // for Word of Command + private int startingLoyalty; private ActivationManaAbilityStep currentActivatingManaAbilitiesStep = ActivationManaAbilityStep.BEFORE; @@ -79,6 +79,7 @@ public class Spell extends StackObjectImpl implements Card { this.color = affectedCard.getColor(null).copy(); this.frameColor = affectedCard.getFrameColor(null).copy(); this.frameStyle = affectedCard.getFrameStyle(); + this.startingLoyalty = affectedCard.getStartingLoyalty(); this.id = ability.getId(); this.zoneChangeCounter = affectedCard.getZoneChangeCounter(game); // sync card's ZCC with spell (copy spell settings) this.ability = ability; @@ -132,6 +133,7 @@ public class Spell extends StackObjectImpl implements Card { this.currentActivatingManaAbilitiesStep = spell.currentActivatingManaAbilitiesStep; this.targetChanged = spell.targetChanged; + this.startingLoyalty = spell.startingLoyalty; } public boolean activate(Game game, boolean noMana) { @@ -274,7 +276,7 @@ public class Spell extends StackObjectImpl implements Card { CardUtil.copyTo(token).from(card, game, this); // The token that a resolving copy of a spell becomes isn’t said to have been “created.” (2020-09-25) if (token.putOntoBattlefield(1, game, ability, getControllerId(), false, false, null, false)) { - permId = token.getLastAddedToken(); + permId = token.getLastAddedTokenIds().stream().findFirst().orElse(null); flag = true; } else { permId = null; @@ -655,11 +657,12 @@ public class Spell extends StackObjectImpl implements Card { @Override public int getStartingLoyalty() { - return card.getStartingLoyalty(); + return this.startingLoyalty; } @Override public void setStartingLoyalty(int startingLoyalty) { + this.startingLoyalty = startingLoyalty; } @Override @@ -816,20 +819,6 @@ public class Spell extends StackObjectImpl implements Card { return spellCopy; } - @Override - public void adjustCosts(Ability ability, Game game) { - if (card != null) { - card.adjustCosts(ability, game); - } - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (card != null) { - card.adjustTargets(ability, game); - } - } - @Override public boolean removeFromZone(Game game, Zone fromZone, Ability source) { return card.removeFromZone(game, fromZone, source); @@ -1103,16 +1092,6 @@ public class Spell extends StackObjectImpl implements Card { public void setIsAllCreatureTypes(Game game, boolean value) { } - @Override - public List getTextParts() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public TextPart addTextPart(TextPart textPart) { - 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. diff --git a/Mage/src/main/java/mage/game/stack/SpellStack.java b/Mage/src/main/java/mage/game/stack/SpellStack.java index 8a355a85dce..473bb29b3e0 100644 --- a/Mage/src/main/java/mage/game/stack/SpellStack.java +++ b/Mage/src/main/java/mage/game/stack/SpellStack.java @@ -68,7 +68,7 @@ public class SpellStack extends ArrayDeque { // so if logic is changed here check those spells for needed changes too // Concerned cards to check: Hinder, Spell Crumple StackObject stackObject = getStackObject(objectId); - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (stackObject != null && sourceObject != null) { MageObject targetSourceObject = game.getObject(stackObject.getSourceId()); String counteredObjectName, targetSourceName; diff --git a/Mage/src/main/java/mage/game/stack/StackAbility.java b/Mage/src/main/java/mage/game/stack/StackAbility.java index bfddba81ce0..c44b31ba44c 100644 --- a/Mage/src/main/java/mage/game/stack/StackAbility.java +++ b/Mage/src/main/java/mage/game/stack/StackAbility.java @@ -16,7 +16,6 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; import mage.abilities.hint.Hint; import mage.abilities.icon.CardIcon; -import mage.abilities.text.TextPart; import mage.cards.Card; import mage.cards.FrameStyle; import mage.constants.*; @@ -389,22 +388,6 @@ public class StackAbility extends StackObjectImpl implements Ability { this.expansionSetCode = expansionSetCode; } - @Override - public void adjustCosts(Ability ability, Game game) { - Card card = game.getCard(ability.getSourceId()); - if (card != null) { - card.adjustCosts(ability, game); - } - } - - @Override - public void adjustTargets(Ability ability, Game game) { - Card card = game.getCard(ability.getSourceId()); - if (card != null) { - card.adjustTargets(ability, game); - } - } - @Override public boolean checkIfClause(Game game) { return true; @@ -647,18 +630,9 @@ public class StackAbility extends StackObjectImpl implements Ability { } @Override - public List getTextParts() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public TextPart addTextPart(TextPart textPart) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. - } - - @Override - public void setTargetAdjuster(TargetAdjuster targetAdjuster) { + public StackAbility setTargetAdjuster(TargetAdjuster targetAdjuster) { this.targetAdjuster = targetAdjuster; + return this; } @Override diff --git a/Mage/src/main/java/mage/game/stack/StackObjectImpl.java b/Mage/src/main/java/mage/game/stack/StackObjectImpl.java index f24d4e1d73d..3acdd809b5f 100644 --- a/Mage/src/main/java/mage/game/stack/StackObjectImpl.java +++ b/Mage/src/main/java/mage/game/stack/StackObjectImpl.java @@ -324,7 +324,7 @@ public abstract class StackObjectImpl implements StackObject { if (targetNames != null && (forceChange || targetController.chooseUse(outcome, "Change this target: " + targetNames + targetAmount + '?', ability, game))) { - Set possibleTargets = target.possibleTargets(this.getSourceId(), getControllerId(), game); + Set possibleTargets = target.possibleTargets(getControllerId(), ability, game); // choose exactly one other target - already targeted objects are not counted if (forceChange && possibleTargets != null && possibleTargets.size() > 1) { // controller of spell must be used (e.g. TargetOpponent) int iteration = 0; diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index 76fa8680f71..01fdbb229f0 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -609,9 +609,9 @@ public interface Player extends MageItem, Copyable { boolean priority(Game game); - boolean choose(Outcome outcome, Target target, UUID sourceId, Game game); + boolean choose(Outcome outcome, Target target, Ability source, Game game); - boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map options); + boolean choose(Outcome outcome, Target target, Ability source, Game game, Map options); boolean choose(Outcome outcome, Cards cards, TargetCard target, Game game); // TODO: remove to use choose with "Ability source" diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 3b7f1571833..a03d9521f46 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -789,7 +789,7 @@ public abstract class PlayerImpl implements Player, Serializable { return toDiscard; } TargetDiscard target = new TargetDiscard(minAmount, maxAmount, StaticFilters.FILTER_CARD, getId()); - choose(Outcome.Discard, target, source != null ? source.getSourceId() : null, game); + choose(Outcome.Discard, target, source, game); toDiscard.addAll(target.getTargets()); return toDiscard; } @@ -1008,7 +1008,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (card.moveToZone(Zone.LIBRARY, source, game, true) && !(card instanceof PermanentToken) && !card.isCopy()) { Card cardInLib = getLibrary().getFromTop(game); - if (cardInLib != null && cardInLib.getId().equals(card.getId())) { // check needed because e.g. commander can go to command zone + if (cardInLib != null && cardInLib.getId().equals(card.getMainCard().getId())) { // check needed because e.g. commander can go to command zone cardInLib = getLibrary().removeFromTop(game); getLibrary().putCardToTopXPos(cardInLib, xFromTheTop, game); game.informPlayers((withName ? cardInLib.getLogName() : "A card") @@ -1288,8 +1288,10 @@ public abstract class PlayerImpl implements Player, Serializable { //20091005 - 114.2a ActivationStatus activationStatus = playLandAbility.canActivate(this.playerId, game); if (ignoreTiming) { - if (!canPlayLand()) { - return false; // ignore timing does not mean that more lands than normal can be played + if (!canPlayLand() || !isActivePlayer(game)) { + // ignore timing does not mean that more lands than normal can be played + // it also has to be your turn + return false; } } else { if (!activationStatus.canActivate()) { @@ -1521,10 +1523,7 @@ public abstract class PlayerImpl implements Player, Serializable { //20091005 - 603.3c, 603.3d int bookmark = game.bookmarkState(); TriggeredAbility ability = triggeredAbility.copy(); - MageObject sourceObject = ability.getSourceObject(game); - if (sourceObject != null) { - sourceObject.adjustTargets(ability, game); - } + ability.adjustTargets(game); UUID triggerId = null; if (ability.canChooseTarget(game, playerId)) { if (ability.isUsesStack()) { @@ -1571,72 +1570,75 @@ public abstract class PlayerImpl implements Player, Serializable { * @param noMana * @return */ - public static LinkedHashMap getCastableSpellAbilities(Game game, UUID playerId, MageObject object, Zone zone, boolean noMana) { + public static LinkedHashMap getCastableSpellAbilities(Game game, UUID playerId, MageObject object, Zone zone, boolean noMana) { // it uses simple check from spellCanBeActivatedRegularlyNow // reason: no approved info here (e.g. forced to choose spell ability from cast card) - LinkedHashMap useable = new LinkedHashMap<>(); + LinkedHashMap useable = new LinkedHashMap<>(); Abilities allAbilities; if (object instanceof Card) { allAbilities = ((Card) object).getAbilities(game); } else { allAbilities = object.getAbilities(); } - - for (Ability ability : allAbilities) { - if (ability instanceof SpellAbility) { - SpellAbility spellAbility = (SpellAbility) ability; - - switch (spellAbility.getSpellAbilityType()) { - case BASE_ALTERNATE: - // rules: - // If you cast a spell “without paying its mana cost,” you can’t choose to cast it for - // any alternative costs. You can, however, pay additional costs, such as kicker costs. - // If the card has any mandatory additional costs, those must be paid to cast the spell. - // (2021-02-05) - if (!noMana) { - if (spellAbility.spellCanBeActivatedRegularlyNow(playerId, game)) { - useable.put(spellAbility.getId(), spellAbility); // example: Chandra, Torch of Defiance +1 loyal ability - } - return useable; + for (SpellAbility spellAbility : allAbilities + .stream() + .filter(SpellAbility.class::isInstance) + .map(SpellAbility.class::cast) + .collect(Collectors.toList())) { + switch (spellAbility.getSpellAbilityType()) { + case BASE_ALTERNATE: + // rules: + // If you cast a spell “without paying its mana cost,” you can’t choose to cast it for + // any alternative costs. You can, however, pay additional costs, such as kicker costs. + // If the card has any mandatory additional costs, those must be paid to cast the spell. + // (2021-02-05) + if (!noMana) { + if (spellAbility.spellCanBeActivatedRegularlyNow(playerId, game)) { + useable.put(spellAbility.getId(), spellAbility); // example: Chandra, Torch of Defiance +1 loyal ability } - break; - case SPLIT_FUSED: - // rules: - // If you cast a split card with fuse from your hand without paying its mana cost, - // you can choose to use its fuse ability and cast both halves without paying their mana costs. - if (zone == Zone.HAND) { - if (spellAbility.canChooseTarget(game, playerId)) { - useable.put(spellAbility.getId(), spellAbility); - } - } - case SPLIT: - if (((SplitCard) object).getLeftHalfCard().getSpellAbility().canChooseTarget(game, playerId)) { - useable.put(((SplitCard) object).getLeftHalfCard().getSpellAbility().getId(), - ((SplitCard) object).getLeftHalfCard().getSpellAbility()); + return useable; + } + break; + case SPLIT_FUSED: + // rules: + // If you cast a split card with fuse from your hand without paying its mana cost, + // you can choose to use its fuse ability and cast both halves without paying their mana costs. + if (zone == Zone.HAND) { + if (spellAbility.canChooseTarget(game, playerId)) { + useable.put(spellAbility.getId(), spellAbility); } + } + case SPLIT: + if (((SplitCard) object).getLeftHalfCard().getSpellAbility().canChooseTarget(game, playerId)) { + useable.put( + ((SplitCard) object).getLeftHalfCard().getSpellAbility().getId(), + ((SplitCard) object).getLeftHalfCard().getSpellAbility() + ); + } + if (((SplitCard) object).getRightHalfCard().getSpellAbility().canChooseTarget(game, playerId)) { + useable.put( + ((SplitCard) object).getRightHalfCard().getSpellAbility().getId(), + ((SplitCard) object).getRightHalfCard().getSpellAbility() + ); + } + return useable; + case SPLIT_AFTERMATH: + if (zone == Zone.GRAVEYARD) { if (((SplitCard) object).getRightHalfCard().getSpellAbility().canChooseTarget(game, playerId)) { useable.put(((SplitCard) object).getRightHalfCard().getSpellAbility().getId(), ((SplitCard) object).getRightHalfCard().getSpellAbility()); } - return useable; - case SPLIT_AFTERMATH: - if (zone == Zone.GRAVEYARD) { - if (((SplitCard) object).getRightHalfCard().getSpellAbility().canChooseTarget(game, playerId)) { - useable.put(((SplitCard) object).getRightHalfCard().getSpellAbility().getId(), - ((SplitCard) object).getRightHalfCard().getSpellAbility()); - } - } else { - if (((SplitCard) object).getLeftHalfCard().getSpellAbility().canChooseTarget(game, playerId)) { - useable.put(((SplitCard) object).getLeftHalfCard().getSpellAbility().getId(), - ((SplitCard) object).getLeftHalfCard().getSpellAbility()); - } + } else { + if (((SplitCard) object).getLeftHalfCard().getSpellAbility().canChooseTarget(game, playerId)) { + useable.put(((SplitCard) object).getLeftHalfCard().getSpellAbility().getId(), + ((SplitCard) object).getLeftHalfCard().getSpellAbility()); } - return useable; - default: - if (spellAbility.spellCanBeActivatedRegularlyNow(playerId, game)) { - useable.put(spellAbility.getId(), spellAbility); - } - } + } + return useable; + default: + if (spellAbility.spellCanBeActivatedRegularlyNow(playerId, game)) { + useable.put(spellAbility.getId(), spellAbility); + } } } return useable; @@ -2625,10 +2627,9 @@ public abstract class PlayerImpl implements Player, Serializable { Permanent attacker = game.getPermanent(attackerId); if (attacker != null && attacker.canAttack(defenderId, game) - && attacker.isControlledBy(playerId)) { - if (!game.getCombat().declareAttacker(attackerId, defenderId, playerId, game)) { - game.undo(playerId); - } + && attacker.isControlledBy(playerId) + && !game.getCombat().declareAttacker(attackerId, defenderId, playerId, game)) { + game.undo(playerId); } } @@ -2731,7 +2732,7 @@ public abstract class PlayerImpl implements Player, Serializable { } } - if (newTarget.choose(Outcome.Neutral, searchingController.getId(), targetPlayer.getId(), game)) { + if (newTarget.choose(Outcome.Neutral, searchingController.getId(), targetPlayer.getId(), source, game)) { target.getTargets().clear(); for (UUID targetId : newTarget.getTargets()) { target.add(targetId, game); @@ -2759,7 +2760,7 @@ public abstract class PlayerImpl implements Player, Serializable { Set cards = this.getLibrary() .getCards(game) .stream() - .filter(card -> filter.match(card, source.getSourceId(), getId(), game)) + .filter(card -> filter.match(card, getId(), source, game)) .collect(Collectors.toSet()); Card card = RandomUtil.randomFromCollection(cards); if (card == null) { @@ -3471,7 +3472,7 @@ public abstract class PlayerImpl implements Player, Serializable { return false; } if (availableMana != null) { - sourceObject.adjustCosts(copy, game); + copy.adjustCosts(game); game.getContinuousEffects().costModification(copy, game); } boolean canBeCastRegularly = true; @@ -3608,9 +3609,9 @@ public abstract class PlayerImpl implements Player, Serializable { ManaCostsImpl manaCosts = new ManaCostsImpl(); for (Cost cost : alternateSourceCostsAbility.getCosts()) { // AlternativeCost2 replaced by real cost on activate, so getPlayable need to extract that costs here - if (cost instanceof AlternativeCost2) { - if (((AlternativeCost2) cost).getCost() instanceof ManaCost) { - manaCosts.add((ManaCost) ((AlternativeCost2) cost).getCost()); + if (cost instanceof AlternativeCost) { + if (((AlternativeCost) cost).getCost() instanceof ManaCost) { + manaCosts.add((ManaCost) ((AlternativeCost) cost).getCost()); } } else { if (cost instanceof ManaCost) { @@ -3630,7 +3631,7 @@ public abstract class PlayerImpl implements Player, Serializable { copyAbility = ability.copy(); copyAbility.getManaCostsToPay().clear(); copyAbility.getManaCostsToPay().addAll(manaCosts.copy()); - sourceObject.adjustCosts(copyAbility, game); + copyAbility.adjustCosts(game); game.getContinuousEffects().costModification(copyAbility, game); // reduced all cost @@ -3657,9 +3658,9 @@ public abstract class PlayerImpl implements Player, Serializable { ManaCostsImpl manaCosts = new ManaCostsImpl(); for (Cost cost : ((Ability) alternateSourceCosts).getCosts()) { // AlternativeCost2 replaced by real cost on activate, so getPlayable need to extract that costs here - if (cost instanceof AlternativeCost2) { - if (((AlternativeCost2) cost).getCost() instanceof ManaCost) { - manaCosts.add((ManaCost) ((AlternativeCost2) cost).getCost()); + if (cost instanceof AlternativeCost) { + if (((AlternativeCost) cost).getCost() instanceof ManaCost) { + manaCosts.add((ManaCost) ((AlternativeCost) cost).getCost()); } } else { if (cost instanceof ManaCost) { @@ -3679,7 +3680,7 @@ public abstract class PlayerImpl implements Player, Serializable { copyAbility = ability.copy(); copyAbility.getManaCostsToPay().clear(); copyAbility.getManaCostsToPay().addAll(manaCosts.copy()); - sourceObject.adjustCosts(copyAbility, game); + copyAbility.adjustCosts(game); game.getContinuousEffects().costModification(copyAbility, game); // reduced all cost @@ -3707,7 +3708,7 @@ public abstract class PlayerImpl implements Player, Serializable { ManaOptions manaFull = availableMana.copy(); if (ability instanceof SpellAbility) { for (AlternateManaPaymentAbility altAbility : CardUtil.getAbilities(object, game).stream() - .filter(a -> a instanceof AlternateManaPaymentAbility) + .filter(AlternateManaPaymentAbility.class::isInstance) .map(a -> (AlternateManaPaymentAbility) a) .collect(Collectors.toList())) { ManaOptions manaSpecial = altAbility.getManaOptions(ability, game, ability.getManaCostsToPay()); @@ -3740,7 +3741,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (ability instanceof AlternativeSourceCosts && object != null && !(object instanceof Permanent)) { ActivatedAbility playAbility = null; if (object.isLand(game)) { - playAbility = (PlayLandAbility) CardUtil.getAbilities(object, game).stream().filter(a -> a instanceof PlayLandAbility).findFirst().orElse(null); + playAbility = (PlayLandAbility) CardUtil.getAbilities(object, game).stream().filter(PlayLandAbility.class::isInstance).findFirst().orElse(null); } else if (object instanceof Card) { playAbility = ((Card) object).getSpellAbility(); } @@ -4232,7 +4233,7 @@ public abstract class PlayerImpl implements Player, Serializable { } private void addCostTargetOptions(List options, Ability option, int targetNum, Game game) { - for (UUID targetId : option.getCosts().getTargets().get(targetNum).possibleTargets(option.getSourceId(), playerId, game)) { + for (UUID targetId : option.getCosts().getTargets().get(targetNum).possibleTargets(playerId, option, game)) { Ability newOption = option.copy(); newOption.getCosts().getTargets().get(targetNum).addTarget(targetId, option, game, true); if (targetNum < option.getCosts().getTargets().size() - 1) { @@ -4323,7 +4324,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean canPaySacrificeCost(Permanent permanent, Ability source, UUID controllerId, Game game) { - return sacrificeCostFilter == null || !sacrificeCostFilter.match(permanent, source.getSourceId(), controllerId, game); + return sacrificeCostFilter == null || !sacrificeCostFilter.match(permanent, controllerId, source, game); } @Override diff --git a/Mage/src/main/java/mage/players/StubPlayer.java b/Mage/src/main/java/mage/players/StubPlayer.java index ad47e96d2a1..493ad985a23 100644 --- a/Mage/src/main/java/mage/players/StubPlayer.java +++ b/Mage/src/main/java/mage/players/StubPlayer.java @@ -37,7 +37,7 @@ import static com.google.common.collect.Iterables.getOnlyElement; public class StubPlayer extends PlayerImpl implements Player { @Override - public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { + public boolean choose(Outcome outcome, Target target, Ability source, Game game) { if (target instanceof TargetPlayer) { for (Player player : game.getPlayers().values()) { if (player.getId().equals(getId()) && target.canTarget(getId(), game)) { @@ -103,14 +103,14 @@ public class StubPlayer extends PlayerImpl implements Player { } @Override - public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map options) { + public boolean choose(Outcome outcome, Target target, Ability source, Game game, Map options) { return false; } @Override public boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game) { if (target.getFilter().getMessage() != null && target.getFilter().getMessage().endsWith(" more) to put on the bottom of your library")) { - chooseDiscardBottom(game, target.getMinNumberOfTargets(), new ArrayList<>(target.possibleTargets(null, null, game))) + chooseDiscardBottom(game, target.getMinNumberOfTargets(), new ArrayList<>(target.possibleTargets(null, source, game))) .forEach(cardId -> target.add(cardId, game)); } return false; diff --git a/Mage/src/main/java/mage/target/Target.java b/Mage/src/main/java/mage/target/Target.java index 72f5c25a8ae..244fda9f259 100644 --- a/Mage/src/main/java/mage/target/Target.java +++ b/Mage/src/main/java/mage/target/Target.java @@ -34,9 +34,9 @@ public interface Target extends Serializable { void setNotTarget(boolean notTarget); // methods for targets - boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game); + boolean canChoose(UUID sourceControllerId, Ability source, Game game); - Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game); + Set possibleTargets(UUID sourceControllerId, Ability source, Game game); boolean chooseTarget(Outcome outcome, UUID playerId, Ability source, Game game); @@ -70,7 +70,7 @@ public interface Target extends Serializable { Set possibleTargets(UUID sourceControllerId, Game game); - boolean choose(Outcome outcome, UUID playerId, UUID sourceId, Game game); + boolean choose(Outcome outcome, UUID playerId, UUID sourceId, Ability source, Game game); void add(UUID id, Game game); diff --git a/Mage/src/main/java/mage/target/TargetAmount.java b/Mage/src/main/java/mage/target/TargetAmount.java index 692cc0cb741..5fc1db14af1 100644 --- a/Mage/src/main/java/mage/target/TargetAmount.java +++ b/Mage/src/main/java/mage/target/TargetAmount.java @@ -120,7 +120,7 @@ public abstract class TargetAmount extends TargetImpl { @Override public List getTargetOptions(Ability source, Game game) { List options = new ArrayList<>(); - Set possibleTargets = possibleTargets(source.getSourceId(), source.getControllerId(), game); + Set possibleTargets = possibleTargets(source.getControllerId(), source, game); addTargets(this, possibleTargets, options, source, game); diff --git a/Mage/src/main/java/mage/target/TargetCard.java b/Mage/src/main/java/mage/target/TargetCard.java index c74f2b7e74c..c2dfee9e968 100644 --- a/Mage/src/main/java/mage/target/TargetCard.java +++ b/Mage/src/main/java/mage/target/TargetCard.java @@ -53,13 +53,14 @@ public class TargetCard extends TargetObject { /** * Checks if there are enough {@link Card} that can be chosen. * - * @param sourceId - the target event source * @param sourceControllerId - controller of the target event source + * @param source * @param game * @return - true if enough valid {@link Card} exist */ @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + UUID sourceId = source != null ? source.getSourceId() : null; int possibleTargets = 0; if (getNumberOfTargets() == 0) { // if 0 target is valid, the canChoose is always true return true; @@ -72,7 +73,7 @@ public class TargetCard extends TargetObject { } switch (zone) { case HAND: - for (Card card : player.getHand().getCards(filter, sourceId, sourceControllerId, game)) { + for (Card card : player.getHand().getCards(filter, sourceControllerId, source, game)) { if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) { possibleTargets++; if (possibleTargets >= this.minNumberOfTargets) { @@ -82,7 +83,7 @@ public class TargetCard extends TargetObject { } break; case GRAVEYARD: - for (Card card : player.getGraveyard().getCards(filter, sourceId, sourceControllerId, game)) { + for (Card card : player.getGraveyard().getCards(filter, sourceControllerId, source, game)) { if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) { possibleTargets++; if (possibleTargets >= this.minNumberOfTargets) { @@ -120,7 +121,7 @@ public class TargetCard extends TargetObject { .map(game::getCard) .filter(Objects::nonNull) .filter(card -> game.getState().getZone(card.getId()).equals(Zone.COMMAND)) - .filter(card -> filter.match(card, sourceId, sourceControllerId, game)) + .filter(card -> filter.match(card, sourceControllerId, source, game)) .collect(Collectors.toList()); for (Card card : possibleCards) { if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) { @@ -146,25 +147,26 @@ public class TargetCard extends TargetObject { */ @Override public boolean canChoose(UUID sourceControllerId, Game game) { - return canChoose(null, sourceControllerId, game); + return canChoose(sourceControllerId, null, game); } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); + UUID sourceId = source != null ? source.getSourceId() : null; for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); if (player != null) { switch (zone) { case HAND: - for (Card card : player.getHand().getCards(filter, sourceId, sourceControllerId, game)) { + for (Card card : player.getHand().getCards(filter, sourceControllerId, source, game)) { if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) { possibleTargets.add(card.getId()); } } break; case GRAVEYARD: - for (Card card : player.getGraveyard().getCards(filter, sourceId, sourceControllerId, game)) { + for (Card card : player.getGraveyard().getCards(filter, sourceControllerId, source, game)) { if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) { possibleTargets.add(card.getId()); } @@ -173,7 +175,7 @@ public class TargetCard extends TargetObject { case LIBRARY: for (Card card : player.getLibrary().getUniqueCards(game)) { if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) { - if (filter.match(card, sourceId, sourceControllerId, game)) { + if (filter.match(card, sourceControllerId, source, game)) { possibleTargets.add(card.getId()); } } @@ -182,7 +184,7 @@ public class TargetCard extends TargetObject { case EXILED: for (Card card : game.getExile().getPermanentExile().getCards(game)) { if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) { - if (filter.match(card, sourceId, sourceControllerId, game)) { + if (filter.match(card, sourceControllerId, source, game)) { possibleTargets.add(card.getId()); } } @@ -193,7 +195,7 @@ public class TargetCard extends TargetObject { .map(game::getCard) .filter(Objects::nonNull) .filter(card -> game.getState().getZone(card.getId()).equals(Zone.COMMAND)) - .filter(card -> filter.match(card, sourceId, sourceControllerId, game)) + .filter(card -> filter.match(card, sourceControllerId, source, game)) .collect(Collectors.toList()); for (Card card : possibleCards) { if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) { @@ -213,7 +215,7 @@ public class TargetCard extends TargetObject { @Override public Set possibleTargets(UUID sourceControllerId, Game game) { - return possibleTargets(null, sourceControllerId, game); + return possibleTargets(sourceControllerId, (Ability) null, game); } // TODO: check all class targets, if it override canTarget then make sure it override ALL 3 METHODS with canTarget and possibleTargets (method with cards doesn't need) @@ -237,7 +239,7 @@ public class TargetCard extends TargetObject { Card card = game.getCard(id); return card != null && zone != null && zone.match(game.getState().getZone(id)) - && getFilter() != null && getFilter().match(card, playerId, game); + && getFilter() != null && getFilter().match(card, playerId, source, game); } public boolean canTarget(UUID playerId, UUID id, Ability source, Cards cards, Game game) { diff --git a/Mage/src/main/java/mage/target/TargetImpl.java b/Mage/src/main/java/mage/target/TargetImpl.java index 0e1100e5b48..7bb1ff0cc62 100644 --- a/Mage/src/main/java/mage/target/TargetImpl.java +++ b/Mage/src/main/java/mage/target/TargetImpl.java @@ -269,7 +269,7 @@ public abstract class TargetImpl implements Target { } @Override - public boolean choose(Outcome outcome, UUID playerId, UUID sourceId, Game game) { + public boolean choose(Outcome outcome, UUID playerId, UUID sourceId, Ability source, Game game) { Player targetController = getTargetController(game, playerId); if (targetController == null) { return false; @@ -280,7 +280,7 @@ public abstract class TargetImpl implements Target { if (!targetController.canRespond()) { return chosen; } - if (!targetController.choose(outcome, this, sourceId, game)) { + if (!targetController.choose(outcome, this, source, game)) { return chosen; } chosen = targets.size() >= getNumberOfTargets(); @@ -295,7 +295,7 @@ public abstract class TargetImpl implements Target { return false; } - List possibleTargets = new ArrayList<>(possibleTargets(source.getSourceId(), playerId, game)); + List possibleTargets = new ArrayList<>(possibleTargets(playerId, source, game)); chosen = targets.size() >= getNumberOfTargets(); do { @@ -385,7 +385,7 @@ public abstract class TargetImpl implements Target { public List getTargetOptions(Ability source, Game game) { List options = new ArrayList<>(); List possibleTargets = new ArrayList<>(); - possibleTargets.addAll(possibleTargets(source.getSourceId(), source.getControllerId(), game)); + possibleTargets.addAll(possibleTargets(source.getControllerId(), source, game)); possibleTargets.removeAll(getTargets()); // get the length of the array diff --git a/Mage/src/main/java/mage/target/TargetPermanent.java b/Mage/src/main/java/mage/target/TargetPermanent.java index fbeef9d1f77..5747ea098e4 100644 --- a/Mage/src/main/java/mage/target/TargetPermanent.java +++ b/Mage/src/main/java/mage/target/TargetPermanent.java @@ -65,21 +65,21 @@ public class TargetPermanent extends TargetObject { // second for protection from sources (e.g. protection from artifacts + equip ability) if (!isNotTarget()) { if (!permanent.canBeTargetedBy(game.getObject(source.getId()), controllerId, game) - || !permanent.canBeTargetedBy(game.getObject(source.getSourceId()), controllerId, game)) { + || !permanent.canBeTargetedBy(game.getObject(source), controllerId, game)) { return false; } } - return filter.match(permanent, source.getSourceId(), controllerId, game); + return filter.match(permanent, controllerId, source, game); } else { - return filter.match(permanent, null, controllerId, game); + return filter.match(permanent, controllerId, source, game); } } return false; } - public boolean canTarget(UUID controllerId, UUID id, UUID sourceId, Game game, boolean flag) { + public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game, boolean flag) { Permanent permanent = game.getPermanent(id); - return filter.match(permanent, sourceId, controllerId, game); + return filter.match(permanent, controllerId, source, game); } @Override @@ -93,20 +93,20 @@ public class TargetPermanent extends TargetObject { * Takes into account notTarget parameter, in case it's true doesn't check * for protection, shroud etc. * - * @param sourceId the target event source * @param sourceControllerId controller of the target event source + * @param source * @param game * @return true if enough valid {@link Permanent} exist */ @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { int remainingTargets = this.minNumberOfTargets - targets.size(); if (remainingTargets <= 0) { return true; } int count = 0; - MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + MageObject targetSource = game.getObject(source); + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (!targets.containsKey(permanent.getId())) { if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { count++; @@ -149,11 +149,11 @@ public class TargetPermanent extends TargetObject { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { // TODO: check if possible targets works with setTargetController from some cards like Nicol Bolas, Dragon-God Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + MageObject targetSource = game.getObject(source); + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game)) { if (!targets.containsKey(permanent.getId())) { if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { possibleTargets.add(permanent.getId()); diff --git a/Mage/src/main/java/mage/target/TargetPlayer.java b/Mage/src/main/java/mage/target/TargetPlayer.java index e49673aac15..a5f59b11b52 100644 --- a/Mage/src/main/java/mage/target/TargetPlayer.java +++ b/Mage/src/main/java/mage/target/TargetPlayer.java @@ -55,18 +55,18 @@ public class TargetPlayer extends TargetImpl { * Checks if there are enough {@link Player} that can be chosen. Should only * be used for Ability targets since this checks for protection, shroud etc. * - * @param sourceId - the target event source * @param sourceControllerId - controller of the target event source + * @param source * @param game * @return - true if enough valid {@link Player} exist */ @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { int count = 0; - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); - if (player != null && !player.hasLeft() && filter.match(player, sourceId, sourceControllerId, game)) { + if (player != null && !player.hasLeft() && filter.match(player, sourceControllerId, source, game)) { if (player.canBeTargetedBy(targetSource, sourceControllerId, game)) { count++; if (count >= this.minNumberOfTargets) { @@ -103,12 +103,12 @@ public class TargetPlayer extends TargetImpl { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); - if (player != null && !player.hasLeft() && filter.match(player, sourceId, sourceControllerId, game)) { + if (player != null && !player.hasLeft() && filter.match(player, sourceControllerId, source, game)) { if (isNotTarget() || player.canBeTargetedBy(targetSource, sourceControllerId, game)) { possibleTargets.add(playerId); } @@ -149,8 +149,8 @@ public class TargetPlayer extends TargetImpl { Player player = game.getPlayer(id); if (player != null) { if (source != null) { - return (isNotTarget() || player.canBeTargetedBy(game.getObject(source.getSourceId()), source.getControllerId(), game)) - && filter.match(player, source.getSourceId(), source.getControllerId(), game); + return (isNotTarget() || player.canBeTargetedBy(game.getObject(source), source.getControllerId(), game)) + && filter.match(player, source.getControllerId(), source, game); } else { return filter.match(player, game); } diff --git a/Mage/src/main/java/mage/target/TargetSource.java b/Mage/src/main/java/mage/target/TargetSource.java index e0dae36e505..d093d389c1d 100644 --- a/Mage/src/main/java/mage/target/TargetSource.java +++ b/Mage/src/main/java/mage/target/TargetSource.java @@ -79,7 +79,7 @@ public class TargetSource extends TargetObject { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { return canChoose(sourceControllerId, game); } @@ -124,7 +124,7 @@ public class TargetSource extends TargetObject { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { return possibleTargets(sourceControllerId, game); } diff --git a/Mage/src/main/java/mage/target/TargetSpell.java b/Mage/src/main/java/mage/target/TargetSpell.java index b959d8697ea..7fdbf4110f7 100644 --- a/Mage/src/main/java/mage/target/TargetSpell.java +++ b/Mage/src/main/java/mage/target/TargetSpell.java @@ -61,18 +61,21 @@ public class TargetSpell extends TargetObject { return false; } Spell spell = game.getStack().getSpell(id); - return filter.match(spell, source.getSourceId(), source.getControllerId(), game); + return filter.match(spell, source.getControllerId(), source, game); } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + if (this.minNumberOfTargets == 0) { + return true; + } int count = 0; for (StackObject stackObject : game.getStack()) { // rule 114.4. A spell or ability on the stack is an illegal target for itself. - if (sourceId != null && sourceId.equals(stackObject.getSourceId())) { + if (source.getSourceId() != null && source.getSourceId().equals(stackObject.getSourceId())) { continue; } - if (canBeChosen(stackObject, sourceId, sourceControllerId, game)) { + if (canBeChosen(stackObject, sourceControllerId, source, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -84,20 +87,20 @@ public class TargetSpell extends TargetObject { @Override public boolean canChoose(UUID sourceControllerId, Game game) { - return canChoose(null, sourceControllerId, game); + return canChoose(sourceControllerId, null, game); } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { return game.getStack().stream() - .filter(stackObject -> canBeChosen(stackObject, sourceId, sourceControllerId, game)) + .filter(stackObject -> canBeChosen(stackObject, sourceControllerId, source, game)) .map(StackObject::getId) .collect(Collectors.toSet()); } @Override public Set possibleTargets(UUID sourceControllerId, Game game) { - return this.possibleTargets(null, sourceControllerId, game); + return this.possibleTargets(sourceControllerId, null, game); } @Override @@ -105,10 +108,10 @@ public class TargetSpell extends TargetObject { return new TargetSpell(this); } - private boolean canBeChosen(StackObject stackObject, UUID sourceID, UUID sourceControllerId, Game game) { + private boolean canBeChosen(StackObject stackObject, UUID sourceControllerId, Ability source, Game game) { return stackObject instanceof Spell && game.getState().getPlayersInRange(sourceControllerId, game).contains(stackObject.getControllerId()) - && filter.match(stackObject, sourceID, sourceControllerId, game); + && filter.match(stackObject, sourceControllerId, source, game); } @Override diff --git a/Mage/src/main/java/mage/target/TargetStackObject.java b/Mage/src/main/java/mage/target/TargetStackObject.java index 11c084fba93..6dc55855735 100644 --- a/Mage/src/main/java/mage/target/TargetStackObject.java +++ b/Mage/src/main/java/mage/target/TargetStackObject.java @@ -51,15 +51,15 @@ public class TargetStackObject extends TargetObject { @Override public boolean canTarget(UUID id, Ability source, Game game) { StackObject stackObject = game.getStack().getStackObject(id); - return filter.match(stackObject, source.getSourceId(), source.getControllerId(), game); + return filter.match(stackObject, source.getControllerId(), source, game); } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { int count = 0; for (StackObject stackObject : game.getStack()) { if (game.getState().getPlayersInRange(sourceControllerId, game).contains(stackObject.getControllerId()) - && filter.match(stackObject, sourceId, sourceControllerId, game)) { + && filter.match(stackObject, sourceControllerId, source, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -71,15 +71,15 @@ public class TargetStackObject extends TargetObject { @Override public boolean canChoose(UUID sourceControllerId, Game game) { - return canChoose(null, sourceControllerId, game); + return canChoose(sourceControllerId, null, game); } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); for (StackObject stackObject : game.getStack()) { if (game.getState().getPlayersInRange(sourceControllerId, game).contains(stackObject.getControllerId()) - && filter.match(stackObject, sourceId, sourceControllerId, game)) { + && filter.match(stackObject, sourceControllerId, source, game)) { possibleTargets.add(stackObject.getId()); } } @@ -88,7 +88,7 @@ public class TargetStackObject extends TargetObject { @Override public Set possibleTargets(UUID sourceControllerId, Game game) { - return this.possibleTargets(null, sourceControllerId, game); + return this.possibleTargets(sourceControllerId, null, game); } @Override diff --git a/Mage/src/main/java/mage/target/Targets.java b/Mage/src/main/java/mage/target/Targets.java index 2c2a0a4796c..34f09ae4e95 100644 --- a/Mage/src/main/java/mage/target/Targets.java +++ b/Mage/src/main/java/mage/target/Targets.java @@ -4,7 +4,6 @@ import mage.abilities.Ability; import mage.constants.Outcome; import mage.game.Game; import mage.game.events.GameEvent; -import mage.players.Player; import mage.target.targetpointer.*; import org.apache.log4j.Logger; @@ -46,14 +45,14 @@ public class Targets extends ArrayList { return stream().allMatch(Target::isChosen); } - public boolean choose(Outcome outcome, UUID playerId, UUID sourceId, Game game) { + public boolean choose(Outcome outcome, UUID playerId, UUID sourceId, Ability source, Game game) { if (this.size() > 0) { - if (!canChoose(sourceId, playerId, game)) { + if (!canChoose(playerId, source, game)) { return false; } while (!isChosen()) { Target target = this.getUnchosen().get(0); - if (!target.choose(outcome, playerId, sourceId, game)) { + if (!target.choose(outcome, playerId, sourceId, source, game)) { return false; } } @@ -63,7 +62,7 @@ public class Targets extends ArrayList { public boolean chooseTargets(Outcome outcome, UUID playerId, Ability source, boolean noMana, Game game, boolean canCancel) { if (this.size() > 0) { - if (!canChoose(source.getSourceId(), playerId, game)) { + if (!canChoose(playerId, source, game)) { return false; } @@ -113,22 +112,22 @@ public class Targets extends ArrayList { /** * For target choose - * + *

* Checks if there are enough targets that can be chosen. Should only be * used for Ability targets since this checks for protection, shroud etc. * - * @param sourceId - the target event source * @param sourceControllerId - controller of the target event source + * @param source * @param game * @return - true if enough valid targets exist */ - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - return stream().allMatch(target -> target.canChoose(sourceId, sourceControllerId, game)); + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + return stream().allMatch(target -> target.canChoose(sourceControllerId, source, game)); } /** * For non target choose (e.g. cost pay) - * + *

* Checks if there are enough objects that can be selected. Should not be * used for Ability targets since this does not check for protection, shroud * etc. diff --git a/Mage/src/main/java/mage/target/common/TargetActivatedAbility.java b/Mage/src/main/java/mage/target/common/TargetActivatedAbility.java index 0d1e40e512d..03dcbd67276 100644 --- a/Mage/src/main/java/mage/target/common/TargetActivatedAbility.java +++ b/Mage/src/main/java/mage/target/common/TargetActivatedAbility.java @@ -50,11 +50,11 @@ public class TargetActivatedAbility extends TargetObject { && stackObject.getStackAbility() != null && stackObject.getStackAbility().getAbilityType() == AbilityType.ACTIVATED && source != null - && filter.match(stackObject, source.getSourceId(), source.getControllerId(), game); + && filter.match(stackObject, source.getControllerId(), source, game); } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { return canChoose(sourceControllerId, game); } @@ -71,7 +71,7 @@ public class TargetActivatedAbility extends TargetObject { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { return possibleTargets(sourceControllerId, game); } diff --git a/Mage/src/main/java/mage/target/common/TargetActivatedOrTriggeredAbility.java b/Mage/src/main/java/mage/target/common/TargetActivatedOrTriggeredAbility.java index 6552c4bba01..62d5c52a4c7 100644 --- a/Mage/src/main/java/mage/target/common/TargetActivatedOrTriggeredAbility.java +++ b/Mage/src/main/java/mage/target/common/TargetActivatedOrTriggeredAbility.java @@ -42,14 +42,14 @@ public class TargetActivatedOrTriggeredAbility extends TargetObject { } StackObject stackObject = game.getStack().getStackObject(id); - return isActivatedOrTriggeredAbility(stackObject) && source != null && filter.match(stackObject, source.getSourceId(), source.getControllerId(), game); + return isActivatedOrTriggeredAbility(stackObject) && source != null && filter.match(stackObject, source.getControllerId(), source, game); } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { for (StackObject stackObject : game.getStack()) { if (isActivatedOrTriggeredAbility(stackObject) - && filter.match(stackObject, sourceId, sourceControllerId, game)) { + && filter.match(stackObject, sourceControllerId, source, game)) { return true; } } @@ -64,7 +64,7 @@ public class TargetActivatedOrTriggeredAbility extends TargetObject { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { return possibleTargets(sourceControllerId, game); } diff --git a/Mage/src/main/java/mage/target/common/TargetActivatedOrTriggeredAbilityOrLegendarySpell.java b/Mage/src/main/java/mage/target/common/TargetActivatedOrTriggeredAbilityOrLegendarySpell.java index f8e04dd2f22..8a4168eb993 100644 --- a/Mage/src/main/java/mage/target/common/TargetActivatedOrTriggeredAbilityOrLegendarySpell.java +++ b/Mage/src/main/java/mage/target/common/TargetActivatedOrTriggeredAbilityOrLegendarySpell.java @@ -44,14 +44,14 @@ public class TargetActivatedOrTriggeredAbilityOrLegendarySpell extends TargetObj } StackObject stackObject = game.getStack().getStackObject(id); - return isActivatedOrTriggeredAbilityOrLegendarySpell(stackObject) && source != null && filter.match(stackObject, source.getSourceId(), source.getControllerId(), game); + return isActivatedOrTriggeredAbilityOrLegendarySpell(stackObject) && source != null && filter.match(stackObject, source.getControllerId(), source, game); } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { for (StackObject stackObject : game.getStack()) { if (isActivatedOrTriggeredAbilityOrLegendarySpell(stackObject) - && filter.match(stackObject, sourceId, sourceControllerId, game)) { + && filter.match(stackObject, sourceControllerId, source, game)) { return true; } } @@ -66,7 +66,7 @@ public class TargetActivatedOrTriggeredAbilityOrLegendarySpell extends TargetObj } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { return possibleTargets(sourceControllerId, game); } diff --git a/Mage/src/main/java/mage/target/common/TargetAnyTarget.java b/Mage/src/main/java/mage/target/common/TargetAnyTarget.java index 1fd701564af..8a76cf96a1c 100644 --- a/Mage/src/main/java/mage/target/common/TargetAnyTarget.java +++ b/Mage/src/main/java/mage/target/common/TargetAnyTarget.java @@ -76,9 +76,9 @@ public class TargetAnyTarget extends TargetImpl { Player player = game.getPlayer(id); if (source != null) { - MageObject targetSource = game.getObject(source.getSourceId()); + MageObject targetSource = game.getObject(source); if (permanent != null) { - return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(permanent, source.getControllerId(), source, game); } if (player != null) { return player.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(player, game); @@ -96,16 +96,16 @@ public class TargetAnyTarget extends TargetImpl { * be chosen. Should only be used for Ability targets since this checks for * protection, shroud etc. * - * @param sourceId - the target event source * @param sourceControllerId - controller of the target event source + * @param source * @param game * @return - true if enough valid {@link Permanent} or {@link Player} exist */ @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { int count = 0; - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) { @@ -117,7 +117,7 @@ public class TargetAnyTarget extends TargetImpl { } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) { - if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { + if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceControllerId, source, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -152,7 +152,7 @@ public class TargetAnyTarget extends TargetImpl { } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) { - if (filter.match(permanent, null, sourceControllerId, game)) { + if (filter.match(permanent, sourceControllerId, null, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -164,22 +164,22 @@ public class TargetAnyTarget extends TargetImpl { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) - && filter.match(player, sourceId, sourceControllerId, game)) { + && filter.match(player, sourceControllerId, source, game)) { possibleTargets.add(playerId); } } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) { if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) - && filter.match(permanent, sourceId, sourceControllerId, game)) { + && filter.match(permanent, sourceControllerId, source, game)) { possibleTargets.add(permanent.getId()); } } @@ -199,7 +199,7 @@ public class TargetAnyTarget extends TargetImpl { } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) { - if (filter.getPermanentFilter().match(permanent, null, sourceControllerId, game)) { + if (filter.getPermanentFilter().match(permanent, sourceControllerId, null, game)) { possibleTargets.add(permanent.getId()); } } diff --git a/Mage/src/main/java/mage/target/common/TargetAttackingOrBlockingCreature.java b/Mage/src/main/java/mage/target/common/TargetAttackingOrBlockingCreature.java index 8d5f87c606e..53ba1106521 100644 --- a/Mage/src/main/java/mage/target/common/TargetAttackingOrBlockingCreature.java +++ b/Mage/src/main/java/mage/target/common/TargetAttackingOrBlockingCreature.java @@ -1,7 +1,6 @@ - - package mage.target.common; +import mage.filter.StaticFilters; import mage.filter.common.FilterAttackingOrBlockingCreature; import mage.target.TargetPermanent; @@ -12,11 +11,11 @@ import mage.target.TargetPermanent; public class TargetAttackingOrBlockingCreature extends TargetPermanent { public TargetAttackingOrBlockingCreature() { - this(1, 1, new FilterAttackingOrBlockingCreature(), false); + this(1, 1, StaticFilters.FILTER_ATTACKING_OR_BLOCKING_CREATURE, false); } public TargetAttackingOrBlockingCreature(int numTargets) { - this(numTargets, numTargets, new FilterAttackingOrBlockingCreature(), false); + this(numTargets, numTargets, StaticFilters.FILTER_ATTACKING_OR_BLOCKING_CREATURE, false); } public TargetAttackingOrBlockingCreature(int minNumTargets, int maxNumTargets, FilterAttackingOrBlockingCreature filter, boolean notTarget) { diff --git a/Mage/src/main/java/mage/target/common/TargetCardInExile.java b/Mage/src/main/java/mage/target/common/TargetCardInExile.java index a68aa088f7c..2457789a2cc 100644 --- a/Mage/src/main/java/mage/target/common/TargetCardInExile.java +++ b/Mage/src/main/java/mage/target/common/TargetCardInExile.java @@ -52,7 +52,7 @@ public class TargetCardInExile extends TargetCard { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); if (allExileZones) { for (Card card : game.getExile().getAllCards(game)) { @@ -74,11 +74,11 @@ public class TargetCardInExile extends TargetCard { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { if (allExileZones) { int numberTargets = 0; for(ExileZone exileZone : game.getExile().getExileZones()) { - numberTargets += exileZone.count(filter, sourceId, sourceControllerId, game); + numberTargets += exileZone.count(filter, sourceControllerId, source, game); if (numberTargets >= this.minNumberOfTargets) { return true; } @@ -86,7 +86,7 @@ public class TargetCardInExile extends TargetCard { } else { ExileZone exileZone = game.getExile().getExileZone(zoneId); if (exileZone != null) { - if (exileZone.count(filter, sourceId, sourceControllerId, game) >= this.minNumberOfTargets) { + if (exileZone.count(filter, sourceControllerId, source, game) >= this.minNumberOfTargets) { return true; } } diff --git a/Mage/src/main/java/mage/target/common/TargetCardInGraveyardBattlefieldOrStack.java b/Mage/src/main/java/mage/target/common/TargetCardInGraveyardBattlefieldOrStack.java new file mode 100644 index 00000000000..fa01ba02074 --- /dev/null +++ b/Mage/src/main/java/mage/target/common/TargetCardInGraveyardBattlefieldOrStack.java @@ -0,0 +1,127 @@ +package mage.target.common; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.constants.ComparisonType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.game.stack.StackObject; +import mage.target.TargetCard; + +import java.util.Set; +import java.util.UUID; + +/** + * @author LevelX2 + */ +public class TargetCardInGraveyardBattlefieldOrStack extends TargetCard { + + private static final FilterSpell defaultSpellFilter = new FilterSpell(); + + static { + defaultSpellFilter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, -1)); + } + + protected final FilterPermanent filterPermanent; + protected final FilterSpell filterSpell; + + public TargetCardInGraveyardBattlefieldOrStack(int minNumTargets, int maxNumTargets, FilterCard filterGraveyard, FilterPermanent filterBattlefield) { + this(minNumTargets, maxNumTargets, filterGraveyard, filterBattlefield, defaultSpellFilter, null); + } + + public TargetCardInGraveyardBattlefieldOrStack(int minNumTargets, int maxNumTargets, FilterCard filterGraveyard, FilterPermanent filterBattlefield, FilterSpell filterSpell, String targetName) { + super(minNumTargets, maxNumTargets, Zone.GRAVEYARD, filterGraveyard); // zone for card in graveyard, don't change + this.filterPermanent = filterBattlefield; + this.filterSpell = filterSpell; + this.targetName = targetName != null ? targetName : filter.getMessage() + + " in a graveyard " + + (maxNumTargets > 1 ? " and/or " : " or ") + + this.filterPermanent.getMessage() + + " on the battlefield"; + } + + public TargetCardInGraveyardBattlefieldOrStack(final TargetCardInGraveyardBattlefieldOrStack target) { + super(target); + this.filterPermanent = target.filterPermanent; + this.filterSpell = target.filterSpell; + } + + @Override + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + if (super.canChoose(sourceControllerId, source, game)) { + return true; + } + MageObject targetSource = game.getObject(source); + for (Permanent permanent : game.getBattlefield().getActivePermanents(filterPermanent, sourceControllerId, source, game)) { + if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { + return true; + } + } + for (StackObject stackObject : game.getStack()) { + if (stackObject instanceof Spell + && game.getState().getPlayersInRange(sourceControllerId, game).contains(stackObject.getControllerId()) + && filterSpell.match(stackObject, sourceControllerId, source, game)) { + return true; + } + } + return false; + } + + @Override + public boolean canTarget(UUID id, Ability source, Game game) { + return this.canTarget(source.getControllerId(), id, source, game); + } + + @Override + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + if (super.canTarget(playerId, id, source, game)) { // in graveyard first + return true; + } + Permanent permanent = game.getPermanent(id); + if (permanent != null) { + return filterPermanent.match(permanent, playerId, source, game); + } + Spell spell = game.getSpell(id); + return spell != null && filterSpell.match(spell, playerId, source, game); + } + + @Override + public boolean canTarget(UUID id, Game game) { + return this.canTarget(null, id, null, game); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Game game) { + return this.possibleTargets(sourceControllerId, (Ability) null, game); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); // in graveyard first + MageObject targetSource = game.getObject(source); + for (Permanent permanent : game.getBattlefield().getActivePermanents(filterPermanent, sourceControllerId, source, game)) { + if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { + possibleTargets.add(permanent.getId()); + } + } + for (StackObject stackObject : game.getStack()) { + if (stackObject instanceof Spell + && game.getState().getPlayersInRange(sourceControllerId, game).contains(stackObject.getControllerId()) + && filterSpell.match(stackObject, sourceControllerId, source, game)) { + possibleTargets.add(stackObject.getId()); + } + } + return possibleTargets; + } + + @Override + public TargetCardInGraveyardBattlefieldOrStack copy() { + return new TargetCardInGraveyardBattlefieldOrStack(this); + } +} diff --git a/Mage/src/main/java/mage/target/common/TargetCardInGraveyardOrBattlefield.java b/Mage/src/main/java/mage/target/common/TargetCardInGraveyardOrBattlefield.java deleted file mode 100644 index 0a4824b4eb2..00000000000 --- a/Mage/src/main/java/mage/target/common/TargetCardInGraveyardOrBattlefield.java +++ /dev/null @@ -1,113 +0,0 @@ -package mage.target.common; - -import mage.MageObject; -import mage.abilities.Ability; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.FilterPermanent; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.TargetCard; - -import java.util.Set; -import java.util.UUID; - -/** - * @author LevelX2 - */ -public class TargetCardInGraveyardOrBattlefield extends TargetCard { - - protected final FilterPermanent filterBattlefield; - - public TargetCardInGraveyardOrBattlefield(int minNumTargets, int maxNumTargets, FilterCard filterGraveyard, FilterPermanent filterBattlefield) { - super(minNumTargets, maxNumTargets, Zone.GRAVEYARD, filterGraveyard); // zone for card in graveyard, don't change - this.filterBattlefield = filterBattlefield; - this.targetName = filter.getMessage() - + " in a graveyard " - + (maxNumTargets > 1 ? " and/or " : " or ") - + this.filterBattlefield.getMessage() - + " on the battlefield"; - } - - public TargetCardInGraveyardOrBattlefield(final TargetCardInGraveyardOrBattlefield target) { - super(target); - this.filterBattlefield = target.filterBattlefield; - } - - @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - if (!super.canChoose(sourceId, sourceControllerId, game)) { - MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filterBattlefield, sourceControllerId, game)) { - if ((notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) - && filterBattlefield.match(permanent, sourceId, sourceControllerId, game)) { - return true; - } - } - return false; - } - return true; - } - - @Override - public boolean canTarget(UUID id, Ability source, Game game) { - if (!super.canTarget(id, source, game)) { // in graveyard first - Permanent permanent = game.getPermanent(id); - if (permanent != null) { - return filterBattlefield.match(permanent, game); - } - } - return true; - } - - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { - if (!super.canTarget(playerId, id, source, game)) { // in graveyard first - Permanent permanent = game.getPermanent(id); - if (permanent != null) { - return filterBattlefield.match(permanent, source != null ? source.getSourceId() : null, playerId, game); - } - } - return true; - } - - @Override - public boolean canTarget(UUID id, Game game) { - if (!super.canTarget(id, game)) { // in graveyard first - Permanent permanent = game.getPermanent(id); - if (permanent != null) { - return filterBattlefield.match(permanent, game); - } - } - return true; - } - - @Override - public Set possibleTargets(UUID sourceControllerId, Game game) { - Set possibleTargets = super.possibleTargets(sourceControllerId, game); // in graveyard first - for (Permanent permanent : game.getBattlefield().getActivePermanents(filterBattlefield, sourceControllerId, game)) { - if (filterBattlefield.match(permanent, null, sourceControllerId, game)) { - possibleTargets.add(permanent.getId()); - } - } - return possibleTargets; - } - - @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set possibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); // in graveyard first - MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filterBattlefield, sourceControllerId, sourceId, game)) { - if ((notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) && filterBattlefield.match(permanent, sourceId, sourceControllerId, game)) { - possibleTargets.add(permanent.getId()); - } - } - return possibleTargets; - } - - @Override - public TargetCardInGraveyardOrBattlefield copy() { - return new TargetCardInGraveyardOrBattlefield(this); - } - -} diff --git a/Mage/src/main/java/mage/target/common/TargetCardInHand.java b/Mage/src/main/java/mage/target/common/TargetCardInHand.java index d60d8a5ad08..e0622f1146f 100644 --- a/Mage/src/main/java/mage/target/common/TargetCardInHand.java +++ b/Mage/src/main/java/mage/target/common/TargetCardInHand.java @@ -5,7 +5,6 @@ import mage.cards.Card; import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.events.TargetEvent; import mage.players.Player; import mage.target.TargetCard; @@ -57,12 +56,12 @@ public class TargetCardInHand extends TargetCard { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); Player player = game.getPlayer(sourceControllerId); if (player != null) { - for (Card card : player.getHand().getCards(filter, sourceId, sourceControllerId, game)) { - if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) { + for (Card card : player.getHand().getCards(filter, sourceControllerId, source, game)) { + if (source == null || source.getSourceId() == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, source.getSourceId(), sourceControllerId))) { possibleTargets.add(card.getId()); } } @@ -71,12 +70,12 @@ public class TargetCardInHand extends TargetCard { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { int possibleTargets = 0; Player player = game.getPlayer(sourceControllerId); if (player != null) { - for (Card card : player.getHand().getCards(filter, sourceId, sourceControllerId, game)) { - if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) { + for (Card card : player.getHand().getCards(filter, sourceControllerId, source, game)) { + if (source == null || source.getSourceId() == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, source.getSourceId(), sourceControllerId))) { possibleTargets++; if (possibleTargets >= this.minNumberOfTargets) { return true; diff --git a/Mage/src/main/java/mage/target/common/TargetCardInLibrary.java b/Mage/src/main/java/mage/target/common/TargetCardInLibrary.java index 59b39f4ba89..c3fbe2ce8d0 100644 --- a/Mage/src/main/java/mage/target/common/TargetCardInLibrary.java +++ b/Mage/src/main/java/mage/target/common/TargetCardInLibrary.java @@ -19,7 +19,6 @@ import java.util.List; import java.util.UUID; /** - * * Can be used with SearchLibrary only. User hasn't access to libs. * * @author BetaSteward_at_googlemail.com @@ -56,7 +55,7 @@ public class TargetCardInLibrary extends TargetCard { } @Override - public boolean choose(Outcome outcome, UUID playerId, UUID targetPlayerId, Game game) { // TODO: wtf sourceId named as targetPlayerId?! + public boolean choose(Outcome outcome, UUID playerId, UUID targetPlayerId, Ability source, Game game) { // TODO: wtf sourceId named as targetPlayerId?! Player player = game.getPlayer(playerId); Player targetPlayer = game.getPlayer(targetPlayerId); if (targetPlayer == null) { @@ -82,7 +81,7 @@ public class TargetCardInLibrary extends TargetCard { if (!player.canRespond()) { return chosen; } - if (!player.chooseTarget(outcome, cardsId, this, null, game)) { + if (!player.chooseTarget(outcome, cardsId, this, source, game)) { return chosen; } chosen = targets.size() >= getMinNumberOfTargets(); @@ -93,7 +92,7 @@ public class TargetCardInLibrary extends TargetCard { @Override public boolean canTarget(UUID id, Ability source, Game game) { Card card = game.getPlayer(source.getControllerId()).getLibrary().getCard(id, game); - return filter.match(card, source.getSourceId(), source.getControllerId(), game); + return filter.match(card, source.getControllerId(), source, game); } @Override diff --git a/Mage/src/main/java/mage/target/common/TargetCardInOpponentsGraveyard.java b/Mage/src/main/java/mage/target/common/TargetCardInOpponentsGraveyard.java index 097305fe5f1..858fa342e5d 100644 --- a/Mage/src/main/java/mage/target/common/TargetCardInOpponentsGraveyard.java +++ b/Mage/src/main/java/mage/target/common/TargetCardInOpponentsGraveyard.java @@ -8,7 +8,6 @@ import mage.cards.Card; import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.events.TargetEvent; import mage.players.Player; import mage.target.TargetCard; @@ -47,7 +46,7 @@ public class TargetCardInOpponentsGraveyard extends TargetCard { return false; } } - return filter.match(card, source.getId(), playerId, game); + return filter.match(card, playerId, source, game); } } return false; @@ -72,19 +71,19 @@ public class TargetCardInOpponentsGraveyard extends TargetCard { @Override public boolean canChoose(UUID sourceControllerId, Game game) { - return canChoose(null, sourceControllerId, game); + return canChoose(sourceControllerId, null, game); } /** * Checks if there are enough {@link Card} that can be chosen. * - * @param sourceId - the target event source * @param sourceControllerId - controller of the target event source - * @param game - * @return - true if enough valid {@link Card} exist + * @param source + * @param game + * @return - true if enough valid {@link Card} exist */ @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { int possibleTargets = 0; if (getNumberOfTargets() == 0) { // if 0 target is valid, the canChoose is always true return true; @@ -100,8 +99,8 @@ public class TargetCardInOpponentsGraveyard extends TargetCard { if (!playerId.equals(sourceControllerId)) { Player player = game.getPlayer(playerId); if (player != null) { - for (Card card : player.getGraveyard().getCards(filter, sourceId, sourceControllerId, game)) { - if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) { + for (Card card : player.getGraveyard().getCards(filter, sourceControllerId, source, game)) { + if (source == null || source.getSourceId() == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, source.getSourceId(), sourceControllerId))) { possibleTargets++; if (possibleTargets >= this.minNumberOfTargets) { return true; @@ -115,7 +114,7 @@ public class TargetCardInOpponentsGraveyard extends TargetCard { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); Player sourceController = game.getPlayer(sourceControllerId); for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { @@ -125,8 +124,8 @@ public class TargetCardInOpponentsGraveyard extends TargetCard { Player player = game.getPlayer(playerId); if (player != null) { Set targetsInThisGraveyeard = new HashSet<>(); - for (Card card : player.getGraveyard().getCards(filter, sourceId, sourceControllerId, game)) { - if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) { + for (Card card : player.getGraveyard().getCards(filter, sourceControllerId, source, game)) { + if (source == null || source.getSourceId() == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, source.getSourceId(), sourceControllerId))) { targetsInThisGraveyeard.add(card.getId()); } } diff --git a/Mage/src/main/java/mage/target/common/TargetCardInYourGraveyard.java b/Mage/src/main/java/mage/target/common/TargetCardInYourGraveyard.java index 5a6b38f0c7e..c6bf6018902 100644 --- a/Mage/src/main/java/mage/target/common/TargetCardInYourGraveyard.java +++ b/Mage/src/main/java/mage/target/common/TargetCardInYourGraveyard.java @@ -10,7 +10,6 @@ import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.events.TargetEvent; import mage.players.Player; import mage.target.TargetCard; @@ -55,7 +54,7 @@ public class TargetCardInYourGraveyard extends TargetCard { Card card = game.getCard(id); if (card != null && game.getState().getZone(card.getId()) == Zone.GRAVEYARD) { if (game.getPlayer(source.getControllerId()).getGraveyard().contains(id)) { - return filter.match(card, source.getSourceId(), source.getControllerId(), game); + return filter.match(card, source.getControllerId(), source, game); } } return false; @@ -73,11 +72,11 @@ public class TargetCardInYourGraveyard extends TargetCard { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); Player player = game.getPlayer(sourceControllerId); - for (Card card : player.getGraveyard().getCards(filter, sourceId, sourceControllerId, game)) { - if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) { + for (Card card : player.getGraveyard().getCards(filter, sourceControllerId, source, game)) { + if (source == null || source.getSourceId() == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, source.getSourceId(), sourceControllerId))) { possibleTargets.add(card.getId()); } } @@ -109,15 +108,15 @@ public class TargetCardInYourGraveyard extends TargetCard { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { Player player = game.getPlayer(sourceControllerId); if (player != null) { if (this.minNumberOfTargets == 0) { return true; } int possibleTargets = 0; - for (Card card : player.getGraveyard().getCards(filter, sourceId, sourceControllerId, game)) { - if (sourceId == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, sourceId, sourceControllerId))) { + for (Card card : player.getGraveyard().getCards(filter, sourceControllerId, source, game)) { + if (source == null || source.getSourceId() == null || isNotTarget() || !game.replaceEvent(new TargetEvent(card, source.getSourceId(), sourceControllerId))) { possibleTargets++; if (possibleTargets >= this.minNumberOfTargets) { return true; diff --git a/Mage/src/main/java/mage/target/common/TargetCardWithDifferentNameInLibrary.java b/Mage/src/main/java/mage/target/common/TargetCardWithDifferentNameInLibrary.java new file mode 100644 index 00000000000..73d5adae21d --- /dev/null +++ b/Mage/src/main/java/mage/target/common/TargetCardWithDifferentNameInLibrary.java @@ -0,0 +1,41 @@ +package mage.target.common; + +import mage.abilities.Ability; +import mage.cards.Card; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public class TargetCardWithDifferentNameInLibrary extends TargetCardInLibrary { + + public TargetCardWithDifferentNameInLibrary(int minNumTargets, int maxNumTargets, FilterCard filter) { + super(minNumTargets, maxNumTargets, filter); + } + + protected TargetCardWithDifferentNameInLibrary(final TargetCardWithDifferentNameInLibrary target) { + super(target); + } + + @Override + public TargetCardWithDifferentNameInLibrary copy() { + return new TargetCardWithDifferentNameInLibrary(this); + } + + @Override + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + if (!super.canTarget(playerId, id, source, game)) { + return false; + } + Card card = game.getCard(id); + return card != null + && this.getTargets() + .stream() + .map(game::getCard) + .noneMatch(c -> CardUtil.haveSameNames(c, card)); + } +} diff --git a/Mage/src/main/java/mage/target/common/TargetCreatureOrPlayer.java b/Mage/src/main/java/mage/target/common/TargetCreatureOrPlayer.java index 8dc7dd5c103..f2a09bcd967 100644 --- a/Mage/src/main/java/mage/target/common/TargetCreatureOrPlayer.java +++ b/Mage/src/main/java/mage/target/common/TargetCreatureOrPlayer.java @@ -76,9 +76,9 @@ public class TargetCreatureOrPlayer extends TargetImpl { Player player = game.getPlayer(id); if (source != null) { - MageObject targetSource = game.getObject(source.getSourceId()); + MageObject targetSource = game.getObject(source); if (permanent != null) { - return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(permanent, source.getControllerId(), source, game); } if (player != null) { return player.canBeTargetedBy(targetSource, source.getControllerId(), game) && filter.match(player, game); @@ -96,15 +96,15 @@ public class TargetCreatureOrPlayer extends TargetImpl { * be chosen. Should only be used for Ability targets since this checks for * protection, shroud etc. * - * @param sourceId - the target event source * @param sourceControllerId - controller of the target event source + * @param source * @param game * @return - true if enough valid {@link Permanent} or {@link Player} exist */ @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { int count = 0; - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) { @@ -115,7 +115,7 @@ public class TargetCreatureOrPlayer extends TargetImpl { } } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getCreatureFilter(), sourceControllerId, game)) { - if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { + if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceControllerId, source, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -147,7 +147,7 @@ public class TargetCreatureOrPlayer extends TargetImpl { } } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getCreatureFilter(), sourceControllerId, game)) { - if (filter.match(permanent, null, sourceControllerId, game)) { + if (filter.match(permanent, sourceControllerId, null, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -158,20 +158,20 @@ public class TargetCreatureOrPlayer extends TargetImpl { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) - && filter.getPlayerFilter().match(player, sourceId, sourceControllerId, game)) { + && filter.getPlayerFilter().match(player, sourceControllerId, source, game)) { possibleTargets.add(playerId); } } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getCreatureFilter(), sourceControllerId, game)) { if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) - && filter.getCreatureFilter().match(permanent, sourceId, sourceControllerId, game)) { + && filter.getCreatureFilter().match(permanent, sourceControllerId, source, game)) { possibleTargets.add(permanent.getId()); } } @@ -188,7 +188,7 @@ public class TargetCreatureOrPlayer extends TargetImpl { } } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getCreatureFilter(), sourceControllerId, game)) { - if (filter.getCreatureFilter().match(permanent, null, sourceControllerId, game)) { + if (filter.getCreatureFilter().match(permanent, sourceControllerId, null, game)) { possibleTargets.add(permanent.getId()); } } diff --git a/Mage/src/main/java/mage/target/common/TargetCreaturePermanentSameController.java b/Mage/src/main/java/mage/target/common/TargetCreaturePermanentSameController.java index 0bc13bb3960..fcdb188028a 100644 --- a/Mage/src/main/java/mage/target/common/TargetCreaturePermanentSameController.java +++ b/Mage/src/main/java/mage/target/common/TargetCreaturePermanentSameController.java @@ -1,20 +1,24 @@ - package mage.target.common; -import java.util.UUID; import mage.abilities.Ability; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public class TargetCreaturePermanentSameController extends TargetCreaturePermanent { - public TargetCreaturePermanentSameController(int minNumTargets, int maxNumTargets, FilterCreaturePermanent filter, boolean notTarget) { - super(minNumTargets, maxNumTargets, filter, notTarget); + public TargetCreaturePermanentSameController(int numTargets) { + this(numTargets, StaticFilters.FILTER_PERMANENT_CREATURE); + } + + public TargetCreaturePermanentSameController(int numTargets, FilterCreaturePermanent filter) { + super(numTargets, numTargets, filter, false); } public TargetCreaturePermanentSameController(final TargetCreaturePermanentSameController target) { diff --git a/Mage/src/main/java/mage/target/common/TargetDefender.java b/Mage/src/main/java/mage/target/common/TargetDefender.java index d83839e8060..bbd75386101 100644 --- a/Mage/src/main/java/mage/target/common/TargetDefender.java +++ b/Mage/src/main/java/mage/target/common/TargetDefender.java @@ -38,6 +38,7 @@ public class TargetDefender extends TargetImpl { this.filter = new FilterPlaneswalkerOrPlayer(defenders); this.targetName = filter.getMessage(); this.attackerId = attackerId; + this.notTarget = true; } public TargetDefender(final TargetDefender target) { @@ -52,9 +53,9 @@ public class TargetDefender extends TargetImpl { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { int count = 0; - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); if (player != null @@ -104,9 +105,12 @@ public class TargetDefender extends TargetImpl { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + if (source == null) { + return possibleTargets(sourceControllerId, game); + } Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); if (player != null diff --git a/Mage/src/main/java/mage/target/common/TargetNonlandPermanent.java b/Mage/src/main/java/mage/target/common/TargetNonlandPermanent.java index c60585c1252..fa1143077da 100644 --- a/Mage/src/main/java/mage/target/common/TargetNonlandPermanent.java +++ b/Mage/src/main/java/mage/target/common/TargetNonlandPermanent.java @@ -1,18 +1,16 @@ - - package mage.target.common; +import mage.filter.StaticFilters; import mage.filter.common.FilterNonlandPermanent; import mage.target.TargetPermanent; /** - * * @author BetaSteward_at_googlemail.com */ public class TargetNonlandPermanent extends TargetPermanent { public TargetNonlandPermanent() { - this(1, 1, false); + this(1); } public TargetNonlandPermanent(FilterNonlandPermanent filter) { @@ -20,11 +18,15 @@ public class TargetNonlandPermanent extends TargetPermanent { } public TargetNonlandPermanent(int numTargets) { - this(numTargets, numTargets, new FilterNonlandPermanent(), false); + this(numTargets, numTargets); + } + + public TargetNonlandPermanent(int minNumTargets, int maxNumTargets) { + this(minNumTargets, maxNumTargets, false); } public TargetNonlandPermanent(int minNumTargets, int maxNumTargets, boolean notTarget) { - this(minNumTargets, maxNumTargets, new FilterNonlandPermanent(), notTarget); + this(minNumTargets, maxNumTargets, StaticFilters.FILTER_PERMANENT_NON_LAND, notTarget); } public TargetNonlandPermanent(int minNumTargets, int maxNumTargets, FilterNonlandPermanent filter, boolean notTarget) { diff --git a/Mage/src/main/java/mage/target/common/TargetOpponentsChoicePermanent.java b/Mage/src/main/java/mage/target/common/TargetOpponentsChoicePermanent.java index 61568fd9557..184fba5a6c7 100644 --- a/Mage/src/main/java/mage/target/common/TargetOpponentsChoicePermanent.java +++ b/Mage/src/main/java/mage/target/common/TargetOpponentsChoicePermanent.java @@ -28,8 +28,8 @@ public class TargetOpponentsChoicePermanent extends TargetPermanent { } @Override - public boolean canTarget(UUID controllerId, UUID id, UUID sourceId, Game game, boolean flag) { - return opponentId != null && super.canTarget(opponentId, id, sourceId, game, flag); + public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game, boolean flag) { + return opponentId != null && super.canTarget(opponentId, id, source, game, flag); } @Override @@ -41,12 +41,12 @@ public class TargetOpponentsChoicePermanent extends TargetPermanent { boolean canSourceControllerTarget = true; if (!isNotTarget()) { if (!permanent.canBeTargetedBy(game.getObject(source.getId()), controllerId, game) - || !permanent.canBeTargetedBy(game.getObject(source.getSourceId()), controllerId, game)) { + || !permanent.canBeTargetedBy(game.getObject(source), controllerId, game)) { canSourceControllerTarget = false; } } canSourceControllerTarget &= super.canTarget(opponentId, id, source, game); - canSourceControllerTarget &= filter.match(permanent, source.getSourceId(), opponentId, game); + canSourceControllerTarget &= filter.match(permanent, opponentId, source, game); return canSourceControllerTarget; } } @@ -75,8 +75,8 @@ public class TargetOpponentsChoicePermanent extends TargetPermanent { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - MageObject sourceObject = game.getObject(sourceId); + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + MageObject sourceObject = game.getObject(source); Player player = game.getPlayer(sourceControllerId); if (sourceObject == null || player == null) { return false; @@ -88,7 +88,7 @@ public class TargetOpponentsChoicePermanent extends TargetPermanent { if (opp != null && player.hasOpponent(opp.getId(), game)) { for (Permanent perm : game.getBattlefield().getActivePermanents(opp.getId(), game)) { if (!targets.containsKey(perm.getId()) - && filter.match(perm, sourceId, opp.getId(), game) + && filter.match(perm, opp.getId(), source, game) && perm.canBeTargetedBy(sourceObject, sourceControllerId, game)) { counter++; if (counter >= minNumberOfTargets) { diff --git a/Mage/src/main/java/mage/target/common/TargetOpponentsCreaturePermanent.java b/Mage/src/main/java/mage/target/common/TargetOpponentsCreaturePermanent.java index c8579d9c186..7e3cc12a30e 100644 --- a/Mage/src/main/java/mage/target/common/TargetOpponentsCreaturePermanent.java +++ b/Mage/src/main/java/mage/target/common/TargetOpponentsCreaturePermanent.java @@ -1,32 +1,24 @@ package mage.target.common; -import mage.filter.common.FilterOpponentsCreaturePermanent; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; /** * - * @author Styxo + * @author awjackson */ -public class TargetOpponentsCreaturePermanent extends TargetCreaturePermanent { +public class TargetOpponentsCreaturePermanent extends TargetPermanent { public TargetOpponentsCreaturePermanent() { - this(1, 1, new FilterOpponentsCreaturePermanent(), false); + this(1); } public TargetOpponentsCreaturePermanent(int numTargets) { - this(numTargets, numTargets, new FilterOpponentsCreaturePermanent(), false); + this(numTargets, numTargets); } public TargetOpponentsCreaturePermanent(int minNumTargets, int maxNumTargets) { - this(minNumTargets, maxNumTargets, new FilterOpponentsCreaturePermanent(), false); - } - - public TargetOpponentsCreaturePermanent(FilterOpponentsCreaturePermanent filter) { - super(1, 1, filter, false); - } - - public TargetOpponentsCreaturePermanent(int minNumTargets, int maxNumTargets, FilterOpponentsCreaturePermanent filter, boolean notTarget) { - super(minNumTargets, maxNumTargets, filter, notTarget); - this.targetName = filter.getMessage(); + super(minNumTargets, maxNumTargets, maxNumTargets > 1 ? StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURES : StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE); } public TargetOpponentsCreaturePermanent(final TargetOpponentsCreaturePermanent target) { diff --git a/Mage/src/main/java/mage/target/common/TargetPermanentAmount.java b/Mage/src/main/java/mage/target/common/TargetPermanentAmount.java index 50b6d967a8d..4f31b5d388a 100644 --- a/Mage/src/main/java/mage/target/common/TargetPermanentAmount.java +++ b/Mage/src/main/java/mage/target/common/TargetPermanentAmount.java @@ -19,11 +19,11 @@ import java.util.stream.Collectors; /** * @author TheElk801 */ -public abstract class TargetPermanentAmount extends TargetAmount { +public class TargetPermanentAmount extends TargetAmount { protected final FilterPermanent filter; - TargetPermanentAmount(int amount, FilterPermanent filter) { + public TargetPermanentAmount(int amount, FilterPermanent filter) { // 107.1c If a rule or ability instructs a player to choose “any number,” that player may choose // any positive number or zero, unless something (such as damage or counters) is being divided // or distributed among “any number” of players and/or objects. In that case, a nonzero number @@ -31,18 +31,23 @@ public abstract class TargetPermanentAmount extends TargetAmount { this(StaticValue.get(amount), filter); } - TargetPermanentAmount(DynamicValue amount, FilterPermanent filter) { + public TargetPermanentAmount(DynamicValue amount, FilterPermanent filter) { super(amount); this.zone = Zone.ALL; this.filter = filter; this.targetName = filter.getMessage(); } - TargetPermanentAmount(final TargetPermanentAmount target) { + protected TargetPermanentAmount(final TargetPermanentAmount target) { super(target); this.filter = target.filter.copy(); } + @Override + public TargetPermanentAmount copy() { + return new TargetPermanentAmount(this); + } + @Override public Filter getFilter() { return this.filter; @@ -68,7 +73,7 @@ public abstract class TargetPermanentAmount extends TargetAmount { } MageObject targetSource = source.getSourceObject(game); return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) - && filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + && filter.match(permanent, source.getControllerId(), source, game); } @Override @@ -77,8 +82,8 @@ public abstract class TargetPermanentAmount extends TargetAmount { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - return game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game).size() + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + return game.getBattlefield().getActivePermanents(filter, sourceControllerId, source, game).size() >= this.minNumberOfTargets; } @@ -89,16 +94,16 @@ public abstract class TargetPermanentAmount extends TargetAmount { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { if (getMaxNumberOfTargets() > 0 && getTargets().size() >= getMaxNumberOfTargets()) { return getTargets() .stream() .collect(Collectors.toSet()); } - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); return game .getBattlefield() - .getActivePermanents(filter, sourceControllerId, sourceId, game) + .getActivePermanents(filter, sourceControllerId, source, game) .stream() .filter(Objects::nonNull) .filter(permanent -> permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) @@ -132,7 +137,4 @@ public abstract class TargetPermanentAmount extends TargetAmount { }); return sb.toString().trim(); } - - @Override - public abstract TargetPermanentAmount copy(); } diff --git a/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayer.java b/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayer.java index 40433a2c9ac..7270ab98ed7 100644 --- a/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayer.java +++ b/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayer.java @@ -78,20 +78,20 @@ public class TargetPermanentOrPlayer extends TargetImpl { Player player = game.getPlayer(id); if (source != null) { - MageObject targetSource = game.getObject(source.getSourceId()); + MageObject targetSource = game.getObject(source); if (permanent != null) { if (!isNotTarget()) { if (!permanent.canBeTargetedBy(game.getObject(source.getId()), source.getControllerId(), game) - || !permanent.canBeTargetedBy(game.getObject(source.getSourceId()), source.getControllerId(), game)) { + || !permanent.canBeTargetedBy(game.getObject(source), source.getControllerId(), game)) { return false; } } - return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + return filter.match(permanent, source.getControllerId(), source, game); } if (player != null) { if (!isNotTarget()) { if (!player.canBeTargetedBy(targetSource, source.getControllerId(), game) - || !filter.match(player, source.getSourceId(), source.getControllerId(), game)) { + || !filter.match(player, source.getControllerId(), source, game)) { return false; } } @@ -110,19 +110,19 @@ public class TargetPermanentOrPlayer extends TargetImpl { * {@link mage.players.Player} that can be chosen. Should only be used for * Ability targets since this checks for protection, shroud etc. * - * @param sourceId - the target event source * @param sourceControllerId - controller of the target event source + * @param source * @param game * @return - true if enough valid {@link mage.game.permanent.Permanent} or * {@link mage.players.Player} exist */ @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { int count = 0; - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); - if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, sourceId, sourceControllerId, game)) { + if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, sourceControllerId, source, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -130,7 +130,7 @@ public class TargetPermanentOrPlayer extends TargetImpl { } } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) { - if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { + if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceControllerId, source, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -163,7 +163,7 @@ public class TargetPermanentOrPlayer extends TargetImpl { } } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) { - if (filter.match(permanent, null, sourceControllerId, game) && filter.match(permanent, game)) { + if (filter.match(permanent, sourceControllerId, null, game) && filter.match(permanent, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -174,17 +174,17 @@ public class TargetPermanentOrPlayer extends TargetImpl { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); - if (player != null && (notTarget || player.canBeTargetedBy(targetSource, sourceControllerId, game)) && filter.match(player, sourceId, sourceControllerId, game)) { + if (player != null && (notTarget || player.canBeTargetedBy(targetSource, sourceControllerId, game)) && filter.match(player, sourceControllerId, source, game)) { possibleTargets.add(playerId); } } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) { - if ((notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) && filter.match(permanent, sourceId, sourceControllerId, game)) { + if ((notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) && filter.match(permanent, sourceControllerId, source, game)) { possibleTargets.add(permanent.getId()); } } @@ -201,7 +201,7 @@ public class TargetPermanentOrPlayer extends TargetImpl { } } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) { - if (filter.match(permanent, null, sourceControllerId, game)) { + if (filter.match(permanent, sourceControllerId, null, game)) { possibleTargets.add(permanent.getId()); } } diff --git a/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayerAmount.java b/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayerAmount.java index e56fd0f3a13..c9bda567b8b 100644 --- a/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayerAmount.java +++ b/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayerAmount.java @@ -72,7 +72,7 @@ public abstract class TargetPermanentOrPlayerAmount extends TargetAmount { MageObject targetSource = source.getSourceObject(game); if (permanent != null) { return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) - && filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + && filter.match(permanent, source.getControllerId(), source, game); } if (player != null) { return player.canBeTargetedBy(targetSource, source.getControllerId(), game) @@ -92,10 +92,10 @@ public abstract class TargetPermanentOrPlayerAmount extends TargetAmount { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { // no max targets limit here int count = 0; - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); if (player == null @@ -144,7 +144,7 @@ public abstract class TargetPermanentOrPlayerAmount extends TargetAmount { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); // max targets limit reached (only selected can be choosen again) @@ -153,7 +153,7 @@ public abstract class TargetPermanentOrPlayerAmount extends TargetAmount { return possibleTargets; } - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); game.getState() .getPlayersInRange(sourceControllerId, game) diff --git a/Mage/src/main/java/mage/target/common/TargetPermanentOrSuspendedCard.java b/Mage/src/main/java/mage/target/common/TargetPermanentOrSuspendedCard.java index 64d399238a1..264a488a1c2 100644 --- a/Mage/src/main/java/mage/target/common/TargetPermanentOrSuspendedCard.java +++ b/Mage/src/main/java/mage/target/common/TargetPermanentOrSuspendedCard.java @@ -50,15 +50,15 @@ public class TargetPermanentOrSuspendedCard extends TargetImpl { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - MageObject sourceObject = game.getObject(sourceId); + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { + MageObject sourceObject = game.getObject(source); for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) { - if (permanent.canBeTargetedBy(sourceObject, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { + if (permanent.canBeTargetedBy(sourceObject, sourceControllerId, game) && filter.match(permanent, sourceControllerId, source, game)) { return true; } } for (Card card : game.getExile().getAllCards(game)) { - if (filter.match(card, sourceId, sourceControllerId, game)) { + if (filter.match(card, sourceControllerId, source, game)) { return true; } } @@ -66,16 +66,16 @@ public class TargetPermanentOrSuspendedCard extends TargetImpl { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(20); - MageObject sourceObject = game.getObject(sourceId); + MageObject sourceObject = game.getObject(source); for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) { - if (permanent.canBeTargetedBy(sourceObject, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { + if (permanent.canBeTargetedBy(sourceObject, sourceControllerId, game) && filter.match(permanent, sourceControllerId, source, game)) { possibleTargets.add(permanent.getId()); } } for (Card card : game.getExile().getAllCards(game)) { - if (filter.match(card, sourceId, sourceControllerId, game)) { + if (filter.match(card, sourceControllerId, source, game)) { possibleTargets.add(card.getId()); } } @@ -97,9 +97,9 @@ public class TargetPermanentOrSuspendedCard extends TargetImpl { Permanent permanent = game.getPermanent(id); if (permanent != null) { if (source != null) { - MageObject targetSource = game.getObject(source.getSourceId()); + MageObject targetSource = game.getObject(source); return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) - && filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + && filter.match(permanent, source.getControllerId(), source, game); } else { return filter.match(permanent, game); } @@ -115,12 +115,12 @@ public class TargetPermanentOrSuspendedCard extends TargetImpl { @Override public boolean canChoose(UUID sourceControllerId, Game game) { - return this.canChoose(null, sourceControllerId, game); + return this.canChoose(sourceControllerId, null, game); } @Override public Set possibleTargets(UUID sourceControllerId, Game game) { - return this.possibleTargets(null, sourceControllerId, game); + return this.possibleTargets(sourceControllerId, null, game); } @Override diff --git a/Mage/src/main/java/mage/target/common/TargetSpellOrPermanent.java b/Mage/src/main/java/mage/target/common/TargetSpellOrPermanent.java index 3578c44ffc2..57cdd9417ca 100644 --- a/Mage/src/main/java/mage/target/common/TargetSpellOrPermanent.java +++ b/Mage/src/main/java/mage/target/common/TargetSpellOrPermanent.java @@ -88,9 +88,9 @@ public class TargetSpellOrPermanent extends TargetImpl { Permanent permanent = game.getPermanent(id); if (permanent != null) { if (source != null) { - MageObject targetSource = game.getObject(source.getSourceId()); + MageObject targetSource = game.getObject(source); return permanent.canBeTargetedBy(targetSource, source.getControllerId(), game) - && filter.match(permanent, source.getSourceId(), source.getControllerId(), game); + && filter.match(permanent, source.getControllerId(), source, game); } else { return filter.match(permanent, game); } @@ -110,21 +110,21 @@ public class TargetSpellOrPermanent extends TargetImpl { * {@link mage.game.stack.Spell} that can be chosen. Should only be used for * Ability targets since this checks for protection, shroud etc. * - * @param sourceId - the target event source * @param sourceControllerId - controller of the target event source + * @param source * @param game * @return - true if enough valid {@link mage.game.permanent.Permanent} or * {@link mage.game.stack.Spell} exist */ @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { int count = 0; - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); for (StackObject stackObject : game.getStack()) { Spell spell = game.getStack().getSpell(stackObject.getId()); if (spell != null - && !sourceId.equals(spell.getSourceId()) - && filter.match(spell, sourceId, sourceControllerId, game)) { + && !source.getSourceId().equals(spell.getSourceId()) + && filter.match(spell, sourceControllerId, source, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -132,7 +132,7 @@ public class TargetSpellOrPermanent extends TargetImpl { } } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) { - if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { + if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceControllerId, source, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -158,7 +158,7 @@ public class TargetSpellOrPermanent extends TargetImpl { for (StackObject stackObject : game.getStack()) { Spell spell = game.getStack().getSpell(stackObject.getId()); if (spell != null - && filter.match(spell, null, sourceControllerId, game) && filter.match(spell, game)) { + && filter.match(spell, sourceControllerId, null, game) && filter.match(spell, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -166,7 +166,7 @@ public class TargetSpellOrPermanent extends TargetImpl { } } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) { - if (filter.match(permanent, null, sourceControllerId, game) && filter.match(permanent, game)) { + if (filter.match(permanent, sourceControllerId, null, game) && filter.match(permanent, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -177,19 +177,19 @@ public class TargetSpellOrPermanent extends TargetImpl { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = new HashSet<>(); - MageObject targetSource = game.getObject(sourceId); + MageObject targetSource = game.getObject(source); for (StackObject stackObject : game.getStack()) { Spell spell = game.getStack().getSpell(stackObject.getId()); if (spell != null - && !sourceId.equals(spell.getSourceId()) - && filter.match(spell, sourceId, sourceControllerId, game)) { + && !source.getSourceId().equals(spell.getSourceId()) + && filter.match(spell, sourceControllerId, source, game)) { possibleTargets.add(spell.getId()); } } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) { - if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceId, sourceControllerId, game)) { + if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(permanent, sourceControllerId, source, game)) { possibleTargets.add(permanent.getId()); } } @@ -202,12 +202,12 @@ public class TargetSpellOrPermanent extends TargetImpl { for (StackObject stackObject : game.getStack()) { Spell spell = game.getStack().getSpell(stackObject.getId()); if (spell != null - && filter.match(spell, null, sourceControllerId, game)) { + && filter.match(spell, sourceControllerId, null, game)) { possibleTargets.add(spell.getId()); } } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter.getPermanentFilter(), sourceControllerId, game)) { - if (filter.match(permanent, null, sourceControllerId, game)) { + if (filter.match(permanent, sourceControllerId, null, game)) { possibleTargets.add(permanent.getId()); } } diff --git a/Mage/src/main/java/mage/target/common/TargetTappedPermanentAsYouCast.java b/Mage/src/main/java/mage/target/common/TargetTappedPermanentAsYouCast.java index 50e75403233..cef004cf5d1 100644 --- a/Mage/src/main/java/mage/target/common/TargetTappedPermanentAsYouCast.java +++ b/Mage/src/main/java/mage/target/common/TargetTappedPermanentAsYouCast.java @@ -29,7 +29,7 @@ public class TargetTappedPermanentAsYouCast extends TargetPermanent { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { return game.getBattlefield().getAllActivePermanents(getFilter(), game).stream() .filter(Permanent::isTapped) .map(Permanent::getId) @@ -37,7 +37,7 @@ public class TargetTappedPermanentAsYouCast extends TargetPermanent { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { return game.getBattlefield().getAllActivePermanents(getFilter(), game).stream() .anyMatch(Permanent::isTapped); } diff --git a/Mage/src/main/java/mage/target/common/TargetTriggeredAbility.java b/Mage/src/main/java/mage/target/common/TargetTriggeredAbility.java index 54a7e3513d9..37028f2f19a 100644 --- a/Mage/src/main/java/mage/target/common/TargetTriggeredAbility.java +++ b/Mage/src/main/java/mage/target/common/TargetTriggeredAbility.java @@ -44,7 +44,7 @@ public class TargetTriggeredAbility extends TargetObject { } @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + public boolean canChoose(UUID sourceControllerId, Ability source, Game game) { return canChoose(sourceControllerId, game); } @@ -60,7 +60,7 @@ public class TargetTriggeredAbility extends TargetObject { } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { return possibleTargets(sourceControllerId, game); } diff --git a/Mage/src/main/java/mage/target/targetadjustment/TargetAdjuster.java b/Mage/src/main/java/mage/target/targetadjustment/TargetAdjuster.java index af173fa18f0..20904454459 100644 --- a/Mage/src/main/java/mage/target/targetadjustment/TargetAdjuster.java +++ b/Mage/src/main/java/mage/target/targetadjustment/TargetAdjuster.java @@ -3,11 +3,13 @@ package mage.target.targetadjustment; import mage.abilities.Ability; import mage.game.Game; +import java.io.Serializable; + /** * @author TheElk801 */ -public interface TargetAdjuster { +@FunctionalInterface +public interface TargetAdjuster extends Serializable { void adjustTargets(Ability ability, Game game); - } diff --git a/Mage/src/main/java/mage/target/targetpointer/FixedTargets.java b/Mage/src/main/java/mage/target/targetpointer/FixedTargets.java index 5c8db89f6a9..78d26932f87 100644 --- a/Mage/src/main/java/mage/target/targetpointer/FixedTargets.java +++ b/Mage/src/main/java/mage/target/targetpointer/FixedTargets.java @@ -32,10 +32,11 @@ public class FixedTargets extends TargetPointerImpl { public FixedTargets(Cards cards, Game game) { super(); - - for (UUID targetId : cards) { - MageObjectReference mor = new MageObjectReference(targetId, game); - targets.add(mor); + if (cards != null) { + for (UUID targetId : cards) { + MageObjectReference mor = new MageObjectReference(targetId, game); + targets.add(mor); + } } this.initialized = true; } @@ -92,24 +93,24 @@ public class FixedTargets extends TargetPointerImpl { @Override public List getTargets(Game game, Ability source) { // check target not changed zone - List list = new ArrayList<>(); - for (MageObjectReference mor : targets) { - if (mor.getSourceId() != null && game.getState().getZoneChangeCounter(mor.getSourceId()) == mor.getZoneChangeCounter()) { - list.add(mor.getSourceId()); - } - } - return list; + return targets + .stream() + .filter(mor -> mor.zoneCounterIsCurrent(game)) + .map(MageObjectReference::getSourceId) + .filter(Objects::nonNull) + .collect(Collectors.toList()); } @Override public UUID getFirst(Game game, Ability source) { // check target not changed zone - for (MageObjectReference mor : targets) { - if (game.getState().getZoneChangeCounter(mor.getSourceId()) == mor.getZoneChangeCounter()) { - return mor.getSourceId(); - } - } - return null; + return targets + .stream() + .filter(mor -> mor.zoneCounterIsCurrent(game)) + .map(MageObjectReference::getSourceId) + .filter(Objects::nonNull) + .findFirst() + .orElse(null); } @Override diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index b44a88e9760..9fa38520158 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -1,6 +1,7 @@ package mage.util; import com.google.common.collect.ImmutableList; +import mage.ApprovingObject; import mage.MageObject; import mage.Mana; import mage.abilities.Abilities; @@ -23,6 +24,8 @@ import mage.cards.*; import mage.constants.*; import mage.counters.Counter; import mage.filter.Filter; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; import mage.filter.predicate.mageobject.NamePredicate; import mage.game.CardState; import mage.game.Game; @@ -36,6 +39,7 @@ import mage.game.permanent.token.Token; import mage.game.stack.Spell; import mage.players.Player; import mage.target.Target; +import mage.target.TargetCard; import mage.target.targetpointer.FixedTarget; import mage.util.functions.CopyTokenFunction; import org.apache.log4j.Logger; @@ -529,7 +533,7 @@ public final class CardUtil { } public static String replaceSourceName(String message, String sourceName) { - return message.replace("{this}", sourceName); + return message != null ? message.replace("{this}", sourceName) : null; } public static String booleanToFlipName(boolean flip) { @@ -594,7 +598,11 @@ public final class CardUtil { } public static UUID getExileZoneId(Game game, Ability source) { - return getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); + return getExileZoneId(game, source, 0); + } + + public static UUID getExileZoneId(Game game, Ability source, int offset) { + return getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter() + offset); } public static UUID getExileZoneId(Game game, UUID objectId, int zoneChangeCounter) { @@ -710,7 +718,7 @@ public final class CardUtil { public static String createObjectRealtedWindowTitle(Ability source, Game game, String textSuffix) { String title; if (source != null) { - MageObject sourceObject = game.getObject(source.getSourceId()); + MageObject sourceObject = game.getObject(source); if (sourceObject != null) { title = sourceObject.getIdName() + " [" + source.getSourceObjectZoneChangeCounter() + "]" @@ -948,7 +956,7 @@ public final class CardUtil { } } - private static final String vowels = "aeiouAEIOU"; + private static final String vowels = "aeiouAEIOU8"; public static String addArticle(String text) { if (text.startsWith("a ") @@ -980,7 +988,7 @@ public final class CardUtil { .stream() .map(Mode::getTargets) .flatMap(Collection::stream) - .map(t -> t.possibleTargets(ability.getSourceId(), ability.getControllerId(), game)) + .map(t -> t.possibleTargets(ability.getControllerId(), ability, game)) .flatMap(Collection::stream) .collect(Collectors.toSet()); } @@ -1196,6 +1204,130 @@ public final class CardUtil { } } + public interface SpellCastTracker { + + boolean checkCard(Card card, Game game); + + void addCard(Card card, Ability source, Game game); + } + + private static List getCastableComponents(Card cardToCast, FilterCard filter, Ability source, UUID playerId, Game game, SpellCastTracker spellCastTracker) { + List cards = new ArrayList<>(); + if (cardToCast instanceof CardWithHalves) { + cards.add(((CardWithHalves) cardToCast).getLeftHalfCard()); + cards.add(((CardWithHalves) cardToCast).getRightHalfCard()); + } else if (cardToCast instanceof AdventureCard) { + cards.add(cardToCast); + cards.add(((AdventureCard) cardToCast).getSpellCard()); + } else { + cards.add(cardToCast); + } + cards.removeIf(Objects::isNull); + cards.removeIf(card -> !filter.match(card, playerId, source, game)); + if (spellCastTracker != null) { + cards.removeIf(card -> !spellCastTracker.checkCard(card, game)); + } + return cards; + } + + private static final FilterCard defaultFilter = new FilterCard("card to cast"); + + public static boolean castSpellWithAttributesForFree(Player player, Ability source, Game game, Card card) { + return castSpellWithAttributesForFree(player, source, game, new CardsImpl(card), StaticFilters.FILTER_CARD); + } + + public static boolean castSpellWithAttributesForFree(Player player, Ability source, Game game, Cards cards, FilterCard filter) { + return castSpellWithAttributesForFree(player, source, game, cards, filter, null); + } + + public static boolean castSpellWithAttributesForFree(Player player, Ability source, Game game, Cards cards, FilterCard filter, SpellCastTracker spellCastTracker) { + Map> cardMap = new HashMap<>(); + for (Card card : cards.getCards(game)) { + List castableComponents = getCastableComponents(card, filter, source, player.getId(), game, spellCastTracker); + if (!castableComponents.isEmpty()) { + cardMap.put(card.getId(), castableComponents); + } + } + Card cardToCast; + switch (cardMap.size()) { + case 0: + return false; + case 1: + cardToCast = cards.get(cardMap.keySet().stream().findFirst().orElse(null), game); + break; + default: + Cards castableCards = new CardsImpl(cardMap.keySet()); + TargetCard target = new TargetCard(0, 1, Zone.ALL, defaultFilter); + target.setNotTarget(true); + player.choose(Outcome.PlayForFree, castableCards, target, game); + cardToCast = castableCards.get(target.getFirstTarget(), game); + } + if (cardToCast == null) { + return false; + } + List partsToCast = cardMap.get(cardToCast.getId()); + String partsInfo = partsToCast + .stream() + .map(MageObject::getIdName) + .collect(Collectors.joining(" or ")); + if (cardToCast == null + || partsToCast.size() < 1 + || !player.chooseUse( + Outcome.PlayForFree, "Cast spell without paying its mana cost (" + partsInfo + ")?", source, game + )) { + return false; + } + partsToCast.forEach(card -> game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE)); + boolean result = player.cast( + player.chooseAbilityForCast(cardToCast, game, true), + game, true, new ApprovingObject(source, game) + ); + partsToCast.forEach(card -> game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null)); + if (result && spellCastTracker != null) { + spellCastTracker.addCard(cardToCast, source, game); + } + if (player.isComputer() && !result) { + cards.remove(cardToCast); + } + return result; + } + + private static boolean checkForPlayable(Cards cards, FilterCard filter, Ability source, UUID playerId, Game game, SpellCastTracker spellCastTracker) { + return cards + .getCards(game) + .stream() + .anyMatch(card -> !getCastableComponents(card, filter, source, playerId, game, spellCastTracker).isEmpty()); + } + + public static void castMultipleWithAttributeForFree(Player player, Ability source, Game game, Cards cards, FilterCard filter) { + castMultipleWithAttributeForFree(player, source, game, cards, filter, Integer.MAX_VALUE); + } + + public static void castMultipleWithAttributeForFree(Player player, Ability source, Game game, Cards cards, FilterCard filter, int maxSpells) { + castMultipleWithAttributeForFree(player, source, game, cards, filter, maxSpells, null); + } + + public static void castMultipleWithAttributeForFree(Player player, Ability source, Game game, Cards cards, FilterCard filter, int maxSpells, SpellCastTracker spellCastTracker) { + if (maxSpells == 1) { + CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter); + return; + } + int spellsCast = 0; + cards.removeZone(Zone.STACK, game); + while (player.canRespond() && spellsCast < maxSpells && !cards.isEmpty()) { + if (CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter, spellCastTracker)) { + spellsCast++; + cards.removeZone(Zone.STACK, game); + } else if (!checkForPlayable( + cards, filter, source, player.getId(), game, spellCastTracker + ) || !player.chooseUse( + Outcome.PlayForFree, "Continue casting spells?", source, game + )) { + break; + } + } + } + /** * Pay life in effects * @@ -1284,8 +1416,11 @@ public final class CardUtil { return zcc; } - public static boolean checkCostWords(String text) { - return text != null && costWords.stream().anyMatch(text.toLowerCase(Locale.ENGLISH)::startsWith); + public static String addCostVerb(String text) { + if (costWords.stream().anyMatch(text.toLowerCase(Locale.ENGLISH)::startsWith)) { + return text; + } + return "pay " + text; } /** @@ -1396,14 +1531,22 @@ public final class CardUtil { return "T" + gameState.getTurnNum() + "." + gameState.getTurn().getStep().getType().getStepShortText(); } + public static String concatWithOr(List strings) { + return concatWith(strings, "or"); + } + public static String concatWithAnd(List strings) { + return concatWith(strings, "and"); + } + + private static String concatWith(List strings, String last) { switch (strings.size()) { case 0: return ""; case 1: return strings.get(0); case 2: - return strings.get(0) + " and " + strings.get(1); + return strings.get(0) + " " + last + " " + strings.get(1); } StringBuilder sb = new StringBuilder(); for (int i = 0; i < strings.size(); i++) { @@ -1413,7 +1556,8 @@ public final class CardUtil { } sb.append(", "); if (i == strings.size() - 2) { - sb.append("and "); + sb.append(last); + sb.append(' '); } } return sb.toString(); @@ -1461,4 +1605,15 @@ public final class CardUtil { public static int setOrIncrementValue(T u, Integer i) { return i == null ? 1 : Integer.sum(i, 1); } + + public static String convertStartingLoyalty(int startingLoyalty) { + switch (startingLoyalty) { + case -2: + return "X"; + case -1: + return ""; + default: + return "" + startingLoyalty; + } + } } diff --git a/Mage/src/main/java/mage/util/RandomUtil.java b/Mage/src/main/java/mage/util/RandomUtil.java index 5f2458c4dcc..b0424863455 100644 --- a/Mage/src/main/java/mage/util/RandomUtil.java +++ b/Mage/src/main/java/mage/util/RandomUtil.java @@ -3,6 +3,8 @@ package mage.util; import java.awt.*; import java.util.Collection; import java.util.Random; +import java.util.Set; +import java.util.UUID; /** * Created by IGOUDT on 5-9-2016. diff --git a/Mage/src/main/java/mage/util/functions/CopyTokenFunction.java b/Mage/src/main/java/mage/util/functions/CopyTokenFunction.java index 05f19c50cb6..2ac2cd65214 100644 --- a/Mage/src/main/java/mage/util/functions/CopyTokenFunction.java +++ b/Mage/src/main/java/mage/util/functions/CopyTokenFunction.java @@ -92,6 +92,7 @@ public class CopyTokenFunction implements Function { target.getPower().modifyBaseValue(sourceObj.getPower().getBaseValueModified()); target.getToughness().modifyBaseValue(sourceObj.getToughness().getBaseValueModified()); + target.setStartingLoyalty(sourceObj.getStartingLoyalty()); return target; } @@ -108,6 +109,8 @@ public class CopyTokenFunction implements Function { if (spell != null) { // copied spell puts to battlefield as token, so that token's ZCC must be synced with spell instead card (card can be moved before resolve) target.setZoneChangeCounter(spell.getZoneChangeCounter(game), game); + // Copy starting loyalty from spell (Ob Nixilis, the Adversary) + target.setStartingLoyalty(spell.getStartingLoyalty()); } else { target.setZoneChangeCounter(source.getZoneChangeCounter(game), game); } diff --git a/Mage/src/main/java/mage/watchers/common/AttackedThisTurnWatcher.java b/Mage/src/main/java/mage/watchers/common/AttackedThisTurnWatcher.java index aa74dad37fb..b199c5b431a 100644 --- a/Mage/src/main/java/mage/watchers/common/AttackedThisTurnWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/AttackedThisTurnWatcher.java @@ -19,6 +19,9 @@ public class AttackedThisTurnWatcher extends Watcher { private final Set attackedThisTurnCreatures = new HashSet<>(); private final Map attackedThisTurnCreaturesCounts = new HashMap<>(); + + // issue with Robber of the Rich. it needs to check the subtype of the LKI of the permanent on the battlefield and this fails with MageObjectReference + private final Set attackedThisTurnCreaturesPermanentLKI = new HashSet<>(); public AttackedThisTurnWatcher() { super(WatcherScope.GAME); @@ -28,9 +31,13 @@ public class AttackedThisTurnWatcher extends Watcher { public void watch(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED) { MageObjectReference mor = new MageObjectReference(event.getSourceId(), game); + Permanent permanentOnBattlefield = game.getPermanentOrLKIBattlefield(event.getSourceId()); this.attackedThisTurnCreatures.add(mor); this.attackedThisTurnCreaturesCounts.putIfAbsent(mor, 0); this.attackedThisTurnCreaturesCounts.compute(mor, (k, v) -> (v + 1)); + + // bug with Robber of the Rich as noted above + this.attackedThisTurnCreaturesPermanentLKI.add(permanentOnBattlefield); } } @@ -54,11 +61,16 @@ public class AttackedThisTurnWatcher extends Watcher { } return false; } + + public Set getAttackedThisTurnCreaturesPermanentLKI() { + return this.attackedThisTurnCreaturesPermanentLKI; + } @Override public void reset() { super.reset(); this.attackedThisTurnCreatures.clear(); this.attackedThisTurnCreaturesCounts.clear(); + this.getAttackedThisTurnCreaturesPermanentLKI().clear(); } } diff --git a/Mage/src/main/java/mage/watchers/common/BlockingOrBlockedWatcher.java b/Mage/src/main/java/mage/watchers/common/BlockingOrBlockedWatcher.java new file mode 100644 index 00000000000..66e0abd5551 --- /dev/null +++ b/Mage/src/main/java/mage/watchers/common/BlockingOrBlockedWatcher.java @@ -0,0 +1,56 @@ +package mage.watchers.common; + +import mage.MageObjectReference; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.watchers.Watcher; + +import java.util.*; + +/** + * @author TheElk801 + */ +public class BlockingOrBlockedWatcher extends Watcher { + + private final Map> blockerMap = new HashMap<>(); + + public BlockingOrBlockedWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + switch (event.getType()) { + case BLOCKER_DECLARED: + blockerMap + .computeIfAbsent(new MageObjectReference(event.getTargetId(), game), x -> new HashSet<>()) + .add(new MageObjectReference(event.getSourceId(), game)); + return; + case END_COMBAT_STEP_POST: + blockerMap.clear(); + return; + case REMOVED_FROM_COMBAT: + blockerMap + .values() + .stream() + .forEach(set -> set.removeIf(mor -> mor.refersTo(event.getTargetId(), game))); + } + } + + @Override + public void reset() { + super.reset(); + blockerMap.clear(); + } + + public static boolean check(Permanent attacker, Permanent blocker, Game game) { + return game.getState() + .getWatcher(BlockingOrBlockedWatcher.class) + .blockerMap + .getOrDefault(new MageObjectReference(attacker, game), Collections.emptySet()) + .stream() + .anyMatch(mor -> mor.refersTo(blocker, game)); + } +} diff --git a/Mage/src/main/java/mage/watchers/common/CardsPutIntoGraveyardWatcher.java b/Mage/src/main/java/mage/watchers/common/CardsPutIntoGraveyardWatcher.java index 75ed33cdb59..2c3211c1daa 100644 --- a/Mage/src/main/java/mage/watchers/common/CardsPutIntoGraveyardWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CardsPutIntoGraveyardWatcher.java @@ -13,16 +13,20 @@ import java.util.*; import java.util.stream.Collectors; /** - * Counts amount of cards put into graveyards of players during the current - * turn. Also the UUIDs of cards that went to graveyard from Battlefield this - * turn. + * Counts how many cards are put into each player's graveyard this turn. + * Keeps track of the UUIDs of the cards that went to graveyard this turn. + * from the battlefield, from anywhere other both from anywhere and from only the battlefield. * * @author LevelX2 */ public class CardsPutIntoGraveyardWatcher extends Watcher { + // Number of cards that have entered each players graveyards private final Map amountOfCardsThisTurn = new HashMap<>(); - private final Set cardsPutToGraveyardFromBattlefield = new HashSet<>(); + // UUID of cards that entered the graveyard from the battlefield + private final Set cardsPutIntoGraveyardFromBattlefield = new HashSet<>(); + // UUID of cards that entered the graveyard from everywhere other than the battlefield + private final Set cardsPutIntoGraveyardFromEverywhereElse = new HashSet<>(); public CardsPutIntoGraveyardWatcher() { super(WatcherScope.GAME); @@ -34,33 +38,102 @@ public class CardsPutIntoGraveyardWatcher extends Watcher { || ((ZoneChangeEvent) event).getToZone() != Zone.GRAVEYARD) { return; } + UUID playerId = event.getPlayerId(); if (playerId == null || game.getCard(event.getTargetId()) == null) { return; } + amountOfCardsThisTurn.compute(playerId, (k, amount) -> amount == null ? 1 : Integer.sum(amount, 1)); + if (((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD) { - cardsPutToGraveyardFromBattlefield.add(new MageObjectReference(((ZoneChangeEvent) event).getTarget(), game, 1)); + cardsPutIntoGraveyardFromBattlefield.add(new MageObjectReference(((ZoneChangeEvent) event).getTarget(), game, 1)); + } else { + cardsPutIntoGraveyardFromEverywhereElse.add(new MageObjectReference(((ZoneChangeEvent) event).getTarget(), game, 1)); } } + /** + * The number of cards that were put into a specific player's graveyard this turn. + * + * @param playerId The player's UUID. + * @return The number of cards. + */ public int getAmountCardsPutToGraveyard(UUID playerId) { return amountOfCardsThisTurn.getOrDefault(playerId, 0); } - public Set getCardsPutToGraveyardFromBattlefield(Game game) { - return cardsPutToGraveyardFromBattlefield.stream().map(mor -> mor.getCard(game)).filter(Objects::nonNull).collect(Collectors.toSet()); + /** + * The cards put into any graveyard from the battelfield this turn. + * + * @param game The game to check for. + * @return A set containing the card objects. + */ + public Set getCardsPutIntoGraveyardFromBattlefield(Game game) { + return cardsPutIntoGraveyardFromBattlefield.stream().map(mor -> mor.getCard(game)).filter(Objects::nonNull).collect(Collectors.toSet()); } + /** + * The cards put into any graveyard from anywhere other than the battelfield this turn. + * + * @param game The game to check for. + * @return A set containing the card objects. + */ + public Set getCardsPutIntoGraveyardNotFromBattlefield(Game game) { + return cardsPutIntoGraveyardFromEverywhereElse.stream().map(mor -> mor.getCard(game)).filter(Objects::nonNull).collect(Collectors.toSet()); + } + + /** + * The cards put into any graveyard from anywhere this turn. + * + * @param game The game to check for. + * @return A set containing the card objects. + */ + public Set getCardsPutIntoGraveyardFromAnywhere(Game game) { + Set cardsPutIntoGraveyardFromAnywhere = getCardsPutIntoGraveyardFromBattlefield(game); + cardsPutIntoGraveyardFromAnywhere.addAll(getCardsPutIntoGraveyardNotFromBattlefield(game)); + + return cardsPutIntoGraveyardFromAnywhere; + } + + /** + * Check if the passed card was put into the graveyard from the battlefield this turn. + * + * @param card The card to check. + * @param game The game to check for. + * @return Boolean indicating if the card was put into the graveyard from the battlefield this turn. + */ public boolean checkCardFromBattlefield(Card card, Game game) { - return cardsPutToGraveyardFromBattlefield.stream().anyMatch(mor -> mor.refersTo(card, game)); + return cardsPutIntoGraveyardFromBattlefield.stream().anyMatch(mor -> mor.refersTo(card, game)); + } + + /** + * Check if the passed card was put into the graveyard from anywhere other than the battlefield this turn. + * + * @param card The card to check. + * @param game The game to check for. + * @return Boolean indicating if the card was put into the graveyard from anywhere other than the battlefield this turn. + */ + public boolean checkCardNotFromBattlefield(Card card, Game game) { + return cardsPutIntoGraveyardFromEverywhereElse.stream().anyMatch(mor -> mor.refersTo(card, game)); + } + + /** + * Check if the passed card was put into the graveyard from anywhere this turn. + * + * @param card The card to check. + * @param game The game to check for. + * @return Boolean indicating if the card was put into the graveyard from anywhere this turn. + */ + public boolean checkCardFromAnywhere(Card card, Game game) { + return checkCardFromBattlefield(card, game) || checkCardNotFromBattlefield(card, game); } @Override public void reset() { super.reset(); amountOfCardsThisTurn.clear(); - cardsPutToGraveyardFromBattlefield.clear(); + cardsPutIntoGraveyardFromBattlefield.clear(); + cardsPutIntoGraveyardFromEverywhereElse.clear(); } - } diff --git a/Mage/src/main/java/mage/watchers/common/ControlledModifiedCreatureAsSpellCastWatcher.java b/Mage/src/main/java/mage/watchers/common/ControlledModifiedCreatureAsSpellCastWatcher.java index 4ec8368da0f..e0d6112a228 100644 --- a/Mage/src/main/java/mage/watchers/common/ControlledModifiedCreatureAsSpellCastWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/ControlledModifiedCreatureAsSpellCastWatcher.java @@ -27,7 +27,7 @@ public class ControlledModifiedCreatureAsSpellCastWatcher extends Watcher { super(WatcherScope.GAME); } - private final HashMap spellsCastCondition = new HashMap<>(); + private final HashMap modifiedCreaturesWhenCast = new HashMap<>(); @Override public void watch(GameEvent event, Game game) { @@ -35,8 +35,7 @@ public class ControlledModifiedCreatureAsSpellCastWatcher extends Watcher { Spell spell = game.getSpell(event.getTargetId()); if (spell != null) { MageObjectReference mor = new MageObjectReference(spell, game); - Boolean condition = !game.getBattlefield().getAllActivePermanents(filter, spell.getControllerId(), game).isEmpty(); - spellsCastCondition.put(mor, condition); + modifiedCreaturesWhenCast.put(mor, game.getBattlefield().countAll(filter, spell.getControllerId(), game)); } } } @@ -44,10 +43,10 @@ public class ControlledModifiedCreatureAsSpellCastWatcher extends Watcher { @Override public void reset() { super.reset(); - spellsCastCondition.clear(); + modifiedCreaturesWhenCast.clear(); } - public boolean checkModifiedCondition(MageObjectReference mor) { - return spellsCastCondition.getOrDefault(mor, false); + public int getModifiedCreatureCount(MageObjectReference mor) { + return modifiedCreaturesWhenCast.getOrDefault(mor, 0); } } diff --git a/Mage/src/main/java/mage/watchers/common/CreatedTokenWatcher.java b/Mage/src/main/java/mage/watchers/common/CreatedTokenWatcher.java new file mode 100644 index 00000000000..9f90d038614 --- /dev/null +++ b/Mage/src/main/java/mage/watchers/common/CreatedTokenWatcher.java @@ -0,0 +1,38 @@ +package mage.watchers.common; + +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public class CreatedTokenWatcher extends Watcher { + + private final Set playerIds = new HashSet<>(); + + public CreatedTokenWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.CREATED_TOKEN) { + playerIds.add(event.getPlayerId()); + } + } + + @Override + public void reset() { + playerIds.clear(); + } + + public static boolean checkPlayer(UUID playerId, Game game) { + return game.getState().getWatcher(CreatedTokenWatcher.class).playerIds.contains(playerId); + } +} diff --git a/Mage/src/main/java/mage/watchers/common/DamagedByControlledWatcher.java b/Mage/src/main/java/mage/watchers/common/DamagedByControlledWatcher.java new file mode 100644 index 00000000000..cfc8b28461b --- /dev/null +++ b/Mage/src/main/java/mage/watchers/common/DamagedByControlledWatcher.java @@ -0,0 +1,45 @@ +package mage.watchers.common; + +import mage.MageObjectReference; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.watchers.Watcher; + +import java.util.HashSet; + +/** + * + * @author weirddan455 + */ +public class DamagedByControlledWatcher extends Watcher { + + private final HashSet damagedPermanents = new HashSet<>(); + + public DamagedByControlledWatcher() { + super(WatcherScope.PLAYER); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.DAMAGED_PERMANENT) { + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent != null && permanent.isCreature(game)) { + if (controllerId != null && controllerId.equals(game.getControllerId(event.getSourceId()))) { + damagedPermanents.add(new MageObjectReference(event.getTargetId(), game)); + } + } + } + } + + @Override + public void reset() { + super.reset(); + damagedPermanents.clear(); + } + + public boolean wasDamaged(Permanent permanent, Game game) { + return damagedPermanents.contains(new MageObjectReference(permanent, game)); + } +} diff --git a/Mage/src/main/java/mage/watchers/common/EndStepCountWatcher.java b/Mage/src/main/java/mage/watchers/common/EndStepCountWatcher.java new file mode 100644 index 00000000000..2527cc48bfd --- /dev/null +++ b/Mage/src/main/java/mage/watchers/common/EndStepCountWatcher.java @@ -0,0 +1,38 @@ +package mage.watchers.common; + +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public class EndStepCountWatcher extends Watcher { + + private final Map playerMap = new HashMap<>(); + + public EndStepCountWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.END_TURN_STEP_PRE) { + playerMap.compute(game.getActivePlayerId(), CardUtil::setOrIncrementValue); + } + } + + public static int getCount(UUID playerId, Game game) { + return game + .getState() + .getWatcher(EndStepCountWatcher.class) + .playerMap + .getOrDefault(playerId, 0); + } +} diff --git a/Mage/src/main/java/mage/watchers/common/FirstTimeStepWatcher.java b/Mage/src/main/java/mage/watchers/common/FirstTimeStepWatcher.java deleted file mode 100644 index ebb2f8c232b..00000000000 --- a/Mage/src/main/java/mage/watchers/common/FirstTimeStepWatcher.java +++ /dev/null @@ -1,36 +0,0 @@ - -package mage.watchers.common; - -import mage.constants.WatcherScope; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.watchers.Watcher; - -/** - * The watcher checks if a specific phase event has already happened during the - * current turn. If not it returns false, otherwise true. - * - * @author LevelX2 - */ -public class FirstTimeStepWatcher extends Watcher { - - private final EventType eventType; - - public FirstTimeStepWatcher(EventType eventType) { - super(WatcherScope.GAME); - this.eventType = eventType; - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == eventType) { - condition = true; - } - } - - @Override - public String getBasicKey(){ - return eventType.toString() + FirstTimeStepWatcher.class.getSimpleName(); - } -} diff --git a/Mage/src/main/java/mage/watchers/common/PlanarRollWatcher.java b/Mage/src/main/java/mage/watchers/common/PlanarRollWatcher.java index 65714bfc3a4..9bd1b184a93 100644 --- a/Mage/src/main/java/mage/watchers/common/PlanarRollWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PlanarRollWatcher.java @@ -51,5 +51,12 @@ public class PlanarRollWatcher extends Watcher { super.reset(); numberTimesPlanarDieRolled.clear(); } + + public void removePlanarDieRoll(UUID playerId) { + Integer amount = numberTimesPlanarDieRolled.get(playerId); + if (amount != null){ + numberTimesPlanarDieRolled.put(playerId, amount-1); + } + } } diff --git a/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java b/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java index 94f222340a4..24acfb71ca4 100644 --- a/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java @@ -13,6 +13,7 @@ import mage.game.stack.Spell; import mage.watchers.Watcher; import java.util.*; +import java.util.stream.Stream; /** * @author LevelX2 @@ -59,6 +60,10 @@ public class SpellsCastWatcher extends Watcher { spellsCastFromGraveyard.clear(); } + public Stream getAllSpellsCastThisTurn() { + return spellsCast.values().stream().flatMap(Collection::stream); + } + public List getSpellsCastThisTurn(UUID playerId) { return spellsCast.computeIfAbsent(playerId, x -> new ArrayList<>()); } diff --git a/Utils/cardClass.tmpl b/Utils/cardClass.tmpl index 9d165a4cd2d..da22cf54057 100644 --- a/Utils/cardClass.tmpl +++ b/Utils/cardClass.tmpl @@ -3,7 +3,6 @@ package mage.cards.[=$cardNameFirstLetter=]; import java.util.UUID;[= if ($power || $power eq 0) { if ($planeswalker eq 'true') { - $OUT .= "\nimport mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility;" }else { $OUT .= "\nimport mage.MageInt;" } @@ -30,7 +29,7 @@ public final class [=$className=] extends CardImpl { [=$subType=][=$colors=][= if ($power || $power eq 0) { if ($planeswalker eq 'true') { - $OUT .= "\n this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility($power));"; + $OUT .= "\n this.setStartingLoyalty($power);"; } else { $OUT .= "\n this.power = new MageInt($power);"; $OUT .= "\n this.toughness = new MageInt($toughness);"; diff --git a/Utils/gen-card.pl b/Utils/gen-card.pl index 582ce382030..3aca628e2bb 100755 --- a/Utils/gen-card.pl +++ b/Utils/gen-card.pl @@ -20,7 +20,7 @@ my %keywords; sub toCamelCase { my $string = $_[0]; $string =~ s/\b([\w']+)\b/ucfirst($1)/ge; - $string =~ s/[-,\s\':]//g; + $string =~ s/[-,\s\':.]//g; $string; } diff --git a/Utils/keywords.txt b/Utils/keywords.txt index 610bd3b762e..eee09932023 100644 --- a/Utils/keywords.txt +++ b/Utils/keywords.txt @@ -6,17 +6,20 @@ Assist|new| Basic landcycling|cost| Battle cry|new| Bestow|card, manaString| +Blitz|card, manaString| Bloodthirst|number| Bushido|number| Buyback|manaString| Cascade|new| +Casualty|card, number| Changeling|new| Cleave|card, manaString| +Compleated|instance| Convoke|new| Crew|number| Cumulative upkeep|cost| Cycling|cost| -Dash|card, manaString| +Dash|manaString| Daybound|new| Deathtouch|instance| Demonstrate|new| @@ -52,6 +55,7 @@ Foretell|card, manaString| Friends forever|instance| Haste|instance| Hexproof|instance| +Hideaway|number| Improvise|new| Indestructible|instance| Infect|instance| @@ -64,7 +68,7 @@ Kicker|manaString| Level up|cost| Lifelink|instance| Living weapon|new| -Madness|card, cost| +Madness|cost| Melee|new| Menace|new| Mentor|new| @@ -72,7 +76,7 @@ Miracle|cost| Modular|card, number| Mountaincycling|cost| Mountainwalk|new| -Morph|card, cost| +Morph|cost| Mutate|card, manaString| Myriad|new| Nightbound|new| @@ -90,7 +94,7 @@ Reach|instance| Rebound|new| Reconfigure|manaString| Renown|number| -Replicate|card, manaString| +Replicate|manaString| Riot|new| Scavenge|cost| Shadow|instance| diff --git a/Utils/known-sets.txt b/Utils/known-sets.txt index b556a1bf932..7b87b273618 100644 --- a/Utils/known-sets.txt +++ b/Utils/known-sets.txt @@ -1,3 +1,4 @@ +Alchemy: Innistrad|AlchemyInnistrad| Adventures in the Forgotten Realms|AdventuresInTheForgottenRealms| Forgotten Realms Commander|ForgottenRealmsCommander| Aether Revolt|AetherRevolt| @@ -32,6 +33,7 @@ Commander 2019|Commander2019Edition| Commander 2020|Commander2020Edition| Commander 2021|Commander2021Edition| Commander Legends|CommanderLegends| +Commander Legends: Battle for Baldur's Gate|CommanderLegendsBattleForBaldursGate| Commander Anthology|CommanderAnthology| Commander Anthology 2018|CommanderAnthology2018| Commander's Arsenal|CommandersArsenal| @@ -200,6 +202,8 @@ Shards of Alara|ShardsOfAlara| Starter 1999|Starter1999| Starter 2000|Starter2000| Star Wars|StarWars| +Streets of New Capenna|StreetsOfNewCapenna| +New Capenna Commander|NewCapennaCommander| Strixhaven: School of Mages|StrixhavenSchoolOfMages| Stronghold|Stronghold| Super Series|SuperSeries| diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 32cb261c401..9d9bf712013 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -43749,13 +43749,13 @@ Greasefang, Okiba Boss|Kamigawa: Neon Dynasty|220|R|{1}{W}{B}|Legendary Creature Hidetsugu Consumes All|Kamigawa: Neon Dynasty|221|M|{1}{B}{R}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter.)$I — Destroy each nonland permanent with mana value 1 or less.$II — Exile all graveyards.$III — Exile this Saga, then return it to the battlefield transformed under your control.| Vessel of the All-Consuming|Kamigawa: Neon Dynasty|221|M||Enchantment Creature - Ogre Shaman|3|3|Trample$Whenever Vessel of the All-Consuming deals damage, put a +1/+1 counter on it.$Whenever Vessel of the All-Consuming deals damage to a player, if it has dealt 10 or more damage to that player this turn, they lose the game.| Hinata, Dawn-Crowned|Kamigawa: Neon Dynasty|222|R|{1}{U}{R}{W}|Legendary Creature - Kirin Spirit|4|4|Flying, trample$Spells you cast cost {1} less to cast for each target.$Spells your opponents cast cost {1} more to cast for each target.| -Invigorating Hot Spring|Kamigawa: Neon Dynasty|223|U|{1}{R}{G}|Enchantment|||Invigorating Hot Spring enters the battlefield with four +1/+1 counters on it.$Modified creatures you control have haste.$Remove a +1/+1 counter from Invigoration Hot Springs: Put a +1/+1 counter on target creature you control. Activate only as a sorcery and only once each turn.| +Invigorating Hot Spring|Kamigawa: Neon Dynasty|223|U|{1}{R}{G}|Enchantment|||Invigorating Hot Spring enters the battlefield with four +1/+1 counters on it.$Modified creatures you control have haste.$Remove a +1/+1 counter from Invigorating Hot Spring: Put a +1/+1 counter on target creature you control. Activate only as a sorcery and only once each turn.| Isshin, Two Heavens as One|Kamigawa: Neon Dynasty|224|R|{R}{W}{B}|Legendary Creature - Human Samurai|3|4|If a creature attacking causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.| Jukai Naturalist|Kamigawa: Neon Dynasty|225|U|{G}{W}|Enchantment Creature - Human Monk|2|2|Lifelink$Enchantment spells you cast cost {1} less to cast.| Kaito Shizuki|Kamigawa: Neon Dynasty|226|M|{1}{U}{B}|Legendary Planeswalker - Kaito|3|At the beginning of your end step, if Kaito Shizuki entered the battlefield this turn, he phases out.$+1: Draw a card. Then discard a card unless you attacked this turn.$−2: Create a 1/1 blue Ninja creature token with "This creature can't be blocked."$−7: You get an emblem with "Whenever a creature you control deals combat damage to a player, search your library for a blue or black creature card, put it onto the battlefield, then shuffle."| The Kami War|Kamigawa: Neon Dynasty|227|M|{1}{W}{U}{B}{R}{G}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter.)$I — Exile target nonland permanent an opponent controls.$II — Return up to one other target nonland permanent to its owner's hand. Then each opponent discards a card.$III — Exile this Saga, then return it to the battlefield transformed under your control.| O-Kagachi Made Manifest|Kamigawa: Neon Dynasty|227|M||Enchantment Creature - Dragon Spirit|6|6|O-Kagachi Made Manifest is all colors.$Flying, trample$Whenever O-Kagachi Made Manifest attacks, defending player chooses a nonland card in your graveyard. Return that card to your hand. O-Kagachi Made Manifest gets +X/+0 until end of turn, where X is the mana value of that card.| -Kotose, the Silent Spider|Kamigawa: Neon Dynasty|228|R|{3}{U}{B}|Legendary Creature - Human Ninja|4|4|When Kotose, the Silent Spider enters the battlefield, exile target card in an opponent's graveyard other than a basic land card. Search that player's graveyard, hand, and library for any number of cards with the same name as that card and exile them. For as long as you control Kotose, you may play one of the exiled cards, and you may spend mana as though it were mana of any color to cast it.| +Kotose, the Silent Spider|Kamigawa: Neon Dynasty|228|R|{3}{U}{B}|Legendary Creature - Human Ninja|4|4|When Kotose, the Silent Spider enters the battlefield, exile target card other than a basic land card from an opponent's graveyard. Search that player's graveyard, hand, and library for any number of cards with the same name as that card and exile them. Then that player shuffles. For as long as you control Kotose, you may play one of the exiled cards, and you may spend mana as though it were mana of any color to cast it.| Naomi, Pillar of Order|Kamigawa: Neon Dynasty|229|U|{3}{W}{B}|Legendary Creature - Human Advisor|4|4|Whenever Naomi, Pillar of Order enters the battlefield or attacks, if you control an artifact and an enchantment, create a 2/2 white Samurai creature token with vigilance.| Oni-Cult Anvil|Kamigawa: Neon Dynasty|230|U|{B}{R}|Artifact|||Whenever one or more artifacts you control leave the battlefield during your turn, create a 1/1 colorless Construct artifact creature token. This ability triggers only once each turn.${T}, Sacrifice an artifact: Oni-Cult Anvil deals 1 damage to each opponent. You gain 1 life.| Prodigy's Prototype|Kamigawa: Neon Dynasty|231|U|{1}{W}{U}|Artifact - Vehicle|3|4|Whenever one or more Vehicles you control attack, create a 1/1 colorless Pilot creature token with "This creature crews Vehicles as though its power were 2 greater."$Crew 2| @@ -43817,6 +43817,34 @@ Mountain|Kamigawa: Neon Dynasty|289|C||Basic Land - Mountain|||({T}: Add {R}.)| Forest|Kamigawa: Neon Dynasty|291|C||Basic Land - Forest|||({T}: Add {G}.)| Chishiro, the Shattered Blade|Neon Dynasty Commander|1|M|{2}{R}{G}|Legendary Creature - Snake Samurai|4|4|Whenever an Aura or Equipment enters the battlefield under your control, create a 2/2 red Spirit creature token with menace.$At the beginning of your end step, put a +1/+1 counter on each modified creature you control.| Kotori, Pilot Prodigy|Neon Dynasty Commander|2|M|{1}{W}{U}|Legendary Creature - Moonfolk Pilot|2|4|Vehicles you control have crew 2.$At the beginning of combat on your turn, target artifact creature you control gains lifelink and vigilance until end of turn.| +Kaima, the Fractured Calm|Neon Dynasty Commander|3|M|{2}{R}{G}|Legendary Creature - Spirit|3|3|At the beginning of your end step, goad each creature your opponents control that's enchanted by an Aura you control. Put a +1/+1 counter on Kaima, the Fractured Calm for each creature goaded this way.| +Shorikai, Genesis Engine|Neon Dynasty Commander|4|M|{2}{W}{U}|Legendary Artifact - Vehicle|8|8|{1}, {T}: Draw two cards, then discard a card. Create a 1/1 colorless Pilot creature token with "This creature crews Vehicles as though its power were 2 greater."$Crew 8$Shorikai, Genesis Engine can be your commander.| +Aerial Surveyor|Neon Dynasty Commander|5|R|{2}{W}|Artifact - Vehicle|3|4|Flying$Whenever Aerial Surveyor attacks, if defending player controls more lands than you, search your library for a basic Plains card, put it onto the battlefield tapped, then shuffle.$Crew 2| +Drumbellower|Neon Dynasty Commander|6|R|{2}{W}|Creature - Spirit|2|1|Flying$Untap all creatures you control during each other player's untap step.| +Ironsoul Enforcer|Neon Dynasty Commander|7|R|{4}{W}|Artifact Creature - Human Samurai|4|4|Whenever Ironsoul Enforcer or a commander you control attacks alone, return target artifact card from your graveyard to the battlefield.| +Organic Extinction|Neon Dynasty Commander|8|R|{8}{W}{W}|Sorcery|||Improvise$Destroy all nonartifact creatures.| +Release to Memory|Neon Dynasty Commander|9|R|{3}{W}|Instant|||Exile target opponent's graveyard. For each creature card exiled this way, create a 1/1 colorless Spirit creature token.| +Swift Reconfiguration|Neon Dynasty Commander|10|R|{W}|Enchantment - Aura|||Flash$Enchant creature or Vehicle$Enchanted permanent is a Vehicle artifact with crew 5 and it loses all other card types.| +Access Denied|Neon Dynasty Commander|11|R|{3}{U}{U}|Instant|||Counter target spell. Create X 1/1 colorless Thopter artifact creature tokens with flying, where X is that spell's mana value.| +Cyberdrive Awakener|Neon Dynasty Commander|12|R|{5}{U}|Artifact Creature - Construct|4|4|Flying$Other artifact creatures you control have flying.$When Cyberdrive Awakener enters the battlefield, until end of turn, each noncreature artifact you control becomes an artifact creature with base power and toughness 4/4.| +Imposter Mech|Neon Dynasty Commander|13|R|{1}{U}|Artifact - Vehicle|3|1|You may have Imposter Mech enter the battlefield as a copy of a creature an opponent controls, except its a Vehicle artifact with crew 3 and it loses all other card types.$Crew 3| +Kappa Cannoneer|Neon Dynasty Commander|14|R|{5}{U}|Artifact Creature - Turtle Warrior|4|4|Improvise$Ward {4}$Whenever an artifact enters the battlefield under your control, put a +1/+1 counter on Kappa Cannoneer and it can't be blocked this turn.| +Katsumasa, the Animator|Neon Dynasty Commander|15|R|{2}{U}{U}|Legendary Creature - Moonfolk Artificer|3|3|Flying${2}{U}: Until end of turn, target noncreature artifact you control becomes an artifact creature and gains flying. If it's not a Vehicle, it has base power and toughness 1/1 until end of turn.$At the beginning of your upkeep, put a +1/+1 counter on each of up to three target noncreature artifacts.| +Research Thief|Neon Dynasty Commander|16|R|{4}{U}|Artifact Creature - Moonfolk Wizard|3|3|Flash$Flying$Whenever an artifact creature you control deals combat damage to a player, draw a card.| +Universal Surveillance|Neon Dynasty Commander|17|R|{X}{U}{U}{U}|Sorcery|||Improvise$Draw X cards.| +Akki Battle Squad|Neon Dynasty Commander|18|R|{5}{R}|Creature - Goblin Samurai|6|6|Whenever one or more modified creatures you control attack, untap all modified creatures you control. After this combat phase, there is an additional combat phase. This ability triggers only once each turn.| +Collision of Realms|Neon Dynasty Commander|19|R|{6}{R}|Sorcery|||Each player shuffles all creatures they own into their library. Each player who shuffled a nontoken creature into their library this way reveals cards from the top of their library until they reveal a creature card, then puts that card onto the battlefield and the rest on the bottom of their library in a random order.| +Kami of Celebration|Neon Dynasty Commander|20|R|{4}{R}|Creature - Spirit|3|3|Whenever a modified creature you control attacks, exile the top card of your library. You may play that card this turn.$Whenever you cast a spell from exile, put a +1/+1 counter on target creature you control.| +Komainu Battle Armor|Neon Dynasty Commander|21|R|{2}{R}|Artifact Creature - Equipment Dog|2|2|Menace$Equipped creature gets +2/+2 and has menace.$Whenever Komainu Battle Armor or equipped creature deals combat damage to a player, goad each creature that player controls.$Reconfigure {4}| +Smoke Spirits' Aid|Neon Dynasty Commander|22|R|{X}{R}|Sorcery|||For each of up to X target creatures, create a red Aura enchantment token named Smoke Blessing attached to that creature. Those tokens have enchant creature and "When enchanted creature dies, it deals 1 damage to its controller and you create a Treasure token."| +Unquenchable Fury|Neon Dynasty Commander|23|R|{2}{R}|Enchantment - Aura|||Enchant creature$Enchanted creature has "Whenever this creature attacks, it deals X damage to defending player, where X is the number of cards in their hand."$When Unquenchable Fury is put into your graveyard from the battlfield, return it to your hand.| +Ascendant Acolyte|Neon Dynasty Commander|24|R|{4}{G}|Creature - Human Monk|1|1|Ascendant Acolyte enters the battlefield with a +1/+1 counter on it for each +1/+1 counter among other creatures you control.$At the beginning of your upkeep, double the number of +1/+1 counters on Ascendant Acolyte.| +Concord with the Kami|Neon Dynasty Commander|25|R|{3}{G}|Enchantment|||At the beginning of your end step, choose one or more —$• Put a +1/+1 counter on target creature with a counter on it.$• Draw a card if you control an enchanted creature.$• Create a 1/1 colorless Spirit creature token if you control an equipped creature.| +Kosei, Penitent Warlord|Neon Dynasty Commander|26|R|{1}{G}{G}|Legendary Creature - Ogre Samurai|0|5|As long as Kosei, Penitent Warlord is enchanted, equipped, and has a counter on it, Kosei has "Whenever Kosei, Penitent Warlord deals combat damage to an opponent, you draw that many cards and Kosei deals that much damage to each opponent."| +One with the Kami|Neon Dynasty Commander|27|R|{3}{G}|Enchantment - Aura|||Flash$Enchant creature you control$Whenever enchanted creature or another modified creature you control dies, create X 1/1 colorless Spirit creature tokens, where X is that creature's power.| +Rampant Rejuvenator|Neon Dynasty Commander|28|R|{3}{G}|Creature - Plant Hydra|0|0|Rampant Rejuvenator enters the battlefield with two +1/+1 counters on it.$When Rampant Rejuvenator dies, search your library for up to X basic land cards, where X is Rampant Rejuvenator's power, put them onto the battlefield, then shuffle.| +Silkguard|Neon Dynasty Commander|29|R|{X}{G}|Instant|||Put a +1/+1 counter on each of up to X target creatures you control.$Auras, Equipment, and modified creatures you control gain hexproof until end of turn.| +Tanuki Transplanter|Neon Dynasty Commander|30|R|{3}{G}|Artifact Creature - Equipment Dog|2|4|Whenever Tanuki Transplanter or equipped creature attacks, add an amount of {G} equal to its power. Until end of turn, you don't lose this mana as steps and phases end.$Reconfigure {3}| Myojin of Blooming Dawn|Neon Dynasty Commander|31|R|{5}{W}{W}{W}|Legendary Creature - Spirit|4|6|Myojin of Blooming Dawn enters the battlefield with an indestructible counter on it if you cast it from your hand.$Remove an indestructible counter from Myojin of Blooming Dawn: Create a 1/1 colorless Spirit creature token for each permanent you control.| Yoshimaru, Ever Faithful|Neon Dynasty Commander|32|M|{W}|Legendary Creature - Dog|1|1|Whenever another legendary permanent enters the battlefield under your control, put a +1/+1 counter on Yoshimaru, Ever Faithful.$Partner| Myojin of Cryptic Dreams|Neon Dynasty Commander|33|R|{5}{U}{U}{U}|Legendary Creature - Spirit|3|3|Myojin of Cryptic Dreams enters the battlefield with an indestructible counter on it if you cast it from your hand.$Remove an indestructible counter from Myojin of Cryptic Dreams: Copy target permanent spell you control three times.| @@ -43825,3 +43853,696 @@ Ruthless Technomancer|Neon Dynasty Commander|35|R|{3}{B}|Creature - Human Wizard Myojin of Roaring Blades|Neon Dynasty Commander|36|R|{5}{R}{R}{R}|Legendary Creature - Spirit|7|4|Myojin of Roaring Blades enters the battlefield with an indestructible counter on it if you cast it from your hand.$Remove an indestructible counter from Myojin of Roaring Blades: It deals 7 damage to each of up to three targets.| Go-Shintai of Life's Origin|Neon Dynasty Commander|37|M|{3}{G}|Legendary Enchantment Creature - Shrine|3|4|{W}{U}{B}{R}{G}, {T}: Return target enchantment card from your graveyard to the battlefield.$Whenever Go-Shintai of Life's Origin or another nontoken Shrine enters the battlefield under your control, create a 1/1 colorless Shrine enchantment creature token.| Myojin of Towering Might|Neon Dynasty Commander|38|R|{5}{G}{G}{G}|Legendary Creature - Spirit|8|8|Myojin of Towering Might enters the battlefield with an indestructible counter on it if you cast it from your hand.$Remove an indestructible counter from Myojin of Towering Might: Distribute eight +1/+1 counters among any number of target creatures you control. They gain trample until end of turn.| +Angel of Eternal Dawn|Alchemy: Innistrad|1|R|{2}{W}|Creature - Angel|2|4|Flying$When Angel of Eternal Dawn enters the battlefield, it becomes day.$It can't become night.$Your opponents can't cast spells with mana value greater than the number of turns they have begun.| +Angel of Unity|Alchemy: Innistrad|2|U|{1}{W}|Creature - Angel Cleric|1|3|Flying, lifelink$Whenever Angel of Unity enters the battlefield or you cast a party spell, choose a party creature card in your hand. It perpetually gets +1/+1.| +Captain Eberhart|Alchemy: Innistrad|3|M|{1}{W}|Legendary Creature - Human Soldier|1|1|Double strike$Spells cast from among cards you drew this turn cost {1} less to cast.$Spells cast from among cards your opponents drew this turn cost {1} more to cast.| +Divine Purge|Alchemy: Innistrad|4|R|{1}{W}{W}|Sorcery|||Exile all artifacts and creatures with mana value 3 or less. They perpetually gain "This spell costs {2} more to cast" and "This permanent enters the battlefield tapped." For as long as each of them remain exiled, its owner may play it.| +Ethereal Escort|Alchemy: Innistrad|5|M|{2}{W}|Creature - Spirit|3|3|Lifelink$Whenever Ethereal Escort enters the battlefield or attacks, choose a card in your hand. It perpetually gains lifelink.| +Expedition Supplier|Alchemy: Innistrad|6|R|{2}{W}|Creature - Human Warrior|2|2|Whenever Expedition Supplier or another Human enters the battlefield under your control, conjure a card named Utility Knife onto the battlefield. This ability triggers only once each turn.| +Faithful Disciple|Alchemy: Innistrad|7|U|{1}{W}|Creature - Human Cleric|2|2|Vigilance$When Faithful Disciple dies, draft a card from Faithful Disciple's spellbook.| +Inquisitor Captain|Alchemy: Innistrad|8|R|{3}{W}|Creature - Human Cleric|3|3|Vigilance$When Inquisitor Captain enters the battlefield, if you cast it and there are twenty or more creature cards with mana value 3 or less among cards in your graveyard, hand, and library, seek two creature cards with mana value 3 or less. Put one of them onto the battlefield and shuffle the other into your library.| +Sigardian Evangel|Alchemy: Innistrad|9|R|{1}{W}|Creature - Human Cleric|3|1|When Sigardian Evangel enters the battlefield, conjure a card named Sigardian Evangel into your hand. Discard that card at the beginning of the next end step.$When Sigardian Evangel enters the battlefield, tap target permanent you don't control.| +Slayer's Bounty|Alchemy: Innistrad|10|R|{W}|Legendary Artifact - Clue|||When Slayer's Bounty enters the battlefield, look at the creature cards in target opponent's hand.$Whenever you sacrifice Slayer's Bounty or another Clue, draft a card from Slayer's Bounty's spellbook.${2}, Sacrifice Slayer's Bounty: Draw a card.| +Suntail Squadron|Alchemy: Innistrad|11|R|{2}{W}{W}|Instant|||Conjure a card named Suntail Hawk into your hand. If you have fewer than 7 cards in hand, repeat this process.| +Absorb Energy|Alchemy: Innistrad|12|R|{1}{U}{U}|Instant|||Counter target spell. Cards in your hand that share a card type with that spell perpetually gain "This spell costs {1} less to cast."| +Unexpected Conversion|Alchemy: Innistrad|13|R|{2}{U}|Sorcery|||Draw two cards. Then you may exile an instant or sorcery card from your hand. If you do, search your hand and library for any number of cards with the same name, exile them, then shuffle. Seek an instant or sorcery card for each card exiled from your hand this way.| +Clone Crafter|Alchemy: Innistrad|14|R|{1}{U}|Creature - Human Wizard|1|2|When Clone Crafter enters the battlefield, conjure a duplicate of a random creature card from your opponent's library into your hand. It perpetually gains "You may spend mana as though it were mana of any color to cast this spell."| +Discover the Formula|Alchemy: Innistrad|15|R|{4}{U}{U}|Instant|||Seek three nonland cards, then nonland cards in your hand perpetually gain "This spell costs {1} less to cast."| +Geist of Regret|Alchemy: Innistrad|16|M|{4}{U}|Creature - Spirit|4|5|Flying$When Geist of Regret enters the battlefield, put a random instant card from your library into your graveyard. Then put a random sorcery card from your library into your graveyard.$Whenever you cast an instant or sorcery spell from your graveyard, copy that spell. You may choose new targets for the copy.| +Geistchanneler|Alchemy: Innistrad|17|R|{1}{U}|Creature - Human Wizard|1|3|When Geistchanneler enters the battlefield, choose an instant or sorcery card in your hand with mana value 3 or greater. It perpetually gains "This spell costs {2} less to cast."| +Kindred Denial|Alchemy: Innistrad|18|U|{2}{U}{U}|Instant|||Counter target spell. Seek a card with the same mana value as that spell.| +Obsessive Collector|Alchemy: Innistrad|19|R|{3}{U}|Creature - Spirit|4|3|Flying$Ward {2}$Whenever Obsessive Collector deals combat damage to a player, seek a card with mana value equal to the number of cards in your hand.| +Oglor, Devoted Assistant|Alchemy: Innistrad|20|M|{1}{U}|Legendary Creature - Homunculus|1|1|At the beginning of your upkeep, look at the top two cards of your library, then put one of them into your graveyard.$Whenever a creature card is put into your graveyard from your library or hand, it perpetually gains "When this card leaves your graveyard, create a tapped 2/2 black Zombie creature token."| +Rimewall Protector|Alchemy: Innistrad|21|U|{1}{U}{U}|Creature - Giant Wizard|3|4|Ward {1}$When Rimewall Protector enters the battlefield, each other Giant or Wizard you control and each Giant or Wizard card in your hand perpetually gains ward {1}.| +Sinister Reflections|Alchemy: Innistrad|22|R|{1}{U}|Instant|||Conjure a duplicate of each of up to two target nontoken creatures you control into your hand.| +Tireless Angler|Alchemy: Innistrad|23|R|{2}{U}|Creature - Human Rogue|1|4|Whenever an Island or Swamp enters the battlefield under your control, draft a card from Tireless Angler's spellbook.| +Cursebound Witch|Alchemy: Innistrad|24|U|{B}|Creature - Human Warlock|1|2|When Cursebound Witch dies, draft a card from Cursebound Witch's spellbook.| +Assemble from Parts|Alchemy: Innistrad|25|R|{B}|Instant|||Target creature card in your graveyard perpetually gains "{1}{B}{B}, Exile this card from your graveyard: Shuffle it into your library. Create a token that's a copy of it, except it's a 4/4 black Zombie in addition to its other types. Activate only as a sorcery."| +Break Expectations|Alchemy: Innistrad|26|U|{B}|Sorcery|||Target player reveals all cards with mana value 2 or greater in their hand. You choose a card from among those cards. Exile that card. If a card was exiled this way, that player drafts a card from Break Expectations's spellbook and reveals it.| +Citystalker Connoisseur|Alchemy: Innistrad|27|R|{3}{B}|Creature - Vampire|3|3|Deathtouch$When Citystalker Connoisseur enters the battlefield, target opponent discards a card with the greatest mana value among cards in their hand. Create a Blood token.| +Gutmorn, Pactbound Servant|Alchemy: Innistrad|28|M|{2}{B}|Legendary Creature - Demon|1|3|Flying, deathtouch$Whenever Gutmorn, Pactbound Servant enters the battlefield, each player discards a nonland card.$Whenever a player discards a card during your turn, they choose another player. That player conjures a duplicate of that card into their hand. It perpetually gains "You may spend mana as though it were mana of any color to cast this spell."| +Patient Zero|Alchemy: Innistrad|29|R|{1}{B}|Creature - Zombie|2|2|Lifelink$Damage isn't removed from creatures your opponents control during cleanup steps.| +Predatory Sludge|Alchemy: Innistrad|30|R|{2}{B}|Creature - Ooze|3|3|Menace$As Predatory Sludge enters the battlefield, choose a permanent you don't control. When the chosen permanent is put into a graveyard from the battlefield, conjure a card named Predatory Sludge into your hand.| +Puppet Raiser|Alchemy: Innistrad|31|M|{3}{B}|Creature - Zombie Wizard|3|4|At the beginning of your end step, exile up to one target creature card from your graveyard. If you do, seek a creature card with mana value equal to that mana value of that card plus one. That card perpetually gains menace.| +Sanguine Brushstroke|Alchemy: Innistrad|32|R|{1}{B}{B}|Enchantment|||When Sanguine Brushstroke enters the battlefield, create a Blood token and conjure a card named Blood Artist onto the battlefield.$Whenever you sacrifice a Blood token, each opponent loses 1 life.| +Sap Vitality|Alchemy: Innistrad|33|R|{B}{B}|Instant|||Sap Vitality deals 3 damage to target creature or planeswalker. Choose a creature card in your hand. It perpetually gets +3/+0.| +Veteran Ghoulcaller|Alchemy: Innistrad|34|R|{1}{B}|Creature - Human Rogue|2|1|Menace$Whenever a card in your graveyard is put into your hand, conjure a duplicate of that card into your hand.| +Arms Scavenger|Alchemy: Innistrad|35|R|{1}{R}|Creature - Human Warrior|2|2|At the beginning of your upkeep, draft a card from Arms Scavenger's spellbook, then exile it. Until end of turn, you may play that card.| +Bloodrage Alpha|Alchemy: Innistrad|36|R|{3}{R}|Creature - Wolf|4|4|When Bloodrage Alpha enters the battlefield, choose one —$• Another target Wolf or Werewolf you control fights target creature you don't control.$• When you cast your next Wolf or Werewolf spell, it gains "When this creature enters the battlefield, it fights up to one target creature you don't control."| +Brittle Blast|Alchemy: Innistrad|37|U|{2}{R}|Instant|||Creatures and planeswalkers your opponents control perpetually gain "If this permanent would die, exile it instead." Brittle Blast deals 5 damage to target creature or planeswalker.| +Conductive Current|Alchemy: Innistrad|38|R|{R}{R}{R}|Sorcery|||Conductive Current deals 3 damage to each creature. Choose an instant or sorcery card in your hand. It perpetually gains "If this spell would deal noncombat damage to a permanent or player, it deals that much damage plus 2 instead."| +Electrostatic Blast|Alchemy: Innistrad|39|R|{1}{R}|Instant|||Electrostatic Blast deals 2 damage to any target. When you cast your next instant or sorcery spell, exile the top three cards of your library. You may play one of those cards until end of turn.| +Fearsome Whelp|Alchemy: Innistrad|40|U|{1}{R}|Creature - Dragon|1|1|Flying$At the beginning of your upkeep, each Dragon card in your hand perpetually gains "This spell costs {1} less to cast."| +Frenzied Geistblaster|Alchemy: Innistrad|41|R|{1}{R}|Creature - Human Wizard|2|2|Prowess$When Frenzied Geistblaster enters the battlefield, if there are twenty or more instant and/or sorcery cards among cards in your graveyard, hand, and library, you may discard a card. If you do, seek an instant or sorcery card.| +Rahilda, Wanted Cutthroat|Alchemy: Innistrad|42|M|{1}{R}|Legendary Creature - Human Werewolf|2|2|First strike$When Rahilda, Wanted Cutthroat deals combat damage to a player, exile a nonland card from their library at random. During any turn you attacked with a Wolf or Werewolf, you may cast that card and you may spend mana as though it were mana of any color to cast that spell.$Daybound| +Rahilda, Feral Outlaw|Alchemy: Innistrad|42|M||Legendary Creature - Human Werewolf|2|2|Double strike$When Rahilda, Feral Outlaw deals combat damage to a player, exile a nonland card from their library at random. During any turn you attacked with a Wolf or Werewolf, you may cast that card and you may spend mana as though it were mana of any color to cast that spell.$Nightbound| +Tibalt, Wicked Tormentor|Alchemy: Innistrad|43|M|{3}{R}{R}|Legendary Planeswalker - Tibalt|3|+1: Add {R}{R}. Draft a card from Tibalt, Wicked Tormenter's spellbook, then exile it. Until end of turn, you may cast that card.$+1: Tibalt, Wicked Tormenter deals 4 damage to target creature or planeswalker unless its controller has Tibalt deal 4 damage to them. If they do, you may discard a card. If you do, draw a card.$−X: Create X 1/1 red Devil creature tokens with "When this creature dies, it deals 1 damage to any target."| +Toralf's Disciple|Alchemy: Innistrad|44|R|{2}{R}|Creature - Human Warrior|3|3|Haste$Whenever Toralf's Disciple attacks, conjure four cards named Lightning Bolt into your library, then shuffle.| +Town-Razer Tyrant|Alchemy: Innistrad|45|R|{2}{R}{R}|Creature - Dragon|4|4|Flying$When Town-Razer Tyrant enters the battlefield, target nonbasic land you don't control loses all abilities except mana abilities and gains "At the beginning of your end step, this permanent deals 2 damage to you unless you sacrifice it."| +Antique Collector|Alchemy: Innistrad|46|R|{1}{G}|Creature - Human Rogue|2|2|Antique Collector can't be blocked by creatures with power 2 or less.$When Antique Collector enters the battlefield, creatures you control perpetually gain "When this creature dies, you may shuffle it into its owner's library if its in your graveyard. If you do, investigate."| +Garruk, Wrath of the Wilds|Alchemy: Innistrad|47|M|{2}{G}{G}|Legendary Planeswalker - Garruk|3|+1: Choose a creature card in your hand. It perpetually gets +1/+1 and perpetually gains "This spell costs {1} less to cast."$−1: Draft a card from Garruk, Wrath of the Wilds's spellbook and put it onto the battlefield.$−5: Until end of turn, creatures you control get +3/+3 and gain trample.| +Geistpack Alpha|Alchemy: Innistrad|48|R|{3}{G}|Creature - Wolf|5|4|Trample$When Geistpack Alpha dies, seek a permanent card with mana value equal to the number of lands you control.| +Grizzled Huntmaster|Alchemy: Innistrad|49|R|{1}{G}{G}|Creature - Human Warrior|4|3|When Grizzled Huntmaster enters the battlefield, you may exile a creature card from your hand. If you do, search your hand and library for any number of cards with the same name, exile them, then shuffle. Choose a creature card you own from outside the game. Conjure a duplicate of that card into your hand for each card exiled from your hand this way.| +Hinterland Chef|Alchemy: Innistrad|50|R|{2}{G}|Creature - Human Scout|3|3|When Hinterland Chef enters the battlefield, draft a card from Hinterland Chef's spellbook. It perpetually becomes a Food artifact in addition to its other types and perpetually gains "{2}, {T}, Sacrifice this creature: You gain 3 life."| +Hollowhenge Wrangler|Alchemy: Innistrad|51|R|{3}{G}{G}|Creature - Elemental|6|6|When Hollowhenge Wrangler enters the battlefield, seek a land card.$Discard a land card: Conjure a card named Hollowhenge Beast into your hand. You may also activate this ability while Hollowhenge Wrangler is in your graveyard.| +Ishkanah, Broodmother|Alchemy: Innistrad|52|M|{3}{G}|Legendary Creature - Spider|3|5|Reach$Other Spiders you control get +1/+2.${1}{B/G}, Exile two cards from your graveyard: Draft a card from Ishkanah, Broodmother's spellbook.| +Lupine Harbingers|Alchemy: Innistrad|53|R|{3}{G}|Creature - Wolf|4|4|Trample, haste$Lupine Harbingers enters the battlefield with X +1/+1 counters on it, where X is the number of turns you've begun since it was foretold.$Foretell {4}{G}{G}| +Ravenous Pursuit|Alchemy: Innistrad|54|R|{1}{G}|Sorcery|||Target creature you control deals damage equal to its power to target creature you don't control. Choose a creature card in your hand. It perpetually gets +X/+X, where X is the amount of excess damage dealt this way.| +Settle the Wilds|Alchemy: Innistrad|55|U|{1}{G}{G}|Sorcery|||Seek a basic land card and put it onto the battlefield tapped. Then seek a permanent card with mana value equal to the number of lands you control.| +Tenacious Pup|Alchemy: Innistrad|56|U|{G}|Creature - Wolf|1|2|When Tenacious Pup enters the battlefield, you gain 1 life. When you cast your next creature spell, that creature enters the battlefield with an additional +1/+1 counter, trample counter, and vigilance counter on it.| +Begin Anew|Alchemy: Innistrad|57|R|{G}{G}{W}{W}|Sorcery|||Destroy all creatures. Creature cards in your hand perpetually get +1/+1.| +Gitrog, Horror of Zhava|Alchemy: Innistrad|58|R|{2}{B}{G}|Legendary Creature - Frog Horror|6|6|Menace$At the beginning of each combat, if Gitrog, Horror of Zhava is untapped, any opponent may sacrifice a nontoken creature. If they do, tap Gitrog, Horror of Zhava, then seek a land card and put it onto the battlefield tapped.$Whenever a land enters the battlefield under your control, it perpetually gains "{B}{G}, {T}, Sacrifice this land: Draw a card."| +Key to the Archive|Alchemy: Innistrad|59|R|{4}|Artifact|||Key to the Archive enters the battlefield tapped.$When Key to the Archive enters the battlefield, draft a card from Key to the Archive's spellbook, then discard a card.${T}: Add two mana in any combination of colors.| +Soulstealer Axe|Alchemy: Innistrad|60|U|{1}|Artifact - Equipment|||Equipped creature has trample.$Whenever equipped creature deals combat damage to a player, seek a card with mana value equal to that damage.$Equip {2}| +Wickerwing Effigy|Alchemy: Innistrad|61|R|{3}|Artifact Creature - Scarecrow|1|4|Defender$You may look at the top card of your library any time.$You may cast creature spells from the top of your library.$Whenever you cast a creature spell from your library, it becomes a black Bird in addition to its other colors and types, has flying, and has base power and toughness 1/1.| +Ominous Traveler|Alchemy: Innistrad|62|R|{2}|Creature - Human|1|1|When Ominous Traveler enters the battlefield, draft a card from Ominous Traveler's spellbook. That card perpetually gains "You may spend mana as though it were mana of any color to cast this spell" and "When you cast this spell, return a card named Ominous Traveler you control to its owner's hand."| +Forsaken Crossroads|Alchemy: Innistrad|63|R||Land|||Forsaken Crossroads enters the battlefield tapped.$As Forsaken Crossroads enters the battlefield, choose a color.$When Forsaken Crossroads enters the battlefield, scry 1. If you weren't the starting player, you may untap Forsaken Crossroads instead.${T}: Add one mana of the chosen color.| +Angelic Observer|Streets of New Capenna|1|U|{5}{W}|Creature - Angel Advisor|3|3|This spell costs {1} less to cast for each Citizen you control.$Flying| +Backup Agent|Streets of New Capenna|2|C|{1}{W}|Creature - Human Citizen|1|1|When Backup Agent enters the battlefield, put a +1/+1 counter on target creature.| +Ballroom Brawlers|Streets of New Capenna|3|U|{3}{W}{W}|Creature - Human Warrior|3|5|Whenever Ballroom Brawlers attacks, Ballroom Brawlers and up to one other target creature you control both gain your choice of first strike or lifelink until end of turn.| +Boon of Safety|Streets of New Capenna|4|C|{W}|Instant|||Put a shield counter on target creature.$Scry 1.| +Brokers Initiate|Streets of New Capenna|5|C|{W}|Creature - Cat Citizen|0|4|{4}{G/U}: Brokers Initiate has base power and toughness 5/5 until end of turn.| +Buy Your Silence|Streets of New Capenna|6|C|{4}{W}|Sorcery|||Exile target nonland permanent. Its controller creates a Treasure token.| +Celebrity Fencer|Streets of New Capenna|7|C|{3}{W}|Creature - Elf Druid|3|2|Alliance — Whenever another creature enters the battlefield under your control, put a +1/+1 counter on Celebrity Fencer.| +Citizen's Crowbar|Streets of New Capenna|8|U|{1}{W}|Artifact - Equipment|||When Citizen's Crowbar enters the battlefield, create a 1/1 green and white Citizen creature token, then attach Citizen's Crowbar to it.$Equipped creature gets +1/+1 and has "{W}, {T}, Sacrifice Citizen's Crowbar: Destroy target artifact or enchantment."$Equip {2}| +Dapper Shieldmate|Streets of New Capenna|9|C|{3}{W}|Creature - Human Soldier|2|2|Dapper Shieldmate enters the battlefield with a shield counter on it.$As long as it's your turn, Dapper Shieldmate gets +2/+0.| +Depopulate|Streets of New Capenna|10|R|{2}{W}{W}|Sorcery|||Each player who controls a multicolored creature draws a card. Then destroy all creatures.| +Elspeth Resplendent|Streets of New Capenna|11|M|{3}{W}{W}|Legendary Planeswalker - Elspeth|5|+1: Choose up to one target creature. Put a +1/+1 counter and a counter from among flying, first strike, lifelink, or vigilance on it.$−3: Look at the top seven cards of your library. You may put a permanent card with mana value 3 or less from among them onto the battlefield with a shield counter on it. Put the rest on the bottom of your library in a random order.$−7: Create five 3/3 white Angel creature tokens with flying.| +Extraction Specialist|Streets of New Capenna|12|R|{2}{W}|Creature - Human Rogue|3|2|Lifelink$When Extraction Specialist enters the battlefield, return target creature card with mana value 2 or less from your graveyard to the battlefield. That creature can't attack or block for as long as you control Extraction Specialist.| +Gathering Throng|Streets of New Capenna|13|C|{2}{W}|Creature - Human Citizen|3|1|When Gathering Throng enters the battlefield, you may search your library for any number of cards named Gathering Throng, reveal them, put them into your hand, then shuffle.| +Giada, Font of Hope|Streets of New Capenna|14|R|{1}{W}|Legendary Creature - Angel|2|2|Flying, vigilance$Each other Angel you control enters the battlefield with an additional +1/+1 counter on it for each Angel you already control.${T}: Add {W}. Spend this mana only to cast an Angel spell.| +Halo Fountain|Streets of New Capenna|15|M|{2}{W}|Artifact|||{W}, {T}, Untap a tapped creature you control: Create a 1/1 green and white Citizen creature token.${W}{W}, {T}, Untap two tapped creatures you control: Draw a card.${W}{W}{W}{W}{W}, {T}, Untap fifteen tapped creatures you control: You win the game.| +Hold for Ransom|Streets of New Capenna|16|C|{1}{W}|Enchantment - Aura|||Enchant creature$Enchanted creature can't attack or block and has "{7}: Hold for Ransom's controller sacrifices it and draws a card. Activate only as a sorcery."| +Illuminator Virtuoso|Streets of New Capenna|17|U|{1}{W}|Creature - Human Rogue|1|1|Double strike$Whenever Illuminator Virtuoso becomes the target of a spell you control, it connives.| +Inspiring Overseer|Streets of New Capenna|18|C|{2}{W}|Creature - Angel Cleric|2|1|Flying$When Inspiring Overseer enters the battlefield, you gain 1 life and draw a card.| +Kill Shot|Streets of New Capenna|19|C|{2}{W}|Instant|||Destroy target attacking creature.| +Knockout Blow|Streets of New Capenna|20|U|{2}{W}|Instant|||This spell costs {2} less to cast if it targets a red creature.$Knockout Blow deals 4 damage to target attacking or blocking creature and you gain 2 life.| +Mage's Attendant|Streets of New Capenna|21|U|{2}{W}|Creature - Cat Rogue|3|2|When Mage's Attendant enters the battlefield, create a 1/1 blue Wizard creature token with "{1}, Sacrifice this creature: Counter target noncreature spell unless its controller pays {1}."| +Mysterious Limousine|Streets of New Capenna|22|R|{3}{W}{W}|Artifact - Vehicle|4|4|Whenever Mysterious Limousine enters the battlefield or attacks, exile up to one other target creature until Mysterious Limousine leaves the battlefield. If a creature is put into exile this way, return each other card exiled with Mysterious Limousine to the battlefield under its owner's control.$Crew 2| +Patch Up|Streets of New Capenna|23|U|{2}{W}|Sorcery|||Return up to three target creature cards with total mana value 3 or less from your graveyard to the battlefield.| +Rabble Rousing|Streets of New Capenna|24|R|{4}{W}|Enchantment|||Hideaway 5$Whenever you attack with one or more creatures, create that many 1/1 green and white Citizen creature tokens. Then if you control ten or more creatures, you may play the exiled card without paying its mana cost.| +Raffine's Guidance|Streets of New Capenna|25|C|{W}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +1/+1.$You may cast Raffine's Guidance from your graveyard by paying {2}{W} rather than paying its mana cost.| +Raffine's Informant|Streets of New Capenna|26|C|{1}{W}|Creature - Human Wizard|2|1|When Raffine's Informant enters the battlefield, it connives.| +Refuse to Yield|Streets of New Capenna|27|U|{1}{W}|Instant|||Target creature gets +2/+7 until end of turn. Untap it.| +Revelation of Power|Streets of New Capenna|28|C|{1}{W}|Instant|||Target creature gets +2/+2 until end of turn. If it has a counter on it, it also gains flying and lifelink until end of turn.| +Rumor Gatherer|Streets of New Capenna|29|U|{1}{W}{W}|Creature - Elf Wizard|2|1|Alliance — Whenever another creature enters the battlefield under your control, scry 1. If this is the second time this ability has resolved this turn, draw a card instead.| +Sanctuary Warden|Streets of New Capenna|30|M|{4}{W}{W}|Creature - Angel Soldier|5|5|Flying$Sanctuary Warden enters the battlefield with two shield counters on it.$Whenever Sanctuary Warden enters the battlefield or attacks, you may remove a counter from a creature or planeswalker you control. If you do, draw a card and create a 1/1 green and white Citizen creature token.| +Sky Crier|Streets of New Capenna|31|C|{1}{W}|Creature - Bird Citizen|1|1|Flying, lifelink${3}{W}: You and target opponent each draw a card.| +Speakeasy Server|Streets of New Capenna|32|C|{4}{W}|Creature - Bird Citizen|3|3|Flying$When Speakeasy Server enters the battlefield, you gain 1 life for each other creature you control.| +Swooping Protector|Streets of New Capenna|33|U|{3}{W}|Creature - Bird Citizen|2|1|Flash$Flying$Swooping Protector enters the battlefield with a shield counter on it.| +All-Seeing Arbiter|Streets of New Capenna|34|M|{4}{U}{U}|Creature - Avatar|5|4|Flying$Whenever All-Seeing Arbiter enters the battlefield or attacks, draw two cards, then discard a card.$Whenever you discard a card, target creature an opponent controls gets -X/-0 until your next turn, where X is the number of different mana values among cards in your graveyard.| +Backstreet Bruiser|Streets of New Capenna|35|C|{1}{U}|Creature - Cephalid Rogue|3|3|Defender$As long as there are two or more counters among creatures you control, Backstreet Bruiser can attack as though it didn't have defender.| +Brokers Veteran|Streets of New Capenna|36|C|{1}{U}|Creature - Human Soldier|2|1|When Brokers Veteran dies, put a shield counter on target creature you control.| +Case the Joint|Streets of New Capenna|37|C|{3}{U}|Instant|||Draw two cards, then look at the top card of each player's library.| +Cut Your Losses|Streets of New Capenna|38|R|{4}{U}{U}|Sorcery|||Casualty 2$Target player mills half their library, rounded down.| +Disdainful Stroke|Streets of New Capenna|39|C|{1}{U}|Instant|||Counter target spell with mana value 4 or greater.| +Echo Inspector|Streets of New Capenna|40|C|{3}{U}|Creature - Bird Rogue|2|3|Flying$When Echo Inspector enters the battlefield, it connives.| +Errant, Street Artist|Streets of New Capenna|41|R|{U}|Legendary Creature - Human Rogue|0|3|Flash$Defender, haste${1}{U}, {T}: Copy target spell you control that wasn't cast. You may choose new targets for the copy.| +Even the Score|Streets of New Capenna|42|M|{X}{U}{U}{U}|Instant|||This spell costs {U}{U}{U} less to cast if an opponent has drawn four or more cards this turn.$Draw X cards.| +Expendable Lackey|Streets of New Capenna|43|C|{U}|Creature - Human Citizen|1|1|{1}{U}, Exile Expendable Lackey from your graveyard: Create a 1/1 blue Fish creature token with "This creature can't be blocked." Activate only as a sorcery.| +Faerie Vandal|Streets of New Capenna|44|U|{1}{U}|Creature - Faerie Rogue|1|2|Flash$Flying$Whenever you draw your second card each turn, put a +1/+1 counter on Faerie Vandal.| +Hypnotic Grifter|Streets of New Capenna|45|U|{U}|Creature - Human Rogue|1|2|{3}: Hypnotic Grifter connives.| +Ledger Shredder|Streets of New Capenna|46|R|{1}{U}|Creature - Bird Advisor|1|3|Flying$Whenever a player casts their second spell each turn, Ledger Shredder connives.| +A Little Chat|Streets of New Capenna|47|U|{1}{U}|Instant|||Casualty 1$Look at the top two cards of your library. Put one of them into your hand and the other on the bottom of your library.| +Majestic Metamorphosis|Streets of New Capenna|48|C|{2}{U}|Instant|||Until end of turn, target artifact or creature becomes a 4/4 Angel artifact creature and gains flying.$Draw a card.| +Make Disappear|Streets of New Capenna|49|C|{1}{U}|Instant|||Casualty 1$Counter target spell unless its controller pays {2}.| +Obscura Initiate|Streets of New Capenna|50|C|{2}{U}|Creature - Bird Citizen|2|2|Flying${1}{W/B}: Obscura Initiate gains lifelink until end of turn.| +An Offer You Can't Refuse|Streets of New Capenna|51|U|{U}|Instant|||Counter target noncreature spell. Its controller creates two Treasure tokens.| +Out of the Way|Streets of New Capenna|52|U|{3}{U}|Instant|||This spell costs {2} less to cast if it targets a green permanent.$Return target nonland permanent an opponent controls to its owner's hand.$Draw a card.| +Psionic Snoop|Streets of New Capenna|53|C|{2}{U}|Creature - Human Rogue|0|3|Flash$When Psionic Snoop enters the battlefield, it connives.| +Psychic Pickpocket|Streets of New Capenna|54|U|{4}{U}|Creature - Cephalid Rogue|3|2|When Psychic Pickpocket enters the battlefield, it connives. When it connives this way, return up to one target nonland permanent to its owner's hand.| +Public Enemy|Streets of New Capenna|55|U|{2}{U}|Enchantment - Aura|||Enchant creature$All creatures attack enchanted creature's controller each combat if able.$When enchanted creature dies, draw a card.| +Reservoir Kraken|Streets of New Capenna|56|R|{2}{U}{U}|Creature - Kraken|6|6|Trample, ward {2}$At the beginning of each combat, if Reservoir Kraken is untapped, any opponent may tap an untapped creature they control. If they do, tap Reservoir Kraken and create a 1/1 blue Fish creature token with "This creature can't be blocked."| +Rooftop Nuisance|Streets of New Capenna|57|C|{2}{U}|Sorcery|||Casualty 1$Tap target creature. It doesn't untap during its controller's next untap step.$Draw a card.| +Run Out of Town|Streets of New Capenna|58|C|{3}{U}|Instant|||The owner of target nonland permanent puts it on the top or bottom of their library.| +Security Bypass|Streets of New Capenna|59|C|{1}{U}|Enchantment - Aura|||Enchant creature$As long as enchanted creature is attacking alone, it can't be blocked.$Enchanted creature has "Whenever this creature deals combat damage to a player, it connives."| +Sewer Crocodile|Streets of New Capenna|60|C|{5}{U}|Creature - Crocodile|4|6|{3}{U}: Sewer Crocodile can't be blocked this turn. This ability costs {3} less to activate if there are five or more mana values among cards in your graveyard.| +Sleep with the Fishes|Streets of New Capenna|61|U|{2}{U}{U}|Enchantment - Aura|||Enchant creature$When Sleep with the Fishes enters the battlefield, tap enchanted creature and you create a 1/1 blue Fish creature token with "This creature can't be blocked."$Enchanted creature doesn't untap during its controller's untap step.| +Slip Out the Back|Streets of New Capenna|62|U|{U}|Instant|||Put a +1/+1 counter on target creature. It phases out.| +Undercover Operative|Streets of New Capenna|63|R|{2}{U}{U}|Creature - Shapeshifter Rogue|0|0|You may have Undercover Operative enter the battlefield as a copy of any creature on the battlefield, except it enters with a shield counter on it if you control that creature.| +Wingshield Agent|Streets of New Capenna|64|U|{2}{U}|Creature - Human Soldier|2|3|Wingshield Agent enters the battlefield with a shield counter on it.$Whenever Wingshield Agent attacks, up to one other target creature gains flying until end of turn.| +Wiretapping|Streets of New Capenna|65|R|{4}{U}|Enchantment|||Hideaway 5$Whenever you draw your first card during each of your draw steps, draw a card. Then if you have nine or more cards in hand, you may play the exiled card without paying its mana cost.| +Witness Protection|Streets of New Capenna|66|C|{U}|Enchantment - Aura|||Enchant creature$Enchanted creature loses all abilities and is a green and white Citizen creature with base power and toughness 1/1 named Legitimate Businessperson.| +Angel of Suffering|Streets of New Capenna|67|M|{3}{B}{B}|Creature - Nightmare Angel|5|3|Flying$If damage would be dealt to you, prevent that damage and mill twice that many cards.| +Body Launderer|Streets of New Capenna|68|M|{2}{B}{B}|Creature - Ogre Rogue|3|3|Deathtouch$Whenever another nontoken creature you control dies, Body Launderer connives.$When Body Launderer dies, return another target non-Rogue creature card with equal or lesser power from your graveyard to the battlefield.| +Cemetery Tampering|Streets of New Capenna|69|R|{2}{B}|Enchantment|||Hideaway 5$At the beginning of your upkeep, you may mill three cards. Then if there are twenty or more cards in your graveyard, you may play the exiled card without paying its mana cost.| +Corrupt Court Official|Streets of New Capenna|70|C|{1}{B}|Creature - Human Advisor|1|1|When Corrupt Court Official enters the battlefield, target opponent discards a card.| +Crooked Custodian|Streets of New Capenna|71|C|{1}{B}|Creature - Ogre Rogue|3|2|Crooked Custodian enters the battlefield tapped.| +Cut of the Profits|Streets of New Capenna|72|R|{X}{B}{B}|Sorcery|||Casualty 3$You draw X cards and you lose X life.| +Cutthroat Contender|Streets of New Capenna|73|C|{B}|Creature - Vampire Warrior|1|1|Pay 1 life: Cutthroat Contender gets +1/+0 until end of turn. Activate only once each turn.| +Deal Gone Bad|Streets of New Capenna|74|C|{3}{B}|Instant|||Target creature gets -3/-3 until end of turn. Target player mills three cards.| +Demon's Due|Streets of New Capenna|75|C|{3}{B}|Instant|||Scry 2, then draw two cards. You lose 2 life.| +Dig Up the Body|Streets of New Capenna|76|C|{2}{B}|Instant|||Casualty 1$Mill two cards, then you may return a creature card from your graveyard to your hand.| +Dusk Mangler|Streets of New Capenna|77|U|{5}{B}{B}|Creature - Horror|5|4|As an additional cost to cast this spell, sacrifice a creature, discard a card, or pay 4 life.$When Dusk Mangler enters the battlefield, each opponent sacrifices a creature, discards a card, and loses 4 life.| +Extract the Truth|Streets of New Capenna|78|C|{1}{B}|Sorcery|||Choose one —$• Target opponent reveals their hand. You may choose a creature, enchantment, or planeswalker card from it. That player discards that card.$• Target opponent sacrifices an enchantment.| +Fake Your Own Death|Streets of New Capenna|79|C|{1}{B}|Instant|||Until end of turn, target creature gets +2/+0 and gains "When this creature dies, return it to the battlefield tapped under its owner's control and you create a Treasure token."| +Girder Goons|Streets of New Capenna|80|C|{4}{B}|Creature - Ogre Warrior|4|4|When Girder Goons dies, create a tapped 2/2 black Rogue creature token.$Blitz {3}{B}| +Graveyard Shift|Streets of New Capenna|81|U|{4}{B}|Sorcery|||This spell has flash as long as there are five or more mana values among cards in your graveyard.$Return target creature card from your graveyard to the battlefield.| +Grisly Sigil|Streets of New Capenna|82|U|{B}|Sorcery|||Casualty 1$Choose target creature or planeswalker. If it was dealt noncombat damage this turn, Grisly Sigil deals 3 damage to it and you gain 3 life. Otherwise, Grisly Sigil deals 1 damage to it and you gain 1 life.| +Illicit Shipment|Streets of New Capenna|83|U|{3}{B}{B}|Sorcery|||Casualty 3$Search your library for a card, put it into your hand, then shuffle.| +Incriminate|Streets of New Capenna|84|C|{1}{B}|Sorcery|||Choose two target creatures controlled by the same player. That player sacrifices one of them.| +Join the Maestros|Streets of New Capenna|85|C|{4}{B}|Sorcery|||Casualty 2$Create a 4/3 black Ogre Warrior creature token.| +Maestros Initiate|Streets of New Capenna|86|C|{2}{B}|Creature - Human Citizen|3|1|{4}{U/R}, Exile Maestros Initiate from your graveyard: Draw two cards, then discard a card.| +Midnight Assassin|Streets of New Capenna|87|C|{2}{B}|Creature - Vampire Assassin|1|2|Flying, deathtouch| +Murder|Streets of New Capenna|88|C|{1}{B}{B}|Instant|||Destroy target creature.| +Night Clubber|Streets of New Capenna|89|U|{1}{B}{B}|Creature - Human Warrior|2|2|When Night Clubber enters the battlefield, creatures your opponents control get -1/-1 until end of turn.$Blitz {2}{B}| +Raffine's Silencer|Streets of New Capenna|90|U|{2}{B}|Creature - Human Assassin|1|1|When Raffine's Silencer enters the battlefield, it connives.$When Raffine's Silencer dies, target creature an opponent controls gets -X/-X until end of turn, where X is Raffine's Silencer's power.| +Revel Ruiner|Streets of New Capenna|91|C|{3}{B}|Creature - Cephalid Rogue|3|1|Menace$When Revel Ruiner enters the battlefield, it connives.| +Rogues' Gallery|Streets of New Capenna|92|U|{2}{B}|Sorcery|||For each color, return up to one target creature card of that color from your graveyard to your hand.| +Sanguine Spy|Streets of New Capenna|93|R|{2}{B}|Creature - Vampire Rogue|2|3|Menace, lifelink${1}, Sacrifice another creature: Look at the top card of your library. You may put that card into your graveyard.$At the beginning of your end step, if there are five or more mana values among cards in your graveyard, you may pay 2 life. If you do, draw a card.| +Shadow of Mortality|Streets of New Capenna|94|R|{13}{B}{B}|Creature - Avatar|7|7|If your life total is less than your starting life total, this spell costs {X} less to cast, where X is the difference.| +Shakedown Heavy|Streets of New Capenna|95|R|{2}{B}|Creature - Ogre Warrior|6|4|Menace$Whenever Shakedown Heavy attacks, defending player may have you draw a card. If they do, untap Shakedown Heavy and remove it from combat.| +Tavern Swindler|Streets of New Capenna|96|U|{1}{B}|Creature - Human Rogue|2|2|{T}, Pay 3 life: Flip a coin. If you win the flip, you gain 6 life.| +Tenacious Underdog|Streets of New Capenna|97|R|{1}{B}|Creature - Human Warrior|3|2|Blitz—{2}{B}{B}, Pay 2 life.$You may cast Tenacious Underdog from your graveyard using its blitz ability.| +Vampire Scrivener|Streets of New Capenna|98|U|{4}{B}|Creature - Vampire Warlock|2|2|Flying$Whenever you gain life during your turn, put a +1/+1 counter on Vampire Scrivener.$Whenever you lose life during your turn, put a +1/+1 counter on Vampire Scrivener.| +Whack|Streets of New Capenna|99|U|{3}{B}|Sorcery|||This spell costs {3} less to cast if it targets a white creature.$Target creature gets -4/-4 until end of turn.| +Antagonize|Streets of New Capenna|100|C|{1}{R}|Instant|||Target creature gets +4/+3 until end of turn.| +Arcane Bombardment|Streets of New Capenna|101|M|{4}{R}{R}|Enchantment|||Whenever you cast your first instant or sorcery spell each turn, exile an instant or sorcery card at random from your graveyard. Then copy each card exiled with Arcane Bombardment. You may cast any number of the copies without paying their mana costs.| +Big Score|Streets of New Capenna|102|C|{3}{R}|Instant|||As an additional cost to cast this spell, discard a card.$Draw two cards and create two Treasure tokens.| +Call In a Professional|Streets of New Capenna|103|U|{2}{R}|Instant|||Players can't gain life this turn. Damage can't be prevented this turn. Call In a Professional deals 3 damage to any target.| +Daring Escape|Streets of New Capenna|104|C|{R}|Instant|||Target creature gets +1/+0 and gains first strike until end of turn. Scry 1.| +Devilish Valet|Streets of New Capenna|105|R|{2}{R}|Creature - Devil Warrior|1|3|Trample, haste$Alliance — Whenever another creature enters the battlefield under your control, double Devilish Valet's power until end of turn.| +Exhibition Magician|Streets of New Capenna|106|C|{2}{R}|Creature - Human Wizard|2|1|When Exhibition Magician enters the battlefield, choose one —$• Create a 1/1 green and white Citizen creature token.$• Create a Treasure token.| +Glittering Stockpile|Streets of New Capenna|107|U|{2}{R}|Artifact - Treasure|||{T}: Add {R}. Put a stash counter on Glittering Stockpile.${T}, Sacrifice Glittering Stockpile: Add X mana of any one color, where X is the number of stash counters on Glittering Stockpile.| +Goldhound|Streets of New Capenna|108|C|{R}|Artifact Creature - Treasure Dog|1|1|First strike$Menace${T}, Sacrifice Goldhound: Add one mana of any color.| +Hoard Hauler|Streets of New Capenna|109|R|{3}{R}|Artifact - Vehicle|5|5|Trample$Whenever Hoard Hauler deals combat damage to a player, create a Treasure token for each artifact they control.$Crew 3| +Involuntary Employment|Streets of New Capenna|110|U|{3}{R}|Sorcery|||Gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn. Create a Treasure token.| +Jackhammer|Streets of New Capenna|111|C|{1}{R}|Artifact - Equipment|||Equipped creature gets +2/+0.$Equip {2}| +Jaxis, the Troublemaker|Streets of New Capenna|112|R|{3}{R}|Legendary Creature - Human Warrior|2|3|{R}, {T}, Discard a card: Create a token that's a copy of another target creature you control. It gains haste and "When this creature dies, draw a card." Sacrifice it at the beginning of the next end step. Activate only as a sorcery.$Blitz {1}{R}| +Light 'Em Up|Streets of New Capenna|113|C|{1}{R}|Sorcery|||Casualty 2$Light 'Em Up deals 2 damage to target creature or planeswalker.| +Mayhem Patrol|Streets of New Capenna|114|C|{1}{R}|Creature - Devil Warrior|1|2|Menace$Whenever Mayhem Patrol attacks, target creature gets +1/+0 until end of turn.$Blitz {1}{R}| +Plasma Jockey|Streets of New Capenna|115|C|{3}{R}|Creature - Viashino Warrior|3|1|Whenever Plasma Jockey attacks, target creature an opponent controls can't block this turn.$Blitz {2}{R}| +Professional Face-Breaker|Streets of New Capenna|116|R|{2}{R}|Creature - Human Warrior|2|3|Menace$Whenever one or more creatures you control deal combat damage to a player, create a Treasure token.$Sacrifice a Treasure: Exile the top card of your library. You may play that card this turn.| +Pugnacious Pugilist|Streets of New Capenna|117|U|{3}{R}{R}|Creature - Ogre Warrior|4|4|Whenever Pugnacious Pugilist attacks, create a tapped and attacking 1/1 red Devil creature token with "When this creature dies, it deals 1 damage to any target."$Blitz {3}{R}| +Pyre-Sledge Arsonist|Streets of New Capenna|118|U|{2}{R}|Creature - Viashino Shaman|2|2|{1}, {T}: Pyre-Sledge Arsonist deals X damage to any target, where X is the number of permanents you've sacrificed this turn.| +Ready to Rumble|Streets of New Capenna|119|C|{4}{R}|Sorcery|||Choose one —$• Ready to Rumble deals 5 damage to target creature or planeswalker.$• Destroy target artifact.| +Riveteers Initiate|Streets of New Capenna|120|C|{1}{R}|Creature - Viashino Citizen|2|2|{1}{B/G}: Riveteers Initiate gains deathtouch until end of turn.| +Riveteers Requisitioner|Streets of New Capenna|121|U|{1}{R}|Creature - Viashino Rogue|3|1|When Riveteers Requisitioner dies, create a Treasure token.$Blitz {2}{R}| +Rob the Archives|Streets of New Capenna|122|U|{1}{R}|Sorcery|||Casualty 1$Exile the top two cards of your library. You may play those cards this turn.| +Sizzling Soloist|Streets of New Capenna|123|U|{3}{R}|Creature - Human Citizen|3|2|Alliance — Whenever another creature enters the battlefield under your control, target creature an opponent controls can't block this turn. If this is the second time this ability has resolved this turn, that creature attacks during its controller's next combat phase if able.| +Sticky Fingers|Streets of New Capenna|124|C|{R}|Enchantment - Aura|||Enchant creature$Enchanted creature has menace and "Whenever this creature deals combat damage to a player, create a Treasure token."$When enchanted creature dies, draw a card.| +Strangle|Streets of New Capenna|125|C|{R}|Sorcery|||Strangle deals 3 damage to target creature or planeswalker.| +Structural Assault|Streets of New Capenna|126|R|{3}{R}{R}|Sorcery|||Destroy all artifacts, then Structural Assault deals damage to each creature equal to the number of artifacts that were put into graveyards from the battlefield this turn.| +Torch Breath|Streets of New Capenna|127|U|{X}{R}|Instant|||This spell costs {2} less to cast if it targets a blue permanent.$This spell can't be countered.$Torch Breath deals X damage to target creature or planeswalker.| +Unlucky Witness|Streets of New Capenna|128|U|{R}|Creature - Human Citizen|1|1|When Unlucky Witness dies, exile the top two cards of your library. Until your next end step, you may play one of those cards.| +Urabrask, Heretic Praetor|Streets of New Capenna|129|M|{3}{R}{R}|Legendary Creature - Phyrexian Praetor|4|4|Haste$At the beginning of your upkeep, exile the top card of your library. You may play it this turn.$At the beginning of each opponent's upkeep, the next time they would draw a card this turn, instead they exile the top card of their library. They may play it this turn.| +Widespread Thieving|Streets of New Capenna|130|R|{2}{R}|Enchantment|||Hideaway 5$Whenever you cast a multicolored spell, create a Treasure token. Then you may pay {W}{U}{B}{R}{G}. If you do, you may play the exiled card without paying its mana cost.| +Witty Roastmaster|Streets of New Capenna|131|C|{2}{R}|Creature - Devil Citizen|3|2|Alliance — Whenever another creature enters the battlefield under your control, Witty Roastmaster deals 1 damage to each opponent.| +Wrecking Crew|Streets of New Capenna|132|C|{4}{R}|Creature - Human Warrior|4|5|Reach, trample| +Attended Socialite|Streets of New Capenna|133|C|{1}{G}|Creature - Elf Druid|2|1|Alliance — Whenever another creature enters the battlefield under your control, Attended Socialite gets +1/+1 until end of turn.| +Bootleggers' Stash|Streets of New Capenna|134|M|{5}{G}|Artifact|||Lands you control have "{T}: Create a Treasure token."| +Bouncer's Beatdown|Streets of New Capenna|135|U|{2}{G}|Instant|||This spell costs {2} less to cast if it targets a black permanent.$Bouncer's Beatdown deals X damage to target creature or planeswalker, where X is the greatest power among creatures you control. If that creature or planeswalker would die this turn, exile it instead.| +Broken Wings|Streets of New Capenna|136|C|{2}{G}|Instant|||Destroy target artifact, enchantment, or creature with flying.| +Cabaretti Initiate|Streets of New Capenna|137|C|{G}|Creature - Raccoon Citizen|1|2|{2}{R/W}: Cabaretti Initiate gains double strike until end of turn.| +Caldaia Strongarm|Streets of New Capenna|138|C|{4}{G}|Creature - Human Warrior|2|3|When Caldaia Strongarm enters the battlefield, put two +1/+1 counters on target creature.$Blitz {3}{G}| +Capenna Express|Streets of New Capenna|139|C|{3}{G}|Artifact - Vehicle|6|6|Sacrifice a Treasure: Capenna Express becomes an artifact creature until end of turn.$Crew 3| +Civic Gardener|Streets of New Capenna|140|C|{1}{G}|Creature - Human Citizen|2|2|Whenever Civic Gardener attacks, untap target creature or land.| +Cleanup Crew|Streets of New Capenna|141|U|{4}{G}{G}|Creature - Human Citizen|6|6|When Cleanup Crew enters the battlefield, choose one —$• Destroy target artifact.$• Destroy target enchantment.$• Exile target card from a graveyard.$• You gain 4 life.| +Courier's Briefcase|Streets of New Capenna|142|U|{1}{G}|Artifact - Treasure|||When Courier's Briefcase enters the battlefield, create a 1/1 green and white Citizen creature token.${T}, Sacrifice Courier's Briefcase: Add one mana of any color.${W}{U}{B}{R}{G}, {T}, Sacrifice Courier's Briefcase: Draw three cards.| +Elegant Entourage|Streets of New Capenna|143|U|{3}{G}|Creature - Elf Druid|4|4|Alliance — Whenever another creature enters the battlefield under your control, target creature other than Elegant Entourage gets +1/+1 and gains trample until end of turn.| +Evolving Door|Streets of New Capenna|144|R|{2}{G}|Artifact|||{1}, {T}, Sacrifice a creature: Count the colors of the sacrificed creature, then search your library for a creature card that's exactly that many colors plus one. Exile that card, then shuffle. You may cast the exiled card. Activate only as a sorcery.| +Fight Rigging|Streets of New Capenna|145|R|{2}{G}|Enchantment|||Hideaway 5$At the beginning of combat on your turn, put a +1/+1 counter on target creature you control. Then if you control a creature with power 7 or greater, you may play the exiled card without paying its mana cost.| +For the Family|Streets of New Capenna|146|C|{G}|Instant|||Target creature gets +2/+2 until end of turn. If you control four or more creatures, that creature gets +4/+4 until end of turn instead.| +Freelance Muscle|Streets of New Capenna|147|U|{4}{G}|Creature - Rhino Warrior|4|4|Whenever Freelance Muscle attacks or blocks, it gets +X/+X until end of turn, where X is the greatest power and/or toughness among other creatures you control.| +Gala Greeters|Streets of New Capenna|148|R|{1}{G}|Creature - Elf Druid|1|1|Alliance — Whenever another creature enters the battlefield under your control, choose one that hasn't been chosen this turn —$• Put a +1/+1 counter on Gala Greeters.$• Create a tapped Treasure token.$• You gain 2 life.| +Glittermonger|Streets of New Capenna|149|C|{3}{G}|Creature - Elf Rogue|1|4|{T}: Create a Treasure token.| +High-Rise Sawjack|Streets of New Capenna|150|C|{2}{G}|Creature - Elf Citizen|2|3|Reach$Whenever High-Rise Sawjack blocks a creature with flying, High-Rise Sawjack gets +2/+0 until end of turn.| +Jewel Thief|Streets of New Capenna|151|C|{2}{G}|Creature - Cat Rogue|3|3|Vigilance, trample$When Jewel Thief enters the battlefield, create a Treasure token.| +Luxurious Libation|Streets of New Capenna|152|U|{X}{G}|Instant|||Target creature gets +X/+X until end of turn. Create a 1/1 green and white Citizen creature token.| +Most Wanted|Streets of New Capenna|153|C|{2}{G}|Enchantment - Aura|||Flash$Enchant creature$Enchanted creature gets +2/+1.$When enchanted creature dies, create two Treasure tokens.| +Prizefight|Streets of New Capenna|154|C|{1}{G}|Instant|||Target creature you control fights target creature you don't control.$Create a Treasure token.| +Rhox Pummeler|Streets of New Capenna|155|C|{5}{G}|Creature - Rhino Soldier|6|3|Rhox Pummeler enters the battlefield with a shield counter on it.$Rhox Pummeler has trample as long as it has a shield counter on it.| +Riveteers Decoy|Streets of New Capenna|156|U|{1}{G}|Creature - Human Warrior|3|1|Riveteers Decoy must be blocked if able.$Blitz {3}{G}| +Social Climber|Streets of New Capenna|157|C|{2}{G}|Creature - Human Druid|3|2|Alliance — Whenever another creature enters the battlefield under your control, you gain 1 life.| +Take to the Streets|Streets of New Capenna|158|U|{4}{G}|Sorcery|||Creatures you control get +2/+2 until end of turn. Citizens you control get an additional +1/+1 and gain vigilance until end of turn.| +Titan of Industry|Streets of New Capenna|159|M|{4}{G}{G}{G}|Creature - Elemental|7|7|Reach, trample$When Titan of Industry enters the battlefield, choose two —$• Destroy target artifact or enchantment.$• Target player gains 5 life.$• Create a 4/4 green Rhino Warrior creature token.$• Put a shield counter on a creature you control.| +Topiary Stomper|Streets of New Capenna|160|R|{1}{G}{G}|Creature - Plant Dinosaur|4|4|Vigilance$When Topiary Stomper enters the battlefield, search your library for a basic land card, put it onto the battlefield tapped, then shuffle.$Topiary Stomper can't attack or block unless you control seven or more lands.| +Venom Connoisseur|Streets of New Capenna|161|U|{1}{G}|Creature - Human Druid|2|2|Alliance — Whenever another creature enters the battlefield under your control, Venom Connoisseur gains deathtouch until end of turn. If this is the second time this ability has resolved this turn, all creatures you control gain deathtouch until end of turn.| +Vivien on the Hunt|Streets of New Capenna|162|M|{4}{G}{G}|Legendary Planeswalker - Vivien|4|+2: You may sacrifice a creature. If you do, search your library for a creature card with mana value equal to 1 plus the sacrificed creature's mana value, put it onto the battlefield, then shuffle.$+1: Mill five cards, then put any number of creature cards milled this way into your hand.$−1: Create a 4/4 green Rhino Warrior creature token.| +Voice of the Vermin|Streets of New Capenna|163|U|{3}{G}|Creature - Human Citizen|2|2|Voice of the Vermin enters the battlefield with a shield counter on it.$Whenever Voice of the Vermin attacks, target creature you control has base power and toughness 4/4 until end of turn.| +Warm Welcome|Streets of New Capenna|164|C|{2}{G}|Instant|||Look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. Create a 1/1 green and white Citizen creature token.| +Workshop Warchief|Streets of New Capenna|165|R|{3}{G}{G}|Creature - Rhino Warrior|5|3|Trample$When Workshop Warchief enters the battlefield, you gain 3 life.$When Workshop Warchief dies, create a 4/4 green Rhino Warrior creature token.$Blitz {4}{G}{G}| +Aven Heartstabber|Streets of New Capenna|166|R|{U}{B}|Creature - Bird Assassin|1|1|Flying$As long as there are five or more mana values among cards in your graveyard, Aven Heartstabber gets +2/+2 and has deathtouch.$When Aven Heartstabber dies, mill two cards, then draw a card.| +Black Market Tycoon|Streets of New Capenna|167|R|{R}{G}|Creature - Cat Rogue|2|2|At the beginning of your upkeep, Black Market Tycoon deals 2 damage to you for each Treasure you control.${T}: Create a Treasure token.| +Body Dropper|Streets of New Capenna|168|C|{B}{R}|Creature - Devil Warrior|2|2|Whenever you sacrifice another creature, put a +1/+1 counter on Body Dropper.${B}{R}, Sacrifice another creature: Body Dropper gains menace until end of turn.| +Brazen Upstart|Streets of New Capenna|169|U|{R}{G}{W}|Creature - Elf Shaman|4|2|Vigilance$When Brazen Upstart dies, look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.| +Brokers Ascendancy|Streets of New Capenna|170|R|{G}{W}{U}|Enchantment|||At the beginning of your end step, put a +1/+1 counter on each creature you control and a loyalty counter on each planeswalker you control.| +Brokers Charm|Streets of New Capenna|171|U|{G}{W}{U}|Instant|||Choose one —$• Target creature you control gets +1/+0 until end of turn. It deals damage equal to its power to target creature or planeswalker an opponent controls.$• Destroy target enchantment.$• Draw two cards.| +Cabaretti Ascendancy|Streets of New Capenna|172|R|{R}{G}{W}|Enchantment|||At the beginning of your upkeep, look at the top card of your library. If it's a creature or planeswalker card, you may reveal it and put it into your hand. If you don't put the card into your hand, you may put it on the bottom of your library.| +Cabaretti Charm|Streets of New Capenna|173|U|{R}{G}{W}|Instant|||Choose one —$• Cabaretti Charm deals damage equal to the number of creatures you control to target creature or planeswalker.$• Creatures you control get +1/+1 and gain trample until end of turn.$• Create two 1/1 green and white Citizen creature tokens.| +Celestial Regulator|Streets of New Capenna|174|C|{1}{W}{U}|Creature - Angel Advisor|2|3|Flying$When Celestial Regulator enters the battlefield, choose target creature you don't control and tap it. If you control a creature with a counter on it, the chosen creature doesn't untap during its controller's next untap step.| +Ceremonial Groundbreaker|Streets of New Capenna|175|U|{1}{G}{W}|Artifact - Equipment|||Equipped creature gets +2/+1 and has trample.$Equip Citizen {1}$Equip {3}| +Civil Servant|Streets of New Capenna|176|C|{G}{W}|Creature - Cat Citizen|2|3|Whenever Civil Servant attacks, you may tap another untapped Citizen you control. If you do, Civil Servant gets +1/+0 and gains lifelink until end of turn.| +Cormela, Glamour Thief|Streets of New Capenna|177|U|{1}{U}{B}{R}|Legendary Creature - Vampire Rogue|2|4|Haste${1}, {T}: Add {U}{B}{R}. Spend this mana only to cast instant and/or sorcery spells.$When Cormela, Glamour Thief dies, return up to one target instant or sorcery card from your graveyard to your hand.| +Corpse Appraiser|Streets of New Capenna|178|U|{U}{B}{R}|Creature - Vampire Rogue|3|3|When Corpse Appraiser enters the battlefield, exile up to one target creature card from a graveyard. If a card is put into exile this way, look at the top three cards of your library, then put one of those cards into your hand and the rest into your graveyard.| +Corpse Explosion|Streets of New Capenna|179|R|{1}{B}{R}|Sorcery|||As an additional cost to cast this spell, exile a creature card from your graveyard.$Corpse Explosion deals damage equal to the exiled card's power to each creature and each planeswalker.| +Crew Captain|Streets of New Capenna|180|U|{B}{R}{G}|Creature - Human Warrior|4|2|Haste$Crew Captain has indestructible as long as it entered the battlefield this turn.| +Darling of the Masses|Streets of New Capenna|181|U|{2}{G}{W}|Creature - Elf Citizen|2|4|Other Citizens you control get +1/+0.$Whenever Darling of the Masses attacks, create a 1/1 green and white Citizen creature token.| +Disciplined Duelist|Streets of New Capenna|182|U|{G}{W}{U}|Creature - Human Citizen|2|1|Double strike$Disciplined Duelist enters the battlefield with a shield counter on it.| +Endless Detour|Streets of New Capenna|183|R|{G}{W}{U}|Instant|||The owner of target spell, nonland permanent, or card in a graveyard puts it on the top or bottom of their library.| +Evelyn, the Covetous|Streets of New Capenna|184|R|{2}{U/B}{B}{B/R}|Legendary Creature - Vampire Rogue|2|5|Flash$Whenever Evelyn, the Covetous or another Vampire enters the battlefield under your control, exile the top card of each player's library with a collection counter on it.$Once each turn, you may play a card from exile with a collection counter on it if it was exiled by an ability you controlled, and you may spend mana as though it were any color to cast it.| +Exotic Pets|Streets of New Capenna|185|U|{1}{W}{U}|Instant|||Create two 1/1 blue Fish creature tokens with "This creature can't be blocked." Then for each kind of counter among creatures you control, put a counter of that kind on either of those tokens.| +Falco Spara, Pactweaver|Streets of New Capenna|186|M|{1}{G}{W}{U}|Legendary Creature - Bird Demon|3|3|Flying, trample$Falco Spara, Pactweaver enters the battlefield with a shield counter on it.$You may look at the top card of your library any time.$You may cast spells from the top of your library by removing a counter from a creature you control in addition to paying their other costs.| +Fatal Grudge|Streets of New Capenna|187|U|{B}{R}|Sorcery|||As an additional cost to cast this spell, sacrifice a nonland permanent.$Each opponent chooses a permanent they control that shares a type with the sacrificed permanent and sacrifices it.$Draw a card.| +Fleetfoot Dancer|Streets of New Capenna|188|R|{1}{R}{G}{W}|Creature - Elf Druid|4|4|Trample, lifelink, haste| +Forge Boss|Streets of New Capenna|189|U|{2}{B}{R}|Creature - Human Warrior|3|4|Whenever you sacrifice one or more other creatures, Forge Boss deals 2 damage to each opponent. This ability triggers only once each turn.| +Glamorous Outlaw|Streets of New Capenna|190|C|{3}{U}{B}{R}|Creature - Vampire Rogue|4|5|When Glamorous Outlaw enters the battlefield, it deals 2 damage to each opponent and you scry 2.${2}, Exile Glamorous Outlaw from your hand: Target land gains "{T}: Add {U}, {B}, or {R}" until Glamorous Outlaw is cast from exile. You may cast Glamorous Outlaw for as long as it remains exiled.| +Hostile Takeover|Streets of New Capenna|191|R|{2}{U}{B}{R}|Sorcery|||Up to one target creature has base power and toughness 1/1 until end of turn. Up to one other target creature has base power and toughness 4/4 until end of turn. Then Hostile Takeover deals 3 damage to each creature.| +Incandescent Aria|Streets of New Capenna|192|R|{R}{G}{W}|Sorcery|||Incandescent Aria deals 3 damage to each nontoken creature.| +Jetmir, Nexus of Revels|Streets of New Capenna|193|M|{1}{R}{G}{W}|Legendary Creature - Cat Demon|5|4|Creatures you control get +1/+0 and have vigilance as long as you control three or more creatures.$Creatures you control also get +1/+0 and have trample as long as you control six or more creatures.$Creatures you control also get +1/+0 and have double strike as long as you control nine or more creatures.| +Jetmir's Fixer|Streets of New Capenna|194|C|{R}{G}|Creature - Cat Warrior|2|2|{R}{G}: Jetmir's Fixer gets +1/+1 until end of turn. If mana from a Treasure was spent to activate this ability, put a +1/+1 counter on Jetmir's Fixer instead.| +Jinnie Fay, Jetmir's Second|Streets of New Capenna|195|R|{R/G}{G}{G/W}|Legendary Creature - Elf Druid|3|3|If you would create one or more tokens, you may instead create that many 2/2 green Cat creature tokens with haste or that many 3/1 green Dog creature tokens with vigilance.| +Lagrella, the Magpie|Streets of New Capenna|196|U|{G}{W}{U}|Legendary Creature - Human Soldier|2|3|When Lagrella, the Magpie enters the battlefield, exile any number of other target creatures controlled by different players until Lagrella leaves the battlefield. When an exiled card enters the battlefield under your control this way, put two +1/+1 counters on it.| +Lord Xander, the Collector|Streets of New Capenna|197|M|{4}{U}{B}{R}|Legendary Creature - Vampire Demon Noble|6|6|When Lord Xander, the Collector enters the battlefield, target opponent discards half the cards in their hand, rounded down.$Whenever Lord Xander attacks, defending player mills half their library, rounded down.$When Lord Xander dies, target opponent sacrifices half the nonland permanents they control, rounded down.| +Maestros Ascendancy|Streets of New Capenna|198|R|{U}{B}{R}|Enchantment|||Once during each of your turns, you may cast an instant or sorcery spell from your graveyard by sacrificing a creature in addition to paying its other costs. If a spell cast this way would be put into your graveyard, exile it instead.| +Maestros Charm|Streets of New Capenna|199|U|{U}{B}{R}|Instant|||Choose one —$• Look at the top five cards of your library. Put one of those cards into your hand and the rest into your graveyard.$• Each opponent loses 3 life and you gain 3 life.$• Maestros Charm deals 5 damage to target creature or planeswalker.| +Maestros Diabolist|Streets of New Capenna|200|R|{U}{B}{R}|Creature - Vampire Warrior|1|4|Deathtouch, haste$Whenever Maestros Diabolist attacks, if you don't control a Devil token, create a tapped and attacking 1/1 red Devil creature token with "When this creature dies, it deals 1 damage to any target."| +Masked Bandits|Streets of New Capenna|201|C|{3}{B}{R}{G}|Creature - Raccoon Rogue|5|5|Vigilance$Menace${2}, Exile Masked Bandits from your hand: Target land gains "{T}: Add {B}, {R}, or {G}" until Masked Bandits is cast from exile. You may cast Masked Bandits for as long as it remains exiled.| +Meeting of the Five|Streets of New Capenna|202|M|{3}{W}{U}{B}{R}{G}|Sorcery|||Exile the top ten cards of your library. You may cast spells with exactly three colors from among them this turn. Add {W}{W}{U}{U}{B}{B}{R}{R}{G}{G}. Spend this mana only to cast spells with exactly three colors.| +Metropolis Angel|Streets of New Capenna|203|U|{2}{W}{U}|Creature - Angel Soldier|3|1|Flying$Whenever you attack with one or more creatures with counters on them, draw a card.| +Mr. Orfeo, the Boulder|Streets of New Capenna|204|U|{1}{B}{R}{G}|Legendary Creature - Rhino Warrior|2|4|Whenever you attack, double target creature's power until end of turn.| +Nimble Larcenist|Streets of New Capenna|205|U|{W}{U}{B}|Creature - Bird Rogue|2|1|Flying$When Nimble Larcenist enters the battlefield, target opponent reveals their hand. You choose an artifact, instant, or sorcery card from it and exile that card.| +Ob Nixilis, the Adversary|Streets of New Capenna|206|M|{1}{B}{R}|Legendary Planeswalker - Nixilis|3|Casualty X. The copy isn't legendary and has starting loyalty X.$+1: Each opponent loses 2 life unless they discard a card. If you control a Demon or Devil, you gain 2 life.$−2: Create a 1/1 red Devil creature token with "When this creature dies, it deals 1 damage to any target."$−7: Target player draws seven cards and loses 7 life.| +Obscura Ascendancy|Streets of New Capenna|207|R|{W}{U}{B}|Enchantment|||Whenever you cast a spell, if its mana value is equal to 1 plus the number of soul counters on Obscura Ascendancy, put a soul counter on Obscura Ascendancy, then create a 2/2 white Spirit creature token with flying.$As long as there are five or more soul counters on Obscura Ascendancy, Spirits you control get +3/+3.| +Obscura Charm|Streets of New Capenna|208|U|{W}{U}{B}|Instant|||Choose one —$• Return target multicolored permanent card with mana value 3 or less from your graveyard to the battlefield tapped.$• Counter target instant or sorcery spell.$• Destroy target creature or planeswalker with mana value 3 or less.| +Obscura Interceptor|Streets of New Capenna|209|R|{1}{W}{U}{B}|Creature - Cephalid Wizard|3|1|Flash$Lifelink$When Obscura Interceptor enters the battlefield, it connives. When it connives this way, return up to one target spell to its owner's hand.| +Ognis, the Dragon's Lash|Streets of New Capenna|210|R|{1}{B/R}{R}{R/G}|Legendary Creature - Viashino Warrior|3|3|Haste$Whenever a creature you control with haste attacks, create a tapped Treasure token.| +Park Heights Pegasus|Streets of New Capenna|211|R|{G}{W}|Creature - Pegasus|2|1|Flying, trample$Whenever Park Heights Pegasus deals combat damage to a player, draw a card if you had two or more creatures enter the battlefield under your control this turn.| +Queza, Augur of Agonies|Streets of New Capenna|212|U|{1}{W}{U}{B}|Legendary Creature - Cephalid Advisor|3|4|Whenever you draw a card, target opponent loses 1 life and you gain 1 life.| +Raffine, Scheming Seer|Streets of New Capenna|213|M|{W}{U}{B}|Legendary Creature - Sphinx Demon|1|4|Flying, ward {1}$Whenever you attack, target attacking creature connives X, where X is the number of attacking creatures.| +Rakish Revelers|Streets of New Capenna|214|C|{2}{R}{G}{W}|Creature - Elf Druid Rogue|5|3|When Rakish Revelers enters the battlefield, create a 1/1 green and white Citizen creature token.${2}, Exile Rakish Revelers from your hand: Target land gains "{T}: Add {R}, {G}, or {W}" until Rakish Revelers is cast from exile. You may cast Rakish Revelers for as long as it remains exiled.| +Rigo, Streetwise Mentor|Streets of New Capenna|215|R|{G/W}{W}{W/U}|Legendary Creature - Cat Citizen|2|2|Rigo, Streetwise Mentor enters the battlefield with a shield counter on it.$Whenever you attack a player or planeswalker with one or more creatures with power 1 or less, draw a card.| +Riveteers Ascendancy|Streets of New Capenna|216|R|{B}{R}{G}|Enchantment|||Whenever you sacrifice a creature, you may return target creature card with lesser mana value from your graveyard to the battlefield tapped. Do this only once each turn.| +Riveteers Charm|Streets of New Capenna|217|U|{B}{R}{G}|Instant|||Choose one —$• Target opponent sacrifices a creature or planeswalker they control with the highest mana value among creatures and planeswalkers they control.$• Exile the top three cards of your library. Until your next end step, you may play those cards.$• Exile target player's graveyard.| +Rocco, Cabaretti Caterer|Streets of New Capenna|218|U|{X}{R}{G}{W}|Legendary Creature - Elf Druid|3|1|When Rocco, Cabaretti Caterer enters the battlefield, if you cast it, you may search your library for a creature card with mana value X or less, put it onto the battlefield, then shuffle.| +Scheming Fence|Streets of New Capenna|219|R|{W}{U}|Creature - Human Citizen|2|3|As Scheming Fence enters the battlefield, you may choose a nonland permanent.$Activated abilities of the chosen permanent can't be activated.$Scheming Fence has all activated abilities of the chosen permanent except for loyalty abilities. You may spend mana as though it were mana of any color to activate those abilities.| +Security Rhox|Streets of New Capenna|220|U|{2}{R}{G}|Creature - Rhino Warrior|5|4|You may pay {R}{G} rather than pay this spell's mana cost. Spend only mana produced by Treasures to cast it this way.| +Shattered Seraph|Streets of New Capenna|221|C|{4}{W}{U}{B}|Creature - Angel Rogue|4|4|Flying$When Shattered Seraph enters the battlefield, you gain 3 life.${2}, Exile Shattered Seraph from your hand: Target land gains "{T}: Add {W}, {U}, or {B}" until Shattered Seraph is cast from exile. You may cast Shattered Seraph for as long as it remains exiled.| +Snooping Newsie|Streets of New Capenna|222|C|{U}{B}|Creature - Human Rogue|2|2|When Snooping Newsie enters the battlefield, mill two cards.$As long as there are five or more mana values among cards in your graveyard, Snooping Newsie gets +1/+1 and has lifelink.| +Soul of Emancipation|Streets of New Capenna|223|R|{4}{G}{W}{U}|Creature - Avatar|5|7|When Soul of Emancipation enters the battlefield, destroy up to three other target nonland permanents. For each of those permanents, its controller creates a 3/3 white Angel creature token with flying.| +Spara's Adjudicators|Streets of New Capenna|224|C|{2}{G}{W}{U}|Creature - Cat Citizen|4|4|When Spara's Adjudicators enters the battlefield, target creature an opponent controls can't attack or block until your next turn.${2}, Exile Spara's Adjudicators from your hand: Target land gains "{T}: Add {G}, {W}, or {U}" until Spara's Adjudicators is cast from exile. You may cast Spara's Adjudicators for as long as it remains exiled.| +Stimulus Package|Streets of New Capenna|225|U|{2}{R}{G}|Enchantment|||When Stimulus Package enters the battlefield, create two Treasure tokens.$Sacrifice a Treasure: Create a 1/1 green and white Citizen creature token.| +Syndicate Infiltrator|Streets of New Capenna|226|U|{2}{U}{B}|Creature - Vampire Wizard|3|3|Flying$As long as there are five or more mana values among cards in your graveyard, Syndicate Infiltrator gets +2/+2.| +Tainted Indulgence|Streets of New Capenna|227|U|{U}{B}|Instant|||Draw two cards. Then discard a card unless there are five or more mana values among cards in your graveyard.| +Toluz, Clever Conductor|Streets of New Capenna|228|R|{W/U}{U}{U/B}|Legendary Creature - Human Rogue|3|1|When Toluz, Clever Conductor enters the battlefield, it connives.$Whenever you discard one or more cards, exile them from your graveyard.$When Toluz, Clever Conductor dies, put the cards exiled with it into their owner's hand.| +Unleash the Inferno|Streets of New Capenna|229|R|{1}{B}{R}{G}|Instant|||Unleash the Inferno deals 7 damage to target creature or planeswalker. When it deals excess damage this way, destroy target artifact or enchantment an opponent controls with mana value less than or equal to that amount of excess damage.| +Void Rend|Streets of New Capenna|230|R|{W}{U}{B}|Instant|||This spell can't be countered.$Destroy target nonland permanent.| +Ziatora, the Incinerator|Streets of New Capenna|231|M|{3}{B}{R}{G}|Legendary Creature - Demon Dragon|6|6|Flying$At the beginning of your end step, you may sacrifice another creature. When you do, Ziatora, the Incinerator deals damage equal to that creature's power to any target and you create three Treasure tokens.| +Ziatora's Envoy|Streets of New Capenna|232|R|{1}{B}{R}{G}|Creature - Viashino Warrior|5|4|Trample$Whenever Ziatora's Envoy deals combat damage to a player, look at the top card of your library. You may play a land from the top of your library or cast a spell with mana value less than or equal to the damage dealt from the top of your library without paying its mana cost. If you don't, put that card into your hand.$Blitz {2}{B}{R}{G}| +Arc Spitter|Streets of New Capenna|233|U|{1}|Artifact - Equipment|||Equipped creature has "{1}: This creature deals 1 damage to target creature that's blocking it."$Equip {1}| +Brass Knuckles|Streets of New Capenna|234|U|{4}|Artifact - Equipment|||When you cast this spell, copy it.$Equipped creature has double strike as long as two or more Equipment are attached to it.$Equip {1}| +Cement Shoes|Streets of New Capenna|235|U|{1}|Artifact - Equipment|||Equipped creature gets +3/+3 and has "At the beginning of your end step, tap this creature."$Equipped creature doesn't untap during its controller's untap step.$Equip {2}| +Chrome Cat|Streets of New Capenna|236|C|{3}|Artifact Creature - Cat|3|2|When Chrome Cat enters the battlefield, scry 1.| +Getaway Car|Streets of New Capenna|237|R|{3}|Artifact - Vehicle|4|3|Haste$Whenever Getaway Car attacks or blocks, return up to one target creature that crewed it this turn to its owner's hand.$Crew 1| +Gilded Pinions|Streets of New Capenna|238|C|{2}|Artifact - Equipment|||When Gilded Pinions enters the battlefield, create a Treasure token.$Equipped creature has flying.$Equip {2}| +Halo Scarab|Streets of New Capenna|239|C|{2}|Artifact Creature - Insect|2|1|{2}, Exile Halo Scarab from your graveyard: Create a Treasure token.| +Luxior, Giada's Gift|Streets of New Capenna|240|M|{1}|Legendary Artifact - Equipment|||Equipped creature gets +1/+1 for each counter on it.$Equipped permanent isn't a planeswalker and is a creature in addition to its other types.$Equip planeswalker {1}$Equip {3}| +Ominous Parcel|Streets of New Capenna|241|C|{1}|Artifact|||{2}, {T}, Sacrifice Ominous Parcel: Search your library for a basic land card, reveal it, put it into your hand, then shuffle.${5}, {T}, Sacrifice Ominous Parcel: It deals 4 damage to target creature.| +Paragon of Modernity|Streets of New Capenna|242|C|{4}|Artifact Creature - Angel Warrior|2|2|Flying${3}: Paragon of Modernity gets +1/+1 until end of turn. If exactly three colors of mana were spent to activate this ability, put a +1/+1 counter on it instead.| +Quick-Draw Dagger|Streets of New Capenna|243|C|{3}|Artifact - Equipment|||Flash$When Quick-Draw Dagger enters the battlefield, attach it to target creature you control. That creature gains first strike until end of turn.$Equipped creature gets +1/+1.$Equip {1}| +Scuttling Butler|Streets of New Capenna|244|U|{3}|Artifact Creature - Construct|4|1|At the beginning of combat on your turn, if you control two or more multicolored permanents, Scuttling Butler gains double strike until end of turn.| +Suspicious Bookcase|Streets of New Capenna|245|U|{2}|Artifact Creature - Wall|0|4|Defender${3}, {T}: Target creature can't be blocked this turn.| +Unlicensed Hearse|Streets of New Capenna|246|R|{2}|Artifact - Vehicle|*|*|{T}: Exile up to two target cards from a single graveyard.$Unlicensed Hearse's power and toughness are each equal to the number of cards exiled with it.$Crew 2| +Botanical Plaza|Streets of New Capenna|247|C||Land|||Botanical Plaza enters the battlefield tapped.${T}: Add {G} or {W}.${2}{G}{W}, {T}, Sacrifice Botanical Plaza: Draw a card.| +Brokers Hideout|Streets of New Capenna|248|C||Land|||When Brokers Hideout enters the battlefield, sacrifice it. When you do, search your library for a basic Forest, Plains, or Island card, put it onto the battlefield tapped, then shuffle and you gain 1 life.| +Cabaretti Courtyard|Streets of New Capenna|249|C||Land|||When Cabaretti Courtyard enters the battlefield, sacrifice it. When you do, search your library for a basic Mountain, Forest, or Plains card, put it onto the battlefield tapped, then shuffle and you gain 1 life.| +Jetmir's Garden|Streets of New Capenna|250|R||Land - Mountain Forest Plains|||({T}: Add {R}, {G}, or {W}.)$Jetmir's Garden enters the battlefield tapped.$Cycling {3}| +Maestros Theater|Streets of New Capenna|251|C||Land|||When Maestros Theater enters the battlefield, sacrifice it. When you do, search your library for a basic Island, Swamp, or Mountain card, put it onto the battlefield tapped, then shuffle and you gain 1 life.| +Obscura Storefront|Streets of New Capenna|252|C||Land|||When Obscura Storefront enters the battlefield, sacrifice it. When you do, search your library for a basic Plains, Island, or Swamp card, put it onto the battlefield tapped, then shuffle and you gain 1 life.| +Racers' Ring|Streets of New Capenna|253|C||Land|||Racers' Ring enters the battlefield tapped.${T}: Add {R} or {G}.${2}{R}{G}, {T}, Sacrifice Racers' Ring: Draw a card.| +Raffine's Tower|Streets of New Capenna|254|R||Land - Plains Island Swamp|||({T}: Add {W}, {U}, or {B}.)$Raffine's Tower enters the battlefield tapped.$Cycling {3}| +Riveteers Overlook|Streets of New Capenna|255|C||Land|||When Riveteers Overlook enters the battlefield, sacrifice it. When you do, search your library for a basic Swamp, Mountain, or Forest card, put it onto the battlefield tapped, then shuffle and you gain 1 life.| +Skybridge Towers|Streets of New Capenna|256|C||Land|||Skybridge Towers enters the battlefield tapped.${T}: Add {W} or {U}.${2}{W}{U}, {T}, Sacrifice Skybridge Towers: Draw a card.| +Spara's Headquarters|Streets of New Capenna|257|R||Land - Forest Plains Island|||({T}: Add {G}, {W}, or {U}.)$Spara's Headquarters enters the battlefield tapped.$Cycling {3}| +Tramway Station|Streets of New Capenna|258|C||Land|||Tramway Station enters the battlefield tapped.${T}: Add {B} or {R}.${2}{B}{R}, {T}, Sacrifice Tramway Station: Draw a card.| +Waterfront District|Streets of New Capenna|259|C||Land|||Waterfront District enters the battlefield tapped.${T}: Add {U} or {B}.${2}{U}{B}, {T}, Sacrifice Waterfront District: Draw a card.| +Xander's Lounge|Streets of New Capenna|260|R||Land - Island Swamp Mountain|||({T}: Add {U}, {B}, or {R}.)$Xander's Lounge enters the battlefield tapped.$Cycling {3}| +Ziatora's Proving Ground|Streets of New Capenna|261|R||Land - Swamp Mountain Forest|||({T}: Add {B}, {R}, or {G}.)$Ziatora's Proving Ground enters the battlefield tapped.$Cycling {3}| +Plains|Streets of New Capenna|262|C||Basic Land - Plains|||({T}: Add {W}.)| +Island|Streets of New Capenna|264|C||Basic Land - Island|||({T}: Add {U}.)| +Swamp|Streets of New Capenna|266|C||Basic Land - Swamp|||({T}: Add {B}.)| +Mountain|Streets of New Capenna|268|C||Basic Land - Mountain|||({T}: Add {R}.)| +Forest|Streets of New Capenna|270|C||Basic Land - Forest|||({T}: Add {G}.)| +Ancient Brass Dragon|Commander Legends: Battle for Baldur's Gate|111|M|{5}{B}{B}|Creature - Elder Dragon|7|6|Flying$Whenever Ancient Brass Dragon deals combat damage to a player, roll a d20. When you do, put any number of target creature cards with mana value X or less from graveyards onto the battlefield under your control, where X is the result.| +Elder Brain|Commander Legends: Battle for Baldur's Gate|125|R|{5}{B}{B}|Creature - Horror|6|6|Menace$Whenever Elder Brain attacks a player, exile all cards from that player's hand, then they draw that many cards. You may play lands and cast spells from among the exiled cards for as long as they remain exiled. If you cast a spell this way, you may spend mana as though it were mana of any color to cast it.| +Fireball|Commander Legends: Battle for Baldur's Gate|175|U|{X}{R}|Sorcery|||This spell costs {1} more to cast for each target beyond the first.$Fireball deals X damage divided evenly, rounded down, among any number of targets.| +Lightning Bolt|Commander Legends: Battle for Baldur's Gate|187|C|{R}|Instant|||Lightning Bolt deals 3 damage to any target.| +Wand of Wonder|Commander Legends: Battle for Baldur's Gate|204|R|{3}{R}|Artifact|||{4}, {T}: Roll a d20. Each opponent exiles cards from the top of their library until they exile an instant or sorcery card, then shuffles the rest into their library. You may cast up to X instant and/or sorcery spells from among cards exiled this way without paying their mana costs.$1-9 & X is one$10-19 & X is two.$20 & X is three.| +Minsc & Boo, Timeless Heroes|Commander Legends: Battle for Baldur's Gate|285|M|{2}{R}{G}|Legendary Planeswalker - Minsc|3|When Minsc & Boo, Timeless Heroes enters the battlefield and at the beginning of your upkeep, you may create Boo, a legendary 1/1 red Hamster creature token with trample and haste.$+1: Put three +1/+1 counters on up to one target creature with trample or haste.$−2: Sacrifice a creature. When you do, Minsc & Boo, Timeless Heroes deals X damage to any target, where X is that creature's power. If the sacrificed creature was a Hamster, draw X cards.$Minsc & Boo, Timeless Heroes can be your commander.| +Zevlor, Elturel Exile|Commander Legends: Battle for Baldur's Gate|296|R|{1}{U}{B}{R}|Legendary Creature - Tiefling Warrior|4|2|Haste${2}, {T}: When you next cast an instant or sorcery spell that targets a single opponent or a single permanent an opponent controls this turn, for each other opponent, choose that player or a permanent they control, copy that spell, and the copy targets the chosen permanent.| +Bountiful Promenade|Commander Legends: Battle for Baldur's Gate|348|R||Land|||Bountiful Promenade enters the battlefield tapped unless you have two or more opponents.${T}: Add {G} or {W}.| +Luxury Suite|Commander Legends: Battle for Baldur's Gate|355|R||Land|||Luxury Suite enters the battlefield tapped unless you have two or more opponents.${T}: Add {B} or {R}.| +Morphic Pool|Commander Legends: Battle for Baldur's Gate|357|R||Land|||Morphic Pool enters the battlefield tapped unless you have two or more opponents.${T}: Add {U} or {B}.| +Reflecting Pool|Commander Legends: Battle for Baldur's Gate|358|R||Land|||{T}: Add one mana of any type that a land you control could produce.| +Sea of Clouds|Commander Legends: Battle for Baldur's Gate|360|R||Land|||Sea of Clouds enters the battlefield tapped unless you have two or more opponents.${T}: Add {W} or {U}.| +Spire Garden|Commander Legends: Battle for Baldur's Gate|361|R||Land|||Spire Garden enters the battlefield tapped unless you have two or more opponents.${T}: Add {R} or {G}.| +Anhelo, the Painter|New Capenna Commander|1|M|{U}{B}{R}|Legendary Creature - Vampire Assassin|1|3|Deathtouch$The first instant or sorcery spell you cast each turn has casualty 2.| +Henzie "Toolbox" Torre|New Capenna Commander|2|M|{B}{R}{G}|Legendary Creature - Devil Rogue|3|3|Each creature you cast with mana value 4 or greater has blitz. The blitz cost is equal to its mana cost.$Blitz costs you pay cost {1} less for each time you've cast your commander from the command zone this game.| +Kamiz, Obscura Oculus|New Capenna Commander|3|M|{1}{W}{U}{B}|Legendary Creature - Cephalid Rogue|2|4|Whenever you attack, target attacking creature can't be blocked this turn. It connives. Then choose another attacking creature with lesser power. That creature gains double strike until end of turn.| +Kitt Kanto, Mayhem Diva|New Capenna Commander|4|M|{1}{R}{G}{W}|Legendary Creature - Cat Bard Druid|3|3|When Kitt Kanto enters the battlefield, create a 1/1 green and white Citizen creature token.$At the beginning of combat on each player's turn, you may tap two untapped creatures you control. When you do, target creature that player controls gets +2/+2 and gains trample until end of turn. Goad that creature.| +Perrie, the Pulverizer|New Capenna Commander|5|M|{1}{G}{U}{W}|Legendary Creature - Rhino Soldier|3|3|When Perrie enters the battlefield, put a shield counter on target creature.$Whenever Perrie attacks, target creature you control gains trample and gets +X/+X, where X is the number of different kinds of counters among permanents you control.| +The Beamtown Bullies|New Capenna Commander|6|M|{1}{B}{R}{G}|Legendary Creature - Ogre Devil Warrior|4|4|Vigilance, haste${T}: Target opponent whose turn it is puts target nonlegendary creature card from your graveyard onto the battlefield under their control. It gains haste. Goad it. At the beginning of the next end step, exile it.| +Kros, Defense Contractor|New Capenna Commander|7|M|{1}{G}{W}{U}|Legendary Creature - Cat Advisor|2|4|At the beginning of your upkeep, put a shield counter on target creature an opponent controls.$Whenever you put one or more counters on a creature you don't control, tap that creature and goad it. It gains trample until your next turn.| +Parnesse, the Subtle Brush|New Capenna Commander|8|M|{2}{U}{B}{R}|Legendary Creature - Vampire Wizard|4|4|Whenever you or a permanent you control becomes the target of a spell or ability an opponent controls, counter that spell or ability unless that player pays 4 life.$Whenever you copy a spell, up to one target opponent may also copy that spell. They may choose new targets for that copy.| +Phabine, Boss's Confidant|New Capenna Commander|9|M|{3}{R}{G}{W}|Legendary Creature - Cat Advisor|3|6|Creature tokens you control have haste.$Parley — At the beginning of combat on your turn, each player reveals the top card of their library. For each land card revealed this way, you create a 1/1 green and white Citizen creature token. Then creatures you control get +1/+1 until end of turn for each nonland card revealed this way. Then each player draws a card.| +Tivit, Seller of Secrets|New Capenna Commander|10|M|{3}{W}{U}{B}|Legendary Creature - Sphinx Rogue|6|6|Flying, ward {3}$Council's dilemma — Whenever Tivit enters the battlefield or deals combat damage to a player, starting with you, each player votes for evidence or bribery. For each evidence vote, investigate. For each bribery vote, create a Treasure token.$While voting, you may vote an additional time.| +Aerial Extortionist|New Capenna Commander|11|R|{3}{W}{W}|Creature - Bird Soldier|4|3|Flying$Whenever Aerial Extortionist enters the battlefield or deals combat damage to a player, exile up to one target nonland permanent. For as long as that card remains exiled, its owner may cast it.$Whenever another player casts a spell from anywhere other than their hand, draw a card.| +Angelic Sleuth|New Capenna Commander|12|R|{2}{W}|Creature - Angel Advisor|2|3|Flying$Whenever another permanent you control leaves the battlefield, if it had counters on it, investigate.| +Boss's Chauffeur|New Capenna Commander|13|R|{4}{W}|Creature - Elf Citizen|0|0|Boss's Chauffeur enters the battlefield with a number of +1/+1 counters on it equal to one plus the number of other creatures you control.$Alliance — Whenever another creature enters the battlefield under your control, put a +1/+1 counter on Boss's Chauffeur.$When Boss's Chauffeur dies, create a 1/1 green and white Citizen creature token for each +1/+1 counter on it.| +Contractual Safeguard|New Capenna Commander|14|R|{2}{W}|Instant|||Addendum — If you cast this spell during your main phase, put a shield counter on a creature you control.$Choose a kind of counter on a creature you control. Put a counter of that kind on each other creature you control.| +Damning Verdict|New Capenna Commander|15|R|{3}{W}{W}|Sorcery|||Destroy all creatures with no counters on them.| +Grand Crescendo|New Capenna Commander|16|R|{X}{W}{W}|Instant|||Create X 1/1 green and white Citizen creature tokens. Creatures you control gain indestructible until end of turn.| +Jailbreak|New Capenna Commander|17|R|{1}{W}|Sorcery|||Return target permanent card in an opponent's graveyard to the battlefield under their control. When that permanent enters the battlefield, return up to one target permanent card with equal or lesser mana value from your graveyard to the battlefield.| +Master of Ceremonies|New Capenna Commander|18|R|{3}{W}|Creature - Rhino Druid|3|4|At the beginning of your upkeep, each opponent choses money, friends, or secrets. For each player who chose money, you and that player each create a Treasure token. For each player who chose friends, you and that player each create a 1/1 green and white Citizen creature token. For each player who chose secrets, you and that player each draw a card.| +Resourceful Defense|New Capenna Commander|19|R|{2}{W}|Enchantment|||Whenever a permanent you control leaves the battlefield, if it had counters on it, put those counters on target permanent you control.${4}{W}: Move any number of counters from target permanent you control to another target permanent you control.| +Skyboon Evangelist|New Capenna Commander|20|R|{4}{W}|Creature - Bird Advisor|3|3|Flying$When Skyboon Evangelist enters the battlefield, support 6.$Whenever a creature with a counter on it attacks one of your opponents, that creature gains flying until end of turn.| +Smuggler's Share|New Capenna Commander|21|R|{2}{W}|Enchantment|||At the beginning of each end step, draw a card for each opponent who drew two or more cards this turn, then create a Treasure token for each opponent who had two or more lands enter the battlefield under their control this turn.| +Aven Courier|New Capenna Commander|22|R|{1}{U}|Creature - Bird Advisor|1|1|Flying$Whenever Aven Courier attacks, choose a counter on a permanent you control. Put a counter of that kind on target permanent you control if it doesn't have a counter of that kind on it.| +Cephalid Facetaker|New Capenna Commander|23|R|{2}{U}|Creature - Cephalid Rogue|1|4|Cephalid Facetaker can't be blocked.$At the beginning of combat on your turn, you may have Cephalid Facetaker become a copy of another target creature until end of turn, except its a 1/4 and has "This creature can't be blocked."| +Change of Plans|New Capenna Commander|24|R|{X}{1}{U}|Instant|||Each of X target creatures you control connive. You may have any number of them phase out.| +Extravagant Replication|New Capenna Commander|25|R|{4}{U}{U}|Enchantment|||At the beginning of your upkeep, create a token that's a copy of another target nonland permanent you control.| +Flawless Forgery|New Capenna Commander|26|R|{3}{U}{U}|Sorcery|||Casualty 3$Exile target instant or sorcery card from an opponent's graveyard. Copy that card. You may cast the copy without paying its mana cost.| +In Too Deep|New Capenna Commander|27|R|{U}{U}|Enchantment - Aura|||Split second$Enchant creature, planeswalker, or Clue$Enchanted permanent is a colorless Clue artifact with "{2}, Sacrifice this artifact: Draw a card" and loses all other abilities.| +Mask of the Schemer|New Capenna Commander|28|R|{2}{U}|Artifact - Equipment|||Whenever equipped creature deals combat damage to a player, it connives X, where X is the amount of damage it dealt to that player.$Equip {2}| +Shield Broker|New Capenna Commander|29|R|{3}{U}{U}|Creature - Cephalid Advisor|3|4|When Shield Broker enters the battlefield, put a shield counter on target noncommander creature you don't control. You gain control of that creature for as long as it has a shield counter on it.| +Sinister Concierge|New Capenna Commander|30|R|{1}{U}|Creature - Human Wizard|2|1|When Sinister Concierge dies, you may exile it and put three time counters on it. If you do, exile up to one target creature and put three time counters on it. Each card exiled this way that doesn't have suspend gains suspend.| +Skyway Robber|New Capenna Commander|31|R|{3}{U}|Creature - Bird Rogue|3|3|Flying$Escape—{3}{U}, Exile five other cards from your graveyard.$Skyway Robber escapes with "Whenever Skyway Robber deals combat damage to a player, you may cast an artifact, instant, or sorcery spell from among cards exiled with Skyway Robber without paying its mana cost."| +Storm of Forms|New Capenna Commander|32|R|{3}{U}|Instant|||When you cast this spell, copy it for each kind of counter among permanents you control. You may choose new targets for the copies.$Return target nonland permanent to its owner's hand.| +Bellowing Mauler|New Capenna Commander|33|R|{4}{B}|Creature - Ogre Warrior|4|6|At the beginning of your end step, each player loses 4 life unless they sacrifice a nontoken creature.| +Body Count|New Capenna Commander|34|R|{2}{B}|Instant|||Spectacle {B}$Draw a card for each creature that died under your control this turn.| +Dogged Detective|New Capenna Commander|35|R|{1}{B}|Creature - Human Rogue|2|1|When Dogged Detective enters the battlefield, surveil 2.$Whenever an opponent draws their second card each turn, you may return Dogged Detective from your graveyard to your hand.| +Lethal Scheme|New Capenna Commander|36|R|{2}{B}{B}|Instant|||Convoke$Destroy target creature or planeswalker. Each creature that convoked Lethal Scheme connives.| +Make an Example|New Capenna Commander|37|R|{3}{B}|Sorcery|||Each opponent separates the creatures they control into two piles. For each opponent, you choose one of their piles. Each opponent sacrifices the creatures in their chosen pile.| +Misfortune Teller|New Capenna Commander|38|R|{3}{B}|Creature - Human Warlock|3|1|Deathtouch$Whenever Misfortune Teller enters the battlefield or deals combat damage to a player, exile target card from a graveyard. If it was a creature card, create a 2/2 black Rogue creature token. If it was a land card, create a Treasure token. Otherwise, you gain 3 life.| +Protection Racket|New Capenna Commander|39|R|{2}{B}|Enchantment|||At the beginning of your upkeep, repeat the following process for each opponent in turn order. Reveal the top card of your library. That player pay pay life equal to that card's mana value. If they do, exile that card. Otherwise, put it into your hand.| +Waste Management|New Capenna Commander|40|R|{2}{B}|Instant|||Kicker {3}{B}$Exile up to two target cards from a single graveyard. If this spell was kicked, instead exile target player's graveyard. Create a 2/2 black Rogue creature token for each creature card exiled this way.| +Wave of Rats|New Capenna Commander|41|R|{3}{B}|Creature - Rat|4|2|Trample$When Wave of Rats dies, if it dealt combat damage to a player this turn, return it to the battlefield under its owner's control.$Blitz {4}{B}| +Writ of Return|New Capenna Commander|42|R|{3}{B}{B}|Sorcery|||Return target creature card from your graveyard to the battlefield tapped.$Cipher| +Xander's Pact|New Capenna Commander|43|R|{4}{B}{B}|Sorcery|||Casualty 2$Each opponent exiles the top card of their library. You may cast spells from among those cards this turn. If you cast a spell this way, pay life equal to that spell's mana value rather than pay its mana cost.| +Audacious Swap|New Capenna Commander|44|R|{3}{R}|Instant|||Casualty 2$The owner of target nonenchantment permanent shuffles it into their library, then exiles the top card of their library. If it's a land card, they put it onto the battlefield. Otherwise, they may cast it without paying its mana cost.| +Determined Iteration|New Capenna Commander|45|R|{1}{R}|Enchantment|||At the beginning of combat on your turn, populate. The token created this way gains haste. Sacrifice it at the beginning of the next end step.| +Indulge // Excess|New Capenna Commander|46|R|{2}{R}|Sorcery|||Whenever a creature you control attacks this turn, create a 1/1 green and white Citizen creature token that's tapped and attacking.$Excess${1}{R}$Sorcery$Aftermath$Create a Treasure token for each creature you controlled that dealt combat damage to a player this turn.| +Industrial Advancement|New Capenna Commander|47|R|{3}{R}|Enchantment|||At the beginning of your end step, you may sacrifice a creature. If you do, look at the top X cards of your library, when X is that creature's mana value. You may put a creature card from among them onto the battlefield. Put the rest on the bottom of your library in a random order.| +Life of the Party|New Capenna Commander|48|R|{3}{R}|Creature - Elemental|0|1|First strike, trample, haste$Whenever Life of the Party attacks, it gets +X/+0 until end of turn, where X is the number of creatures you control.$When Life of the Party enters the battlefield, if it's not a token, each opponent creates a token that's a copy of it. The tokens are goaded for the rest of the game.| +Mezzio Mugger|New Capenna Commander|49|R|{4}{R}|Creature - Viashino Rogue|3|3|Whenever Mezzio Mugger attacks, exile the top card of each player's library. You may play those cards this turn, and you may spend mana as though it were mana of any color to cast those spells.$Blitz {2}{R}| +Rain of Riches|New Capenna Commander|50|R|{3}{R}{R}|Enchantment|||When Rain of Riches enters the battlefield, create two Treasure tokens.$The first spell you cast each turn that mana from a Treasure was spent to cast has cascade.| +Rose Room Treasurer|New Capenna Commander|51|R|{3}{R}|Creature - Ogre Warrior|4|3|Alliance — Whenever another creature enters the battlefield under your control, create a Treasure token if this is the first or second time this ability has resolved this turn. Otherwise, you may pay {X}. When you do, Rose Room Treasurer deals X damage to any target.| +Seize the Spotlight|New Capenna Commander|52|R|{2}{R}|Sorcery|||Each opponent choses fame or fortune. For each player who chose fame, gain control of a creature that player controls until end of turn. Untap those creatures and they gain haste until end of turn. For each player who chose fortune, you draw a card and create a Treasure token.| +Spellbinding Soprano|New Capenna Commander|53|R|{1}{R}|Creature - Human Bard|2|2|Whenever Spellbinding Soprano attacks, instant and sorcery spells you cast this turn cost {1} less to cast.$Encore {3}{R}| +Turf War|New Capenna Commander|54|R|{4}{R}|Enchantment|||When Turf War enters the battlefield, for each player, put a contested counter on target land that player controls.$Whenever a creature deals combat damage to a player, if that player controls one or more lands with contested counters on them, that creature's controller gains control of one of those lands of their choice and untaps it.| +Bribe Taker|New Capenna Commander|55|R|{5}{G}|Creature - Rhino Warrior|6|6|Trample$When Bribe Taker enters the battlefield, for each kind of counter on permanents you control, you may put your choice of a +1/+1 counter or a counter of that kind on Bribe Taker.| +Caldaia Guardian|New Capenna Commander|56|R|{3}{G}|Creature - Human Soldier|4|3|Whenever Caldaia Guardian or another creature you control with mana value 4 or greater dies, create two 1/1 green and white Citizen creature tokens.$Blitz {2}{G}| +Crash the Party|New Capenna Commander|57|R|{5}{G}|Instant|||Create a tapped 4/4 green Rhino Warrior creature token for each tapped creature you control.| +Dodgy Jalopy|New Capenna Commander|58|R|{2}{G}|Artifact - Vehicle|*|5|Trample$Dodgy Jalopy's power is equal to the highest mana value among creatures you control.$Crew 3$Scavenge {2}{G}| +Family's Favor|New Capenna Commander|59|R|{2}{G}|Enchantment|||Whenever you attack, put a shield counter on target attacking creature. Until end of turn, it gains "Whenever this creature deals combat damage to a player, remove a shield counter from it. If you do, draw a card."| +First Responder|New Capenna Commander|60|R|{3}{G}|Creature - Ogre Citizen|3|3|Vigilance$At the beginning of your end step, you may return another creature you control to its owner's hand, then put a number of +1/+1 counters equal to that creature's power on First Responder.| +Killer Service|New Capenna Commander|61|R|{2}{G}|Enchantment|||When Killer Service enters the battlefield, create a number of Food tokens equal to the number of opponents you have.$At the beginning of your end step, you may pay {2} and sacrifice a token. If you do, create a 4/4 green Rhino Warrior creature token.| +Next of Kin|New Capenna Commander|62|R|{2}{G}|Enchantment - Aura|||Enchant creature$When enchanted creature dies, you may put a creature card you own with lesser mana value from your hand or from the command zone onto the battlefield. If you do, return Next of Kin to the battlefield attached to that creature at the beginning of the next end step.| +Park Heights Maverick|New Capenna Commander|63|R|{2}{G}|Creature - Human Soldier|2|2|Dethrone$Park Heights Maverick can't be blocked by creatures with power 2 or less.$Whenever Park Heights Maverick deals combat damage to a player or dies, proliferate.| +Scepter of Celebration|New Capenna Commander|64|R|{2}{G}|Artifact - Equipment|||Equipped creature gets +2/+0 and has trample.$Whenever equipped creature deals combat damage to a player, create that many 1/1 green and white Citizen creature tokens.$Equip {3}| +Vivien's Stampede|New Capenna Commander|65|R|{4}{G}{G}|Sorcery|||Each creature you control gains vigilance, trample, and melee until end of turn.$At the beginning of the next main phase this turn, draw a card for each player who was dealt combat damage this turn.| +Agent's Toolkit|New Capenna Commander|66|R|{1}{G}{U}|Artifact - Clue|||Agent's Toolkit enters the battlefield with a +1/+1 counter, a flying counter, a deathtouch counter, and a shield counter on it.$Whenever a creature enters the battlefield under your control, you may move a counter from Agent's Toolkit onto that creature.${2}, Sacrifice Agent's Toolkit: Draw a card.| +Bess, Soul Nourisher|New Capenna Commander|67|R|{1}{G}{W}|Legendary Creature - Human Citizen|1|1|Whenever one or more other creatures with base power and toughness 1/1 enter the battlefield under your control, put a +1/+1 counter on Bess, Soul Nourisher.$Whenever Bess attacks, each other creature you control with base power and toughness 1/1 gets +X/+X until end of turn, where X is the number of +1/+1 counters on Bess.| +Brokers Confluence|New Capenna Commander|68|R|{2}{G}{W}{U}|Instant|||Choose three. You may choose the same mode more than once.$• Proliferate.$• Target creature phases out.$• Counter target activated or triggered ability.| +Cabaretti Confluence|New Capenna Commander|69|R|{3}{R}{G}{W}|Sorcery|||Choose three. You may choose the same mode more than once.$• Create a token that's a copy of target creature you control. It gains haste. Sacrifice it at the beginning of the next end step.$• Exile target artifact or enchantment.$• Creatures target player controls gets +1/+1 and gain first strike until end of turn.| +Cryptic Pursuit|New Capenna Commander|70|R|{2}{U}{R}|Enchantment|||Whenever you cast an instant or sorcery spell from your hand, manifest the top card of your library.$Whenever a face-down creature you control dies, exile it if it's an instant or sorcery card. You may cast that card until the end of your next turn.| +Denry Klin, Editor in Chief|New Capenna Commander|71|R|{2}{W}{U}|Legendary Creature - Cat Advisor|2|2|Denry Klin, Editor in Chief enters the battlefield with your choice of a +1/+1, first strike, or vigilance counter on it.$Whenever a nontoken creature you control enters the battlefield, if Denry has counters on it, put the same number and kind of counters on that creature.| +Grime Gorger|New Capenna Commander|72|R|{2}{B}{G}|Creature - Horror|3|3|Menace$Whenever Grime Gorger attacks, exile up to one card of each card type from defending player's graveyard. Put a +1/+1 on Grime Gorger for each card exiled this way.| +Jolene, the Plunder Queen|New Capenna Commander|73|R|{2}{R}{G}|Legendary Creature - Human Warrior|2|2|Whenever a player attacks one or more of your opponents, that attacking player creates a Treasure token.$If you would create one or more Treasure tokens, instead create those tokens plus an additional Treasure token.$Sacrifice five Treasures: Put five +1/+1 counters on Jolene.| +Life Insurance|New Capenna Commander|74|R|{3}{W}{B}|Enchantment|||Extort$Whenever a nontoken creature dies, you lose 1 life and create a Treasure token.| +Maestros Confluence|New Capenna Commander|75|R|{3}{U}{B}{R}|Sorcery|||Choose three. You may choose the same mode more than once.$• Return target monocolored instant or sorcery card from your graveyard to your hand.$• Target creature gets -3/-3 until end of turn.$• Goad each creature target player controls.| +Obscura Confluence|New Capenna Commander|76|R|{1}{W}{U}{B}|Instant|||Choose three. You may choose the same mode more than once.$• Until end of turn, target creature loses all abilities and has base power and toughness 1/1.$• Target creature connives.$• Target player returns a creature card from their graveyard to their hand.| +Oskar, Rubbish Reclaimer|New Capenna Commander|77|R|{3}{U}{B}|Legendary Creature - Human Wizard|3|3|This spell costs {1} less to cast for each different mana value among cards in your graveyard.$Whenever you discard a nonland card, you may cast it from your graveyard.| +Prosperous Partnership|New Capenna Commander|78|R|{1}{R}{W}|Enchantment|||When Prosperous Partnership enters the battlefield, create two 1/1 green and white Citizen creature tokens.$Tap three untapped creatures you control: Create a Treasure token.| +Riveteers Confluence|New Capenna Commander|79|R|{2}{B}{R}{G}|Sorcery|||Choose three. You may choose the same mode more than once.$• You draw a card and you lose 1 life.$• Riveteers Confluence deals 1 damage to each creature and planeswalker you don't control.$• You may put a land card from your hand or graveyard onto the battlefield tapped.| +Syrix, Carrier of the Flame|New Capenna Commander|80|R|{2}{B}{R}|Legendary Creature - Phoenix|3|3|Flying, haste$At the beginning of each end step, if a creature card left your graveyard this turn, target Phoenix you control deals damage equal to its power to any target.$Whenever another Phoenix you control dies, you may cast Syrix, Carrier of the Flame from your graveyard.| +Currency Converter|New Capenna Commander|81|R|{1}|Artifact|||Whenever you discard a card, you may exile that card from your graveyard.${2}, {T}: Draw a card, then discard a card.${T}: Put a card exiled with Currency Converter into your graveyard. If it's a land card, create a Treasure token. If it's a nonland card, create a 2/2 black Rogue creature token.| +False Floor|New Capenna Commander|82|R|{4}|Artifact|||False Floor enters the battlefield tapped.$Creatures enter the battlefield tapped.${2}, {T}, Exile False Floor: Exile all untapped creatures. Activate only as a sorcery.| +Gavel of the Righteous|New Capenna Commander|83|R|{2}|Artifact - Equipment|||At the beginning of combat on your turn, put a charge counter on Gavel of the Righteous.$Equipped creature gets +1/+1 for each counter on Gavel of the Righteous.$As long as Gavel of the Righteous has four or more counters on it, equipped creature has double strike.$Equip—Pay {3} or remove a counter from Gavel of the Righteous.| +Smuggler's Buggy|New Capenna Commander|84|R|{4}|Artifact - Vehicle|5|5|Hideaway 4$Whenever Smuggler's Buggy deals combat damage to a player, you may cast the exiled card without paying its mana cost. If you do, return Smuggler's Buggy to its owner's hand.$Crew 2| +Weathered Sentinels|New Capenna Commander|85|R|{3}|Artifact Creature - Wall|2|5|Defender, vigilance, reach, trample$Weathered Sentinels can attack players who attacked you during their last turn as though it didn't have defender.$Whenever Weathered Sentinels attacks, it gets +3/+3 and gains indestructible until end of turn.| +Bennie Bracks, Zoologist|New Capenna Commander|86|M|{3}{W}|Legendary Creature - Elf Druid|3|2|Convoke$At the beginning of each end step, if you created a token this turn, draw a card.| +Tenuous Truce|New Capenna Commander|87|R|{1}{W}|Enchantment - Aura|||Enchant opponent$At the beginning of enchanted opponent's end step, you and that player each draw a card.$When you attack enchanted opponent or a planeswalker they control or when they attack you or a planeswalker you control, sacrifice Tenuous Truce.| +Swindler's Scheme|New Capenna Commander|88|R|{2}{U}|Enchantment|||Whenever an opponent casts a spell from their hand, you may reveal the top card of your library. If it shares a card type with that spell, counter that spell and that opponent may cast the revealed card without paying its mana cost.| +Mari, the Killing Quill|New Capenna Commander|89|R|{1}{B}{B}|Legendary Creature - Vampire Assassin|3|2|Whenever a creature an opponent controls dies, exile it with a hit counter on it.$Assassins, Mercenaries, and Rogues you control have deathtouch and "Whenever this creature deals combat damage to a player, you may remove a hit counter from a card that player owns in exile. If you do, draw a card and create two Treasure tokens."| +Spiteful Repossession|New Capenna Commander|90|R|{4}{R}|Sorcery|||Spiteful Repossession deals damage to each opponent who controls more lands than you equal to the difference. Then create a number of Treasure tokens equal to the damage dealt this way.| +Boxing Ring|New Capenna Commander|91|R|{1}{G}|Artifact|||Whenever a creature enters the battlefield under your control, it fights up to one target creature you don't control with the same mana value.${T}: Create a Treasure token. Activate only if you control a creature that fought this turn.| +Vazi, Keen Negotiator|New Capenna Commander|92|R|{2}{B}{R}{G}|Legendary Creature - Human Advisor|3|3|Haste${T}: Target opponent creates X Treasure tokens, where X is the number of Treasure tokens you created this turn.$Whenever an opponent casts a spell or activates an ability, if mana from a Treasure was spent to cast or activate it, put a +1/+1 counter on target creature, then draw a card.| +Threefold Signal|New Capenna Commander|93|M|{3}|Artifact|||When Threefold Signal enters the battlefield, scry 3.$Each spell you cast that's exactly three colors has replicate {3}.| +Artisan of Kozilek|New Capenna Commander|191|U|{9}|Creature - Eldrazi|10|9|When you cast this spell, you may return target creature card from your graveyard to the battlefield.$Annihilator 2| +Archon of Coronation|New Capenna Commander|192|M|{4}{W}{W}|Creature - Archon|5|5|Flying$When Archon of Coronation enters the battlefield, you become the monarch.$As long as you're the monarch, damage doesn't cause you to lose life.| +Austere Command|New Capenna Commander|193|R|{4}{W}{W}|Sorcery|||Choose two —$• Destroy all artifacts.$• Destroy all enchantments.$• Destroy all creatures with mana value 3 or less.$• Destroy all creatures with mana value 4 or greater.| +Avenging Huntbonder|New Capenna Commander|194|R|{3}{W}{W}|Creature - Human Warrior|3|3|Double strike$Whenever Avenging Huntbonder attacks, put a double strike counter on another target attacking creature.| +Call the Coppercoats|New Capenna Commander|195|R|{2}{W}|Instant|||Strive — This spell costs {1}{W} more to cast for each target beyond the first.$Choose any number of target opponents. Create X 1/1 white Human Soldier creature tokens, where X is the number of creatures those opponents control.| +Declaration in Stone|New Capenna Commander|196|R|{1}{W}|Sorcery|||Exile target creature and all other creatures its controller controls with the same name as that creature. That player investigates for each nontoken creature exiled this way.| +Duelist's Heritage|New Capenna Commander|197|R|{2}{W}|Enchantment|||Whenever one or more creatures attack, you may have target attacking creature gain double strike until end of turn.| +Dusk // Dawn|New Capenna Commander|198|R|{2}{W}{W}|Sorcery|||Destroy all creatures with power 3 or greater.$Dawn${3}{W}{W}$Sorcery$Aftermath$Return all creature cards with power 2 or less from your graveyard to your hand.| +Felidar Retreat|New Capenna Commander|199|R|{3}{W}|Enchantment|||Landfall — Whenever a land enters the battlefield under your control, choose one —$• Create a 2/2 white Cat Beast creature token.$• Put a +1/+1 counter on each creature you control. Those creatures gain vigilance until end of turn.| +Fell the Mighty|New Capenna Commander|200|R|{4}{W}|Sorcery|||Destroy all creatures with power greater than target creature's power.| +Generous Gift|New Capenna Commander|201|U|{2}{W}|Instant|||Destroy target permanent. Its controller creates a 3/3 green Elephant creature token.| +Grateful Apparition|New Capenna Commander|202|U|{1}{W}|Creature - Spirit|1|1|Flying$Whenever Grateful Apparition deals combat damage to a player or planeswalker, proliferate.| +Hoofprints of the Stag|New Capenna Commander|203|R|{1}{W}|Tribal Enchantment - Elemental|||Whenever you draw a card, you may put a hoofprint counter on Hoofprints of the Stag.${2}{W}, Remove four hoofprint counters from Hoofprints of the Stag: Create a 4/4 white Elemental creature token with flying. Activate only during your turn.| +Intangible Virtue|New Capenna Commander|204|U|{1}{W}|Enchantment|||Creature tokens you control get +1/+1 and have vigilance.| +Luminarch Aspirant|New Capenna Commander|205|R|{1}{W}|Creature - Human Cleric|1|1|At the beginning of combat on your turn, put a +1/+1 counter on target creature you control.| +Martial Coup|New Capenna Commander|206|R|{X}{W}{W}|Sorcery|||Create X 1/1 white Soldier creature tokens. If X is 5 or more, destroy all other creatures.| +Orzhov Advokist|New Capenna Commander|207|U|{2}{W}|Creature - Human Advisor|1|4|At the beginning of your upkeep, each player may put two +1/+1 counters on a creature they control. If a player does, creatures that player controls can't attack you or planeswalkers you control until your next turn.| +Path to Exile|New Capenna Commander|208|U|{W}|Instant|||Exile target creature. Its controller may search their library for a basic land card, put that card onto the battlefield tapped, then shuffle.| +Planar Outburst|New Capenna Commander|209|R|{3}{W}{W}|Sorcery|||Destroy all nonland creatures.$Awaken 4—{5}{W}{W}{W}| +Sun Titan|New Capenna Commander|210|M|{4}{W}{W}|Creature - Giant|6|6|Vigilance$Whenever Sun Titan enters the battlefield or attacks, you may return target permanent card with mana value 3 or less from your graveyard to the battlefield.| +Swords to Plowshares|New Capenna Commander|211|U|{W}|Instant|||Exile target creature. Its controller gains life equal to its power.| +Together Forever|New Capenna Commander|212|R|{W}{W}|Enchantment|||When Together Forever enters the battlefield, support 2.${1}: Choose target creature with a counter on it. When that creature dies this turn, return that card to its owner's hand.| +Champion of Wits|New Capenna Commander|213|R|{2}{U}|Creature - Naga Wizard|2|1|When Champion of Wits enters the battlefield, you may draw cards equal to its power. If you do, discard two cards.$Eternalize {5}{U}{U}| +Chasm Skulker|New Capenna Commander|214|R|{2}{U}|Creature - Squid Horror|1|1|Whenever you draw a card, put a +1/+1 counter on Chasm Skulker.$When Chasm Skulker dies, create X 1/1 blue Squid creature tokens with islandwalk, where X is the number of +1/+1 counters on Chasm Skulker.| +Clone Legion|New Capenna Commander|215|M|{7}{U}{U}|Sorcery|||For each creature target player controls, create a token that's a copy of that creature.| +Commit // Memory|New Capenna Commander|216|R|{3}{U}|Instant|||Put target spell or nonland permanent into its owner's library second from the top.$Memory${4}{U}{U}$Sorcery$Aftermath$Each player shuffles their hand and graveyard into their library, then draws seven cards.| +Daring Saboteur|New Capenna Commander|217|U|{1}{U}|Creature - Human Pirate|2|1|{2}{U}: Daring Saboteur can't be blocked this turn.$Whenever Daring Saboteur deals combat damage to a player, you may draw a card. If you do, discard a card.| +Deep Analysis|New Capenna Commander|218|C|{3}{U}|Sorcery|||Target player draws two cards.$Flashback—{1}{U}, Pay 3 life.| +Dig Through Time|New Capenna Commander|219|R|{6}{U}{U}|Instant|||Delve$Look at the top seven cards of your library. Put two of them into your hand and the rest on the bottom of your library in any order.| +Drawn from Dreams|New Capenna Commander|220|R|{2}{U}{U}|Sorcery|||Look at the top seven cards of your library. Put two of them into your hand and the rest on the bottom of your library in a random order.| +Fact or Fiction|New Capenna Commander|221|U|{3}{U}|Instant|||Reveal the top five cards of your library. An opponent separates those cards into two piles. Put one pile into your hand and the other into your graveyard.| +Frantic Search|New Capenna Commander|222|C|{2}{U}|Instant|||Draw two cards, then discard two cards. Untap up to three lands.| +Ghostly Pilferer|New Capenna Commander|223|R|{1}{U}|Creature - Spirit Rogue|2|1|Whenever Ghostly Pilferer becomes untapped, you may pay {2}. If you do, draw a card.$Whenever an opponent casts a spell from anywhere other than their hand, draw a card.$Discard a card: Ghostly Pilferer can't be blocked this turn.| +Identity Thief|New Capenna Commander|224|R|{2}{U}{U}|Creature - Shapeshifter|0|3|Whenever Identity Thief attacks, you may exile another target nontoken creature. If you do, Identity Thief becomes a copy of that creature until end of turn. Return the exiled card to the battlefield under its owner's control at the beginning of the next end step.| +Looter il-Kor|New Capenna Commander|225|C|{1}{U}|Creature - Kor Rogue|1|1|Shadow$Whenever Looter il-Kor deals damage to an opponent, draw a card, then discard a card.| +Midnight Clock|New Capenna Commander|226|R|{2}{U}|Artifact|||{T}: Add {U}.${2}{U}: Put an hour counter on Midnight Clock.$At the beginning of each upkeep, put an hour counter on Midnight Clock.$When the twelfth hour counter is put on Midnight Clock, shuffle your hand and graveyard into your library, then draw seven cards. Exile Midnight Clock.| +Mystic Confluence|New Capenna Commander|227|R|{3}{U}{U}|Instant|||Choose three. You may choose the same mode more than once.$• Counter target spell unless its controller pays {3}.$• Return target creature to its owner's hand.$• Draw a card.| +Nadir Kraken|New Capenna Commander|228|R|{1}{U}{U}|Creature - Kraken|2|3|Whenever you draw a card, you may pay {1}. If you do, put a +1/+1 counter on Nadir Kraken and create a 1/1 blue Tentacle creature token.| +Ponder|New Capenna Commander|229|C|{U}|Sorcery|||Look at the top three cards of your library, then put them back in any order. You may shuffle.$Draw a card.| +Preordain|New Capenna Commander|230|C|{U}|Sorcery|||Scry 2, then draw a card.| +River's Rebuke|New Capenna Commander|231|R|{4}{U}{U}|Sorcery|||Return all nonland permanents target player controls to their owner's hand.| +Skyship Plunderer|New Capenna Commander|232|U|{1}{U}|Creature - Human Pirate|2|1|Flying$Whenever Skyship Plunderer deals combat damage to a player, for each kind of counter on target permanent or player, give that permanent or player another counter of that kind.| +Stolen Identity|New Capenna Commander|233|R|{4}{U}{U}|Sorcery|||Create a token that's a copy of target artifact or creature.$Cipher| +Talrand's Invocation|New Capenna Commander|234|U|{2}{U}{U}|Sorcery|||Create two 2/2 blue Drake creature tokens with flying.| +Tezzeret's Gambit|New Capenna Commander|235|R|{3}{U/P}|Sorcery|||({U/P} can be paid with either {U} or 2 life.)$Draw two cards, then proliferate.| +Thrummingbird|New Capenna Commander|236|U|{1}{U}|Creature - Phyrexian Bird Horror|1|1|Flying$Whenever Thrummingbird deals combat damage to a player, proliferate.| +Treasure Cruise|New Capenna Commander|237|C|{7}{U}|Sorcery|||Delve$Draw three cards.| +Whirler Rogue|New Capenna Commander|238|U|{2}{U}{U}|Creature - Human Rogue Artificer|2|2|When Whirler Rogue enters the battlefield, create two 1/1 colorless Thopter artifact creature tokens with flying.$Tap two untapped artifacts you control: Target creature can't be blocked this turn.| +Wingspan Mentor|New Capenna Commander|239|U|{2}{U}|Creature - Human Wizard|1|3|When Wingspan Mentor enters the battlefield, put a flying counter on target non-Human creature you control.${2}{U}, {T}: Put a +1/+1 counter on each creature you control with flying.| +Zndrsplt's Judgment|New Capenna Commander|240|R|{4}{U}|Sorcery|||For each player, choose friend or foe. Each friend creates a token that's a copy of a creature they control. Each foe returns a creature they control to its owner's hand.| +Aether Snap|New Capenna Commander|241|R|{3}{B}{B}|Sorcery|||Remove all counters from all permanents and exile all tokens.| +Army of the Damned|New Capenna Commander|242|M|{5}{B}{B}{B}|Sorcery|||Create thirteen tapped 2/2 black Zombie creature tokens.$Flashback {7}{B}{B}{B}| +Bloodsoaked Champion|New Capenna Commander|243|R|{B}|Creature - Human Warrior|2|1|Bloodsoaked Champion can't block.$Raid — {1}{B}: Return Bloodsoaked Champion from your graveyard to the battlefield. Activate only if you attacked this turn.| +Custodi Lich|New Capenna Commander|244|R|{3}{B}{B}|Creature - Zombie Cleric|4|2|When Custodi Lich enters the battlefield, you become the monarch.$Whenever you become the monarch, target player sacrifices a creature.| +Damnable Pact|New Capenna Commander|245|R|{X}{B}{B}|Sorcery|||Target player draws X cards and loses X life.| +Deathbringer Regent|New Capenna Commander|246|R|{5}{B}{B}|Creature - Dragon|5|6|Flying$When Deathbringer Regent enters the battlefield, if you cast it from your hand and there are five or more other creatures on the battlefield, destroy all other creatures.| +Disciple of Bolas|New Capenna Commander|247|R|{3}{B}|Creature - Human Wizard|2|1|When Disciple of Bolas enters the battlefield, sacrifice another creature. You gain X life and draw X cards, where X is that creature's power.| +Drana, Liberator of Malakir|New Capenna Commander|248|M|{1}{B}{B}|Legendary Creature - Vampire Ally|2|3|Flying, first strike$Whenever Drana, Liberator of Malakir deals combat damage to a player, put a +1/+1 counter on each attacking creature you control.| +Dread Summons|New Capenna Commander|249|R|{X}{B}{B}|Sorcery|||Each player mills X cards. For each creature card put into a graveyard this way, you create a tapped 2/2 black Zombie creature token.| +Feed the Swarm|New Capenna Commander|250|C|{1}{B}|Sorcery|||Destroy target creature or enchantment an opponent controls. You lose life equal to that permanent's mana value.| +Graveblade Marauder|New Capenna Commander|251|R|{2}{B}|Creature - Human Warrior|1|4|Deathtouch$Whenever Graveblade Marauder deals combat damage to a player, that player loses life equal to the number of creature cards in your graveyard.| +Hex|New Capenna Commander|252|R|{4}{B}{B}|Sorcery|||Destroy six target creatures.| +Nightmare Unmaking|New Capenna Commander|253|R|{3}{B}{B}|Sorcery|||Choose one —$• Exile each creature with power greater than the number of cards in your hand.$• Exile each creature with power less than the number of cards in your hand.| +Noxious Gearhulk|New Capenna Commander|254|M|{4}{B}{B}|Artifact Creature - Construct|5|4|Menace$When Noxious Gearhulk enters the battlefield, you may destroy another target creature. If a creature is destroyed this way, you gain life equal to its toughness.| +Painful Truths|New Capenna Commander|255|R|{2}{B}|Sorcery|||Converge — You draw X cards and you lose X life, where X is the number of colors of mana spent to cast this spell.| +Profane Command|New Capenna Commander|256|R|{X}{B}{B}|Sorcery|||Choose two —$• Target player loses X life.$• Return target creature card with mana value X or less from your graveyard to the battlefield.$• Target creature gets -X/-X until end of turn.$• Up to X target creatures gain fear until end of turn.| +Puppeteer Clique|New Capenna Commander|257|R|{3}{B}{B}|Creature - Faerie Wizard|3|2|Flying$When Puppeteer Clique enters the battlefield, put target creature card from an opponent's graveyard onto the battlefield under your control. It gains haste. At the beginning of your next end step, exile it.$Persist| +Reign of the Pit|New Capenna Commander|258|R|{4}{B}{B}|Sorcery|||Each player sacrifices a creature. Create an X/X black Demon creature token with flying, where X is the total power of the creatures sacrificed this way.| +Sever the Bloodline|New Capenna Commander|259|R|{3}{B}|Sorcery|||Exile target creature and all other creatures with the same name as that creature.$Flashback {5}{B}{B}| +Skyclave Shade|New Capenna Commander|260|R|{1}{B}|Creature - Shade|3|1|Kicker {2}{B}$Skyclave Shade can't block.$If Skyclave Shade was kicked, it enters the battlefield with two +1/+1 counters on it.$Landfall — Whenever a land enters the battlefield under your control, if Skyclave Shade is in your graveyard and it's your turn, you may cast it from your graveyard this turn.| +Victimize|New Capenna Commander|261|U|{2}{B}|Sorcery|||Choose two target creature cards in your graveyard. Sacrifice a creature. If you do, return the chosen cards to the battlefield tapped.| +Woe Strider|New Capenna Commander|262|R|{2}{B}|Creature - Horror|3|2|When Woe Strider enters the battlefield, create a 0/1 white Goat creature token.$Sacrifice another creature: Scry 1.$Escape—{3}{B}{B}, Exile four other cards from your graveyard.$Woe Strider escapes with two +1/+1 counters on it.| +Agitator Ant|New Capenna Commander|263|R|{2}{R}|Creature - Insect|2|2|At the beginning of your end step, each player may put two +1/+1 counters on a creature they control. Goad each creature that had counters put on it this way.| +Blasphemous Act|New Capenna Commander|264|R|{8}{R}|Sorcery|||This spell costs {1} less to cast for each creature on the battlefield.$Blasphemous Act deals 13 damage to each creature.| +Chain Reaction|New Capenna Commander|265|R|{2}{R}{R}|Sorcery|||Chain Reaction deals X damage to each creature, where X is the number of creatures on the battlefield.| +Chaos Warp|New Capenna Commander|266|R|{2}{R}|Instant|||The owner of target permanent shuffles it into their library, then reveals the top card of their library. If it's a permanent card, they put it onto the battlefield.| +Double Vision|New Capenna Commander|267|R|{3}{R}{R}|Enchantment|||Whenever you cast your first instant or sorcery spell each turn, copy that spell. You may choose new targets for the copy.| +Etali, Primal Storm|New Capenna Commander|268|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 spells from among those cards without paying their mana costs.| +Inferno Titan|New Capenna Commander|269|M|{4}{R}{R}|Creature - Giant|6|6|{R}: Inferno Titan gets +1/+0 until end of turn.$Whenever Inferno Titan enters the battlefield or attacks, it deals 3 damage divided as you choose among one, two, or three targets.| +Kazuul, Tyrant of the Cliffs|New Capenna Commander|270|R|{3}{R}{R}|Legendary Creature - Ogre Warrior|5|4|Whenever a creature an opponent controls attacks, if you're the defending player, create a 3/3 red Ogre creature token unless that creature's controller pays {3}.| +Magus of the Wheel|New Capenna Commander|271|R|{2}{R}|Creature - Human Wizard|3|3|{1}{R}, {T}, Sacrifice Magus of the Wheel: Each player discards their hand, then draws seven cards.| +Outpost Siege|New Capenna Commander|272|R|{3}{R}|Enchantment|||As Outpost Siege enters the battlefield, choose Khans or Dragons.$• Khans — At the beginning of your upkeep, exile the top card of your library. Until end of turn, you may play that card.$• Dragons — Whenever a creature you control leaves the battlefield, Outpost Siege deals 1 damage to any target.| +Rekindling Phoenix|New Capenna Commander|273|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."| +Rite of the Raging Storm|New Capenna Commander|274|U|{3}{R}{R}|Enchantment|||Creatures named Lightning Rager can't attack you or planeswalkers you control.$At the beginning of each player's upkeep, that player creates a 5/1 red Elemental creature token named Lightning Rager. It has trample, haste, and "At the beginning of the end step, sacrifice this creature."| +Squee, the Immortal|New Capenna Commander|275|R|{1}{R}{R}|Legendary Creature - Goblin|2|1|You may cast Squee, the Immortal from your graveyard or from exile.| +Stalking Vengeance|New Capenna Commander|276|R|{5}{R}{R}|Creature - Avatar|5|5|Haste$Whenever another creature you control dies, it deals damage equal to its power to target player or planeswalker.| +Warstorm Surge|New Capenna Commander|277|R|{5}{R}|Enchantment|||Whenever a creature enters the battlefield under your control, it deals damage equal to its power to any target.| +Zurzoth, Chaos Rider|New Capenna Commander|278|R|{2}{R}|Legendary Creature - Devil|2|3|Whenever an opponent draws their first card each turn, if it's not their turn, you create a 1/1 red Devil creature token with "When this creature dies, it deals 1 damage to any target."$Whenever one or more Devils you control attack one or more players, you and those players each draw a card, then discard a card at random.| +Arasta of the Endless Web|New Capenna Commander|279|R|{2}{G}{G}|Legendary Enchantment Creature - Spider|3|5|Reach$Whenever an opponent casts an instant or sorcery spell, create a 1/2 green Spider creature token with reach.| +Avenger of Zendikar|New Capenna Commander|280|M|{5}{G}{G}|Creature - Elemental|5|5|When Avenger of Zendikar enters the battlefield, create a 0/1 green Plant creature token for each land you control.$Landfall — Whenever a land enters the battlefield under your control, you may put a +1/+1 counter on each Plant creature you control.| +Awakening Zone|New Capenna Commander|281|R|{2}{G}|Enchantment|||At the beginning of your upkeep, you may create a 0/1 colorless Eldrazi Spawn creature token. It has "Sacrifice this creature: Add {C}."| +Beast Within|New Capenna Commander|282|U|{2}{G}|Instant|||Destroy target permanent. Its controller creates a 3/3 green Beast creature token.| +Beastmaster Ascension|New Capenna Commander|283|R|{2}{G}|Enchantment|||Whenever a creature you control attacks, you may put a quest counter on Beastmaster Ascension.$As long as Beastmaster Ascension has seven or more quest counters on it, creatures you control get +5/+5.| +Champion of Lambholt|New Capenna Commander|284|R|{1}{G}{G}|Creature - Human Warrior|1|1|Creatures with power less than Champion of Lambholt's power can't block creatures you control.$Whenever another creature enters the battlefield under your control, put a +1/+1 counter on Champion of Lambholt.| +Cultivate|New Capenna Commander|285|U|{2}{G}|Sorcery|||Search your library for up to two basic land cards, reveal those cards, put one onto the battlefield tapped and the other into your hand, then shuffle.| +Devoted Druid|New Capenna Commander|286|U|{1}{G}|Creature - Elf Druid|0|2|{T}: Add {G}.$Put a -1/-1 counter on Devoted Druid: Untap Devoted Druid.| +Evolution Sage|New Capenna Commander|287|U|{2}{G}|Creature - Elf Druid|3|2|Whenever a land enters the battlefield under your control, proliferate.| +Evolutionary Leap|New Capenna Commander|288|R|{1}{G}|Enchantment|||{G}, Sacrifice a creature: Reveal cards from the top of your library until you reveal a creature card. Put that card into your hand and the rest on the bottom of your library in a random order.| +Explore|New Capenna Commander|289|C|{1}{G}|Sorcery|||You may play an additional land this turn.$Draw a card.| +Farseek|New Capenna Commander|290|C|{1}{G}|Sorcery|||Search your library for a Plains, Island, Swamp, or Mountain card, put it onto the battlefield tapped, then shuffle.| +Forgotten Ancient|New Capenna Commander|291|R|{3}{G}|Creature - Elemental|0|3|Whenever a player casts a spell, you may put a +1/+1 counter on Forgotten Ancient.$At the beginning of your upkeep, you may move any number of +1/+1 counters from Forgotten Ancient onto other creatures.| +Garruk's Uprising|New Capenna Commander|292|U|{2}{G}|Enchantment|||When Garruk's Uprising enters the battlefield, if you control a creature with power 4 or greater, draw a card.$Creatures you control have trample.$Whenever a creature with power 4 or greater enters the battlefield under your control, draw a card.| +Giant Adephage|New Capenna Commander|293|M|{5}{G}{G}|Creature - Insect|7|7|Trample$Whenever Giant Adephage deals combat damage to a player, create a token that's a copy of Giant Adephage.| +Greenwarden of Murasa|New Capenna Commander|294|M|{4}{G}{G}|Creature - Elemental|5|4|When Greenwarden of Murasa enters the battlefield, you may return target card from your graveyard to your hand.$When Greenwarden of Murasa dies, you may exile it. If you do, return target card from your graveyard to your hand.| +Harmonize|New Capenna Commander|295|U|{2}{G}{G}|Sorcery|||Draw three cards.| +Incubation Druid|New Capenna Commander|296|R|{1}{G}|Creature - Elf Druid|0|2|{T}: Add one mana of any type that a land you control could produce. If Incubation Druid has a +1/+1 counter on it, add three mana of that type instead.${3}{G}{G}: Adapt 3.| +Indrik Stomphowler|New Capenna Commander|297|U|{4}{G}|Creature - Beast|4|4|When Indrik Stomphowler enters the battlefield, destroy target artifact or enchantment.| +Kodama's Reach|New Capenna Commander|298|C|{2}{G}|Sorcery - Arcane|||Search your library for up to two basic land cards, reveal those cards, put one onto the battlefield tapped and the other into your hand, then shuffle.| +Leafkin Druid|New Capenna Commander|299|C|{1}{G}|Creature - Elemental Druid|0|3|{T}: Add {G}. If you control four or more creatures, add {G}{G} instead.| +Life's Legacy|New Capenna Commander|300|R|{1}{G}|Sorcery|||As an additional cost to cast this spell, sacrifice a creature.$Draw cards equal to the sacrificed creature's power.| +Migration Path|New Capenna Commander|301|U|{3}{G}|Sorcery|||Search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle.$Cycling {2}| +Mitotic Slime|New Capenna Commander|302|R|{4}{G}|Creature - Ooze|4|4|When Mitotic Slime dies, create two 2/2 green Ooze creature tokens. They have "When this creature dies, create two 1/1 green Ooze creature tokens."| +Overgrown Battlement|New Capenna Commander|303|U|{1}{G}|Creature - Wall|0|4|Defender${T}: Add {G} for each creature with defender you control.| +Rampant Growth|New Capenna Commander|304|C|{1}{G}|Sorcery|||Search your library for a basic land card, put that card onto the battlefield tapped, then shuffle.| +Rishkar, Peema Renegade|New Capenna Commander|305|R|{2}{G}|Legendary Creature - Elf Druid|2|2|When Rishkar, Peema Renegade enters the battlefield, put a +1/+1 counter on each of up to two target creatures.$Each creature you control with a counter on it has "{T}: Add {G}."| +Rishkar's Expertise|New Capenna Commander|306|R|{4}{G}{G}|Sorcery|||Draw cards equal to the greatest power among creatures you control.$You may cast a spell with mana value 5 or less from your hand without paying its mana cost.| +Sakura-Tribe Elder|New Capenna Commander|307|C|{1}{G}|Creature - Snake Shaman|1|1|Sacrifice Sakura-Tribe Elder: Search your library for a basic land card, put that card onto the battlefield tapped, then shuffle.| +Sandwurm Convergence|New Capenna Commander|308|R|{6}{G}{G}|Enchantment|||Creatures with flying can't attack you or planeswalkers you control.$At the beginning of your end step, create a 5/5 green Wurm creature token.| +Scavenging Ooze|New Capenna Commander|309|R|{1}{G}|Creature - Ooze|2|2|{G}: Exile target card from a graveyard. If it was a creature card, put a +1/+1 counter on Scavenging Ooze and you gain 1 life.| +Scute Swarm|New Capenna Commander|310|R|{2}{G}|Creature - Insect|1|1|Landfall — Whenever a land enters the battlefield under your control, create a 1/1 green Insect creature token. If you control six or more lands, create a token that's a copy of Scute Swarm instead.| +Shamanic Revelation|New Capenna Commander|311|R|{3}{G}{G}|Sorcery|||Draw a card for each creature you control.$Ferocious — You gain 4 life for each creature you control with power 4 or greater.| +Slippery Bogbonder|New Capenna Commander|312|R|{3}{G}|Creature - Human Druid|3|3|Flash$Hexproof$When Slippery Bogbonder enters the battlefield, put a hexproof counter on target creature. Then move any number of counters from among creatures you control onto that creature.| +Steelbane Hydra|New Capenna Commander|313|R|{X}{G}{G}|Creature - Turtle Hydra|0|0|Steelbane Hydra enters the battlefield with X +1/+1 counters on it.${2}{G}, Remove a +1/+1 counter from Steelbane Hydra: Destroy target artifact or enchantment.| +Sylvan Offering|New Capenna Commander|314|R|{X}{G}|Sorcery|||Choose an opponent. You and that player each create an X/X green Treefolk creature token.$Choose an opponent. You and that player each create X 1/1 green Elf Warrior creature tokens.| +Temur Sabertooth|New Capenna Commander|315|U|{2}{G}{G}|Creature - Cat|4|3|{1}{G}: You may return another creature you control to its owner's hand. If you do, Temur Sabertooth gains indestructible until end of turn.| +Thragtusk|New Capenna Commander|316|R|{4}{G}|Creature - Beast|5|3|When Thragtusk enters the battlefield, you gain 5 life.$When Thragtusk leaves the battlefield, create a 3/3 green Beast creature token.| +Thunderfoot Baloth|New Capenna Commander|317|R|{4}{G}{G}|Creature - Beast|5|5|Trample$Lieutenant — As long as you control your commander, Thunderfoot Baloth gets +2/+2 and other creatures you control get +2/+2 and have trample.| +Treeshaker Chimera|New Capenna Commander|318|R|{5}{G}{G}|Creature - Chimera|8|5|All creatures able to block Treeshaker Chimera do so.$When Treeshaker Chimera dies, draw three cards.| +Wall of Roots|New Capenna Commander|319|C|{1}{G}|Creature - Plant Wall|0|5|Defender$Put a -0/-1 counter on Wall of Roots: Add {G}. Activate only once each turn.| +Wickerbough Elder|New Capenna Commander|320|C|{3}{G}|Creature - Treefolk Shaman|4|4|Wickerbough Elder enters the battlefield with a -1/-1 counter on it.${G}, Remove a -1/-1 counter from Wickerbough Elder: Destroy target artifact or enchantment.| +Wood Elves|New Capenna Commander|321|C|{2}{G}|Creature - Elf Scout|1|1|When Wood Elves enters the battlefield, search your library for a Forest card, put that card onto the battlefield, then shuffle.| +Woodfall Primus|New Capenna Commander|322|R|{5}{G}{G}{G}|Creature - Treefolk Shaman|6|6|Trample$When Woodfall Primus enters the battlefield, destroy target noncreature permanent.$Persist| +World Shaper|New Capenna Commander|323|R|{3}{G}|Creature - Merfolk Shaman|3|3|Whenever World Shaper attacks, you may mill three cards.$When World Shaper dies, return all land cards from your graveyard to the battlefield tapped.| +Ajani Unyielding|New Capenna Commander|324|M|{4}{G}{W}|Legendary Planeswalker - Ajani|4|+2: Reveal the top three cards of your library. Put all nonland permanent cards revealed this way into your hand and the rest on the bottom of your library in any order.$−2: Exile target creature. Its controller gains life equal to its power.$−9: Put five +1/+1 counters on each creature you control and five loyalty counters on each other planeswalker you control.| +Alela, Artful Provocateur|New Capenna Commander|325|M|{1}{W}{U}{B}|Legendary Creature - Faerie Warlock|2|3|Flying, deathtouch, lifelink$Other creatures you control with flying get +1/+0.$Whenever you cast an artifact or enchantment spell, create a 1/1 blue Faerie creature token with flying.| +Artifact Mutation|New Capenna Commander|326|R|{R}{G}|Instant|||Destroy target artifact. It can't be regenerated. Create X 1/1 green Saproling creature tokens, where X is that artifact's mana value.| +Assemble the Legion|New Capenna Commander|327|R|{3}{R}{W}|Enchantment|||At the beginning of your upkeep, put a muster counter on Assemble the Legion. Then create a 1/1 red and white Soldier creature token with haste for each muster counter on Assemble the Legion.| +Aura Mutation|New Capenna Commander|328|R|{G}{W}|Instant|||Destroy target enchantment. Create X 1/1 green Saproling creature tokens, where X is that enchantment's mana value.| +Aven Mimeomancer|New Capenna Commander|329|R|{1}{W}{U}|Creature - Bird Wizard|3|1|Flying$At the beginning of your upkeep, you may put a feather counter on target creature. If you do, that creature has base power and toughness 3/1 and has flying for as long as it has a feather counter on it.| +Bant Charm|New Capenna Commander|330|U|{G}{W}{U}|Instant|||Choose one —$• Destroy target artifact.$• Put target creature on the bottom of its owner's library.$• Counter target instant spell.| +Bedevil|New Capenna Commander|331|R|{B}{B}{R}|Instant|||Destroy target artifact, creature, or planeswalker.| +Boros Charm|New Capenna Commander|332|U|{R}{W}|Instant|||Choose one —$• Boros Charm deals 4 damage to target player or planeswalker.$• Permanents you control gain indestructible until end of turn.$• Target creature gains double strike until end of turn.| +Call the Skybreaker|New Capenna Commander|333|R|{5}{U/R}{U/R}|Sorcery|||Create a 5/5 blue and red Elemental creature token with flying.$Retrace| +Camaraderie|New Capenna Commander|334|R|{4}{G}{W}|Sorcery|||You gain X life and draw X cards, where X is the number of creatures you control. Creatures you control get +1/+1 until end of turn.| +Daxos of Meletis|New Capenna Commander|335|R|{1}{W}{U}|Legendary Creature - Human Soldier|2|2|Daxos of Meletis can't be blocked by creatures with power 3 or greater.$Whenever Daxos of Meletis deals combat damage to a player, exile the top card of that player's library. You gain life equal to that card's mana value. Until end of turn, you may cast that card and you may spend mana as though it were mana of any color to cast that spell.| +Deathreap Ritual|New Capenna Commander|336|U|{2}{B}{G}|Enchantment|||Morbid — At the beginning of each end step, if a creature died this turn, you may draw a card.| +Dragonlord Ojutai|New Capenna Commander|337|M|{3}{W}{U}|Legendary Creature - Elder Dragon|5|4|Flying$Dragonlord Ojutai has hexproof as long as it's untapped.$Whenever Dragonlord Ojutai deals combat damage to a player, look at the top three cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order.| +Fallen Shinobi|New Capenna Commander|338|R|{3}{U}{B}|Creature - Zombie Ninja|5|4|Ninjutsu {2}{U}{B}$Whenever Fallen Shinobi deals combat damage to a player, that player exiles the top two cards of their library. Until end of turn, you may play those cards without paying their mana costs.| +Fathom Mage|New Capenna Commander|339|R|{2}{G}{U}|Creature - Human Wizard|1|1|Evolve$Whenever a +1/+1 counter is put on Fathom Mage, you may draw a card.| +Gahiji, Honored One|New Capenna Commander|340|M|{2}{R}{G}{W}|Legendary Creature - Beast|4|4|Whenever a creature attacks one of your opponents or a planeswalker an opponent controls, that creature gets +2/+0 until end of turn.| +Goblin Electromancer|New Capenna Commander|341|C|{U}{R}|Creature - Goblin Wizard|2|2|Instant and sorcery spells you cast cost {1} less to cast.| +Inkfathom Witch|New Capenna Commander|342|U|{1}{U/B}|Creature - Merfolk Wizard|1|1|Fear${2}{U}{B}: Each unblocked creature has base power and toughness 4/1 until end of turn.| +Jenara, Asura of War|New Capenna Commander|343|M|{G}{W}{U}|Legendary Creature - Angel|3|3|Flying${1}{W}: Put a +1/+1 counter on Jenara, Asura of War.| +Kess, Dissident Mage|New Capenna Commander|344|M|{1}{U}{B}{R}|Legendary Creature - Human Wizard|3|4|Flying$Once during each of your turns, you may cast an instant or sorcery spell from your graveyard. If a spell cast this way would be put into your graveyard, exile it instead.| +Kresh the Bloodbraided|New Capenna Commander|345|M|{2}{B}{R}{G}|Legendary Creature - Human Warrior|3|3|Whenever another creature dies, you may put X +1/+1 counters on Kresh the Bloodbraided, where X is that creature's power.| +March of the Multitudes|New Capenna Commander|346|M|{X}{G}{W}{W}|Instant|||Convoke$Create X 1/1 white Soldier creature tokens with lifelink.| +Mask of Riddles|New Capenna Commander|347|U|{U}{B}|Artifact - Equipment|||Equipped creature has fear.$Whenever equipped creature deals combat damage to a player, you may draw a card.$Equip {2}| +Primal Empathy|New Capenna Commander|348|U|{1}{G}{U}|Enchantment|||At the beginning of your upkeep, draw a card if you control a creature with the greatest power among creatures on the battlefield. Otherwise, put a +1/+1 counter on a creature you control.| +Roalesk, Apex Hybrid|New Capenna Commander|349|M|{2}{G}{G}{U}|Legendary Creature - Human Mutant|4|5|Flying, trample$When Roalesk, Apex Hybrid enters the battlefield, put two +1/+1 counters on another target creature you control.$When Roalesk dies, proliferate, then proliferate again.| +Selvala, Explorer Returned|New Capenna Commander|350|R|{1}{G}{W}|Legendary Creature - Elf Scout|2|4|Parley — {T}: Each player reveals the top card of their library. For each nonland card revealed this way, add {G} and you gain 1 life. Then each player draws a card.| +Shadowmage Infiltrator|New Capenna Commander|351|U|{1}{U}{B}|Creature - Human Wizard|1|3|Fear$Whenever Shadowmage Infiltrator deals combat damage to a player, you may draw a card.| +Silent-Blade Oni|New Capenna Commander|352|R|{3}{U}{U}{B}{B}|Creature - Demon Ninja|6|5|Ninjutsu {4}{U}{B}$Whenever Silent-Blade Oni deals combat damage to a player, look at that player's hand. You may cast a spell from among those cards without paying its mana cost.| +Terminate|New Capenna Commander|353|U|{B}{R}|Instant|||Destroy target creature. It can't be regenerated.| +Thief of Sanity|New Capenna Commander|354|R|{1}{U}{B}|Creature - Specter|2|2|Flying$Whenever Thief of Sanity deals combat damage to a player, look at the top three cards of that player's library, exile one of them face down, then put the rest into their graveyard. You may look at and cast that card for as long as it remains exiled, and you may spend mana as though it were mana of any type to cast that spell.| +Urban Evolution|New Capenna Commander|355|U|{3}{G}{U}|Sorcery|||Draw three cards. You may play an additional land this turn.| +Utter End|New Capenna Commander|356|R|{2}{W}{B}|Instant|||Exile target nonland permanent.| +Vorel of the Hull Clade|New Capenna Commander|357|R|{1}{G}{U}|Legendary Creature - Human Merfolk|1|4|{G}{U}, {T}: Double the number of each kind of counter on target artifact, creature, or land.| +Windgrace's Judgment|New Capenna Commander|358|R|{3}{B}{G}|Instant|||For any number of opponents, destroy target nonland permanent that player controls.| +Wrexial, the Risen Deep|New Capenna Commander|359|M|{3}{U}{U}{B}|Legendary Creature - Kraken|5|8|Islandwalk, swampwalk$Whenever Wrexial, the Risen Deep deals combat damage to a player, you may cast target instant or sorcery card from that player's graveyard without paying its mana cost. If that spell would be put into a graveyard this turn, exile it instead.| +Arcane Signet|New Capenna Commander|360|C|{2}|Artifact|||{T}: Add one mana of any color in your commander's color identity.| +Azorius Signet|New Capenna Commander|361|U|{2}|Artifact|||{1}, {T}: Add {W}{U}.| +Bloodthirsty Blade|New Capenna Commander|362|U|{2}|Artifact - Equipment|||Equipped creature gets +2/+0 and is goaded.${1}: Attach Bloodthirsty Blade to target creature an opponent controls. Activate only as a sorcery.| +Commander's Sphere|New Capenna Commander|363|C|{3}|Artifact|||{T}: Add one mana of any color in your commander's color identity.$Sacrifice Commander's Sphere: Draw a card.| +Crystalline Giant|New Capenna Commander|364|R|{3}|Artifact Creature - Giant|3|3|At the beginning of combat on your turn, choose a kind of counter at random that Crystalline Giant doesn't have on it from among flying, first strike, deathtouch, hexproof, lifelink, menace, reach, trample, vigilance, and +1/+1. Put a counter of that kind on Crystalline Giant.| +Dimir Signet|New Capenna Commander|365|C|{2}|Artifact|||{1}, {T}: Add {U}{B}.| +Everflowing Chalice|New Capenna Commander|366|C|{0}|Artifact|||Multikicker {2}$Everflowing Chalice enters the battlefield with a charge counter on it for each time it was kicked.${T}: Add {C} for each charge counter on Everflowing Chalice.| +Fellwar Stone|New Capenna Commander|367|U|{2}|Artifact|||{T}: Add one mana of any color that a land an opponent controls could produce.| +Idol of Oblivion|New Capenna Commander|368|R|{2}|Artifact|||{T}: Draw a card. Activate only if you created a token this turn.${8}, {T}, Sacrifice Idol of Oblivion: Create a 10/10 colorless Eldrazi creature token.| +Izzet Signet|New Capenna Commander|369|U|{2}|Artifact|||{1}, {T}: Add {U}{R}.| +Lifecrafter's Bestiary|New Capenna Commander|370|R|{3}|Artifact|||At the beginning of your upkeep, scry 1.$Whenever you cast a creature spell, you may pay {G}. If you do, draw a card.| +Lightning Greaves|New Capenna Commander|371|U|{2}|Artifact - Equipment|||Equipped creature has haste and shroud.$Equip {0}| +Mimic Vat|New Capenna Commander|372|R|{3}|Artifact|||Imprint — Whenever a nontoken creature dies, you may exile that card. If you do, return each other card exiled with Mimic Vat to its owner's graveyard.${3}, {T}: Create a token that's a copy of a card exiled with Mimic Vat. It gains haste. Exile it at the beginning of the next end step.| +Oblivion Stone|New Capenna Commander|373|R|{3}|Artifact|||{4}, {T}: Put a fate counter on target permanent.${5}, {T}, Sacrifice Oblivion Stone: Destroy each nonland permanent without a fate counter on it, then remove all fate counters from all permanents.| +Oracle's Vault|New Capenna Commander|374|R|{4}|Artifact|||{2}, {T}: Exile the top card of your library. Until end of turn, you may play that card. Put a brick counter on Oracle's Vault.${T}: Exile the top card of your library. Until end of turn, you may play that card without paying its mana cost. Activate only if there are three or more brick counters on Oracle's Vault.| +Orzhov Signet|New Capenna Commander|375|U|{2}|Artifact|||{1}, {T}: Add {W}{B}.| +Power Conduit|New Capenna Commander|376|U|{2}|Artifact|||{T}, Remove a counter from a permanent you control: Choose one —$• Put a charge counter on target artifact.$• Put a +1/+1 counter on target creature.| +Quietus Spike|New Capenna Commander|377|R|{3}|Artifact - Equipment|||Equipped creature has deathtouch.$Whenever equipped creature deals combat damage to a player, that player loses half their life, rounded up.$Equip {3}| +Rakdos Signet|New Capenna Commander|378|U|{2}|Artifact|||{1}, {T}: Add {B}{R}.| +Sol Ring|New Capenna Commander|379|U|{1}|Artifact|||{T}: Add {C}{C}.| +Solemn Simulacrum|New Capenna Commander|380|R|{4}|Artifact Creature - Golem|2|2|When Solemn Simulacrum enters the battlefield, you may search your library for a basic land card, put that card onto the battlefield tapped, then shuffle.$When Solemn Simulacrum dies, you may draw a card.| +Strionic Resonator|New Capenna Commander|381|R|{2}|Artifact|||{2}, {T}: Copy target triggered ability you control. You may choose new targets for the copy.| +Swiftfoot Boots|New Capenna Commander|382|U|{2}|Artifact - Equipment|||Equipped creature has hexproof and haste.$Equip {1}| +Twinning Staff|New Capenna Commander|383|R|{3}|Artifact|||If you would copy a spell one or more times, instead copy it that many times plus an additional time. You may choose new targets for the additional copy.${7}, {T}: Copy target instant or sorcery spell you control. You may choose new targets for the copy.| +Wayfarer's Bauble|New Capenna Commander|384|C|{1}|Artifact|||{2}, {T}, Sacrifice Wayfarer's Bauble: Search your library for a basic land card, put that card onto the battlefield tapped, then shuffle.| +Arcane Sanctum|New Capenna Commander|385|U||Land|||Arcane Sanctum enters the battlefield tapped.${T}: Add {W}, {U}, or {B}.| +Ash Barrens|New Capenna Commander|386|U||Land|||{T}: Add {C}.$Basic landcycling {1}| +Bant Panorama|New Capenna Commander|387|C||Land|||{T}: Add {C}.${1}, {T}, Sacrifice Bant Panorama: Search your library for a basic Forest, Plains, or Island card, put it onto the battlefield tapped, then shuffle.| +Blighted Woodland|New Capenna Commander|388|U||Land|||{T}: Add {C}.${3}{G}, {T}, Sacrifice Blighted Woodland: Search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle.| +Canopy Vista|New Capenna Commander|389|R||Land - Forest Plains|||({T}: Add {G} or {W}.)$Canopy Vista enters the battlefield tapped unless you control two or more basic lands.| +Cascade Bluffs|New Capenna Commander|390|R||Land|||{T}: Add {C}.${U/R}, {T}: Add {U}{U}, {U}{R}, or {R}{R}.| +Castle Ardenvale|New Capenna Commander|391|R||Land|||Castle Ardenvale enters the battlefield tapped unless you control a Plains.${T}: Add {W}.${2}{W}{W}, {T}: Create a 1/1 white Human creature token.| +Castle Embereth|New Capenna Commander|392|R||Land|||Castle Embereth enters the battlefield tapped unless you control a Mountain.${T}: Add {R}.${1}{R}{R}, {T}: Creatures you control get +1/+0 until end of turn.| +Choked Estuary|New Capenna Commander|393|R||Land|||As Choked Estuary enters the battlefield, you may reveal an Island or Swamp card from your hand. If you don't, Choked Estuary enters the battlefield tapped.${T}: Add {U} or {B}.| +Cinder Glade|New Capenna Commander|394|R||Land - Mountain Forest|||({T}: Add {R} or {G}.)$Cinder Glade enters the battlefield tapped unless you control two or more basic lands.| +Command Tower|New Capenna Commander|395|C||Land|||{T}: Add one mana of any color in your commander's color identity.| +Creeping Tar Pit|New Capenna Commander|396|R||Land|||Creeping Tar Pit enters the battlefield tapped.${T}: Add {U} or {B}.${1}{U}{B}: Creeping Tar Pit becomes a 3/2 blue and black Elemental creature until end of turn and can't be blocked this turn. It's still a land.| +Crumbling Necropolis|New Capenna Commander|397|U||Land|||Crumbling Necropolis enters the battlefield tapped.${T}: Add {U}, {B}, or {R}.| +Darkwater Catacombs|New Capenna Commander|398|R||Land|||{1}, {T}: Add {U}{B}.| +Esper Panorama|New Capenna Commander|399|C||Land|||{T}: Add {C}.${1}, {T}, Sacrifice Esper Panorama: Search your library for a basic Plains, Island, or Swamp card, put it onto the battlefield tapped, then shuffle.| +Exotic Orchard|New Capenna Commander|400|R||Land|||{T}: Add one mana of any color that a land an opponent controls could produce.| +Fetid Heath|New Capenna Commander|401|R||Land|||{T}: Add {C}.${W/B}, {T}: Add {W}{W}, {W}{B}, or {B}{B}.| +Flooded Grove|New Capenna Commander|402|R||Land|||{T}: Add {C}.${G/U}, {T}: Add {G}{G}, {G}{U}, or {U}{U}.| +Foreboding Ruins|New Capenna Commander|403|R||Land|||As Foreboding Ruins enters the battlefield, you may reveal a Swamp or Mountain card from your hand. If you don't, Foreboding Ruins enters the battlefield tapped.${T}: Add {B} or {R}.| +Fortified Village|New Capenna Commander|404|R||Land|||As Fortified Village enters the battlefield, you may reveal a Forest or Plains card from your hand. If you don't, Fortified Village enters the battlefield tapped.${T}: Add {G} or {W}.| +Game Trail|New Capenna Commander|405|R||Land|||As Game Trail enters the battlefield, you may reveal a Mountain or Forest card from your hand. If you don't, Game Trail enters the battlefield tapped.${T}: Add {R} or {G}.| +Gavony Township|New Capenna Commander|406|R||Land|||{T}: Add {C}.${2}{G}{W}, {T}: Put a +1/+1 counter on each creature you control.| +Grixis Panorama|New Capenna Commander|407|C||Land|||{T}: Add {C}.${1}, {T}, Sacrifice Grixis Panorama: Search your library for a basic Island, Swamp, or Mountain card, put it onto the battlefield tapped, then shuffle.| +Jund Panorama|New Capenna Commander|408|C||Land|||{T}: Add {C}.${1}, {T}, Sacrifice Jund Panorama: Search your library for a basic Swamp, Mountain, or Forest card, put it onto the battlefield tapped, then shuffle.| +Jungle Shrine|New Capenna Commander|409|U||Land|||Jungle Shrine enters the battlefield tapped.${T}: Add {R}, {G}, or {W}.| +Karn's Bastion|New Capenna Commander|410|R||Land|||{T}: Add {C}.${4}, {T}: Proliferate.| +Kessig Wolf Run|New Capenna Commander|411|R||Land|||{T}: Add {C}.${X}{R}{G}, {T}: Target creature gets +X/+0 and gains trample until end of turn.| +Littjara Mirrorlake|New Capenna Commander|412|U||Land|||Littjara Mirrorlake enters the battlefield tapped.${T}: Add {U}.${2}{G}{G}{U}, {T}, Sacrifice Littjara Mirrorlake: Create a token that's a copy of target creature you control, except it enters the battlefield with an additional +1/+1 counter on it. Activate only as a sorcery.| +Llanowar Reborn|New Capenna Commander|413|U||Land|||Llanowar Reborn enters the battlefield tapped.${T}: Add {G}.$Graft 1| +Mossfire Valley|New Capenna Commander|414|R||Land|||{1}, {T}: Add {R}{G}.| +Mosswort Bridge|New Capenna Commander|415|R||Land|||Hideaway${T}: Add {G}.${G}, {T}: You may play the exiled card without paying its mana cost if creatures you control have total power 10 or greater.| +Myriad Landscape|New Capenna Commander|416|U||Land|||Myriad Landscape enters the battlefield tapped.${T}: Add {C}.${2}, {T}, Sacrifice Myriad Landscape: Search your library for up to two basic land cards that share a land type, put them onto the battlefield tapped, then shuffle.| +Naya Panorama|New Capenna Commander|417|C||Land|||{T}: Add {C}.${1}, {T}, Sacrifice Naya Panorama: Search your library for a basic Mountain, Forest, or Plains card, put it onto the battlefield tapped, then shuffle.| +Nesting Grounds|New Capenna Commander|418|R||Land|||{T}: Add {C}.${1}, {T}: Move a counter from target permanent you control onto another target permanent. Activate only as a sorcery.| +Path of Ancestry|New Capenna Commander|419|C||Land|||Path of Ancestry enters the battlefield tapped.${T}: Add one mana of any color in your commander's color identity. When that mana is spent to cast a creature spell that shares a creature type with your commander, scry 1.| +Port Town|New Capenna Commander|420|R||Land|||As Port Town enters the battlefield, you may reveal a Plains or Island card from your hand. If you don't, Port Town enters the battlefield tapped.${T}: Add {W} or {U}.| +Prairie Stream|New Capenna Commander|421|R||Land - Plains Island|||({T}: Add {W} or {U}.)$Prairie Stream enters the battlefield tapped unless you control two or more basic lands.| +Rogue's Passage|New Capenna Commander|422|U||Land|||{T}: Add {C}.${4}, {T}: Target creature can't be blocked this turn.| +Rugged Prairie|New Capenna Commander|423|R||Land|||{T}: Add {C}.${R/W}, {T}: Add {R}{R}, {R}{W}, or {W}{W}.| +Savage Lands|New Capenna Commander|424|U||Land|||Savage Lands enters the battlefield tapped.${T}: Add {B}, {R}, or {G}.| +Seaside Citadel|New Capenna Commander|425|U||Land|||Seaside Citadel enters the battlefield tapped.${T}: Add {G}, {W}, or {U}.| +Shadowblood Ridge|New Capenna Commander|426|R||Land|||{1}, {T}: Add {B}{R}.| +Skycloud Expanse|New Capenna Commander|427|R||Land|||{1}, {T}: Add {W}{U}.| +Smoldering Marsh|New Capenna Commander|428|R||Land - Swamp Mountain|||({T}: Add {B} or {R}.)$Smoldering Marsh enters the battlefield tapped unless you control two or more basic lands.| +Spinerock Knoll|New Capenna Commander|429|R||Land|||Hideaway${T}: Add {R}.${R}, {T}: You may play the exiled card without paying its mana cost if an opponent was dealt 7 or more damage this turn.| +Sungrass Prairie|New Capenna Commander|430|R||Land|||{1}, {T}: Add {G}{W}.| +Sunken Hollow|New Capenna Commander|431|R||Land - Island Swamp|||({T}: Add {U} or {B}.)$Sunken Hollow enters the battlefield tapped unless you control two or more basic lands.| +Temple of Epiphany|New Capenna Commander|432|R||Land|||Temple of Epiphany enters the battlefield tapped.$When Temple of Epiphany enters the battlefield, scry 1.${T}: Add {U} or {R}.| +Temple of Malady|New Capenna Commander|433|R||Land|||Temple of Malady enters the battlefield tapped.$When Temple of Malady enters the battlefield, scry 1.${T}: Add {B} or {G}.| +Temple of Mystery|New Capenna Commander|434|R||Land|||Temple of Mystery enters the battlefield tapped.$When Temple of Mystery enters the battlefield, scry 1.${T}: Add {G} or {U}.| +Temple of Silence|New Capenna Commander|435|R||Land|||Temple of Silence enters the battlefield tapped.$When Temple of Silence enters the battlefield, scry 1.${T}: Add {W} or {B}.| +Temple of the False God|New Capenna Commander|436|U||Land|||{T}: Add {C}{C}. Activate only if you control five or more lands.| +Temple of Triumph|New Capenna Commander|437|R||Land|||Temple of Triumph enters the battlefield tapped.$When Temple of Triumph enters the battlefield, scry 1.${T}: Add {R} or {W}.| +Thriving Bluff|New Capenna Commander|438|C||Land|||Thriving Bluff enters the battlefield tapped.$As Thriving Bluff enters the battlefield, choose a color other than red.${T}: Add {R} or one mana of the chosen color.| +Thriving Grove|New Capenna Commander|439|C||Land|||Thriving Grove enters the battlefield tapped.$As Thriving Grove enters the battlefield, choose a color other than green.${T}: Add {G} or one mana of the chosen color.| +Thriving Heath|New Capenna Commander|440|C||Land|||Thriving Heath enters the battlefield tapped.$As Thriving Heath enters the battlefield, choose a color other than white.${T}: Add {W} or one mana of the chosen color.| +Thriving Isle|New Capenna Commander|441|C||Land|||Thriving Isle enters the battlefield tapped.$As Thriving Isle enters the battlefield, choose a color other than blue.${T}: Add {U} or one mana of the chosen color.| +Thriving Moor|New Capenna Commander|442|C||Land|||Thriving Moor enters the battlefield tapped.$As Thriving Moor enters the battlefield, choose a color other than black.${T}: Add {B} or one mana of the chosen color.| +Twilight Mire|New Capenna Commander|443|R||Land|||{T}: Add {C}.${B/G}, {T}: Add {B}{B}, {B}{G}, or {G}{G}.| +Vivid Creek|New Capenna Commander|444|U||Land|||Vivid Creek enters the battlefield tapped with two charge counters on it.${T}: Add {U}.${T}, Remove a charge counter from Vivid Creek: Add one mana of any color.| +Vivid Grove|New Capenna Commander|445|U||Land|||Vivid Grove enters the battlefield tapped with two charge counters on it.${T}: Add {G}.${T}, Remove a charge counter from Vivid Grove: Add one mana of any color.| +Vivid Meadow|New Capenna Commander|446|U||Land|||Vivid Meadow enters the battlefield tapped with two charge counters on it.${T}: Add {W}.${T}, Remove a charge counter from Vivid Meadow: Add one mana of any color.| +Windbrisk Heights|New Capenna Commander|447|R||Land|||Hideaway${T}: Add {W}.${W}, {T}: You may play the exiled card without paying its mana cost if you attacked with three or more creatures this turn.| diff --git a/Utils/mtg-sets-data.txt b/Utils/mtg-sets-data.txt index 4b3897e82d7..787435a4b97 100644 --- a/Utils/mtg-sets-data.txt +++ b/Utils/mtg-sets-data.txt @@ -8,6 +8,7 @@ Classic Sixth Edition|6ED| Seventh Edition|7ED| Eighth Edition|8ED| Ninth Edition|9ED| +Alchemy: Innistrad|Y22| Adventures in the Forgotten Realms|AFR| Forgotten Realms Commander|AFC| Aether Revolt|AER| @@ -39,6 +40,7 @@ Commander 2019 Edition|C19| Commander 2020 Edition|C20| Commander 2021 Edition|C21| Commander Legends|CMR| +Commander Legends: Battle for Baldur's Gate|CLB| Champions of Kamigawa|CHK| Chronicles|CHR| Clash Pack|CLASH| @@ -199,6 +201,8 @@ Shadowmoor|SHM| Shadows over Innistrad|SOI| Saviors of Kamigawa|SOK| Scars of Mirrodin|SOM| +Streets of New Capenna|SNC| +New Capenna Commander|NCC| Stronghold|STH| Super Series|SUS| Theros|THS|